12ea3f6a0SMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0 270f59c90SMayulong 370f59c90SMayulong #include <linux/delay.h> 470f59c90SMayulong #include <linux/err.h> 57f3ac6c5SMauro Carvalho Chehab #include <linux/interrupt.h> 670f59c90SMayulong #include <linux/io.h> 770f59c90SMayulong #include <linux/kernel.h> 870f59c90SMayulong #include <linux/module.h> 97f3ac6c5SMauro Carvalho Chehab #include <linux/of.h> 107f3ac6c5SMauro Carvalho Chehab #include <linux/platform_device.h> 1170f59c90SMayulong #include <linux/seq_file.h> 127f3ac6c5SMauro Carvalho Chehab #include <linux/slab.h> 1370f59c90SMayulong #include <linux/spmi.h> 1470f59c90SMayulong 1570f59c90SMayulong /* 1670f59c90SMayulong * SPMI register addr 1770f59c90SMayulong */ 1870f59c90SMayulong #define SPMI_CHANNEL_OFFSET 0x0300 1970f59c90SMayulong #define SPMI_SLAVE_OFFSET 0x20 2070f59c90SMayulong 2170f59c90SMayulong #define SPMI_APB_SPMI_CMD_BASE_ADDR 0x0100 222ea3f6a0SMauro Carvalho Chehab 2370f59c90SMayulong #define SPMI_APB_SPMI_WDATA0_BASE_ADDR 0x0104 2470f59c90SMayulong #define SPMI_APB_SPMI_WDATA1_BASE_ADDR 0x0108 2570f59c90SMayulong #define SPMI_APB_SPMI_WDATA2_BASE_ADDR 0x010c 2670f59c90SMayulong #define SPMI_APB_SPMI_WDATA3_BASE_ADDR 0x0110 2770f59c90SMayulong 2870f59c90SMayulong #define SPMI_APB_SPMI_STATUS_BASE_ADDR 0x0200 2970f59c90SMayulong 3070f59c90SMayulong #define SPMI_APB_SPMI_RDATA0_BASE_ADDR 0x0204 3170f59c90SMayulong #define SPMI_APB_SPMI_RDATA1_BASE_ADDR 0x0208 3270f59c90SMayulong #define SPMI_APB_SPMI_RDATA2_BASE_ADDR 0x020c 3370f59c90SMayulong #define SPMI_APB_SPMI_RDATA3_BASE_ADDR 0x0210 3470f59c90SMayulong 3570f59c90SMayulong #define SPMI_PER_DATAREG_BYTE 4 3670f59c90SMayulong /* 3770f59c90SMayulong * SPMI cmd register 3870f59c90SMayulong */ 392ea3f6a0SMauro Carvalho Chehab #define SPMI_APB_SPMI_CMD_EN BIT(31) 4070f59c90SMayulong #define SPMI_APB_SPMI_CMD_TYPE_OFFSET 24 4170f59c90SMayulong #define SPMI_APB_SPMI_CMD_LENGTH_OFFSET 20 42974e3bdcSMauro Carvalho Chehab #define SPMI_APB_SPMI_CMD_SLAVEID_OFFSET 16 43974e3bdcSMauro Carvalho Chehab #define SPMI_APB_SPMI_CMD_ADDR_OFFSET 0 4470f59c90SMayulong 4570f59c90SMayulong /* Command Opcodes */ 462ea3f6a0SMauro Carvalho Chehab 4770f59c90SMayulong enum spmi_controller_cmd_op_code { 4870f59c90SMayulong SPMI_CMD_REG_ZERO_WRITE = 0, 4970f59c90SMayulong SPMI_CMD_REG_WRITE = 1, 5070f59c90SMayulong SPMI_CMD_REG_READ = 2, 5170f59c90SMayulong SPMI_CMD_EXT_REG_WRITE = 3, 5270f59c90SMayulong SPMI_CMD_EXT_REG_READ = 4, 5370f59c90SMayulong SPMI_CMD_EXT_REG_WRITE_L = 5, 5470f59c90SMayulong SPMI_CMD_EXT_REG_READ_L = 6, 5570f59c90SMayulong SPMI_CMD_REG_RESET = 7, 5670f59c90SMayulong SPMI_CMD_REG_SLEEP = 8, 5770f59c90SMayulong SPMI_CMD_REG_SHUTDOWN = 9, 5870f59c90SMayulong SPMI_CMD_REG_WAKEUP = 10, 5970f59c90SMayulong }; 6070f59c90SMayulong 6170f59c90SMayulong /* 6270f59c90SMayulong * SPMI status register 6370f59c90SMayulong */ 642ea3f6a0SMauro Carvalho Chehab #define SPMI_APB_TRANS_DONE BIT(0) 652ea3f6a0SMauro Carvalho Chehab #define SPMI_APB_TRANS_FAIL BIT(2) 6670f59c90SMayulong 6770f59c90SMayulong /* Command register fields */ 6870f59c90SMayulong #define SPMI_CONTROLLER_CMD_MAX_BYTE_COUNT 16 6970f59c90SMayulong 7070f59c90SMayulong /* Maximum number of support PMIC peripherals */ 7170f59c90SMayulong #define SPMI_CONTROLLER_TIMEOUT_US 1000 72974e3bdcSMauro Carvalho Chehab #define SPMI_CONTROLLER_MAX_TRANS_BYTES 16 7370f59c90SMayulong 7470f59c90SMayulong struct spmi_controller_dev { 7570f59c90SMayulong struct spmi_controller *controller; 7670f59c90SMayulong struct device *dev; 7770f59c90SMayulong void __iomem *base; 7870f59c90SMayulong spinlock_t lock; 7970f59c90SMayulong u32 channel; 8070f59c90SMayulong }; 8170f59c90SMayulong 824d914a8cSMauro Carvalho Chehab static int spmi_controller_wait_for_done(struct device *dev, 834d914a8cSMauro Carvalho Chehab struct spmi_controller_dev *ctrl_dev, 8470f59c90SMayulong void __iomem *base, u8 sid, u16 addr) 8570f59c90SMayulong { 8670f59c90SMayulong u32 timeout = SPMI_CONTROLLER_TIMEOUT_US; 877f3ac6c5SMauro Carvalho Chehab u32 status, offset; 88974e3bdcSMauro Carvalho Chehab 89974e3bdcSMauro Carvalho Chehab offset = SPMI_APB_SPMI_STATUS_BASE_ADDR; 90974e3bdcSMauro Carvalho Chehab offset += SPMI_CHANNEL_OFFSET * ctrl_dev->channel + SPMI_SLAVE_OFFSET * sid; 9170f59c90SMayulong 927f3ac6c5SMauro Carvalho Chehab do { 932ea3f6a0SMauro Carvalho Chehab status = readl(base + offset); 9470f59c90SMayulong 9570f59c90SMayulong if (status & SPMI_APB_TRANS_DONE) { 9670f59c90SMayulong if (status & SPMI_APB_TRANS_FAIL) { 974d914a8cSMauro Carvalho Chehab dev_err(dev, "%s: transaction failed (0x%x)\n", 9870f59c90SMayulong __func__, status); 9970f59c90SMayulong return -EIO; 10070f59c90SMayulong } 1014d914a8cSMauro Carvalho Chehab dev_dbg(dev, "%s: status 0x%x\n", __func__, status); 10270f59c90SMayulong return 0; 10370f59c90SMayulong } 1042ea3f6a0SMauro Carvalho Chehab udelay(1); 1057f3ac6c5SMauro Carvalho Chehab } while (timeout--); 10670f59c90SMayulong 1074d914a8cSMauro Carvalho Chehab dev_err(dev, "%s: timeout, status 0x%x\n", __func__, status); 1082ea3f6a0SMauro Carvalho Chehab return -ETIMEDOUT; 1092ea3f6a0SMauro Carvalho Chehab } 11070f59c90SMayulong 11170f59c90SMayulong static int spmi_read_cmd(struct spmi_controller *ctrl, 1127f3ac6c5SMauro Carvalho Chehab u8 opc, u8 slave_id, u16 slave_addr, u8 *__buf, size_t bc) 11370f59c90SMayulong { 11470f59c90SMayulong struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev); 1157f3ac6c5SMauro Carvalho Chehab u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel; 11670f59c90SMayulong unsigned long flags; 1176af36450SMauro Carvalho Chehab u8 *buf = __buf; 11870f59c90SMayulong u32 cmd, data; 11970f59c90SMayulong int rc; 12070f59c90SMayulong u8 op_code, i; 12170f59c90SMayulong 12270f59c90SMayulong if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) { 1234d914a8cSMauro Carvalho Chehab dev_err(&ctrl->dev, 1244c6491a3SYueHaibing "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n", 1254d914a8cSMauro Carvalho Chehab SPMI_CONTROLLER_MAX_TRANS_BYTES, bc); 12670f59c90SMayulong return -EINVAL; 12770f59c90SMayulong } 12870f59c90SMayulong 1297f3ac6c5SMauro Carvalho Chehab switch (opc) { 1307f3ac6c5SMauro Carvalho Chehab case SPMI_CMD_READ: 13170f59c90SMayulong op_code = SPMI_CMD_REG_READ; 1327f3ac6c5SMauro Carvalho Chehab break; 1337f3ac6c5SMauro Carvalho Chehab case SPMI_CMD_EXT_READ: 13470f59c90SMayulong op_code = SPMI_CMD_EXT_REG_READ; 1357f3ac6c5SMauro Carvalho Chehab break; 1367f3ac6c5SMauro Carvalho Chehab case SPMI_CMD_EXT_READL: 13770f59c90SMayulong op_code = SPMI_CMD_EXT_REG_READ_L; 1387f3ac6c5SMauro Carvalho Chehab break; 1397f3ac6c5SMauro Carvalho Chehab default: 1407f3ac6c5SMauro Carvalho Chehab dev_err(&ctrl->dev, "invalid read cmd 0x%x\n", opc); 14170f59c90SMayulong return -EINVAL; 14270f59c90SMayulong } 14370f59c90SMayulong 1442ea3f6a0SMauro Carvalho Chehab cmd = SPMI_APB_SPMI_CMD_EN | 1452ea3f6a0SMauro Carvalho Chehab (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) | 1462ea3f6a0SMauro Carvalho Chehab ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) | 1477f3ac6c5SMauro Carvalho Chehab ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) | /* slvid */ 1487f3ac6c5SMauro Carvalho Chehab ((slave_addr & 0xffff) << SPMI_APB_SPMI_CMD_ADDR_OFFSET); /* slave_addr */ 14970f59c90SMayulong 1502ea3f6a0SMauro Carvalho Chehab spin_lock_irqsave(&spmi_controller->lock, flags); 15170f59c90SMayulong 1522ea3f6a0SMauro Carvalho Chehab writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR); 15370f59c90SMayulong 1544d914a8cSMauro Carvalho Chehab rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller, 1557f3ac6c5SMauro Carvalho Chehab spmi_controller->base, slave_id, slave_addr); 15670f59c90SMayulong if (rc) 15770f59c90SMayulong goto done; 15870f59c90SMayulong 1597f3ac6c5SMauro Carvalho Chehab for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) { 1607f3ac6c5SMauro Carvalho Chehab data = readl(spmi_controller->base + chnl_ofst + 1617f3ac6c5SMauro Carvalho Chehab SPMI_SLAVE_OFFSET * slave_id + 1627f3ac6c5SMauro Carvalho Chehab SPMI_APB_SPMI_RDATA0_BASE_ADDR + 1637f3ac6c5SMauro Carvalho Chehab i * SPMI_PER_DATAREG_BYTE); 1641b9419d1SJuan Antonio Aldea-Armenteros data = be32_to_cpu((__be32 __force)data); 1652ea3f6a0SMauro Carvalho Chehab if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) { 16670f59c90SMayulong memcpy(buf, &data, sizeof(data)); 16770f59c90SMayulong buf += sizeof(data); 16870f59c90SMayulong } else { 1692ea3f6a0SMauro Carvalho Chehab memcpy(buf, &data, bc % SPMI_PER_DATAREG_BYTE); 17070f59c90SMayulong buf += (bc % SPMI_PER_DATAREG_BYTE); 17170f59c90SMayulong } 1727f3ac6c5SMauro Carvalho Chehab } 17370f59c90SMayulong 17470f59c90SMayulong done: 17570f59c90SMayulong spin_unlock_irqrestore(&spmi_controller->lock, flags); 17670f59c90SMayulong if (rc) 1774d914a8cSMauro Carvalho Chehab dev_err(&ctrl->dev, 1784c6491a3SYueHaibing "spmi read wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n", 1797f3ac6c5SMauro Carvalho Chehab opc, slave_id, slave_addr, bc + 1); 1806af36450SMauro Carvalho Chehab else 1817f3ac6c5SMauro Carvalho Chehab dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, read value: %*ph\n", 1827f3ac6c5SMauro Carvalho Chehab __func__, slave_id, slave_addr, (int)bc, __buf); 1836af36450SMauro Carvalho Chehab 18470f59c90SMayulong return rc; 1852ea3f6a0SMauro Carvalho Chehab } 18670f59c90SMayulong 18770f59c90SMayulong static int spmi_write_cmd(struct spmi_controller *ctrl, 1887f3ac6c5SMauro Carvalho Chehab u8 opc, u8 slave_id, u16 slave_addr, const u8 *__buf, size_t bc) 18970f59c90SMayulong { 19070f59c90SMayulong struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev); 1917f3ac6c5SMauro Carvalho Chehab u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel; 1926af36450SMauro Carvalho Chehab const u8 *buf = __buf; 19370f59c90SMayulong unsigned long flags; 1948788a30cSMauro Carvalho Chehab u32 cmd, data; 19570f59c90SMayulong int rc; 19670f59c90SMayulong u8 op_code, i; 19770f59c90SMayulong 19870f59c90SMayulong if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) { 1994d914a8cSMauro Carvalho Chehab dev_err(&ctrl->dev, 2004c6491a3SYueHaibing "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n", 2014d914a8cSMauro Carvalho Chehab SPMI_CONTROLLER_MAX_TRANS_BYTES, bc); 20270f59c90SMayulong return -EINVAL; 20370f59c90SMayulong } 20470f59c90SMayulong 2057f3ac6c5SMauro Carvalho Chehab switch (opc) { 2067f3ac6c5SMauro Carvalho Chehab case SPMI_CMD_WRITE: 20770f59c90SMayulong op_code = SPMI_CMD_REG_WRITE; 2087f3ac6c5SMauro Carvalho Chehab break; 2097f3ac6c5SMauro Carvalho Chehab case SPMI_CMD_EXT_WRITE: 21070f59c90SMayulong op_code = SPMI_CMD_EXT_REG_WRITE; 2117f3ac6c5SMauro Carvalho Chehab break; 2127f3ac6c5SMauro Carvalho Chehab case SPMI_CMD_EXT_WRITEL: 21370f59c90SMayulong op_code = SPMI_CMD_EXT_REG_WRITE_L; 2147f3ac6c5SMauro Carvalho Chehab break; 2157f3ac6c5SMauro Carvalho Chehab default: 2167f3ac6c5SMauro Carvalho Chehab dev_err(&ctrl->dev, "invalid write cmd 0x%x\n", opc); 21770f59c90SMayulong return -EINVAL; 21870f59c90SMayulong } 21970f59c90SMayulong 2202ea3f6a0SMauro Carvalho Chehab cmd = SPMI_APB_SPMI_CMD_EN | 2212ea3f6a0SMauro Carvalho Chehab (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) | 2222ea3f6a0SMauro Carvalho Chehab ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) | 2237f3ac6c5SMauro Carvalho Chehab ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) | 2247f3ac6c5SMauro Carvalho Chehab ((slave_addr & 0xffff) << SPMI_APB_SPMI_CMD_ADDR_OFFSET); 22570f59c90SMayulong 22670f59c90SMayulong /* Write data to FIFOs */ 2272ea3f6a0SMauro Carvalho Chehab spin_lock_irqsave(&spmi_controller->lock, flags); 22870f59c90SMayulong 2297f3ac6c5SMauro Carvalho Chehab for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) { 2308788a30cSMauro Carvalho Chehab data = 0; 2312ea3f6a0SMauro Carvalho Chehab if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) { 23270f59c90SMayulong memcpy(&data, buf, sizeof(data)); 23370f59c90SMayulong buf += sizeof(data); 23470f59c90SMayulong } else { 2352ea3f6a0SMauro Carvalho Chehab memcpy(&data, buf, bc % SPMI_PER_DATAREG_BYTE); 23670f59c90SMayulong buf += (bc % SPMI_PER_DATAREG_BYTE); 23770f59c90SMayulong } 23870f59c90SMayulong 2391b9419d1SJuan Antonio Aldea-Armenteros writel((u32 __force)cpu_to_be32(data), 2407f3ac6c5SMauro Carvalho Chehab spmi_controller->base + chnl_ofst + 2417f3ac6c5SMauro Carvalho Chehab SPMI_APB_SPMI_WDATA0_BASE_ADDR + 2427f3ac6c5SMauro Carvalho Chehab SPMI_PER_DATAREG_BYTE * i); 2437f3ac6c5SMauro Carvalho Chehab } 24470f59c90SMayulong 24570f59c90SMayulong /* Start the transaction */ 2462ea3f6a0SMauro Carvalho Chehab writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR); 24770f59c90SMayulong 2484d914a8cSMauro Carvalho Chehab rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller, 2497f3ac6c5SMauro Carvalho Chehab spmi_controller->base, slave_id, 2507f3ac6c5SMauro Carvalho Chehab slave_addr); 25170f59c90SMayulong spin_unlock_irqrestore(&spmi_controller->lock, flags); 25270f59c90SMayulong 25370f59c90SMayulong if (rc) 2544c6491a3SYueHaibing dev_err(&ctrl->dev, "spmi write wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n", 2557f3ac6c5SMauro Carvalho Chehab opc, slave_id, slave_addr, bc); 2566af36450SMauro Carvalho Chehab else 2577f3ac6c5SMauro Carvalho Chehab dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, wrote value: %*ph\n", 2587f3ac6c5SMauro Carvalho Chehab __func__, slave_id, slave_addr, (int)bc, __buf); 25970f59c90SMayulong 26070f59c90SMayulong return rc; 2612ea3f6a0SMauro Carvalho Chehab } 2622ea3f6a0SMauro Carvalho Chehab 26370f59c90SMayulong static int spmi_controller_probe(struct platform_device *pdev) 26470f59c90SMayulong { 26570f59c90SMayulong struct spmi_controller_dev *spmi_controller; 26670f59c90SMayulong struct spmi_controller *ctrl; 26770f59c90SMayulong struct resource *iores; 2687f3ac6c5SMauro Carvalho Chehab int ret; 2696af36450SMauro Carvalho Chehab 27070f59c90SMayulong ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*spmi_controller)); 27170f59c90SMayulong if (!ctrl) { 27270f59c90SMayulong dev_err(&pdev->dev, "can not allocate spmi_controller data\n"); 2732ea3f6a0SMauro Carvalho Chehab return -ENOMEM; 27470f59c90SMayulong } 27570f59c90SMayulong spmi_controller = spmi_controller_get_drvdata(ctrl); 27670f59c90SMayulong spmi_controller->controller = ctrl; 27770f59c90SMayulong 27870f59c90SMayulong iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); 27970f59c90SMayulong if (!iores) { 28070f59c90SMayulong dev_err(&pdev->dev, "can not get resource!\n"); 28112b38ea0SChristophe JAILLET ret = -EINVAL; 28212b38ea0SChristophe JAILLET goto err_put_controller; 28370f59c90SMayulong } 28470f59c90SMayulong 285dbbc8fdfSDan Carpenter spmi_controller->base = devm_ioremap(&pdev->dev, iores->start, 286dbbc8fdfSDan Carpenter resource_size(iores)); 28770f59c90SMayulong if (!spmi_controller->base) { 28870f59c90SMayulong dev_err(&pdev->dev, "can not remap base addr!\n"); 28912b38ea0SChristophe JAILLET ret = -EADDRNOTAVAIL; 29012b38ea0SChristophe JAILLET goto err_put_controller; 29170f59c90SMayulong } 29270f59c90SMayulong 293*fcc84fe1SMauro Carvalho Chehab ret = of_property_read_u32(pdev->dev.of_node, "hisilicon,spmi-channel", 2942ea3f6a0SMauro Carvalho Chehab &spmi_controller->channel); 29570f59c90SMayulong if (ret) { 2966196331eSMauro Carvalho Chehab dev_err(&pdev->dev, "can not get channel\n"); 29712b38ea0SChristophe JAILLET ret = -ENODEV; 29812b38ea0SChristophe JAILLET goto err_put_controller; 29970f59c90SMayulong } 30070f59c90SMayulong 30170f59c90SMayulong platform_set_drvdata(pdev, spmi_controller); 30270f59c90SMayulong dev_set_drvdata(&ctrl->dev, spmi_controller); 30370f59c90SMayulong 30470f59c90SMayulong spin_lock_init(&spmi_controller->lock); 30570f59c90SMayulong 30670f59c90SMayulong ctrl->nr = spmi_controller->channel; 30770f59c90SMayulong ctrl->dev.parent = pdev->dev.parent; 30870f59c90SMayulong ctrl->dev.of_node = of_node_get(pdev->dev.of_node); 30970f59c90SMayulong 31070f59c90SMayulong /* Callbacks */ 31170f59c90SMayulong ctrl->read_cmd = spmi_read_cmd; 31270f59c90SMayulong ctrl->write_cmd = spmi_write_cmd; 31370f59c90SMayulong 31470f59c90SMayulong ret = spmi_controller_add(ctrl); 31512b38ea0SChristophe JAILLET if (ret) { 31612b38ea0SChristophe JAILLET dev_err(&pdev->dev, "spmi_controller_add failed with error %d!\n", ret); 31712b38ea0SChristophe JAILLET goto err_put_controller; 31812b38ea0SChristophe JAILLET } 31985eb5344SMauro Carvalho Chehab 32012b38ea0SChristophe JAILLET return 0; 32112b38ea0SChristophe JAILLET 32212b38ea0SChristophe JAILLET err_put_controller: 32312b38ea0SChristophe JAILLET spmi_controller_put(ctrl); 3242ea3f6a0SMauro Carvalho Chehab return ret; 32570f59c90SMayulong } 32670f59c90SMayulong 32770f59c90SMayulong static int spmi_del_controller(struct platform_device *pdev) 32870f59c90SMayulong { 32970f59c90SMayulong struct spmi_controller *ctrl = platform_get_drvdata(pdev); 33070f59c90SMayulong 33170f59c90SMayulong spmi_controller_remove(ctrl); 33212b38ea0SChristophe JAILLET spmi_controller_put(ctrl); 33370f59c90SMayulong return 0; 33470f59c90SMayulong } 33570f59c90SMayulong 3362ea3f6a0SMauro Carvalho Chehab static const struct of_device_id spmi_controller_match_table[] = { 337de1a93b6SMauro Carvalho Chehab { 338de1a93b6SMauro Carvalho Chehab .compatible = "hisilicon,kirin970-spmi-controller", 3392ea3f6a0SMauro Carvalho Chehab }, 3402ea3f6a0SMauro Carvalho Chehab {} 34170f59c90SMayulong }; 34285eb5344SMauro Carvalho Chehab MODULE_DEVICE_TABLE(of, spmi_controller_match_table); 34370f59c90SMayulong 34470f59c90SMayulong static struct platform_driver spmi_controller_driver = { 34570f59c90SMayulong .probe = spmi_controller_probe, 34670f59c90SMayulong .remove = spmi_del_controller, 34770f59c90SMayulong .driver = { 3487f3ac6c5SMauro Carvalho Chehab .name = "hisi_spmi_controller", 34970f59c90SMayulong .of_match_table = spmi_controller_match_table, 3502ea3f6a0SMauro Carvalho Chehab }, 3512ea3f6a0SMauro Carvalho Chehab }; 3522ea3f6a0SMauro Carvalho Chehab 35370f59c90SMayulong static int __init spmi_controller_init(void) 35470f59c90SMayulong { 3552ea3f6a0SMauro Carvalho Chehab return platform_driver_register(&spmi_controller_driver); 35670f59c90SMayulong } 35770f59c90SMayulong postcore_initcall(spmi_controller_init); 35870f59c90SMayulong 35970f59c90SMayulong static void __exit spmi_controller_exit(void) 36070f59c90SMayulong { 36170f59c90SMayulong platform_driver_unregister(&spmi_controller_driver); 36270f59c90SMayulong } 36370f59c90SMayulong module_exit(spmi_controller_exit); 36470f59c90SMayulong 3652ea3f6a0SMauro Carvalho Chehab MODULE_LICENSE("GPL v2"); 3662ea3f6a0SMauro Carvalho Chehab MODULE_VERSION("1.0"); 367e4cebcaeSColin Ian King MODULE_ALIAS("platform:spmi_controller"); 368