1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Ingenic JZ4755 SoC CGU driver |
4 | * Heavily based on JZ4725b CGU driver |
5 | * |
6 | * Copyright (C) 2022 Siarhei Volkau |
7 | * Author: Siarhei Volkau <lis8215@gmail.com> |
8 | */ |
9 | |
10 | #include <linux/clk-provider.h> |
11 | #include <linux/delay.h> |
12 | #include <linux/of.h> |
13 | |
14 | #include <dt-bindings/clock/ingenic,jz4755-cgu.h> |
15 | |
16 | #include "cgu.h" |
17 | #include "pm.h" |
18 | |
19 | /* CGU register offsets */ |
20 | #define CGU_REG_CPCCR 0x00 |
21 | #define CGU_REG_CPPCR 0x10 |
22 | #define CGU_REG_CLKGR 0x20 |
23 | #define CGU_REG_OPCR 0x24 |
24 | #define CGU_REG_I2SCDR 0x60 |
25 | #define CGU_REG_LPCDR 0x64 |
26 | #define CGU_REG_MSCCDR 0x68 |
27 | #define CGU_REG_SSICDR 0x74 |
28 | #define CGU_REG_CIMCDR 0x7C |
29 | |
30 | static struct ingenic_cgu *cgu; |
31 | |
32 | static const s8 pll_od_encoding[4] = { |
33 | 0x0, 0x1, -1, 0x3, |
34 | }; |
35 | |
36 | static const u8 jz4755_cgu_cpccr_div_table[] = { |
37 | 1, 2, 3, 4, 6, 8, |
38 | }; |
39 | |
40 | static const u8 jz4755_cgu_pll_half_div_table[] = { |
41 | 2, 1, |
42 | }; |
43 | |
44 | static const struct ingenic_cgu_clk_info jz4755_cgu_clocks[] = { |
45 | |
46 | /* External clocks */ |
47 | |
48 | [JZ4755_CLK_EXT] = { "ext" , CGU_CLK_EXT }, |
49 | [JZ4755_CLK_OSC32K] = { "osc32k" , CGU_CLK_EXT }, |
50 | |
51 | [JZ4755_CLK_PLL] = { |
52 | "pll" , CGU_CLK_PLL, |
53 | .parents = { JZ4755_CLK_EXT, }, |
54 | .pll = { |
55 | .reg = CGU_REG_CPPCR, |
56 | .rate_multiplier = 1, |
57 | .m_shift = 23, |
58 | .m_bits = 9, |
59 | .m_offset = 2, |
60 | .n_shift = 18, |
61 | .n_bits = 5, |
62 | .n_offset = 2, |
63 | .od_shift = 16, |
64 | .od_bits = 2, |
65 | .od_max = 4, |
66 | .od_encoding = pll_od_encoding, |
67 | .stable_bit = 10, |
68 | .bypass_reg = CGU_REG_CPPCR, |
69 | .bypass_bit = 9, |
70 | .enable_bit = 8, |
71 | }, |
72 | }, |
73 | |
74 | /* Muxes & dividers */ |
75 | |
76 | [JZ4755_CLK_PLL_HALF] = { |
77 | "pll half" , CGU_CLK_DIV, |
78 | .parents = { JZ4755_CLK_PLL, }, |
79 | .div = { |
80 | CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1, 0, |
81 | jz4755_cgu_pll_half_div_table, |
82 | }, |
83 | }, |
84 | |
85 | [JZ4755_CLK_EXT_HALF] = { |
86 | "ext half" , CGU_CLK_DIV, |
87 | .parents = { JZ4755_CLK_EXT, }, |
88 | .div = { |
89 | CGU_REG_CPCCR, 30, 1, 1, -1, -1, -1, 0, |
90 | NULL, |
91 | }, |
92 | }, |
93 | |
94 | [JZ4755_CLK_CCLK] = { |
95 | "cclk" , CGU_CLK_DIV, |
96 | .parents = { JZ4755_CLK_PLL, }, |
97 | .div = { |
98 | CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0, |
99 | jz4755_cgu_cpccr_div_table, |
100 | }, |
101 | }, |
102 | |
103 | [JZ4755_CLK_H0CLK] = { |
104 | "hclk" , CGU_CLK_DIV, |
105 | .parents = { JZ4755_CLK_PLL, }, |
106 | .div = { |
107 | CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0, |
108 | jz4755_cgu_cpccr_div_table, |
109 | }, |
110 | }, |
111 | |
112 | [JZ4755_CLK_PCLK] = { |
113 | "pclk" , CGU_CLK_DIV, |
114 | .parents = { JZ4755_CLK_PLL, }, |
115 | .div = { |
116 | CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0, |
117 | jz4755_cgu_cpccr_div_table, |
118 | }, |
119 | }, |
120 | |
121 | [JZ4755_CLK_MCLK] = { |
122 | "mclk" , CGU_CLK_DIV, |
123 | .parents = { JZ4755_CLK_PLL, }, |
124 | .div = { |
125 | CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0, |
126 | jz4755_cgu_cpccr_div_table, |
127 | }, |
128 | }, |
129 | |
130 | [JZ4755_CLK_H1CLK] = { |
131 | "h1clk" , CGU_CLK_DIV, |
132 | .parents = { JZ4755_CLK_PLL, }, |
133 | .div = { |
134 | CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0, |
135 | jz4755_cgu_cpccr_div_table, |
136 | }, |
137 | }, |
138 | |
139 | [JZ4755_CLK_UDC] = { |
140 | "udc" , CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, |
141 | .parents = { JZ4755_CLK_EXT_HALF, JZ4755_CLK_PLL_HALF, }, |
142 | .mux = { CGU_REG_CPCCR, 29, 1 }, |
143 | .div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 }, |
144 | .gate = { CGU_REG_CLKGR, 10 }, |
145 | }, |
146 | |
147 | [JZ4755_CLK_LCD] = { |
148 | "lcd" , CGU_CLK_DIV | CGU_CLK_GATE, |
149 | .parents = { JZ4755_CLK_PLL_HALF, }, |
150 | .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 }, |
151 | .gate = { CGU_REG_CLKGR, 9 }, |
152 | }, |
153 | |
154 | [JZ4755_CLK_MMC] = { |
155 | "mmc" , CGU_CLK_DIV, |
156 | .parents = { JZ4755_CLK_PLL_HALF, }, |
157 | .div = { CGU_REG_MSCCDR, 0, 1, 5, -1, -1, -1 }, |
158 | }, |
159 | |
160 | [JZ4755_CLK_I2S] = { |
161 | "i2s" , CGU_CLK_MUX | CGU_CLK_DIV, |
162 | .parents = { JZ4755_CLK_EXT_HALF, JZ4755_CLK_PLL_HALF, }, |
163 | .mux = { CGU_REG_CPCCR, 31, 1 }, |
164 | .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 }, |
165 | }, |
166 | |
167 | [JZ4755_CLK_SPI] = { |
168 | "spi" , CGU_CLK_DIV | CGU_CLK_GATE, |
169 | .parents = { JZ4755_CLK_PLL_HALF, }, |
170 | .div = { CGU_REG_SSICDR, 0, 1, 4, -1, -1, -1 }, |
171 | .gate = { CGU_REG_CLKGR, 4 }, |
172 | }, |
173 | |
174 | [JZ4755_CLK_TVE] = { |
175 | "tve" , CGU_CLK_MUX | CGU_CLK_GATE, |
176 | .parents = { JZ4755_CLK_LCD, JZ4755_CLK_EXT, }, |
177 | .mux = { CGU_REG_LPCDR, 31, 1 }, |
178 | .gate = { CGU_REG_CLKGR, 18 }, |
179 | }, |
180 | |
181 | [JZ4755_CLK_RTC] = { |
182 | "rtc" , CGU_CLK_MUX | CGU_CLK_GATE, |
183 | .parents = { JZ4755_CLK_EXT512, JZ4755_CLK_OSC32K, }, |
184 | .mux = { CGU_REG_OPCR, 2, 1}, |
185 | .gate = { CGU_REG_CLKGR, 2 }, |
186 | }, |
187 | |
188 | [JZ4755_CLK_CIM] = { |
189 | "cim" , CGU_CLK_DIV | CGU_CLK_GATE, |
190 | .parents = { JZ4755_CLK_PLL_HALF, }, |
191 | .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 }, |
192 | .gate = { CGU_REG_CLKGR, 8 }, |
193 | }, |
194 | |
195 | /* Gate-only clocks */ |
196 | |
197 | [JZ4755_CLK_UART0] = { |
198 | "uart0" , CGU_CLK_GATE, |
199 | .parents = { JZ4755_CLK_EXT_HALF, }, |
200 | .gate = { CGU_REG_CLKGR, 0 }, |
201 | }, |
202 | |
203 | [JZ4755_CLK_UART1] = { |
204 | "uart1" , CGU_CLK_GATE, |
205 | .parents = { JZ4755_CLK_EXT_HALF, }, |
206 | .gate = { CGU_REG_CLKGR, 14 }, |
207 | }, |
208 | |
209 | [JZ4755_CLK_UART2] = { |
210 | "uart2" , CGU_CLK_GATE, |
211 | .parents = { JZ4755_CLK_EXT_HALF, }, |
212 | .gate = { CGU_REG_CLKGR, 15 }, |
213 | }, |
214 | |
215 | [JZ4755_CLK_ADC] = { |
216 | "adc" , CGU_CLK_GATE, |
217 | .parents = { JZ4755_CLK_EXT_HALF, }, |
218 | .gate = { CGU_REG_CLKGR, 7 }, |
219 | }, |
220 | |
221 | [JZ4755_CLK_AIC] = { |
222 | "aic" , CGU_CLK_GATE, |
223 | .parents = { JZ4755_CLK_EXT_HALF, }, |
224 | .gate = { CGU_REG_CLKGR, 5 }, |
225 | }, |
226 | |
227 | [JZ4755_CLK_I2C] = { |
228 | "i2c" , CGU_CLK_GATE, |
229 | .parents = { JZ4755_CLK_EXT_HALF, }, |
230 | .gate = { CGU_REG_CLKGR, 3 }, |
231 | }, |
232 | |
233 | [JZ4755_CLK_BCH] = { |
234 | "bch" , CGU_CLK_GATE, |
235 | .parents = { JZ4755_CLK_H1CLK, }, |
236 | .gate = { CGU_REG_CLKGR, 11 }, |
237 | }, |
238 | |
239 | [JZ4755_CLK_TCU] = { |
240 | "tcu" , CGU_CLK_GATE, |
241 | .parents = { JZ4755_CLK_EXT, }, |
242 | .gate = { CGU_REG_CLKGR, 1 }, |
243 | }, |
244 | |
245 | [JZ4755_CLK_DMA] = { |
246 | "dma" , CGU_CLK_GATE, |
247 | .parents = { JZ4755_CLK_PCLK, }, |
248 | .gate = { CGU_REG_CLKGR, 12 }, |
249 | }, |
250 | |
251 | [JZ4755_CLK_MMC0] = { |
252 | "mmc0" , CGU_CLK_GATE, |
253 | .parents = { JZ4755_CLK_MMC, }, |
254 | .gate = { CGU_REG_CLKGR, 6 }, |
255 | }, |
256 | |
257 | [JZ4755_CLK_MMC1] = { |
258 | "mmc1" , CGU_CLK_GATE, |
259 | .parents = { JZ4755_CLK_MMC, }, |
260 | .gate = { CGU_REG_CLKGR, 16 }, |
261 | }, |
262 | |
263 | [JZ4755_CLK_AUX_CPU] = { |
264 | "aux_cpu" , CGU_CLK_GATE, |
265 | .parents = { JZ4755_CLK_H1CLK, }, |
266 | .gate = { CGU_REG_CLKGR, 24 }, |
267 | }, |
268 | |
269 | [JZ4755_CLK_AHB1] = { |
270 | "ahb1" , CGU_CLK_GATE, |
271 | .parents = { JZ4755_CLK_H1CLK, }, |
272 | .gate = { CGU_REG_CLKGR, 23 }, |
273 | }, |
274 | |
275 | [JZ4755_CLK_IDCT] = { |
276 | "idct" , CGU_CLK_GATE, |
277 | .parents = { JZ4755_CLK_H1CLK, }, |
278 | .gate = { CGU_REG_CLKGR, 22 }, |
279 | }, |
280 | |
281 | [JZ4755_CLK_DB] = { |
282 | "db" , CGU_CLK_GATE, |
283 | .parents = { JZ4755_CLK_H1CLK, }, |
284 | .gate = { CGU_REG_CLKGR, 21 }, |
285 | }, |
286 | |
287 | [JZ4755_CLK_ME] = { |
288 | "me" , CGU_CLK_GATE, |
289 | .parents = { JZ4755_CLK_H1CLK, }, |
290 | .gate = { CGU_REG_CLKGR, 20 }, |
291 | }, |
292 | |
293 | [JZ4755_CLK_MC] = { |
294 | "mc" , CGU_CLK_GATE, |
295 | .parents = { JZ4755_CLK_H1CLK, }, |
296 | .gate = { CGU_REG_CLKGR, 19 }, |
297 | }, |
298 | |
299 | [JZ4755_CLK_TSSI] = { |
300 | "tssi" , CGU_CLK_GATE, |
301 | .parents = { JZ4755_CLK_EXT_HALF/* not sure */, }, |
302 | .gate = { CGU_REG_CLKGR, 17 }, |
303 | }, |
304 | |
305 | [JZ4755_CLK_IPU] = { |
306 | "ipu" , CGU_CLK_GATE, |
307 | .parents = { JZ4755_CLK_PLL_HALF/* not sure */, }, |
308 | .gate = { CGU_REG_CLKGR, 13 }, |
309 | }, |
310 | |
311 | [JZ4755_CLK_EXT512] = { |
312 | "ext/512" , CGU_CLK_FIXDIV, |
313 | .parents = { JZ4755_CLK_EXT, }, |
314 | |
315 | .fixdiv = { 512 }, |
316 | }, |
317 | |
318 | [JZ4755_CLK_UDC_PHY] = { |
319 | "udc_phy" , CGU_CLK_GATE, |
320 | .parents = { JZ4755_CLK_EXT_HALF, }, |
321 | .gate = { CGU_REG_OPCR, 6, true }, |
322 | }, |
323 | }; |
324 | |
325 | static void __init jz4755_cgu_init(struct device_node *np) |
326 | { |
327 | int retval; |
328 | |
329 | cgu = ingenic_cgu_new(clock_info: jz4755_cgu_clocks, |
330 | ARRAY_SIZE(jz4755_cgu_clocks), np); |
331 | if (!cgu) { |
332 | pr_err("%s: failed to initialise CGU\n" , __func__); |
333 | return; |
334 | } |
335 | |
336 | retval = ingenic_cgu_register_clocks(cgu); |
337 | if (retval) |
338 | pr_err("%s: failed to register CGU Clocks\n" , __func__); |
339 | |
340 | ingenic_cgu_register_syscore_ops(cgu); |
341 | } |
342 | /* |
343 | * CGU has some children devices, this is useful for probing children devices |
344 | * in the case where the device node is compatible with "simple-mfd". |
345 | */ |
346 | CLK_OF_DECLARE_DRIVER(jz4755_cgu, "ingenic,jz4755-cgu" , jz4755_cgu_init); |
347 | |