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