555 lines · c
1// SPDX-License-Identifier: GPL-2.02//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 0x0014#define SWINF_WFVLDCLR 0x0615 16#define GET_SWINF(x) (((x) >> 1) & 0x7)17 18#define PMIF_CMD_REG_0 019#define PMIF_CMD_REG 120#define PMIF_CMD_EXT_REG 221#define PMIF_CMD_EXT_REG_LONG 322 23#define PMIF_DELAY_US 1024#define PMIF_TIMEOUT_US (10 * 1000)25 26#define PMIF_CHAN_OFFSET 0x527 28#define PMIF_MAX_CLKS 329 30#define SPMI_OP_ST_BUSY 131 32struct ch_reg {33 u32 ch_sta;34 u32 wdata;35 u32 rdata;36 u32 ch_send;37 u32 ch_rdy;38};39 40struct pmif_data {41 const u32 *regs;42 const u32 *spmimst_regs;43 u32 soc_chan;44};45 46struct 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 56static const char * const pmif_clock_names[] = {57 "pmif_sys_ck", "pmif_tmr_ck", "spmimst_clk_mux",58};59 60enum 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 108static 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 156static 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 204enum 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 228static 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 243static 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 265static u32 pmif_readl(struct pmif *arb, enum pmif_regs reg)266{267 return readl(arb->base + arb->data->regs[reg]);268}269 270static void pmif_writel(struct pmif *arb, u32 val, enum pmif_regs reg)271{272 writel(val, arb->base + arb->data->regs[reg]);273}274 275static 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 280static 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 289static 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 311static 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 else337 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 378static 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 /* Check for argument validation. */388 if (unlikely(sid & ~0xf)) {389 dev_err(&ctrl->dev, "exceed the max slv id\n");390 return -EINVAL;391 }392 393 if (len > 4) {394 dev_err(&ctrl->dev, "pmif supports 1..4 bytes per trans, but:%zu requested", len);395 396 return -EINVAL;397 }398 399 /* Check the opcode */400 if (opc >= 0x40 && opc <= 0x5F)401 opc = PMIF_CMD_REG;402 else if ((opc <= 0xF) || (opc >= 0x30 && opc <= 0x37))403 opc = PMIF_CMD_EXT_REG_LONG;404 else if (opc >= 0x80)405 opc = PMIF_CMD_REG_0;406 else407 return -EINVAL;408 409 /* Set the write data. */410 memcpy(&wdata, buf, len);411 412 raw_spin_lock_irqsave(&arb->lock, flags);413 /* Wait for Software Interface FSM state to be IDLE. */414 inf_reg = &arb->chan;415 ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],416 data, GET_SWINF(data) == SWINF_IDLE,417 PMIF_DELAY_US, PMIF_TIMEOUT_US);418 if (ret < 0) {419 /* set channel ready if the data has transferred */420 if (pmif_is_fsm_vldclr(arb))421 pmif_writel(arb, 1, inf_reg->ch_rdy);422 raw_spin_unlock_irqrestore(&arb->lock, flags);423 dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n");424 return ret;425 }426 427 pmif_writel(arb, wdata, inf_reg->wdata);428 429 /* Send the command. */430 cmd = (opc << 30) | BIT(29) | (sid << 24) | ((len - 1) << 16) | addr;431 pmif_writel(arb, cmd, inf_reg->ch_send);432 raw_spin_unlock_irqrestore(&arb->lock, flags);433 434 return 0;435}436 437static const struct pmif_data mt6873_pmif_arb = {438 .regs = mt6873_regs,439 .spmimst_regs = mt6873_spmi_regs,440 .soc_chan = 2,441};442 443static const struct pmif_data mt8195_pmif_arb = {444 .regs = mt8195_regs,445 .spmimst_regs = mt8195_spmi_regs,446 .soc_chan = 2,447};448 449static int mtk_spmi_probe(struct platform_device *pdev)450{451 struct pmif *arb;452 struct spmi_controller *ctrl;453 int err, i;454 u32 chan_offset;455 456 ctrl = devm_spmi_controller_alloc(&pdev->dev, sizeof(*arb));457 if (IS_ERR(ctrl))458 return PTR_ERR(ctrl);459 460 arb = spmi_controller_get_drvdata(ctrl);461 arb->data = device_get_match_data(&pdev->dev);462 if (!arb->data) {463 dev_err(&pdev->dev, "Cannot get drv_data\n");464 return -EINVAL;465 }466 467 arb->base = devm_platform_ioremap_resource_byname(pdev, "pmif");468 if (IS_ERR(arb->base))469 return PTR_ERR(arb->base);470 471 arb->spmimst_base = devm_platform_ioremap_resource_byname(pdev, "spmimst");472 if (IS_ERR(arb->spmimst_base))473 return PTR_ERR(arb->spmimst_base);474 475 arb->nclks = ARRAY_SIZE(pmif_clock_names);476 for (i = 0; i < arb->nclks; i++)477 arb->clks[i].id = pmif_clock_names[i];478 479 err = clk_bulk_get(&pdev->dev, arb->nclks, arb->clks);480 if (err) {481 dev_err(&pdev->dev, "Failed to get clocks: %d\n", err);482 return err;483 }484 485 err = clk_bulk_prepare_enable(arb->nclks, arb->clks);486 if (err) {487 dev_err(&pdev->dev, "Failed to enable clocks: %d\n", err);488 goto err_put_clks;489 }490 491 ctrl->cmd = pmif_arb_cmd;492 ctrl->read_cmd = pmif_spmi_read_cmd;493 ctrl->write_cmd = pmif_spmi_write_cmd;494 495 chan_offset = PMIF_CHAN_OFFSET * arb->data->soc_chan;496 arb->chan.ch_sta = PMIF_SWINF_0_STA + chan_offset;497 arb->chan.wdata = PMIF_SWINF_0_WDATA_31_0 + chan_offset;498 arb->chan.rdata = PMIF_SWINF_0_RDATA_31_0 + chan_offset;499 arb->chan.ch_send = PMIF_SWINF_0_ACC + chan_offset;500 arb->chan.ch_rdy = PMIF_SWINF_0_VLD_CLR + chan_offset;501 502 raw_spin_lock_init(&arb->lock);503 504 platform_set_drvdata(pdev, ctrl);505 506 err = spmi_controller_add(ctrl);507 if (err)508 goto err_domain_remove;509 510 return 0;511 512err_domain_remove:513 clk_bulk_disable_unprepare(arb->nclks, arb->clks);514err_put_clks:515 clk_bulk_put(arb->nclks, arb->clks);516 return err;517}518 519static void mtk_spmi_remove(struct platform_device *pdev)520{521 struct spmi_controller *ctrl = platform_get_drvdata(pdev);522 struct pmif *arb = spmi_controller_get_drvdata(ctrl);523 524 spmi_controller_remove(ctrl);525 clk_bulk_disable_unprepare(arb->nclks, arb->clks);526 clk_bulk_put(arb->nclks, arb->clks);527}528 529static const struct of_device_id mtk_spmi_match_table[] = {530 {531 .compatible = "mediatek,mt6873-spmi",532 .data = &mt6873_pmif_arb,533 }, {534 .compatible = "mediatek,mt8195-spmi",535 .data = &mt8195_pmif_arb,536 }, {537 /* sentinel */538 },539};540MODULE_DEVICE_TABLE(of, mtk_spmi_match_table);541 542static struct platform_driver mtk_spmi_driver = {543 .driver = {544 .name = "spmi-mtk",545 .of_match_table = mtk_spmi_match_table,546 },547 .probe = mtk_spmi_probe,548 .remove_new = mtk_spmi_remove,549};550module_platform_driver(mtk_spmi_driver);551 552MODULE_AUTHOR("Hsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com>");553MODULE_DESCRIPTION("MediaTek SPMI Driver");554MODULE_LICENSE("GPL");555