1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // Copyright (c) 2021 MediaTek Inc. 4 5 #include <linux/clk.h> 6 #include <linux/iopoll.h> 7 #include <linux/module.h> 8 #include <linux/of.h> 9 #include <linux/platform_device.h> 10 #include <linux/property.h> 11 #include <linux/spmi.h> 12 13 #define SWINF_IDLE 0x00 14 #define SWINF_WFVLDCLR 0x06 15 16 #define GET_SWINF(x) (((x) >> 1) & 0x7) 17 18 #define PMIF_CMD_REG_0 0 19 #define PMIF_CMD_REG 1 20 #define PMIF_CMD_EXT_REG 2 21 #define PMIF_CMD_EXT_REG_LONG 3 22 23 #define PMIF_DELAY_US 10 24 #define PMIF_TIMEOUT_US (10 * 1000) 25 26 #define PMIF_CHAN_OFFSET 0x5 27 28 #define PMIF_MAX_CLKS 3 29 30 #define SPMI_OP_ST_BUSY 1 31 32 struct ch_reg { 33 u32 ch_sta; 34 u32 wdata; 35 u32 rdata; 36 u32 ch_send; 37 u32 ch_rdy; 38 }; 39 40 struct pmif_data { 41 const u32 *regs; 42 const u32 *spmimst_regs; 43 u32 soc_chan; 44 }; 45 46 struct pmif { 47 void __iomem *base; 48 void __iomem *spmimst_base; 49 struct ch_reg chan; 50 struct clk_bulk_data clks[PMIF_MAX_CLKS]; 51 size_t nclks; 52 const struct pmif_data *data; 53 raw_spinlock_t lock; 54 }; 55 56 static const char * const pmif_clock_names[] = { 57 "pmif_sys_ck", "pmif_tmr_ck", "spmimst_clk_mux", 58 }; 59 60 enum pmif_regs { 61 PMIF_INIT_DONE, 62 PMIF_INF_EN, 63 PMIF_ARB_EN, 64 PMIF_CMDISSUE_EN, 65 PMIF_TIMER_CTRL, 66 PMIF_SPI_MODE_CTRL, 67 PMIF_IRQ_EVENT_EN_0, 68 PMIF_IRQ_FLAG_0, 69 PMIF_IRQ_CLR_0, 70 PMIF_IRQ_EVENT_EN_1, 71 PMIF_IRQ_FLAG_1, 72 PMIF_IRQ_CLR_1, 73 PMIF_IRQ_EVENT_EN_2, 74 PMIF_IRQ_FLAG_2, 75 PMIF_IRQ_CLR_2, 76 PMIF_IRQ_EVENT_EN_3, 77 PMIF_IRQ_FLAG_3, 78 PMIF_IRQ_CLR_3, 79 PMIF_IRQ_EVENT_EN_4, 80 PMIF_IRQ_FLAG_4, 81 PMIF_IRQ_CLR_4, 82 PMIF_WDT_EVENT_EN_0, 83 PMIF_WDT_FLAG_0, 84 PMIF_WDT_EVENT_EN_1, 85 PMIF_WDT_FLAG_1, 86 PMIF_SWINF_0_STA, 87 PMIF_SWINF_0_WDATA_31_0, 88 PMIF_SWINF_0_RDATA_31_0, 89 PMIF_SWINF_0_ACC, 90 PMIF_SWINF_0_VLD_CLR, 91 PMIF_SWINF_1_STA, 92 PMIF_SWINF_1_WDATA_31_0, 93 PMIF_SWINF_1_RDATA_31_0, 94 PMIF_SWINF_1_ACC, 95 PMIF_SWINF_1_VLD_CLR, 96 PMIF_SWINF_2_STA, 97 PMIF_SWINF_2_WDATA_31_0, 98 PMIF_SWINF_2_RDATA_31_0, 99 PMIF_SWINF_2_ACC, 100 PMIF_SWINF_2_VLD_CLR, 101 PMIF_SWINF_3_STA, 102 PMIF_SWINF_3_WDATA_31_0, 103 PMIF_SWINF_3_RDATA_31_0, 104 PMIF_SWINF_3_ACC, 105 PMIF_SWINF_3_VLD_CLR, 106 }; 107 108 static const u32 mt6873_regs[] = { 109 [PMIF_INIT_DONE] = 0x0000, 110 [PMIF_INF_EN] = 0x0024, 111 [PMIF_ARB_EN] = 0x0150, 112 [PMIF_CMDISSUE_EN] = 0x03B4, 113 [PMIF_TIMER_CTRL] = 0x03E0, 114 [PMIF_SPI_MODE_CTRL] = 0x0400, 115 [PMIF_IRQ_EVENT_EN_0] = 0x0418, 116 [PMIF_IRQ_FLAG_0] = 0x0420, 117 [PMIF_IRQ_CLR_0] = 0x0424, 118 [PMIF_IRQ_EVENT_EN_1] = 0x0428, 119 [PMIF_IRQ_FLAG_1] = 0x0430, 120 [PMIF_IRQ_CLR_1] = 0x0434, 121 [PMIF_IRQ_EVENT_EN_2] = 0x0438, 122 [PMIF_IRQ_FLAG_2] = 0x0440, 123 [PMIF_IRQ_CLR_2] = 0x0444, 124 [PMIF_IRQ_EVENT_EN_3] = 0x0448, 125 [PMIF_IRQ_FLAG_3] = 0x0450, 126 [PMIF_IRQ_CLR_3] = 0x0454, 127 [PMIF_IRQ_EVENT_EN_4] = 0x0458, 128 [PMIF_IRQ_FLAG_4] = 0x0460, 129 [PMIF_IRQ_CLR_4] = 0x0464, 130 [PMIF_WDT_EVENT_EN_0] = 0x046C, 131 [PMIF_WDT_FLAG_0] = 0x0470, 132 [PMIF_WDT_EVENT_EN_1] = 0x0474, 133 [PMIF_WDT_FLAG_1] = 0x0478, 134 [PMIF_SWINF_0_ACC] = 0x0C00, 135 [PMIF_SWINF_0_WDATA_31_0] = 0x0C04, 136 [PMIF_SWINF_0_RDATA_31_0] = 0x0C14, 137 [PMIF_SWINF_0_VLD_CLR] = 0x0C24, 138 [PMIF_SWINF_0_STA] = 0x0C28, 139 [PMIF_SWINF_1_ACC] = 0x0C40, 140 [PMIF_SWINF_1_WDATA_31_0] = 0x0C44, 141 [PMIF_SWINF_1_RDATA_31_0] = 0x0C54, 142 [PMIF_SWINF_1_VLD_CLR] = 0x0C64, 143 [PMIF_SWINF_1_STA] = 0x0C68, 144 [PMIF_SWINF_2_ACC] = 0x0C80, 145 [PMIF_SWINF_2_WDATA_31_0] = 0x0C84, 146 [PMIF_SWINF_2_RDATA_31_0] = 0x0C94, 147 [PMIF_SWINF_2_VLD_CLR] = 0x0CA4, 148 [PMIF_SWINF_2_STA] = 0x0CA8, 149 [PMIF_SWINF_3_ACC] = 0x0CC0, 150 [PMIF_SWINF_3_WDATA_31_0] = 0x0CC4, 151 [PMIF_SWINF_3_RDATA_31_0] = 0x0CD4, 152 [PMIF_SWINF_3_VLD_CLR] = 0x0CE4, 153 [PMIF_SWINF_3_STA] = 0x0CE8, 154 }; 155 156 static const u32 mt8195_regs[] = { 157 [PMIF_INIT_DONE] = 0x0000, 158 [PMIF_INF_EN] = 0x0024, 159 [PMIF_ARB_EN] = 0x0150, 160 [PMIF_CMDISSUE_EN] = 0x03B8, 161 [PMIF_TIMER_CTRL] = 0x03E4, 162 [PMIF_SPI_MODE_CTRL] = 0x0408, 163 [PMIF_IRQ_EVENT_EN_0] = 0x0420, 164 [PMIF_IRQ_FLAG_0] = 0x0428, 165 [PMIF_IRQ_CLR_0] = 0x042C, 166 [PMIF_IRQ_EVENT_EN_1] = 0x0430, 167 [PMIF_IRQ_FLAG_1] = 0x0438, 168 [PMIF_IRQ_CLR_1] = 0x043C, 169 [PMIF_IRQ_EVENT_EN_2] = 0x0440, 170 [PMIF_IRQ_FLAG_2] = 0x0448, 171 [PMIF_IRQ_CLR_2] = 0x044C, 172 [PMIF_IRQ_EVENT_EN_3] = 0x0450, 173 [PMIF_IRQ_FLAG_3] = 0x0458, 174 [PMIF_IRQ_CLR_3] = 0x045C, 175 [PMIF_IRQ_EVENT_EN_4] = 0x0460, 176 [PMIF_IRQ_FLAG_4] = 0x0468, 177 [PMIF_IRQ_CLR_4] = 0x046C, 178 [PMIF_WDT_EVENT_EN_0] = 0x0474, 179 [PMIF_WDT_FLAG_0] = 0x0478, 180 [PMIF_WDT_EVENT_EN_1] = 0x047C, 181 [PMIF_WDT_FLAG_1] = 0x0480, 182 [PMIF_SWINF_0_ACC] = 0x0800, 183 [PMIF_SWINF_0_WDATA_31_0] = 0x0804, 184 [PMIF_SWINF_0_RDATA_31_0] = 0x0814, 185 [PMIF_SWINF_0_VLD_CLR] = 0x0824, 186 [PMIF_SWINF_0_STA] = 0x0828, 187 [PMIF_SWINF_1_ACC] = 0x0840, 188 [PMIF_SWINF_1_WDATA_31_0] = 0x0844, 189 [PMIF_SWINF_1_RDATA_31_0] = 0x0854, 190 [PMIF_SWINF_1_VLD_CLR] = 0x0864, 191 [PMIF_SWINF_1_STA] = 0x0868, 192 [PMIF_SWINF_2_ACC] = 0x0880, 193 [PMIF_SWINF_2_WDATA_31_0] = 0x0884, 194 [PMIF_SWINF_2_RDATA_31_0] = 0x0894, 195 [PMIF_SWINF_2_VLD_CLR] = 0x08A4, 196 [PMIF_SWINF_2_STA] = 0x08A8, 197 [PMIF_SWINF_3_ACC] = 0x08C0, 198 [PMIF_SWINF_3_WDATA_31_0] = 0x08C4, 199 [PMIF_SWINF_3_RDATA_31_0] = 0x08D4, 200 [PMIF_SWINF_3_VLD_CLR] = 0x08E4, 201 [PMIF_SWINF_3_STA] = 0x08E8, 202 }; 203 204 enum spmi_regs { 205 SPMI_OP_ST_CTRL, 206 SPMI_GRP_ID_EN, 207 SPMI_OP_ST_STA, 208 SPMI_MST_SAMPL, 209 SPMI_MST_REQ_EN, 210 SPMI_REC_CTRL, 211 SPMI_REC0, 212 SPMI_REC1, 213 SPMI_REC2, 214 SPMI_REC3, 215 SPMI_REC4, 216 SPMI_MST_DBG, 217 218 /* MT8195 spmi regs */ 219 SPMI_MST_RCS_CTRL, 220 SPMI_SLV_3_0_EINT, 221 SPMI_SLV_7_4_EINT, 222 SPMI_SLV_B_8_EINT, 223 SPMI_SLV_F_C_EINT, 224 SPMI_REC_CMD_DEC, 225 SPMI_DEC_DBG, 226 }; 227 228 static const u32 mt6873_spmi_regs[] = { 229 [SPMI_OP_ST_CTRL] = 0x0000, 230 [SPMI_GRP_ID_EN] = 0x0004, 231 [SPMI_OP_ST_STA] = 0x0008, 232 [SPMI_MST_SAMPL] = 0x000c, 233 [SPMI_MST_REQ_EN] = 0x0010, 234 [SPMI_REC_CTRL] = 0x0040, 235 [SPMI_REC0] = 0x0044, 236 [SPMI_REC1] = 0x0048, 237 [SPMI_REC2] = 0x004c, 238 [SPMI_REC3] = 0x0050, 239 [SPMI_REC4] = 0x0054, 240 [SPMI_MST_DBG] = 0x00fc, 241 }; 242 243 static const u32 mt8195_spmi_regs[] = { 244 [SPMI_OP_ST_CTRL] = 0x0000, 245 [SPMI_GRP_ID_EN] = 0x0004, 246 [SPMI_OP_ST_STA] = 0x0008, 247 [SPMI_MST_SAMPL] = 0x000C, 248 [SPMI_MST_REQ_EN] = 0x0010, 249 [SPMI_MST_RCS_CTRL] = 0x0014, 250 [SPMI_SLV_3_0_EINT] = 0x0020, 251 [SPMI_SLV_7_4_EINT] = 0x0024, 252 [SPMI_SLV_B_8_EINT] = 0x0028, 253 [SPMI_SLV_F_C_EINT] = 0x002C, 254 [SPMI_REC_CTRL] = 0x0040, 255 [SPMI_REC0] = 0x0044, 256 [SPMI_REC1] = 0x0048, 257 [SPMI_REC2] = 0x004C, 258 [SPMI_REC3] = 0x0050, 259 [SPMI_REC4] = 0x0054, 260 [SPMI_REC_CMD_DEC] = 0x005C, 261 [SPMI_DEC_DBG] = 0x00F8, 262 [SPMI_MST_DBG] = 0x00FC, 263 }; 264 265 static u32 pmif_readl(struct pmif *arb, enum pmif_regs reg) 266 { 267 return readl(arb->base + arb->data->regs[reg]); 268 } 269 270 static void pmif_writel(struct pmif *arb, u32 val, enum pmif_regs reg) 271 { 272 writel(val, arb->base + arb->data->regs[reg]); 273 } 274 275 static void mtk_spmi_writel(struct pmif *arb, u32 val, enum spmi_regs reg) 276 { 277 writel(val, arb->spmimst_base + arb->data->spmimst_regs[reg]); 278 } 279 280 static bool pmif_is_fsm_vldclr(struct pmif *arb) 281 { 282 u32 reg_rdata; 283 284 reg_rdata = pmif_readl(arb, arb->chan.ch_sta); 285 286 return GET_SWINF(reg_rdata) == SWINF_WFVLDCLR; 287 } 288 289 static int pmif_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid) 290 { 291 struct pmif *arb = spmi_controller_get_drvdata(ctrl); 292 u32 rdata, cmd; 293 int ret; 294 295 /* Check the opcode */ 296 if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP) 297 return -EINVAL; 298 299 cmd = opc - SPMI_CMD_RESET; 300 301 mtk_spmi_writel(arb, (cmd << 0x4) | sid, SPMI_OP_ST_CTRL); 302 ret = readl_poll_timeout_atomic(arb->spmimst_base + arb->data->spmimst_regs[SPMI_OP_ST_STA], 303 rdata, (rdata & SPMI_OP_ST_BUSY) == SPMI_OP_ST_BUSY, 304 PMIF_DELAY_US, PMIF_TIMEOUT_US); 305 if (ret < 0) 306 dev_err(&ctrl->dev, "timeout, err = %d\n", ret); 307 308 return ret; 309 } 310 311 static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, 312 u16 addr, u8 *buf, size_t len) 313 { 314 struct pmif *arb = spmi_controller_get_drvdata(ctrl); 315 struct ch_reg *inf_reg; 316 int ret; 317 u32 data, cmd; 318 unsigned long flags; 319 320 /* Check for argument validation. */ 321 if (sid & ~0xf) { 322 dev_err(&ctrl->dev, "exceed the max slv id\n"); 323 return -EINVAL; 324 } 325 326 if (len > 4) { 327 dev_err(&ctrl->dev, "pmif supports 1..4 bytes per trans, but:%zu requested", len); 328 329 return -EINVAL; 330 } 331 332 if (opc >= 0x60 && opc <= 0x7f) 333 opc = PMIF_CMD_REG; 334 else if ((opc >= 0x20 && opc <= 0x2f) || (opc >= 0x38 && opc <= 0x3f)) 335 opc = PMIF_CMD_EXT_REG_LONG; 336 else 337 return -EINVAL; 338 339 raw_spin_lock_irqsave(&arb->lock, flags); 340 /* Wait for Software Interface FSM state to be IDLE. */ 341 inf_reg = &arb->chan; 342 ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta], 343 data, GET_SWINF(data) == SWINF_IDLE, 344 PMIF_DELAY_US, PMIF_TIMEOUT_US); 345 if (ret < 0) { 346 /* set channel ready if the data has transferred */ 347 if (pmif_is_fsm_vldclr(arb)) 348 pmif_writel(arb, 1, inf_reg->ch_rdy); 349 raw_spin_unlock_irqrestore(&arb->lock, flags); 350 dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n"); 351 return ret; 352 } 353 354 /* Send the command. */ 355 cmd = (opc << 30) | (sid << 24) | ((len - 1) << 16) | addr; 356 pmif_writel(arb, cmd, inf_reg->ch_send); 357 raw_spin_unlock_irqrestore(&arb->lock, flags); 358 359 /* 360 * Wait for Software Interface FSM state to be WFVLDCLR, 361 * read the data and clear the valid flag. 362 */ 363 ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta], 364 data, GET_SWINF(data) == SWINF_WFVLDCLR, 365 PMIF_DELAY_US, PMIF_TIMEOUT_US); 366 if (ret < 0) { 367 dev_err(&ctrl->dev, "failed to wait for SWINF_WFVLDCLR\n"); 368 return ret; 369 } 370 371 data = pmif_readl(arb, inf_reg->rdata); 372 memcpy(buf, &data, len); 373 pmif_writel(arb, 1, inf_reg->ch_rdy); 374 375 return 0; 376 } 377 378 static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, 379 u16 addr, const u8 *buf, size_t len) 380 { 381 struct pmif *arb = spmi_controller_get_drvdata(ctrl); 382 struct ch_reg *inf_reg; 383 int ret; 384 u32 data, wdata, cmd; 385 unsigned long flags; 386 387 if (len > 4) { 388 dev_err(&ctrl->dev, "pmif supports 1..4 bytes per trans, but:%zu requested", len); 389 390 return -EINVAL; 391 } 392 393 /* Check the opcode */ 394 if (opc >= 0x40 && opc <= 0x5F) 395 opc = PMIF_CMD_REG; 396 else if ((opc <= 0xF) || (opc >= 0x30 && opc <= 0x37)) 397 opc = PMIF_CMD_EXT_REG_LONG; 398 else if (opc >= 0x80) 399 opc = PMIF_CMD_REG_0; 400 else 401 return -EINVAL; 402 403 /* Set the write data. */ 404 memcpy(&wdata, buf, len); 405 406 raw_spin_lock_irqsave(&arb->lock, flags); 407 /* Wait for Software Interface FSM state to be IDLE. */ 408 inf_reg = &arb->chan; 409 ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta], 410 data, GET_SWINF(data) == SWINF_IDLE, 411 PMIF_DELAY_US, PMIF_TIMEOUT_US); 412 if (ret < 0) { 413 /* set channel ready if the data has transferred */ 414 if (pmif_is_fsm_vldclr(arb)) 415 pmif_writel(arb, 1, inf_reg->ch_rdy); 416 raw_spin_unlock_irqrestore(&arb->lock, flags); 417 dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n"); 418 return ret; 419 } 420 421 pmif_writel(arb, wdata, inf_reg->wdata); 422 423 /* Send the command. */ 424 cmd = (opc << 30) | BIT(29) | (sid << 24) | ((len - 1) << 16) | addr; 425 pmif_writel(arb, cmd, inf_reg->ch_send); 426 raw_spin_unlock_irqrestore(&arb->lock, flags); 427 428 return 0; 429 } 430 431 static const struct pmif_data mt6873_pmif_arb = { 432 .regs = mt6873_regs, 433 .spmimst_regs = mt6873_spmi_regs, 434 .soc_chan = 2, 435 }; 436 437 static const struct pmif_data mt8195_pmif_arb = { 438 .regs = mt8195_regs, 439 .spmimst_regs = mt8195_spmi_regs, 440 .soc_chan = 2, 441 }; 442 443 static int mtk_spmi_probe(struct platform_device *pdev) 444 { 445 struct pmif *arb; 446 struct spmi_controller *ctrl; 447 int err, i; 448 u32 chan_offset; 449 450 ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*arb)); 451 if (!ctrl) 452 return -ENOMEM; 453 454 arb = spmi_controller_get_drvdata(ctrl); 455 arb->data = device_get_match_data(&pdev->dev); 456 if (!arb->data) { 457 err = -EINVAL; 458 dev_err(&pdev->dev, "Cannot get drv_data\n"); 459 goto err_put_ctrl; 460 } 461 462 arb->base = devm_platform_ioremap_resource_byname(pdev, "pmif"); 463 if (IS_ERR(arb->base)) { 464 err = PTR_ERR(arb->base); 465 goto err_put_ctrl; 466 } 467 468 arb->spmimst_base = devm_platform_ioremap_resource_byname(pdev, "spmimst"); 469 if (IS_ERR(arb->spmimst_base)) { 470 err = PTR_ERR(arb->spmimst_base); 471 goto err_put_ctrl; 472 } 473 474 arb->nclks = ARRAY_SIZE(pmif_clock_names); 475 for (i = 0; i < arb->nclks; i++) 476 arb->clks[i].id = pmif_clock_names[i]; 477 478 err = devm_clk_bulk_get(&pdev->dev, arb->nclks, arb->clks); 479 if (err) { 480 dev_err(&pdev->dev, "Failed to get clocks: %d\n", err); 481 goto err_put_ctrl; 482 } 483 484 err = clk_bulk_prepare_enable(arb->nclks, arb->clks); 485 if (err) { 486 dev_err(&pdev->dev, "Failed to enable clocks: %d\n", err); 487 goto err_put_ctrl; 488 } 489 490 ctrl->cmd = pmif_arb_cmd; 491 ctrl->read_cmd = pmif_spmi_read_cmd; 492 ctrl->write_cmd = pmif_spmi_write_cmd; 493 494 chan_offset = PMIF_CHAN_OFFSET * arb->data->soc_chan; 495 arb->chan.ch_sta = PMIF_SWINF_0_STA + chan_offset; 496 arb->chan.wdata = PMIF_SWINF_0_WDATA_31_0 + chan_offset; 497 arb->chan.rdata = PMIF_SWINF_0_RDATA_31_0 + chan_offset; 498 arb->chan.ch_send = PMIF_SWINF_0_ACC + chan_offset; 499 arb->chan.ch_rdy = PMIF_SWINF_0_VLD_CLR + chan_offset; 500 501 raw_spin_lock_init(&arb->lock); 502 503 platform_set_drvdata(pdev, ctrl); 504 505 err = spmi_controller_add(ctrl); 506 if (err) 507 goto err_domain_remove; 508 509 return 0; 510 511 err_domain_remove: 512 clk_bulk_disable_unprepare(arb->nclks, arb->clks); 513 err_put_ctrl: 514 spmi_controller_put(ctrl); 515 return err; 516 } 517 518 static void mtk_spmi_remove(struct platform_device *pdev) 519 { 520 struct spmi_controller *ctrl = platform_get_drvdata(pdev); 521 struct pmif *arb = spmi_controller_get_drvdata(ctrl); 522 523 clk_bulk_disable_unprepare(arb->nclks, arb->clks); 524 spmi_controller_remove(ctrl); 525 spmi_controller_put(ctrl); 526 } 527 528 static const struct of_device_id mtk_spmi_match_table[] = { 529 { 530 .compatible = "mediatek,mt6873-spmi", 531 .data = &mt6873_pmif_arb, 532 }, { 533 .compatible = "mediatek,mt8195-spmi", 534 .data = &mt8195_pmif_arb, 535 }, { 536 /* sentinel */ 537 }, 538 }; 539 MODULE_DEVICE_TABLE(of, mtk_spmi_match_table); 540 541 static struct platform_driver mtk_spmi_driver = { 542 .driver = { 543 .name = "spmi-mtk", 544 .of_match_table = mtk_spmi_match_table, 545 }, 546 .probe = mtk_spmi_probe, 547 .remove_new = mtk_spmi_remove, 548 }; 549 module_platform_driver(mtk_spmi_driver); 550 551 MODULE_AUTHOR("Hsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com>"); 552 MODULE_DESCRIPTION("MediaTek SPMI Driver"); 553 MODULE_LICENSE("GPL"); 554