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(addr: 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, addr: 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, addr: 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, reg: 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, val: (cmd << 0x4) | sid, reg: 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, val: 1, reg: 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, val: cmd, reg: 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, reg: inf_reg->rdata); |
372 | memcpy(buf, &data, len); |
373 | pmif_writel(arb, val: 1, reg: 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 | /* 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 | else |
407 | 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, val: 1, reg: 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, val: wdata, reg: inf_reg->wdata); |
428 | |
429 | /* Send the command. */ |
430 | cmd = (opc << 30) | BIT(29) | (sid << 24) | ((len - 1) << 16) | addr; |
431 | pmif_writel(arb, val: cmd, reg: inf_reg->ch_send); |
432 | raw_spin_unlock_irqrestore(&arb->lock, flags); |
433 | |
434 | return 0; |
435 | } |
436 | |
437 | static const struct pmif_data mt6873_pmif_arb = { |
438 | .regs = mt6873_regs, |
439 | .spmimst_regs = mt6873_spmi_regs, |
440 | .soc_chan = 2, |
441 | }; |
442 | |
443 | static const struct pmif_data mt8195_pmif_arb = { |
444 | .regs = mt8195_regs, |
445 | .spmimst_regs = mt8195_spmi_regs, |
446 | .soc_chan = 2, |
447 | }; |
448 | |
449 | static 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(parent: &pdev->dev, size: sizeof(*arb)); |
457 | if (IS_ERR(ptr: ctrl)) |
458 | return PTR_ERR(ptr: ctrl); |
459 | |
460 | arb = spmi_controller_get_drvdata(ctrl); |
461 | arb->data = device_get_match_data(dev: &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, name: "pmif" ); |
468 | if (IS_ERR(ptr: arb->base)) |
469 | return PTR_ERR(ptr: arb->base); |
470 | |
471 | arb->spmimst_base = devm_platform_ioremap_resource_byname(pdev, name: "spmimst" ); |
472 | if (IS_ERR(ptr: arb->spmimst_base)) |
473 | return PTR_ERR(ptr: 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(dev: &pdev->dev, num_clks: arb->nclks, clks: 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(num_clks: arb->nclks, clks: 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, data: ctrl); |
505 | |
506 | err = spmi_controller_add(ctrl); |
507 | if (err) |
508 | goto err_domain_remove; |
509 | |
510 | return 0; |
511 | |
512 | err_domain_remove: |
513 | clk_bulk_disable_unprepare(num_clks: arb->nclks, clks: arb->clks); |
514 | err_put_clks: |
515 | clk_bulk_put(num_clks: arb->nclks, clks: arb->clks); |
516 | return err; |
517 | } |
518 | |
519 | static 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(num_clks: arb->nclks, clks: arb->clks); |
526 | clk_bulk_put(num_clks: arb->nclks, clks: arb->clks); |
527 | } |
528 | |
529 | static 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 | }; |
540 | MODULE_DEVICE_TABLE(of, mtk_spmi_match_table); |
541 | |
542 | static 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 | }; |
550 | module_platform_driver(mtk_spmi_driver); |
551 | |
552 | MODULE_AUTHOR("Hsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com>" ); |
553 | MODULE_DESCRIPTION("MediaTek SPMI Driver" ); |
554 | MODULE_LICENSE("GPL" ); |
555 | |