Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Copyright (c) 2021 MediaTek Inc.
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     /* MT8195 spmi regs */
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     /* Check the opcode */
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     /* Check for argument validation. */
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     /* Wait for Software Interface FSM state to be IDLE. */
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         /* set channel ready if the data has transferred */
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     /* Send the command. */
0351     cmd = (opc << 30) | (sid << 24) | ((len - 1) << 16) | addr;
0352     pmif_writel(arb, cmd, inf_reg->ch_send);
0353 
0354     /*
0355      * Wait for Software Interface FSM state to be WFVLDCLR,
0356      * read the data and clear the valid flag.
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     /* Check the opcode */
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     /* Wait for Software Interface FSM state to be IDLE. */
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         /* set channel ready if the data has transferred */
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     /* Set the write data. */
0411     memcpy(&data, buf, len);
0412     pmif_writel(arb, data, inf_reg->wdata);
0413 
0414     /* Send the command. */
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         /* sentinel */
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");