0001
0002
0003
0004
0005 #include <linux/clk.h>
0006 #include <linux/iopoll.h>
0007 #include <linux/module.h>
0008 #include <linux/of.h>
0009 #include <linux/platform_device.h>
0010 #include <linux/property.h>
0011 #include <linux/spmi.h>
0012
0013 #define SWINF_IDLE 0x00
0014 #define SWINF_WFVLDCLR 0x06
0015
0016 #define GET_SWINF(x) (((x) >> 1) & 0x7)
0017
0018 #define PMIF_CMD_REG_0 0
0019 #define PMIF_CMD_REG 1
0020 #define PMIF_CMD_EXT_REG 2
0021 #define PMIF_CMD_EXT_REG_LONG 3
0022
0023 #define PMIF_DELAY_US 10
0024 #define PMIF_TIMEOUT_US (10 * 1000)
0025
0026 #define PMIF_CHAN_OFFSET 0x5
0027
0028 #define PMIF_MAX_CLKS 3
0029
0030 #define SPMI_OP_ST_BUSY 1
0031
0032 struct ch_reg {
0033 u32 ch_sta;
0034 u32 wdata;
0035 u32 rdata;
0036 u32 ch_send;
0037 u32 ch_rdy;
0038 };
0039
0040 struct pmif_data {
0041 const u32 *regs;
0042 const u32 *spmimst_regs;
0043 u32 soc_chan;
0044 };
0045
0046 struct pmif {
0047 void __iomem *base;
0048 void __iomem *spmimst_base;
0049 struct ch_reg chan;
0050 struct clk_bulk_data clks[PMIF_MAX_CLKS];
0051 size_t nclks;
0052 const struct pmif_data *data;
0053 };
0054
0055 static const char * const pmif_clock_names[] = {
0056 "pmif_sys_ck", "pmif_tmr_ck", "spmimst_clk_mux",
0057 };
0058
0059 enum pmif_regs {
0060 PMIF_INIT_DONE,
0061 PMIF_INF_EN,
0062 PMIF_ARB_EN,
0063 PMIF_CMDISSUE_EN,
0064 PMIF_TIMER_CTRL,
0065 PMIF_SPI_MODE_CTRL,
0066 PMIF_IRQ_EVENT_EN_0,
0067 PMIF_IRQ_FLAG_0,
0068 PMIF_IRQ_CLR_0,
0069 PMIF_IRQ_EVENT_EN_1,
0070 PMIF_IRQ_FLAG_1,
0071 PMIF_IRQ_CLR_1,
0072 PMIF_IRQ_EVENT_EN_2,
0073 PMIF_IRQ_FLAG_2,
0074 PMIF_IRQ_CLR_2,
0075 PMIF_IRQ_EVENT_EN_3,
0076 PMIF_IRQ_FLAG_3,
0077 PMIF_IRQ_CLR_3,
0078 PMIF_IRQ_EVENT_EN_4,
0079 PMIF_IRQ_FLAG_4,
0080 PMIF_IRQ_CLR_4,
0081 PMIF_WDT_EVENT_EN_0,
0082 PMIF_WDT_FLAG_0,
0083 PMIF_WDT_EVENT_EN_1,
0084 PMIF_WDT_FLAG_1,
0085 PMIF_SWINF_0_STA,
0086 PMIF_SWINF_0_WDATA_31_0,
0087 PMIF_SWINF_0_RDATA_31_0,
0088 PMIF_SWINF_0_ACC,
0089 PMIF_SWINF_0_VLD_CLR,
0090 PMIF_SWINF_1_STA,
0091 PMIF_SWINF_1_WDATA_31_0,
0092 PMIF_SWINF_1_RDATA_31_0,
0093 PMIF_SWINF_1_ACC,
0094 PMIF_SWINF_1_VLD_CLR,
0095 PMIF_SWINF_2_STA,
0096 PMIF_SWINF_2_WDATA_31_0,
0097 PMIF_SWINF_2_RDATA_31_0,
0098 PMIF_SWINF_2_ACC,
0099 PMIF_SWINF_2_VLD_CLR,
0100 PMIF_SWINF_3_STA,
0101 PMIF_SWINF_3_WDATA_31_0,
0102 PMIF_SWINF_3_RDATA_31_0,
0103 PMIF_SWINF_3_ACC,
0104 PMIF_SWINF_3_VLD_CLR,
0105 };
0106
0107 static const u32 mt6873_regs[] = {
0108 [PMIF_INIT_DONE] = 0x0000,
0109 [PMIF_INF_EN] = 0x0024,
0110 [PMIF_ARB_EN] = 0x0150,
0111 [PMIF_CMDISSUE_EN] = 0x03B4,
0112 [PMIF_TIMER_CTRL] = 0x03E0,
0113 [PMIF_SPI_MODE_CTRL] = 0x0400,
0114 [PMIF_IRQ_EVENT_EN_0] = 0x0418,
0115 [PMIF_IRQ_FLAG_0] = 0x0420,
0116 [PMIF_IRQ_CLR_0] = 0x0424,
0117 [PMIF_IRQ_EVENT_EN_1] = 0x0428,
0118 [PMIF_IRQ_FLAG_1] = 0x0430,
0119 [PMIF_IRQ_CLR_1] = 0x0434,
0120 [PMIF_IRQ_EVENT_EN_2] = 0x0438,
0121 [PMIF_IRQ_FLAG_2] = 0x0440,
0122 [PMIF_IRQ_CLR_2] = 0x0444,
0123 [PMIF_IRQ_EVENT_EN_3] = 0x0448,
0124 [PMIF_IRQ_FLAG_3] = 0x0450,
0125 [PMIF_IRQ_CLR_3] = 0x0454,
0126 [PMIF_IRQ_EVENT_EN_4] = 0x0458,
0127 [PMIF_IRQ_FLAG_4] = 0x0460,
0128 [PMIF_IRQ_CLR_4] = 0x0464,
0129 [PMIF_WDT_EVENT_EN_0] = 0x046C,
0130 [PMIF_WDT_FLAG_0] = 0x0470,
0131 [PMIF_WDT_EVENT_EN_1] = 0x0474,
0132 [PMIF_WDT_FLAG_1] = 0x0478,
0133 [PMIF_SWINF_0_ACC] = 0x0C00,
0134 [PMIF_SWINF_0_WDATA_31_0] = 0x0C04,
0135 [PMIF_SWINF_0_RDATA_31_0] = 0x0C14,
0136 [PMIF_SWINF_0_VLD_CLR] = 0x0C24,
0137 [PMIF_SWINF_0_STA] = 0x0C28,
0138 [PMIF_SWINF_1_ACC] = 0x0C40,
0139 [PMIF_SWINF_1_WDATA_31_0] = 0x0C44,
0140 [PMIF_SWINF_1_RDATA_31_0] = 0x0C54,
0141 [PMIF_SWINF_1_VLD_CLR] = 0x0C64,
0142 [PMIF_SWINF_1_STA] = 0x0C68,
0143 [PMIF_SWINF_2_ACC] = 0x0C80,
0144 [PMIF_SWINF_2_WDATA_31_0] = 0x0C84,
0145 [PMIF_SWINF_2_RDATA_31_0] = 0x0C94,
0146 [PMIF_SWINF_2_VLD_CLR] = 0x0CA4,
0147 [PMIF_SWINF_2_STA] = 0x0CA8,
0148 [PMIF_SWINF_3_ACC] = 0x0CC0,
0149 [PMIF_SWINF_3_WDATA_31_0] = 0x0CC4,
0150 [PMIF_SWINF_3_RDATA_31_0] = 0x0CD4,
0151 [PMIF_SWINF_3_VLD_CLR] = 0x0CE4,
0152 [PMIF_SWINF_3_STA] = 0x0CE8,
0153 };
0154
0155 static const u32 mt8195_regs[] = {
0156 [PMIF_INIT_DONE] = 0x0000,
0157 [PMIF_INF_EN] = 0x0024,
0158 [PMIF_ARB_EN] = 0x0150,
0159 [PMIF_CMDISSUE_EN] = 0x03B8,
0160 [PMIF_TIMER_CTRL] = 0x03E4,
0161 [PMIF_SPI_MODE_CTRL] = 0x0408,
0162 [PMIF_IRQ_EVENT_EN_0] = 0x0420,
0163 [PMIF_IRQ_FLAG_0] = 0x0428,
0164 [PMIF_IRQ_CLR_0] = 0x042C,
0165 [PMIF_IRQ_EVENT_EN_1] = 0x0430,
0166 [PMIF_IRQ_FLAG_1] = 0x0438,
0167 [PMIF_IRQ_CLR_1] = 0x043C,
0168 [PMIF_IRQ_EVENT_EN_2] = 0x0440,
0169 [PMIF_IRQ_FLAG_2] = 0x0448,
0170 [PMIF_IRQ_CLR_2] = 0x044C,
0171 [PMIF_IRQ_EVENT_EN_3] = 0x0450,
0172 [PMIF_IRQ_FLAG_3] = 0x0458,
0173 [PMIF_IRQ_CLR_3] = 0x045C,
0174 [PMIF_IRQ_EVENT_EN_4] = 0x0460,
0175 [PMIF_IRQ_FLAG_4] = 0x0468,
0176 [PMIF_IRQ_CLR_4] = 0x046C,
0177 [PMIF_WDT_EVENT_EN_0] = 0x0474,
0178 [PMIF_WDT_FLAG_0] = 0x0478,
0179 [PMIF_WDT_EVENT_EN_1] = 0x047C,
0180 [PMIF_WDT_FLAG_1] = 0x0480,
0181 [PMIF_SWINF_0_ACC] = 0x0800,
0182 [PMIF_SWINF_0_WDATA_31_0] = 0x0804,
0183 [PMIF_SWINF_0_RDATA_31_0] = 0x0814,
0184 [PMIF_SWINF_0_VLD_CLR] = 0x0824,
0185 [PMIF_SWINF_0_STA] = 0x0828,
0186 [PMIF_SWINF_1_ACC] = 0x0840,
0187 [PMIF_SWINF_1_WDATA_31_0] = 0x0844,
0188 [PMIF_SWINF_1_RDATA_31_0] = 0x0854,
0189 [PMIF_SWINF_1_VLD_CLR] = 0x0864,
0190 [PMIF_SWINF_1_STA] = 0x0868,
0191 [PMIF_SWINF_2_ACC] = 0x0880,
0192 [PMIF_SWINF_2_WDATA_31_0] = 0x0884,
0193 [PMIF_SWINF_2_RDATA_31_0] = 0x0894,
0194 [PMIF_SWINF_2_VLD_CLR] = 0x08A4,
0195 [PMIF_SWINF_2_STA] = 0x08A8,
0196 [PMIF_SWINF_3_ACC] = 0x08C0,
0197 [PMIF_SWINF_3_WDATA_31_0] = 0x08C4,
0198 [PMIF_SWINF_3_RDATA_31_0] = 0x08D4,
0199 [PMIF_SWINF_3_VLD_CLR] = 0x08E4,
0200 [PMIF_SWINF_3_STA] = 0x08E8,
0201 };
0202
0203 enum spmi_regs {
0204 SPMI_OP_ST_CTRL,
0205 SPMI_GRP_ID_EN,
0206 SPMI_OP_ST_STA,
0207 SPMI_MST_SAMPL,
0208 SPMI_MST_REQ_EN,
0209 SPMI_REC_CTRL,
0210 SPMI_REC0,
0211 SPMI_REC1,
0212 SPMI_REC2,
0213 SPMI_REC3,
0214 SPMI_REC4,
0215 SPMI_MST_DBG,
0216
0217
0218 SPMI_MST_RCS_CTRL,
0219 SPMI_SLV_3_0_EINT,
0220 SPMI_SLV_7_4_EINT,
0221 SPMI_SLV_B_8_EINT,
0222 SPMI_SLV_F_C_EINT,
0223 SPMI_REC_CMD_DEC,
0224 SPMI_DEC_DBG,
0225 };
0226
0227 static const u32 mt6873_spmi_regs[] = {
0228 [SPMI_OP_ST_CTRL] = 0x0000,
0229 [SPMI_GRP_ID_EN] = 0x0004,
0230 [SPMI_OP_ST_STA] = 0x0008,
0231 [SPMI_MST_SAMPL] = 0x000c,
0232 [SPMI_MST_REQ_EN] = 0x0010,
0233 [SPMI_REC_CTRL] = 0x0040,
0234 [SPMI_REC0] = 0x0044,
0235 [SPMI_REC1] = 0x0048,
0236 [SPMI_REC2] = 0x004c,
0237 [SPMI_REC3] = 0x0050,
0238 [SPMI_REC4] = 0x0054,
0239 [SPMI_MST_DBG] = 0x00fc,
0240 };
0241
0242 static const u32 mt8195_spmi_regs[] = {
0243 [SPMI_OP_ST_CTRL] = 0x0000,
0244 [SPMI_GRP_ID_EN] = 0x0004,
0245 [SPMI_OP_ST_STA] = 0x0008,
0246 [SPMI_MST_SAMPL] = 0x000C,
0247 [SPMI_MST_REQ_EN] = 0x0010,
0248 [SPMI_MST_RCS_CTRL] = 0x0014,
0249 [SPMI_SLV_3_0_EINT] = 0x0020,
0250 [SPMI_SLV_7_4_EINT] = 0x0024,
0251 [SPMI_SLV_B_8_EINT] = 0x0028,
0252 [SPMI_SLV_F_C_EINT] = 0x002C,
0253 [SPMI_REC_CTRL] = 0x0040,
0254 [SPMI_REC0] = 0x0044,
0255 [SPMI_REC1] = 0x0048,
0256 [SPMI_REC2] = 0x004C,
0257 [SPMI_REC3] = 0x0050,
0258 [SPMI_REC4] = 0x0054,
0259 [SPMI_REC_CMD_DEC] = 0x005C,
0260 [SPMI_DEC_DBG] = 0x00F8,
0261 [SPMI_MST_DBG] = 0x00FC,
0262 };
0263
0264 static u32 pmif_readl(struct pmif *arb, enum pmif_regs reg)
0265 {
0266 return readl(arb->base + arb->data->regs[reg]);
0267 }
0268
0269 static void pmif_writel(struct pmif *arb, u32 val, enum pmif_regs reg)
0270 {
0271 writel(val, arb->base + arb->data->regs[reg]);
0272 }
0273
0274 static void mtk_spmi_writel(struct pmif *arb, u32 val, enum spmi_regs reg)
0275 {
0276 writel(val, arb->spmimst_base + arb->data->spmimst_regs[reg]);
0277 }
0278
0279 static bool pmif_is_fsm_vldclr(struct pmif *arb)
0280 {
0281 u32 reg_rdata;
0282
0283 reg_rdata = pmif_readl(arb, arb->chan.ch_sta);
0284
0285 return GET_SWINF(reg_rdata) == SWINF_WFVLDCLR;
0286 }
0287
0288 static int pmif_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
0289 {
0290 struct pmif *arb = spmi_controller_get_drvdata(ctrl);
0291 u32 rdata, cmd;
0292 int ret;
0293
0294
0295 if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP)
0296 return -EINVAL;
0297
0298 cmd = opc - SPMI_CMD_RESET;
0299
0300 mtk_spmi_writel(arb, (cmd << 0x4) | sid, SPMI_OP_ST_CTRL);
0301 ret = readl_poll_timeout_atomic(arb->spmimst_base + arb->data->spmimst_regs[SPMI_OP_ST_STA],
0302 rdata, (rdata & SPMI_OP_ST_BUSY) == SPMI_OP_ST_BUSY,
0303 PMIF_DELAY_US, PMIF_TIMEOUT_US);
0304 if (ret < 0)
0305 dev_err(&ctrl->dev, "timeout, err = %d\n", ret);
0306
0307 return ret;
0308 }
0309
0310 static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
0311 u16 addr, u8 *buf, size_t len)
0312 {
0313 struct pmif *arb = spmi_controller_get_drvdata(ctrl);
0314 struct ch_reg *inf_reg;
0315 int ret;
0316 u32 data, cmd;
0317
0318
0319 if (sid & ~0xf) {
0320 dev_err(&ctrl->dev, "exceed the max slv id\n");
0321 return -EINVAL;
0322 }
0323
0324 if (len > 4) {
0325 dev_err(&ctrl->dev, "pmif supports 1..4 bytes per trans, but:%zu requested", len);
0326
0327 return -EINVAL;
0328 }
0329
0330 if (opc >= 0x60 && opc <= 0x7f)
0331 opc = PMIF_CMD_REG;
0332 else if ((opc >= 0x20 && opc <= 0x2f) || (opc >= 0x38 && opc <= 0x3f))
0333 opc = PMIF_CMD_EXT_REG_LONG;
0334 else
0335 return -EINVAL;
0336
0337
0338 inf_reg = &arb->chan;
0339 ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],
0340 data, GET_SWINF(data) == SWINF_IDLE,
0341 PMIF_DELAY_US, PMIF_TIMEOUT_US);
0342 if (ret < 0) {
0343
0344 if (pmif_is_fsm_vldclr(arb))
0345 pmif_writel(arb, 1, inf_reg->ch_rdy);
0346 dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n");
0347 return ret;
0348 }
0349
0350
0351 cmd = (opc << 30) | (sid << 24) | ((len - 1) << 16) | addr;
0352 pmif_writel(arb, cmd, inf_reg->ch_send);
0353
0354
0355
0356
0357
0358 ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],
0359 data, GET_SWINF(data) == SWINF_WFVLDCLR,
0360 PMIF_DELAY_US, PMIF_TIMEOUT_US);
0361 if (ret < 0) {
0362 dev_err(&ctrl->dev, "failed to wait for SWINF_WFVLDCLR\n");
0363 return ret;
0364 }
0365
0366 data = pmif_readl(arb, inf_reg->rdata);
0367 memcpy(buf, &data, len);
0368 pmif_writel(arb, 1, inf_reg->ch_rdy);
0369
0370 return 0;
0371 }
0372
0373 static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
0374 u16 addr, const u8 *buf, size_t len)
0375 {
0376 struct pmif *arb = spmi_controller_get_drvdata(ctrl);
0377 struct ch_reg *inf_reg;
0378 int ret;
0379 u32 data, cmd;
0380
0381 if (len > 4) {
0382 dev_err(&ctrl->dev, "pmif supports 1..4 bytes per trans, but:%zu requested", len);
0383
0384 return -EINVAL;
0385 }
0386
0387
0388 if (opc >= 0x40 && opc <= 0x5F)
0389 opc = PMIF_CMD_REG;
0390 else if ((opc <= 0xF) || (opc >= 0x30 && opc <= 0x37))
0391 opc = PMIF_CMD_EXT_REG_LONG;
0392 else if (opc >= 0x80)
0393 opc = PMIF_CMD_REG_0;
0394 else
0395 return -EINVAL;
0396
0397
0398 inf_reg = &arb->chan;
0399 ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],
0400 data, GET_SWINF(data) == SWINF_IDLE,
0401 PMIF_DELAY_US, PMIF_TIMEOUT_US);
0402 if (ret < 0) {
0403
0404 if (pmif_is_fsm_vldclr(arb))
0405 pmif_writel(arb, 1, inf_reg->ch_rdy);
0406 dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n");
0407 return ret;
0408 }
0409
0410
0411 memcpy(&data, buf, len);
0412 pmif_writel(arb, data, inf_reg->wdata);
0413
0414
0415 cmd = (opc << 30) | BIT(29) | (sid << 24) | ((len - 1) << 16) | addr;
0416 pmif_writel(arb, cmd, inf_reg->ch_send);
0417
0418 return 0;
0419 }
0420
0421 static const struct pmif_data mt6873_pmif_arb = {
0422 .regs = mt6873_regs,
0423 .spmimst_regs = mt6873_spmi_regs,
0424 .soc_chan = 2,
0425 };
0426
0427 static const struct pmif_data mt8195_pmif_arb = {
0428 .regs = mt8195_regs,
0429 .spmimst_regs = mt8195_spmi_regs,
0430 .soc_chan = 2,
0431 };
0432
0433 static int mtk_spmi_probe(struct platform_device *pdev)
0434 {
0435 struct pmif *arb;
0436 struct spmi_controller *ctrl;
0437 int err, i;
0438 u32 chan_offset;
0439
0440 ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*arb));
0441 if (!ctrl)
0442 return -ENOMEM;
0443
0444 arb = spmi_controller_get_drvdata(ctrl);
0445 arb->data = device_get_match_data(&pdev->dev);
0446 if (!arb->data) {
0447 err = -EINVAL;
0448 dev_err(&pdev->dev, "Cannot get drv_data\n");
0449 goto err_put_ctrl;
0450 }
0451
0452 arb->base = devm_platform_ioremap_resource_byname(pdev, "pmif");
0453 if (IS_ERR(arb->base)) {
0454 err = PTR_ERR(arb->base);
0455 goto err_put_ctrl;
0456 }
0457
0458 arb->spmimst_base = devm_platform_ioremap_resource_byname(pdev, "spmimst");
0459 if (IS_ERR(arb->spmimst_base)) {
0460 err = PTR_ERR(arb->spmimst_base);
0461 goto err_put_ctrl;
0462 }
0463
0464 arb->nclks = ARRAY_SIZE(pmif_clock_names);
0465 for (i = 0; i < arb->nclks; i++)
0466 arb->clks[i].id = pmif_clock_names[i];
0467
0468 err = devm_clk_bulk_get(&pdev->dev, arb->nclks, arb->clks);
0469 if (err) {
0470 dev_err(&pdev->dev, "Failed to get clocks: %d\n", err);
0471 goto err_put_ctrl;
0472 }
0473
0474 err = clk_bulk_prepare_enable(arb->nclks, arb->clks);
0475 if (err) {
0476 dev_err(&pdev->dev, "Failed to enable clocks: %d\n", err);
0477 goto err_put_ctrl;
0478 }
0479
0480 ctrl->cmd = pmif_arb_cmd;
0481 ctrl->read_cmd = pmif_spmi_read_cmd;
0482 ctrl->write_cmd = pmif_spmi_write_cmd;
0483
0484 chan_offset = PMIF_CHAN_OFFSET * arb->data->soc_chan;
0485 arb->chan.ch_sta = PMIF_SWINF_0_STA + chan_offset;
0486 arb->chan.wdata = PMIF_SWINF_0_WDATA_31_0 + chan_offset;
0487 arb->chan.rdata = PMIF_SWINF_0_RDATA_31_0 + chan_offset;
0488 arb->chan.ch_send = PMIF_SWINF_0_ACC + chan_offset;
0489 arb->chan.ch_rdy = PMIF_SWINF_0_VLD_CLR + chan_offset;
0490
0491 platform_set_drvdata(pdev, ctrl);
0492
0493 err = spmi_controller_add(ctrl);
0494 if (err)
0495 goto err_domain_remove;
0496
0497 return 0;
0498
0499 err_domain_remove:
0500 clk_bulk_disable_unprepare(arb->nclks, arb->clks);
0501 err_put_ctrl:
0502 spmi_controller_put(ctrl);
0503 return err;
0504 }
0505
0506 static int mtk_spmi_remove(struct platform_device *pdev)
0507 {
0508 struct spmi_controller *ctrl = platform_get_drvdata(pdev);
0509 struct pmif *arb = spmi_controller_get_drvdata(ctrl);
0510
0511 clk_bulk_disable_unprepare(arb->nclks, arb->clks);
0512 spmi_controller_remove(ctrl);
0513 spmi_controller_put(ctrl);
0514 return 0;
0515 }
0516
0517 static const struct of_device_id mtk_spmi_match_table[] = {
0518 {
0519 .compatible = "mediatek,mt6873-spmi",
0520 .data = &mt6873_pmif_arb,
0521 }, {
0522 .compatible = "mediatek,mt8195-spmi",
0523 .data = &mt8195_pmif_arb,
0524 }, {
0525
0526 },
0527 };
0528 MODULE_DEVICE_TABLE(of, mtk_spmi_match_table);
0529
0530 static struct platform_driver mtk_spmi_driver = {
0531 .driver = {
0532 .name = "spmi-mtk",
0533 .of_match_table = of_match_ptr(mtk_spmi_match_table),
0534 },
0535 .probe = mtk_spmi_probe,
0536 .remove = mtk_spmi_remove,
0537 };
0538 module_platform_driver(mtk_spmi_driver);
0539
0540 MODULE_AUTHOR("Hsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com>");
0541 MODULE_DESCRIPTION("MediaTek SPMI Driver");
0542 MODULE_LICENSE("GPL");