]>
Commit | Line | Data |
---|---|---|
e874a669 EL |
1 | /* |
2 | * Copyright 2013 Emilio López | |
3 | * | |
4 | * Emilio López <emilio@elopez.com.ar> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | */ | |
16 | ||
17 | #include <linux/clk-provider.h> | |
18 | #include <linux/clkdev.h> | |
e874a669 EL |
19 | #include <linux/of.h> |
20 | #include <linux/of_address.h> | |
cfb0086d | 21 | #include <linux/reset-controller.h> |
601da9d0 | 22 | #include <linux/spinlock.h> |
e874a669 EL |
23 | |
24 | #include "clk-factors.h" | |
25 | ||
26 | static DEFINE_SPINLOCK(clk_lock); | |
27 | ||
40a5dcba EL |
28 | /* Maximum number of parents our clocks have */ |
29 | #define SUNXI_MAX_PARENTS 5 | |
30 | ||
e874a669 | 31 | /** |
81ba6c5e | 32 | * sun4i_get_pll1_factors() - calculates n, k, m, p factors for PLL1 |
e874a669 EL |
33 | * PLL1 rate is calculated as follows |
34 | * rate = (parent_rate * n * (k + 1) >> p) / (m + 1); | |
35 | * parent_rate is always 24Mhz | |
36 | */ | |
37 | ||
81ba6c5e | 38 | static void sun4i_get_pll1_factors(u32 *freq, u32 parent_rate, |
e874a669 EL |
39 | u8 *n, u8 *k, u8 *m, u8 *p) |
40 | { | |
41 | u8 div; | |
42 | ||
43 | /* Normalize value to a 6M multiple */ | |
44 | div = *freq / 6000000; | |
45 | *freq = 6000000 * div; | |
46 | ||
47 | /* we were called to round the frequency, we can now return */ | |
48 | if (n == NULL) | |
49 | return; | |
50 | ||
51 | /* m is always zero for pll1 */ | |
52 | *m = 0; | |
53 | ||
54 | /* k is 1 only on these cases */ | |
55 | if (*freq >= 768000000 || *freq == 42000000 || *freq == 54000000) | |
56 | *k = 1; | |
57 | else | |
58 | *k = 0; | |
59 | ||
60 | /* p will be 3 for divs under 10 */ | |
61 | if (div < 10) | |
62 | *p = 3; | |
63 | ||
64 | /* p will be 2 for divs between 10 - 20 and odd divs under 32 */ | |
65 | else if (div < 20 || (div < 32 && (div & 1))) | |
66 | *p = 2; | |
67 | ||
68 | /* p will be 1 for even divs under 32, divs under 40 and odd pairs | |
69 | * of divs between 40-62 */ | |
70 | else if (div < 40 || (div < 64 && (div & 2))) | |
71 | *p = 1; | |
72 | ||
73 | /* any other entries have p = 0 */ | |
74 | else | |
75 | *p = 0; | |
76 | ||
77 | /* calculate a suitable n based on k and p */ | |
78 | div <<= *p; | |
79 | div /= (*k + 1); | |
80 | *n = div / 4; | |
81 | } | |
82 | ||
6a721db1 MR |
83 | /** |
84 | * sun6i_a31_get_pll1_factors() - calculates n, k and m factors for PLL1 | |
85 | * PLL1 rate is calculated as follows | |
86 | * rate = parent_rate * (n + 1) * (k + 1) / (m + 1); | |
87 | * parent_rate should always be 24MHz | |
88 | */ | |
89 | static void sun6i_a31_get_pll1_factors(u32 *freq, u32 parent_rate, | |
90 | u8 *n, u8 *k, u8 *m, u8 *p) | |
91 | { | |
92 | /* | |
93 | * We can operate only on MHz, this will make our life easier | |
94 | * later. | |
95 | */ | |
96 | u32 freq_mhz = *freq / 1000000; | |
97 | u32 parent_freq_mhz = parent_rate / 1000000; | |
98 | ||
99 | /* | |
100 | * Round down the frequency to the closest multiple of either | |
101 | * 6 or 16 | |
102 | */ | |
103 | u32 round_freq_6 = round_down(freq_mhz, 6); | |
104 | u32 round_freq_16 = round_down(freq_mhz, 16); | |
105 | ||
106 | if (round_freq_6 > round_freq_16) | |
107 | freq_mhz = round_freq_6; | |
108 | else | |
109 | freq_mhz = round_freq_16; | |
e874a669 | 110 | |
6a721db1 MR |
111 | *freq = freq_mhz * 1000000; |
112 | ||
113 | /* | |
114 | * If the factors pointer are null, we were just called to | |
115 | * round down the frequency. | |
116 | * Exit. | |
117 | */ | |
118 | if (n == NULL) | |
119 | return; | |
120 | ||
121 | /* If the frequency is a multiple of 32 MHz, k is always 3 */ | |
122 | if (!(freq_mhz % 32)) | |
123 | *k = 3; | |
124 | /* If the frequency is a multiple of 9 MHz, k is always 2 */ | |
125 | else if (!(freq_mhz % 9)) | |
126 | *k = 2; | |
127 | /* If the frequency is a multiple of 8 MHz, k is always 1 */ | |
128 | else if (!(freq_mhz % 8)) | |
129 | *k = 1; | |
130 | /* Otherwise, we don't use the k factor */ | |
131 | else | |
132 | *k = 0; | |
133 | ||
134 | /* | |
135 | * If the frequency is a multiple of 2 but not a multiple of | |
136 | * 3, m is 3. This is the first time we use 6 here, yet we | |
137 | * will use it on several other places. | |
138 | * We use this number because it's the lowest frequency we can | |
139 | * generate (with n = 0, k = 0, m = 3), so every other frequency | |
140 | * somehow relates to this frequency. | |
141 | */ | |
142 | if ((freq_mhz % 6) == 2 || (freq_mhz % 6) == 4) | |
143 | *m = 2; | |
144 | /* | |
145 | * If the frequency is a multiple of 6MHz, but the factor is | |
146 | * odd, m will be 3 | |
147 | */ | |
148 | else if ((freq_mhz / 6) & 1) | |
149 | *m = 3; | |
150 | /* Otherwise, we end up with m = 1 */ | |
151 | else | |
152 | *m = 1; | |
153 | ||
154 | /* Calculate n thanks to the above factors we already got */ | |
155 | *n = freq_mhz * (*m + 1) / ((*k + 1) * parent_freq_mhz) - 1; | |
156 | ||
157 | /* | |
158 | * If n end up being outbound, and that we can still decrease | |
159 | * m, do it. | |
160 | */ | |
161 | if ((*n + 1) > 31 && (*m + 1) > 1) { | |
162 | *n = (*n + 1) / 2 - 1; | |
163 | *m = (*m + 1) / 2 - 1; | |
164 | } | |
165 | } | |
e874a669 | 166 | |
515c1a4b CYT |
167 | /** |
168 | * sun8i_a23_get_pll1_factors() - calculates n, k, m, p factors for PLL1 | |
169 | * PLL1 rate is calculated as follows | |
170 | * rate = (parent_rate * (n + 1) * (k + 1) >> p) / (m + 1); | |
171 | * parent_rate is always 24Mhz | |
172 | */ | |
173 | ||
174 | static void sun8i_a23_get_pll1_factors(u32 *freq, u32 parent_rate, | |
175 | u8 *n, u8 *k, u8 *m, u8 *p) | |
176 | { | |
177 | u8 div; | |
178 | ||
179 | /* Normalize value to a 6M multiple */ | |
180 | div = *freq / 6000000; | |
181 | *freq = 6000000 * div; | |
182 | ||
183 | /* we were called to round the frequency, we can now return */ | |
184 | if (n == NULL) | |
185 | return; | |
186 | ||
187 | /* m is always zero for pll1 */ | |
188 | *m = 0; | |
189 | ||
190 | /* k is 1 only on these cases */ | |
191 | if (*freq >= 768000000 || *freq == 42000000 || *freq == 54000000) | |
192 | *k = 1; | |
193 | else | |
194 | *k = 0; | |
195 | ||
196 | /* p will be 2 for divs under 20 and odd divs under 32 */ | |
197 | if (div < 20 || (div < 32 && (div & 1))) | |
198 | *p = 2; | |
199 | ||
200 | /* p will be 1 for even divs under 32, divs under 40 and odd pairs | |
201 | * of divs between 40-62 */ | |
202 | else if (div < 40 || (div < 64 && (div & 2))) | |
203 | *p = 1; | |
204 | ||
205 | /* any other entries have p = 0 */ | |
206 | else | |
207 | *p = 0; | |
208 | ||
209 | /* calculate a suitable n based on k and p */ | |
210 | div <<= *p; | |
211 | div /= (*k + 1); | |
212 | *n = div / 4 - 1; | |
213 | } | |
214 | ||
d584c133 EL |
215 | /** |
216 | * sun4i_get_pll5_factors() - calculates n, k factors for PLL5 | |
217 | * PLL5 rate is calculated as follows | |
218 | * rate = parent_rate * n * (k + 1) | |
219 | * parent_rate is always 24Mhz | |
220 | */ | |
221 | ||
222 | static void sun4i_get_pll5_factors(u32 *freq, u32 parent_rate, | |
223 | u8 *n, u8 *k, u8 *m, u8 *p) | |
224 | { | |
225 | u8 div; | |
226 | ||
227 | /* Normalize value to a parent_rate multiple (24M) */ | |
228 | div = *freq / parent_rate; | |
229 | *freq = parent_rate * div; | |
230 | ||
231 | /* we were called to round the frequency, we can now return */ | |
232 | if (n == NULL) | |
233 | return; | |
234 | ||
235 | if (div < 31) | |
236 | *k = 0; | |
237 | else if (div / 2 < 31) | |
238 | *k = 1; | |
239 | else if (div / 3 < 31) | |
240 | *k = 2; | |
241 | else | |
242 | *k = 3; | |
243 | ||
244 | *n = DIV_ROUND_UP(div, (*k+1)); | |
245 | } | |
246 | ||
92ef67c5 MR |
247 | /** |
248 | * sun6i_a31_get_pll6_factors() - calculates n, k factors for A31 PLL6 | |
249 | * PLL6 rate is calculated as follows | |
250 | * rate = parent_rate * n * (k + 1) / 2 | |
251 | * parent_rate is always 24Mhz | |
252 | */ | |
253 | ||
254 | static void sun6i_a31_get_pll6_factors(u32 *freq, u32 parent_rate, | |
255 | u8 *n, u8 *k, u8 *m, u8 *p) | |
256 | { | |
257 | u8 div; | |
258 | ||
259 | /* | |
260 | * We always have 24MHz / 2, so we can just say that our | |
261 | * parent clock is 12MHz. | |
262 | */ | |
263 | parent_rate = parent_rate / 2; | |
264 | ||
265 | /* Normalize value to a parent_rate multiple (24M / 2) */ | |
266 | div = *freq / parent_rate; | |
267 | *freq = parent_rate * div; | |
268 | ||
269 | /* we were called to round the frequency, we can now return */ | |
270 | if (n == NULL) | |
271 | return; | |
272 | ||
273 | *k = div / 32; | |
274 | if (*k > 3) | |
275 | *k = 3; | |
d584c133 | 276 | |
92ef67c5 MR |
277 | *n = DIV_ROUND_UP(div, (*k+1)); |
278 | } | |
d584c133 | 279 | |
e874a669 | 280 | /** |
81ba6c5e | 281 | * sun4i_get_apb1_factors() - calculates m, p factors for APB1 |
e874a669 EL |
282 | * APB1 rate is calculated as follows |
283 | * rate = (parent_rate >> p) / (m + 1); | |
284 | */ | |
285 | ||
81ba6c5e | 286 | static void sun4i_get_apb1_factors(u32 *freq, u32 parent_rate, |
e874a669 EL |
287 | u8 *n, u8 *k, u8 *m, u8 *p) |
288 | { | |
289 | u8 calcm, calcp; | |
290 | ||
291 | if (parent_rate < *freq) | |
292 | *freq = parent_rate; | |
293 | ||
22260139 | 294 | parent_rate = DIV_ROUND_UP(parent_rate, *freq); |
e874a669 EL |
295 | |
296 | /* Invalid rate! */ | |
297 | if (parent_rate > 32) | |
298 | return; | |
299 | ||
300 | if (parent_rate <= 4) | |
301 | calcp = 0; | |
302 | else if (parent_rate <= 8) | |
303 | calcp = 1; | |
304 | else if (parent_rate <= 16) | |
305 | calcp = 2; | |
306 | else | |
307 | calcp = 3; | |
308 | ||
309 | calcm = (parent_rate >> calcp) - 1; | |
310 | ||
311 | *freq = (parent_rate >> calcp) / (calcm + 1); | |
312 | ||
313 | /* we were called to round the frequency, we can now return */ | |
314 | if (n == NULL) | |
315 | return; | |
316 | ||
317 | *m = calcm; | |
318 | *p = calcp; | |
319 | } | |
320 | ||
321 | ||
322 | ||
7551769a | 323 | |
6f863417 CYT |
324 | /** |
325 | * sun7i_a20_get_out_factors() - calculates m, p factors for CLK_OUT_A/B | |
326 | * CLK_OUT rate is calculated as follows | |
327 | * rate = (parent_rate >> p) / (m + 1); | |
328 | */ | |
329 | ||
330 | static void sun7i_a20_get_out_factors(u32 *freq, u32 parent_rate, | |
331 | u8 *n, u8 *k, u8 *m, u8 *p) | |
332 | { | |
333 | u8 div, calcm, calcp; | |
334 | ||
335 | /* These clocks can only divide, so we will never be able to achieve | |
336 | * frequencies higher than the parent frequency */ | |
337 | if (*freq > parent_rate) | |
338 | *freq = parent_rate; | |
339 | ||
22260139 | 340 | div = DIV_ROUND_UP(parent_rate, *freq); |
6f863417 CYT |
341 | |
342 | if (div < 32) | |
343 | calcp = 0; | |
344 | else if (div / 2 < 32) | |
345 | calcp = 1; | |
346 | else if (div / 4 < 32) | |
347 | calcp = 2; | |
348 | else | |
349 | calcp = 3; | |
350 | ||
351 | calcm = DIV_ROUND_UP(div, 1 << calcp); | |
352 | ||
353 | *freq = (parent_rate >> calcp) / calcm; | |
354 | ||
355 | /* we were called to round the frequency, we can now return */ | |
356 | if (n == NULL) | |
357 | return; | |
358 | ||
359 | *m = calcm - 1; | |
360 | *p = calcp; | |
361 | } | |
362 | ||
95713978 EL |
363 | /** |
364 | * clk_sunxi_mmc_phase_control() - configures MMC clock phase control | |
365 | */ | |
366 | ||
a97181ad | 367 | void clk_sunxi_mmc_phase_control(struct clk *clk, u8 sample, u8 output) |
95713978 EL |
368 | { |
369 | #define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw) | |
370 | #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw) | |
371 | ||
a97181ad | 372 | struct clk_hw *hw = __clk_get_hw(clk); |
95713978 EL |
373 | struct clk_composite *composite = to_clk_composite(hw); |
374 | struct clk_hw *rate_hw = composite->rate_hw; | |
375 | struct clk_factors *factors = to_clk_factors(rate_hw); | |
376 | unsigned long flags = 0; | |
377 | u32 reg; | |
378 | ||
379 | if (factors->lock) | |
380 | spin_lock_irqsave(factors->lock, flags); | |
381 | ||
382 | reg = readl(factors->reg); | |
383 | ||
384 | /* set sample clock phase control */ | |
385 | reg &= ~(0x7 << 20); | |
386 | reg |= ((sample & 0x7) << 20); | |
387 | ||
388 | /* set output clock phase control */ | |
389 | reg &= ~(0x7 << 8); | |
390 | reg |= ((output & 0x7) << 8); | |
391 | ||
392 | writel(reg, factors->reg); | |
393 | ||
394 | if (factors->lock) | |
395 | spin_unlock_irqrestore(factors->lock, flags); | |
396 | } | |
397 | EXPORT_SYMBOL(clk_sunxi_mmc_phase_control); | |
398 | ||
399 | ||
e874a669 EL |
400 | /** |
401 | * sunxi_factors_clk_setup() - Setup function for factor clocks | |
402 | */ | |
403 | ||
81ba6c5e | 404 | static struct clk_factors_config sun4i_pll1_config = { |
e874a669 EL |
405 | .nshift = 8, |
406 | .nwidth = 5, | |
407 | .kshift = 4, | |
408 | .kwidth = 2, | |
409 | .mshift = 0, | |
410 | .mwidth = 2, | |
411 | .pshift = 16, | |
412 | .pwidth = 2, | |
413 | }; | |
414 | ||
6a721db1 MR |
415 | static struct clk_factors_config sun6i_a31_pll1_config = { |
416 | .nshift = 8, | |
417 | .nwidth = 5, | |
418 | .kshift = 4, | |
419 | .kwidth = 2, | |
420 | .mshift = 0, | |
421 | .mwidth = 2, | |
422 | }; | |
423 | ||
515c1a4b CYT |
424 | static struct clk_factors_config sun8i_a23_pll1_config = { |
425 | .nshift = 8, | |
426 | .nwidth = 5, | |
427 | .kshift = 4, | |
428 | .kwidth = 2, | |
429 | .mshift = 0, | |
430 | .mwidth = 2, | |
431 | .pshift = 16, | |
432 | .pwidth = 2, | |
433 | .n_start = 1, | |
434 | }; | |
435 | ||
d584c133 EL |
436 | static struct clk_factors_config sun4i_pll5_config = { |
437 | .nshift = 8, | |
438 | .nwidth = 5, | |
439 | .kshift = 4, | |
440 | .kwidth = 2, | |
441 | }; | |
442 | ||
92ef67c5 MR |
443 | static struct clk_factors_config sun6i_a31_pll6_config = { |
444 | .nshift = 8, | |
445 | .nwidth = 5, | |
446 | .kshift = 4, | |
447 | .kwidth = 2, | |
448 | }; | |
449 | ||
81ba6c5e | 450 | static struct clk_factors_config sun4i_apb1_config = { |
e874a669 EL |
451 | .mshift = 0, |
452 | .mwidth = 5, | |
453 | .pshift = 16, | |
454 | .pwidth = 2, | |
455 | }; | |
456 | ||
6f863417 CYT |
457 | /* user manual says "n" but it's really "p" */ |
458 | static struct clk_factors_config sun7i_a20_out_config = { | |
459 | .mshift = 8, | |
460 | .mwidth = 5, | |
461 | .pshift = 20, | |
462 | .pwidth = 2, | |
463 | }; | |
464 | ||
52be7cc8 | 465 | static const struct factors_data sun4i_pll1_data __initconst = { |
d838ff33 | 466 | .enable = 31, |
81ba6c5e MR |
467 | .table = &sun4i_pll1_config, |
468 | .getter = sun4i_get_pll1_factors, | |
e874a669 EL |
469 | }; |
470 | ||
52be7cc8 | 471 | static const struct factors_data sun6i_a31_pll1_data __initconst = { |
d838ff33 | 472 | .enable = 31, |
6a721db1 MR |
473 | .table = &sun6i_a31_pll1_config, |
474 | .getter = sun6i_a31_get_pll1_factors, | |
475 | }; | |
476 | ||
515c1a4b CYT |
477 | static const struct factors_data sun8i_a23_pll1_data __initconst = { |
478 | .enable = 31, | |
479 | .table = &sun8i_a23_pll1_config, | |
480 | .getter = sun8i_a23_get_pll1_factors, | |
481 | }; | |
482 | ||
5a8ddf26 EL |
483 | static const struct factors_data sun7i_a20_pll4_data __initconst = { |
484 | .enable = 31, | |
485 | .table = &sun4i_pll5_config, | |
486 | .getter = sun4i_get_pll5_factors, | |
487 | }; | |
488 | ||
d584c133 EL |
489 | static const struct factors_data sun4i_pll5_data __initconst = { |
490 | .enable = 31, | |
491 | .table = &sun4i_pll5_config, | |
492 | .getter = sun4i_get_pll5_factors, | |
667f542d CYT |
493 | .name = "pll5", |
494 | }; | |
495 | ||
496 | static const struct factors_data sun4i_pll6_data __initconst = { | |
497 | .enable = 31, | |
498 | .table = &sun4i_pll5_config, | |
499 | .getter = sun4i_get_pll5_factors, | |
500 | .name = "pll6", | |
d584c133 EL |
501 | }; |
502 | ||
92ef67c5 MR |
503 | static const struct factors_data sun6i_a31_pll6_data __initconst = { |
504 | .enable = 31, | |
505 | .table = &sun6i_a31_pll6_config, | |
506 | .getter = sun6i_a31_get_pll6_factors, | |
507 | }; | |
508 | ||
52be7cc8 | 509 | static const struct factors_data sun4i_apb1_data __initconst = { |
93746e70 EL |
510 | .mux = 24, |
511 | .muxmask = BIT(1) | BIT(0), | |
81ba6c5e MR |
512 | .table = &sun4i_apb1_config, |
513 | .getter = sun4i_get_apb1_factors, | |
e874a669 EL |
514 | }; |
515 | ||
6f863417 CYT |
516 | static const struct factors_data sun7i_a20_out_data __initconst = { |
517 | .enable = 31, | |
518 | .mux = 24, | |
e94f8cb3 | 519 | .muxmask = BIT(1) | BIT(0), |
6f863417 CYT |
520 | .table = &sun7i_a20_out_config, |
521 | .getter = sun7i_a20_get_out_factors, | |
522 | }; | |
523 | ||
5f4e0be3 | 524 | static struct clk * __init sunxi_factors_clk_setup(struct device_node *node, |
601da9d0 | 525 | const struct factors_data *data) |
e874a669 | 526 | { |
601da9d0 | 527 | return sunxi_factors_register(node, data, &clk_lock); |
e874a669 EL |
528 | } |
529 | ||
530 | ||
531 | ||
532 | /** | |
533 | * sunxi_mux_clk_setup() - Setup function for muxes | |
534 | */ | |
535 | ||
536 | #define SUNXI_MUX_GATE_WIDTH 2 | |
537 | ||
538 | struct mux_data { | |
539 | u8 shift; | |
540 | }; | |
541 | ||
52be7cc8 | 542 | static const struct mux_data sun4i_cpu_mux_data __initconst = { |
e874a669 EL |
543 | .shift = 16, |
544 | }; | |
545 | ||
52be7cc8 | 546 | static const struct mux_data sun6i_a31_ahb1_mux_data __initconst = { |
6a721db1 MR |
547 | .shift = 12, |
548 | }; | |
549 | ||
e874a669 EL |
550 | static void __init sunxi_mux_clk_setup(struct device_node *node, |
551 | struct mux_data *data) | |
552 | { | |
553 | struct clk *clk; | |
554 | const char *clk_name = node->name; | |
edaf3fb5 | 555 | const char *parents[SUNXI_MAX_PARENTS]; |
89a9456d | 556 | void __iomem *reg; |
e874a669 EL |
557 | int i = 0; |
558 | ||
559 | reg = of_iomap(node, 0); | |
560 | ||
edaf3fb5 EL |
561 | while (i < SUNXI_MAX_PARENTS && |
562 | (parents[i] = of_clk_get_parent_name(node, i)) != NULL) | |
e874a669 EL |
563 | i++; |
564 | ||
f64111eb CYT |
565 | of_property_read_string(node, "clock-output-names", &clk_name); |
566 | ||
819c1de3 JH |
567 | clk = clk_register_mux(NULL, clk_name, parents, i, |
568 | CLK_SET_RATE_NO_REPARENT, reg, | |
e874a669 EL |
569 | data->shift, SUNXI_MUX_GATE_WIDTH, |
570 | 0, &clk_lock); | |
571 | ||
572 | if (clk) { | |
573 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | |
574 | clk_register_clkdev(clk, clk_name, NULL); | |
575 | } | |
576 | } | |
577 | ||
578 | ||
579 | ||
580 | /** | |
581 | * sunxi_divider_clk_setup() - Setup function for simple divider clocks | |
582 | */ | |
583 | ||
e874a669 | 584 | struct div_data { |
70855bb5 MR |
585 | u8 shift; |
586 | u8 pow; | |
587 | u8 width; | |
ea5671bf | 588 | const struct clk_div_table *table; |
e874a669 EL |
589 | }; |
590 | ||
52be7cc8 | 591 | static const struct div_data sun4i_axi_data __initconst = { |
70855bb5 MR |
592 | .shift = 0, |
593 | .pow = 0, | |
594 | .width = 2, | |
e874a669 EL |
595 | }; |
596 | ||
515c1a4b CYT |
597 | static const struct clk_div_table sun8i_a23_axi_table[] __initconst = { |
598 | { .val = 0, .div = 1 }, | |
599 | { .val = 1, .div = 2 }, | |
600 | { .val = 2, .div = 3 }, | |
601 | { .val = 3, .div = 4 }, | |
602 | { .val = 4, .div = 4 }, | |
603 | { .val = 5, .div = 4 }, | |
604 | { .val = 6, .div = 4 }, | |
605 | { .val = 7, .div = 4 }, | |
606 | { } /* sentinel */ | |
607 | }; | |
608 | ||
609 | static const struct div_data sun8i_a23_axi_data __initconst = { | |
610 | .width = 3, | |
611 | .table = sun8i_a23_axi_table, | |
612 | }; | |
613 | ||
52be7cc8 | 614 | static const struct div_data sun4i_ahb_data __initconst = { |
70855bb5 MR |
615 | .shift = 4, |
616 | .pow = 1, | |
617 | .width = 2, | |
e874a669 EL |
618 | }; |
619 | ||
cfe4c93b CYT |
620 | static const struct clk_div_table sun4i_apb0_table[] __initconst = { |
621 | { .val = 0, .div = 2 }, | |
622 | { .val = 1, .div = 2 }, | |
623 | { .val = 2, .div = 4 }, | |
624 | { .val = 3, .div = 8 }, | |
625 | { } /* sentinel */ | |
626 | }; | |
627 | ||
52be7cc8 | 628 | static const struct div_data sun4i_apb0_data __initconst = { |
70855bb5 MR |
629 | .shift = 8, |
630 | .pow = 1, | |
631 | .width = 2, | |
cfe4c93b | 632 | .table = sun4i_apb0_table, |
e874a669 EL |
633 | }; |
634 | ||
635 | static void __init sunxi_divider_clk_setup(struct device_node *node, | |
636 | struct div_data *data) | |
637 | { | |
638 | struct clk *clk; | |
639 | const char *clk_name = node->name; | |
640 | const char *clk_parent; | |
89a9456d | 641 | void __iomem *reg; |
e874a669 EL |
642 | |
643 | reg = of_iomap(node, 0); | |
644 | ||
645 | clk_parent = of_clk_get_parent_name(node, 0); | |
646 | ||
f64111eb CYT |
647 | of_property_read_string(node, "clock-output-names", &clk_name); |
648 | ||
ea5671bf CYT |
649 | clk = clk_register_divider_table(NULL, clk_name, clk_parent, 0, |
650 | reg, data->shift, data->width, | |
651 | data->pow ? CLK_DIVIDER_POWER_OF_TWO : 0, | |
652 | data->table, &clk_lock); | |
e874a669 EL |
653 | if (clk) { |
654 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | |
655 | clk_register_clkdev(clk, clk_name, NULL); | |
656 | } | |
657 | } | |
658 | ||
659 | ||
13569a70 | 660 | |
cfb0086d HG |
661 | /** |
662 | * sunxi_gates_reset... - reset bits in leaf gate clk registers handling | |
663 | */ | |
664 | ||
665 | struct gates_reset_data { | |
666 | void __iomem *reg; | |
667 | spinlock_t *lock; | |
668 | struct reset_controller_dev rcdev; | |
669 | }; | |
670 | ||
671 | static int sunxi_gates_reset_assert(struct reset_controller_dev *rcdev, | |
672 | unsigned long id) | |
673 | { | |
674 | struct gates_reset_data *data = container_of(rcdev, | |
675 | struct gates_reset_data, | |
676 | rcdev); | |
677 | unsigned long flags; | |
678 | u32 reg; | |
679 | ||
680 | spin_lock_irqsave(data->lock, flags); | |
681 | ||
682 | reg = readl(data->reg); | |
683 | writel(reg & ~BIT(id), data->reg); | |
684 | ||
685 | spin_unlock_irqrestore(data->lock, flags); | |
686 | ||
687 | return 0; | |
688 | } | |
689 | ||
690 | static int sunxi_gates_reset_deassert(struct reset_controller_dev *rcdev, | |
691 | unsigned long id) | |
692 | { | |
693 | struct gates_reset_data *data = container_of(rcdev, | |
694 | struct gates_reset_data, | |
695 | rcdev); | |
696 | unsigned long flags; | |
697 | u32 reg; | |
698 | ||
699 | spin_lock_irqsave(data->lock, flags); | |
700 | ||
701 | reg = readl(data->reg); | |
702 | writel(reg | BIT(id), data->reg); | |
703 | ||
704 | spin_unlock_irqrestore(data->lock, flags); | |
705 | ||
706 | return 0; | |
707 | } | |
708 | ||
709 | static struct reset_control_ops sunxi_gates_reset_ops = { | |
710 | .assert = sunxi_gates_reset_assert, | |
711 | .deassert = sunxi_gates_reset_deassert, | |
712 | }; | |
713 | ||
13569a70 EL |
714 | /** |
715 | * sunxi_gates_clk_setup() - Setup function for leaf gates on clocks | |
716 | */ | |
717 | ||
718 | #define SUNXI_GATES_MAX_SIZE 64 | |
719 | ||
720 | struct gates_data { | |
721 | DECLARE_BITMAP(mask, SUNXI_GATES_MAX_SIZE); | |
cfb0086d | 722 | u32 reset_mask; |
13569a70 EL |
723 | }; |
724 | ||
52be7cc8 | 725 | static const struct gates_data sun4i_axi_gates_data __initconst = { |
13569a70 EL |
726 | .mask = {1}, |
727 | }; | |
728 | ||
52be7cc8 | 729 | static const struct gates_data sun4i_ahb_gates_data __initconst = { |
13569a70 EL |
730 | .mask = {0x7F77FFF, 0x14FB3F}, |
731 | }; | |
732 | ||
52be7cc8 | 733 | static const struct gates_data sun5i_a10s_ahb_gates_data __initconst = { |
2371dd88 MR |
734 | .mask = {0x147667e7, 0x185915}, |
735 | }; | |
736 | ||
52be7cc8 | 737 | static const struct gates_data sun5i_a13_ahb_gates_data __initconst = { |
4f985b4c MR |
738 | .mask = {0x107067e7, 0x185111}, |
739 | }; | |
740 | ||
52be7cc8 | 741 | static const struct gates_data sun6i_a31_ahb1_gates_data __initconst = { |
6a721db1 MR |
742 | .mask = {0xEDFE7F62, 0x794F931}, |
743 | }; | |
744 | ||
52be7cc8 | 745 | static const struct gates_data sun7i_a20_ahb_gates_data __initconst = { |
1fb2e4aa MR |
746 | .mask = { 0x12f77fff, 0x16ff3f }, |
747 | }; | |
748 | ||
515c1a4b CYT |
749 | static const struct gates_data sun8i_a23_ahb1_gates_data __initconst = { |
750 | .mask = {0x25386742, 0x2505111}, | |
751 | }; | |
752 | ||
0b0f0802 CYT |
753 | static const struct gates_data sun9i_a80_ahb0_gates_data __initconst = { |
754 | .mask = {0xF5F12B}, | |
755 | }; | |
756 | ||
757 | static const struct gates_data sun9i_a80_ahb1_gates_data __initconst = { | |
758 | .mask = {0x1E20003}, | |
759 | }; | |
760 | ||
761 | static const struct gates_data sun9i_a80_ahb2_gates_data __initconst = { | |
762 | .mask = {0x9B7}, | |
763 | }; | |
764 | ||
52be7cc8 | 765 | static const struct gates_data sun4i_apb0_gates_data __initconst = { |
13569a70 EL |
766 | .mask = {0x4EF}, |
767 | }; | |
768 | ||
52be7cc8 | 769 | static const struct gates_data sun5i_a10s_apb0_gates_data __initconst = { |
2371dd88 MR |
770 | .mask = {0x469}, |
771 | }; | |
772 | ||
52be7cc8 | 773 | static const struct gates_data sun5i_a13_apb0_gates_data __initconst = { |
4f985b4c MR |
774 | .mask = {0x61}, |
775 | }; | |
776 | ||
52be7cc8 | 777 | static const struct gates_data sun7i_a20_apb0_gates_data __initconst = { |
1fb2e4aa MR |
778 | .mask = { 0x4ff }, |
779 | }; | |
780 | ||
0b0f0802 CYT |
781 | static const struct gates_data sun9i_a80_apb0_gates_data __initconst = { |
782 | .mask = {0xEB822}, | |
783 | }; | |
784 | ||
52be7cc8 | 785 | static const struct gates_data sun4i_apb1_gates_data __initconst = { |
13569a70 EL |
786 | .mask = {0xFF00F7}, |
787 | }; | |
788 | ||
52be7cc8 | 789 | static const struct gates_data sun5i_a10s_apb1_gates_data __initconst = { |
2371dd88 MR |
790 | .mask = {0xf0007}, |
791 | }; | |
792 | ||
52be7cc8 | 793 | static const struct gates_data sun5i_a13_apb1_gates_data __initconst = { |
4f985b4c MR |
794 | .mask = {0xa0007}, |
795 | }; | |
796 | ||
52be7cc8 | 797 | static const struct gates_data sun6i_a31_apb1_gates_data __initconst = { |
6a721db1 MR |
798 | .mask = {0x3031}, |
799 | }; | |
800 | ||
515c1a4b CYT |
801 | static const struct gates_data sun8i_a23_apb1_gates_data __initconst = { |
802 | .mask = {0x3021}, | |
803 | }; | |
804 | ||
52be7cc8 | 805 | static const struct gates_data sun6i_a31_apb2_gates_data __initconst = { |
6a721db1 MR |
806 | .mask = {0x3F000F}, |
807 | }; | |
808 | ||
52be7cc8 | 809 | static const struct gates_data sun7i_a20_apb1_gates_data __initconst = { |
1fb2e4aa MR |
810 | .mask = { 0xff80ff }, |
811 | }; | |
812 | ||
0b0f0802 CYT |
813 | static const struct gates_data sun9i_a80_apb1_gates_data __initconst = { |
814 | .mask = {0x3F001F}, | |
815 | }; | |
816 | ||
515c1a4b CYT |
817 | static const struct gates_data sun8i_a23_apb2_gates_data __initconst = { |
818 | .mask = {0x1F0007}, | |
819 | }; | |
820 | ||
5abdbf2f RB |
821 | static const struct gates_data sun4i_a10_usb_gates_data __initconst = { |
822 | .mask = {0x1C0}, | |
823 | .reset_mask = 0x07, | |
824 | }; | |
825 | ||
826 | static const struct gates_data sun5i_a13_usb_gates_data __initconst = { | |
827 | .mask = {0x140}, | |
828 | .reset_mask = 0x03, | |
829 | }; | |
830 | ||
e0e7943c MR |
831 | static const struct gates_data sun6i_a31_usb_gates_data __initconst = { |
832 | .mask = { BIT(18) | BIT(17) | BIT(16) | BIT(10) | BIT(9) | BIT(8) }, | |
833 | .reset_mask = BIT(2) | BIT(1) | BIT(0), | |
834 | }; | |
835 | ||
13569a70 EL |
836 | static void __init sunxi_gates_clk_setup(struct device_node *node, |
837 | struct gates_data *data) | |
838 | { | |
839 | struct clk_onecell_data *clk_data; | |
cfb0086d | 840 | struct gates_reset_data *reset_data; |
13569a70 EL |
841 | const char *clk_parent; |
842 | const char *clk_name; | |
89a9456d | 843 | void __iomem *reg; |
13569a70 EL |
844 | int qty; |
845 | int i = 0; | |
846 | int j = 0; | |
13569a70 EL |
847 | |
848 | reg = of_iomap(node, 0); | |
849 | ||
850 | clk_parent = of_clk_get_parent_name(node, 0); | |
851 | ||
852 | /* Worst-case size approximation and memory allocation */ | |
853 | qty = find_last_bit(data->mask, SUNXI_GATES_MAX_SIZE); | |
854 | clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL); | |
855 | if (!clk_data) | |
856 | return; | |
857 | clk_data->clks = kzalloc((qty+1) * sizeof(struct clk *), GFP_KERNEL); | |
858 | if (!clk_data->clks) { | |
859 | kfree(clk_data); | |
860 | return; | |
861 | } | |
862 | ||
863 | for_each_set_bit(i, data->mask, SUNXI_GATES_MAX_SIZE) { | |
864 | of_property_read_string_index(node, "clock-output-names", | |
865 | j, &clk_name); | |
866 | ||
13569a70 | 867 | clk_data->clks[i] = clk_register_gate(NULL, clk_name, |
70eab199 | 868 | clk_parent, 0, |
13569a70 EL |
869 | reg + 4 * (i/32), i % 32, |
870 | 0, &clk_lock); | |
871 | WARN_ON(IS_ERR(clk_data->clks[i])); | |
d14e4705 | 872 | clk_register_clkdev(clk_data->clks[i], clk_name, NULL); |
13569a70 EL |
873 | |
874 | j++; | |
875 | } | |
876 | ||
877 | /* Adjust to the real max */ | |
878 | clk_data->clk_num = i; | |
879 | ||
880 | of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); | |
cfb0086d HG |
881 | |
882 | /* Register a reset controler for gates with reset bits */ | |
883 | if (data->reset_mask == 0) | |
884 | return; | |
885 | ||
886 | reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL); | |
887 | if (!reset_data) | |
888 | return; | |
889 | ||
890 | reset_data->reg = reg; | |
891 | reset_data->lock = &clk_lock; | |
892 | reset_data->rcdev.nr_resets = __fls(data->reset_mask) + 1; | |
893 | reset_data->rcdev.ops = &sunxi_gates_reset_ops; | |
894 | reset_data->rcdev.of_node = node; | |
895 | reset_controller_register(&reset_data->rcdev); | |
13569a70 EL |
896 | } |
897 | ||
d584c133 EL |
898 | |
899 | ||
900 | /** | |
901 | * sunxi_divs_clk_setup() helper data | |
902 | */ | |
903 | ||
904 | #define SUNXI_DIVS_MAX_QTY 2 | |
905 | #define SUNXI_DIVISOR_WIDTH 2 | |
906 | ||
907 | struct divs_data { | |
908 | const struct factors_data *factors; /* data for the factor clock */ | |
909 | struct { | |
910 | u8 fixed; /* is it a fixed divisor? if not... */ | |
911 | struct clk_div_table *table; /* is it a table based divisor? */ | |
912 | u8 shift; /* otherwise it's a normal divisor with this shift */ | |
913 | u8 pow; /* is it power-of-two based? */ | |
914 | u8 gate; /* is it independently gateable? */ | |
915 | } div[SUNXI_DIVS_MAX_QTY]; | |
916 | }; | |
917 | ||
918 | static struct clk_div_table pll6_sata_tbl[] = { | |
919 | { .val = 0, .div = 6, }, | |
920 | { .val = 1, .div = 12, }, | |
921 | { .val = 2, .div = 18, }, | |
922 | { .val = 3, .div = 24, }, | |
923 | { } /* sentinel */ | |
924 | }; | |
925 | ||
926 | static const struct divs_data pll5_divs_data __initconst = { | |
927 | .factors = &sun4i_pll5_data, | |
928 | .div = { | |
929 | { .shift = 0, .pow = 0, }, /* M, DDR */ | |
930 | { .shift = 16, .pow = 1, }, /* P, other */ | |
931 | } | |
932 | }; | |
933 | ||
934 | static const struct divs_data pll6_divs_data __initconst = { | |
667f542d | 935 | .factors = &sun4i_pll6_data, |
d584c133 EL |
936 | .div = { |
937 | { .shift = 0, .table = pll6_sata_tbl, .gate = 14 }, /* M, SATA */ | |
938 | { .fixed = 2 }, /* P, other */ | |
939 | } | |
940 | }; | |
941 | ||
942 | /** | |
943 | * sunxi_divs_clk_setup() - Setup function for leaf divisors on clocks | |
944 | * | |
945 | * These clocks look something like this | |
946 | * ________________________ | |
947 | * | ___divisor 1---|----> to consumer | |
948 | * parent >--| pll___/___divisor 2---|----> to consumer | |
949 | * | \_______________|____> to consumer | |
950 | * |________________________| | |
951 | */ | |
952 | ||
953 | static void __init sunxi_divs_clk_setup(struct device_node *node, | |
954 | struct divs_data *data) | |
955 | { | |
956 | struct clk_onecell_data *clk_data; | |
97e36b3c | 957 | const char *parent; |
d584c133 EL |
958 | const char *clk_name; |
959 | struct clk **clks, *pclk; | |
960 | struct clk_hw *gate_hw, *rate_hw; | |
961 | const struct clk_ops *rate_ops; | |
962 | struct clk_gate *gate = NULL; | |
963 | struct clk_fixed_factor *fix_factor; | |
964 | struct clk_divider *divider; | |
89a9456d | 965 | void __iomem *reg; |
d584c133 EL |
966 | int i = 0; |
967 | int flags, clkflags; | |
968 | ||
969 | /* Set up factor clock that we will be dividing */ | |
970 | pclk = sunxi_factors_clk_setup(node, data->factors); | |
97e36b3c | 971 | parent = __clk_get_name(pclk); |
d584c133 EL |
972 | |
973 | reg = of_iomap(node, 0); | |
974 | ||
975 | clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL); | |
976 | if (!clk_data) | |
977 | return; | |
978 | ||
d1933689 | 979 | clks = kzalloc((SUNXI_DIVS_MAX_QTY+1) * sizeof(*clks), GFP_KERNEL); |
d584c133 EL |
980 | if (!clks) |
981 | goto free_clkdata; | |
982 | ||
983 | clk_data->clks = clks; | |
984 | ||
985 | /* It's not a good idea to have automatic reparenting changing | |
986 | * our RAM clock! */ | |
987 | clkflags = !strcmp("pll5", parent) ? 0 : CLK_SET_RATE_PARENT; | |
988 | ||
989 | for (i = 0; i < SUNXI_DIVS_MAX_QTY; i++) { | |
990 | if (of_property_read_string_index(node, "clock-output-names", | |
991 | i, &clk_name) != 0) | |
992 | break; | |
993 | ||
994 | gate_hw = NULL; | |
995 | rate_hw = NULL; | |
996 | rate_ops = NULL; | |
997 | ||
998 | /* If this leaf clock can be gated, create a gate */ | |
999 | if (data->div[i].gate) { | |
1000 | gate = kzalloc(sizeof(*gate), GFP_KERNEL); | |
1001 | if (!gate) | |
1002 | goto free_clks; | |
1003 | ||
1004 | gate->reg = reg; | |
1005 | gate->bit_idx = data->div[i].gate; | |
1006 | gate->lock = &clk_lock; | |
1007 | ||
1008 | gate_hw = &gate->hw; | |
1009 | } | |
1010 | ||
1011 | /* Leaves can be fixed or configurable divisors */ | |
1012 | if (data->div[i].fixed) { | |
1013 | fix_factor = kzalloc(sizeof(*fix_factor), GFP_KERNEL); | |
1014 | if (!fix_factor) | |
1015 | goto free_gate; | |
1016 | ||
1017 | fix_factor->mult = 1; | |
1018 | fix_factor->div = data->div[i].fixed; | |
1019 | ||
1020 | rate_hw = &fix_factor->hw; | |
1021 | rate_ops = &clk_fixed_factor_ops; | |
1022 | } else { | |
1023 | divider = kzalloc(sizeof(*divider), GFP_KERNEL); | |
1024 | if (!divider) | |
1025 | goto free_gate; | |
1026 | ||
1027 | flags = data->div[i].pow ? CLK_DIVIDER_POWER_OF_TWO : 0; | |
1028 | ||
1029 | divider->reg = reg; | |
1030 | divider->shift = data->div[i].shift; | |
1031 | divider->width = SUNXI_DIVISOR_WIDTH; | |
1032 | divider->flags = flags; | |
1033 | divider->lock = &clk_lock; | |
1034 | divider->table = data->div[i].table; | |
1035 | ||
1036 | rate_hw = ÷r->hw; | |
1037 | rate_ops = &clk_divider_ops; | |
1038 | } | |
1039 | ||
1040 | /* Wrap the (potential) gate and the divisor on a composite | |
1041 | * clock to unify them */ | |
1042 | clks[i] = clk_register_composite(NULL, clk_name, &parent, 1, | |
1043 | NULL, NULL, | |
1044 | rate_hw, rate_ops, | |
1045 | gate_hw, &clk_gate_ops, | |
1046 | clkflags); | |
1047 | ||
1048 | WARN_ON(IS_ERR(clk_data->clks[i])); | |
1049 | clk_register_clkdev(clks[i], clk_name, NULL); | |
1050 | } | |
1051 | ||
1052 | /* The last clock available on the getter is the parent */ | |
1053 | clks[i++] = pclk; | |
1054 | ||
1055 | /* Adjust to the real max */ | |
1056 | clk_data->clk_num = i; | |
1057 | ||
1058 | of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); | |
1059 | ||
1060 | return; | |
1061 | ||
1062 | free_gate: | |
1063 | kfree(gate); | |
1064 | free_clks: | |
1065 | kfree(clks); | |
1066 | free_clkdata: | |
1067 | kfree(clk_data); | |
1068 | } | |
1069 | ||
1070 | ||
1071 | ||
e874a669 | 1072 | /* Matches for factors clocks */ |
52be7cc8 | 1073 | static const struct of_device_id clk_factors_match[] __initconst = { |
fd1b22f6 | 1074 | {.compatible = "allwinner,sun4i-a10-pll1-clk", .data = &sun4i_pll1_data,}, |
6a721db1 | 1075 | {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,}, |
515c1a4b | 1076 | {.compatible = "allwinner,sun8i-a23-pll1-clk", .data = &sun8i_a23_pll1_data,}, |
5a8ddf26 | 1077 | {.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,}, |
92ef67c5 | 1078 | {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,}, |
fd1b22f6 | 1079 | {.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,}, |
6f863417 | 1080 | {.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,}, |
e874a669 EL |
1081 | {} |
1082 | }; | |
1083 | ||
1084 | /* Matches for divider clocks */ | |
52be7cc8 | 1085 | static const struct of_device_id clk_div_match[] __initconst = { |
fd1b22f6 | 1086 | {.compatible = "allwinner,sun4i-a10-axi-clk", .data = &sun4i_axi_data,}, |
515c1a4b | 1087 | {.compatible = "allwinner,sun8i-a23-axi-clk", .data = &sun8i_a23_axi_data,}, |
fd1b22f6 MR |
1088 | {.compatible = "allwinner,sun4i-a10-ahb-clk", .data = &sun4i_ahb_data,}, |
1089 | {.compatible = "allwinner,sun4i-a10-apb0-clk", .data = &sun4i_apb0_data,}, | |
e874a669 EL |
1090 | {} |
1091 | }; | |
1092 | ||
d584c133 EL |
1093 | /* Matches for divided outputs */ |
1094 | static const struct of_device_id clk_divs_match[] __initconst = { | |
fd1b22f6 MR |
1095 | {.compatible = "allwinner,sun4i-a10-pll5-clk", .data = &pll5_divs_data,}, |
1096 | {.compatible = "allwinner,sun4i-a10-pll6-clk", .data = &pll6_divs_data,}, | |
d584c133 EL |
1097 | {} |
1098 | }; | |
1099 | ||
e874a669 | 1100 | /* Matches for mux clocks */ |
52be7cc8 | 1101 | static const struct of_device_id clk_mux_match[] __initconst = { |
fd1b22f6 | 1102 | {.compatible = "allwinner,sun4i-a10-cpu-clk", .data = &sun4i_cpu_mux_data,}, |
6a721db1 | 1103 | {.compatible = "allwinner,sun6i-a31-ahb1-mux-clk", .data = &sun6i_a31_ahb1_mux_data,}, |
e874a669 EL |
1104 | {} |
1105 | }; | |
1106 | ||
13569a70 | 1107 | /* Matches for gate clocks */ |
52be7cc8 | 1108 | static const struct of_device_id clk_gates_match[] __initconst = { |
fd1b22f6 MR |
1109 | {.compatible = "allwinner,sun4i-a10-axi-gates-clk", .data = &sun4i_axi_gates_data,}, |
1110 | {.compatible = "allwinner,sun4i-a10-ahb-gates-clk", .data = &sun4i_ahb_gates_data,}, | |
2371dd88 | 1111 | {.compatible = "allwinner,sun5i-a10s-ahb-gates-clk", .data = &sun5i_a10s_ahb_gates_data,}, |
4f985b4c | 1112 | {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,}, |
6a721db1 | 1113 | {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,}, |
1fb2e4aa | 1114 | {.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,}, |
515c1a4b | 1115 | {.compatible = "allwinner,sun8i-a23-ahb1-gates-clk", .data = &sun8i_a23_ahb1_gates_data,}, |
0b0f0802 CYT |
1116 | {.compatible = "allwinner,sun9i-a80-ahb0-gates-clk", .data = &sun9i_a80_ahb0_gates_data,}, |
1117 | {.compatible = "allwinner,sun9i-a80-ahb1-gates-clk", .data = &sun9i_a80_ahb1_gates_data,}, | |
1118 | {.compatible = "allwinner,sun9i-a80-ahb2-gates-clk", .data = &sun9i_a80_ahb2_gates_data,}, | |
fd1b22f6 | 1119 | {.compatible = "allwinner,sun4i-a10-apb0-gates-clk", .data = &sun4i_apb0_gates_data,}, |
2371dd88 | 1120 | {.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,}, |
4f985b4c | 1121 | {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,}, |
1fb2e4aa | 1122 | {.compatible = "allwinner,sun7i-a20-apb0-gates-clk", .data = &sun7i_a20_apb0_gates_data,}, |
0b0f0802 | 1123 | {.compatible = "allwinner,sun9i-a80-apb0-gates-clk", .data = &sun9i_a80_apb0_gates_data,}, |
fd1b22f6 | 1124 | {.compatible = "allwinner,sun4i-a10-apb1-gates-clk", .data = &sun4i_apb1_gates_data,}, |
2371dd88 | 1125 | {.compatible = "allwinner,sun5i-a10s-apb1-gates-clk", .data = &sun5i_a10s_apb1_gates_data,}, |
4f985b4c | 1126 | {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,}, |
6a721db1 | 1127 | {.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,}, |
1fb2e4aa | 1128 | {.compatible = "allwinner,sun7i-a20-apb1-gates-clk", .data = &sun7i_a20_apb1_gates_data,}, |
515c1a4b | 1129 | {.compatible = "allwinner,sun8i-a23-apb1-gates-clk", .data = &sun8i_a23_apb1_gates_data,}, |
0b0f0802 | 1130 | {.compatible = "allwinner,sun9i-a80-apb1-gates-clk", .data = &sun9i_a80_apb1_gates_data,}, |
6a721db1 | 1131 | {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,}, |
515c1a4b | 1132 | {.compatible = "allwinner,sun8i-a23-apb2-gates-clk", .data = &sun8i_a23_apb2_gates_data,}, |
5abdbf2f RB |
1133 | {.compatible = "allwinner,sun4i-a10-usb-clk", .data = &sun4i_a10_usb_gates_data,}, |
1134 | {.compatible = "allwinner,sun5i-a13-usb-clk", .data = &sun5i_a13_usb_gates_data,}, | |
e0e7943c | 1135 | {.compatible = "allwinner,sun6i-a31-usb-clk", .data = &sun6i_a31_usb_gates_data,}, |
13569a70 EL |
1136 | {} |
1137 | }; | |
1138 | ||
e874a669 EL |
1139 | static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_match, |
1140 | void *function) | |
1141 | { | |
1142 | struct device_node *np; | |
1143 | const struct div_data *data; | |
1144 | const struct of_device_id *match; | |
1145 | void (*setup_function)(struct device_node *, const void *) = function; | |
1146 | ||
cb7d5f42 | 1147 | for_each_matching_node_and_match(np, clk_match, &match) { |
e874a669 EL |
1148 | data = match->data; |
1149 | setup_function(np, data); | |
1150 | } | |
1151 | } | |
1152 | ||
134a6690 | 1153 | static void __init sunxi_init_clocks(const char *clocks[], int nclocks) |
8e6a4c40 | 1154 | { |
134a6690 | 1155 | unsigned int i; |
8e6a4c40 | 1156 | |
e874a669 EL |
1157 | /* Register factor clocks */ |
1158 | of_sunxi_table_clock_setup(clk_factors_match, sunxi_factors_clk_setup); | |
1159 | ||
1160 | /* Register divider clocks */ | |
1161 | of_sunxi_table_clock_setup(clk_div_match, sunxi_divider_clk_setup); | |
1162 | ||
d584c133 EL |
1163 | /* Register divided output clocks */ |
1164 | of_sunxi_table_clock_setup(clk_divs_match, sunxi_divs_clk_setup); | |
1165 | ||
e874a669 EL |
1166 | /* Register mux clocks */ |
1167 | of_sunxi_table_clock_setup(clk_mux_match, sunxi_mux_clk_setup); | |
13569a70 EL |
1168 | |
1169 | /* Register gate clocks */ | |
1170 | of_sunxi_table_clock_setup(clk_gates_match, sunxi_gates_clk_setup); | |
8e6a4c40 | 1171 | |
134a6690 MR |
1172 | /* Protect the clocks that needs to stay on */ |
1173 | for (i = 0; i < nclocks; i++) { | |
1174 | struct clk *clk = clk_get(NULL, clocks[i]); | |
1175 | ||
1176 | if (!IS_ERR(clk)) | |
1177 | clk_prepare_enable(clk); | |
1178 | } | |
1179 | } | |
1180 | ||
1181 | static const char *sun4i_a10_critical_clocks[] __initdata = { | |
1182 | "pll5_ddr", | |
70eab199 | 1183 | "ahb_sdram", |
134a6690 MR |
1184 | }; |
1185 | ||
1186 | static void __init sun4i_a10_init_clocks(struct device_node *node) | |
1187 | { | |
1188 | sunxi_init_clocks(sun4i_a10_critical_clocks, | |
1189 | ARRAY_SIZE(sun4i_a10_critical_clocks)); | |
1190 | } | |
1191 | CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks); | |
1192 | ||
1193 | static const char *sun5i_critical_clocks[] __initdata = { | |
134a6690 | 1194 | "pll5_ddr", |
70eab199 | 1195 | "ahb_sdram", |
134a6690 MR |
1196 | }; |
1197 | ||
1198 | static void __init sun5i_init_clocks(struct device_node *node) | |
1199 | { | |
1200 | sunxi_init_clocks(sun5i_critical_clocks, | |
1201 | ARRAY_SIZE(sun5i_critical_clocks)); | |
1202 | } | |
1203 | CLK_OF_DECLARE(sun5i_a10s_clk_init, "allwinner,sun5i-a10s", sun5i_init_clocks); | |
1204 | CLK_OF_DECLARE(sun5i_a13_clk_init, "allwinner,sun5i-a13", sun5i_init_clocks); | |
1205 | CLK_OF_DECLARE(sun7i_a20_clk_init, "allwinner,sun7i-a20", sun5i_init_clocks); | |
1206 | ||
1207 | static const char *sun6i_critical_clocks[] __initdata = { | |
2df73f40 | 1208 | "cpu", |
efb3184c | 1209 | "ahb1_sdram", |
134a6690 MR |
1210 | }; |
1211 | ||
1212 | static void __init sun6i_init_clocks(struct device_node *node) | |
1213 | { | |
1214 | sunxi_init_clocks(sun6i_critical_clocks, | |
1215 | ARRAY_SIZE(sun6i_critical_clocks)); | |
e874a669 | 1216 | } |
134a6690 | 1217 | CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks); |
515c1a4b | 1218 | CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun6i_init_clocks); |
0b0f0802 CYT |
1219 | |
1220 | static void __init sun9i_init_clocks(struct device_node *node) | |
1221 | { | |
1222 | sunxi_init_clocks(NULL, 0); | |
1223 | } | |
1224 | CLK_OF_DECLARE(sun9i_a80_clk_init, "allwinner,sun9i-a80", sun9i_init_clocks); |