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> | |
19 | #include <linux/clk/sunxi.h> | |
20 | #include <linux/of.h> | |
21 | #include <linux/of_address.h> | |
22 | ||
23 | #include "clk-factors.h" | |
24 | ||
25 | static DEFINE_SPINLOCK(clk_lock); | |
26 | ||
27 | /** | |
81ba6c5e | 28 | * sun4i_osc_clk_setup() - Setup function for gatable oscillator |
e874a669 EL |
29 | */ |
30 | ||
31 | #define SUNXI_OSC24M_GATE 0 | |
32 | ||
81ba6c5e | 33 | static void __init sun4i_osc_clk_setup(struct device_node *node) |
e874a669 EL |
34 | { |
35 | struct clk *clk; | |
38e4aa00 EL |
36 | struct clk_fixed_rate *fixed; |
37 | struct clk_gate *gate; | |
e874a669 | 38 | const char *clk_name = node->name; |
38e4aa00 | 39 | u32 rate; |
e874a669 | 40 | |
38e4aa00 EL |
41 | /* allocate fixed-rate and gate clock structs */ |
42 | fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL); | |
43 | if (!fixed) | |
44 | return; | |
45 | gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); | |
46 | if (!gate) { | |
47 | kfree(fixed); | |
48 | return; | |
49 | } | |
e874a669 | 50 | |
38e4aa00 EL |
51 | if (of_property_read_u32(node, "clock-frequency", &rate)) |
52 | return; | |
53 | ||
54 | /* set up gate and fixed rate properties */ | |
55 | gate->reg = of_iomap(node, 0); | |
56 | gate->bit_idx = SUNXI_OSC24M_GATE; | |
57 | gate->lock = &clk_lock; | |
58 | fixed->fixed_rate = rate; | |
e874a669 | 59 | |
38e4aa00 EL |
60 | clk = clk_register_composite(NULL, clk_name, |
61 | NULL, 0, | |
62 | NULL, NULL, | |
63 | &fixed->hw, &clk_fixed_rate_ops, | |
64 | &gate->hw, &clk_gate_ops, | |
65 | CLK_IS_ROOT); | |
e874a669 | 66 | |
ee85e9bd | 67 | if (!IS_ERR(clk)) { |
e874a669 EL |
68 | of_clk_add_provider(node, of_clk_src_simple_get, clk); |
69 | clk_register_clkdev(clk, clk_name, NULL); | |
70 | } | |
71 | } | |
81ba6c5e | 72 | CLK_OF_DECLARE(sun4i_osc, "allwinner,sun4i-osc-clk", sun4i_osc_clk_setup); |
e874a669 EL |
73 | |
74 | ||
75 | ||
76 | /** | |
81ba6c5e | 77 | * sun4i_get_pll1_factors() - calculates n, k, m, p factors for PLL1 |
e874a669 EL |
78 | * PLL1 rate is calculated as follows |
79 | * rate = (parent_rate * n * (k + 1) >> p) / (m + 1); | |
80 | * parent_rate is always 24Mhz | |
81 | */ | |
82 | ||
81ba6c5e | 83 | static void sun4i_get_pll1_factors(u32 *freq, u32 parent_rate, |
e874a669 EL |
84 | u8 *n, u8 *k, u8 *m, u8 *p) |
85 | { | |
86 | u8 div; | |
87 | ||
88 | /* Normalize value to a 6M multiple */ | |
89 | div = *freq / 6000000; | |
90 | *freq = 6000000 * div; | |
91 | ||
92 | /* we were called to round the frequency, we can now return */ | |
93 | if (n == NULL) | |
94 | return; | |
95 | ||
96 | /* m is always zero for pll1 */ | |
97 | *m = 0; | |
98 | ||
99 | /* k is 1 only on these cases */ | |
100 | if (*freq >= 768000000 || *freq == 42000000 || *freq == 54000000) | |
101 | *k = 1; | |
102 | else | |
103 | *k = 0; | |
104 | ||
105 | /* p will be 3 for divs under 10 */ | |
106 | if (div < 10) | |
107 | *p = 3; | |
108 | ||
109 | /* p will be 2 for divs between 10 - 20 and odd divs under 32 */ | |
110 | else if (div < 20 || (div < 32 && (div & 1))) | |
111 | *p = 2; | |
112 | ||
113 | /* p will be 1 for even divs under 32, divs under 40 and odd pairs | |
114 | * of divs between 40-62 */ | |
115 | else if (div < 40 || (div < 64 && (div & 2))) | |
116 | *p = 1; | |
117 | ||
118 | /* any other entries have p = 0 */ | |
119 | else | |
120 | *p = 0; | |
121 | ||
122 | /* calculate a suitable n based on k and p */ | |
123 | div <<= *p; | |
124 | div /= (*k + 1); | |
125 | *n = div / 4; | |
126 | } | |
127 | ||
6a721db1 MR |
128 | /** |
129 | * sun6i_a31_get_pll1_factors() - calculates n, k and m factors for PLL1 | |
130 | * PLL1 rate is calculated as follows | |
131 | * rate = parent_rate * (n + 1) * (k + 1) / (m + 1); | |
132 | * parent_rate should always be 24MHz | |
133 | */ | |
134 | static void sun6i_a31_get_pll1_factors(u32 *freq, u32 parent_rate, | |
135 | u8 *n, u8 *k, u8 *m, u8 *p) | |
136 | { | |
137 | /* | |
138 | * We can operate only on MHz, this will make our life easier | |
139 | * later. | |
140 | */ | |
141 | u32 freq_mhz = *freq / 1000000; | |
142 | u32 parent_freq_mhz = parent_rate / 1000000; | |
143 | ||
144 | /* | |
145 | * Round down the frequency to the closest multiple of either | |
146 | * 6 or 16 | |
147 | */ | |
148 | u32 round_freq_6 = round_down(freq_mhz, 6); | |
149 | u32 round_freq_16 = round_down(freq_mhz, 16); | |
150 | ||
151 | if (round_freq_6 > round_freq_16) | |
152 | freq_mhz = round_freq_6; | |
153 | else | |
154 | freq_mhz = round_freq_16; | |
e874a669 | 155 | |
6a721db1 MR |
156 | *freq = freq_mhz * 1000000; |
157 | ||
158 | /* | |
159 | * If the factors pointer are null, we were just called to | |
160 | * round down the frequency. | |
161 | * Exit. | |
162 | */ | |
163 | if (n == NULL) | |
164 | return; | |
165 | ||
166 | /* If the frequency is a multiple of 32 MHz, k is always 3 */ | |
167 | if (!(freq_mhz % 32)) | |
168 | *k = 3; | |
169 | /* If the frequency is a multiple of 9 MHz, k is always 2 */ | |
170 | else if (!(freq_mhz % 9)) | |
171 | *k = 2; | |
172 | /* If the frequency is a multiple of 8 MHz, k is always 1 */ | |
173 | else if (!(freq_mhz % 8)) | |
174 | *k = 1; | |
175 | /* Otherwise, we don't use the k factor */ | |
176 | else | |
177 | *k = 0; | |
178 | ||
179 | /* | |
180 | * If the frequency is a multiple of 2 but not a multiple of | |
181 | * 3, m is 3. This is the first time we use 6 here, yet we | |
182 | * will use it on several other places. | |
183 | * We use this number because it's the lowest frequency we can | |
184 | * generate (with n = 0, k = 0, m = 3), so every other frequency | |
185 | * somehow relates to this frequency. | |
186 | */ | |
187 | if ((freq_mhz % 6) == 2 || (freq_mhz % 6) == 4) | |
188 | *m = 2; | |
189 | /* | |
190 | * If the frequency is a multiple of 6MHz, but the factor is | |
191 | * odd, m will be 3 | |
192 | */ | |
193 | else if ((freq_mhz / 6) & 1) | |
194 | *m = 3; | |
195 | /* Otherwise, we end up with m = 1 */ | |
196 | else | |
197 | *m = 1; | |
198 | ||
199 | /* Calculate n thanks to the above factors we already got */ | |
200 | *n = freq_mhz * (*m + 1) / ((*k + 1) * parent_freq_mhz) - 1; | |
201 | ||
202 | /* | |
203 | * If n end up being outbound, and that we can still decrease | |
204 | * m, do it. | |
205 | */ | |
206 | if ((*n + 1) > 31 && (*m + 1) > 1) { | |
207 | *n = (*n + 1) / 2 - 1; | |
208 | *m = (*m + 1) / 2 - 1; | |
209 | } | |
210 | } | |
e874a669 EL |
211 | |
212 | /** | |
81ba6c5e | 213 | * sun4i_get_apb1_factors() - calculates m, p factors for APB1 |
e874a669 EL |
214 | * APB1 rate is calculated as follows |
215 | * rate = (parent_rate >> p) / (m + 1); | |
216 | */ | |
217 | ||
81ba6c5e | 218 | static void sun4i_get_apb1_factors(u32 *freq, u32 parent_rate, |
e874a669 EL |
219 | u8 *n, u8 *k, u8 *m, u8 *p) |
220 | { | |
221 | u8 calcm, calcp; | |
222 | ||
223 | if (parent_rate < *freq) | |
224 | *freq = parent_rate; | |
225 | ||
226 | parent_rate = (parent_rate + (*freq - 1)) / *freq; | |
227 | ||
228 | /* Invalid rate! */ | |
229 | if (parent_rate > 32) | |
230 | return; | |
231 | ||
232 | if (parent_rate <= 4) | |
233 | calcp = 0; | |
234 | else if (parent_rate <= 8) | |
235 | calcp = 1; | |
236 | else if (parent_rate <= 16) | |
237 | calcp = 2; | |
238 | else | |
239 | calcp = 3; | |
240 | ||
241 | calcm = (parent_rate >> calcp) - 1; | |
242 | ||
243 | *freq = (parent_rate >> calcp) / (calcm + 1); | |
244 | ||
245 | /* we were called to round the frequency, we can now return */ | |
246 | if (n == NULL) | |
247 | return; | |
248 | ||
249 | *m = calcm; | |
250 | *p = calcp; | |
251 | } | |
252 | ||
253 | ||
254 | ||
255 | /** | |
256 | * sunxi_factors_clk_setup() - Setup function for factor clocks | |
257 | */ | |
258 | ||
259 | struct factors_data { | |
260 | struct clk_factors_config *table; | |
261 | void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p); | |
262 | }; | |
263 | ||
81ba6c5e | 264 | static struct clk_factors_config sun4i_pll1_config = { |
e874a669 EL |
265 | .nshift = 8, |
266 | .nwidth = 5, | |
267 | .kshift = 4, | |
268 | .kwidth = 2, | |
269 | .mshift = 0, | |
270 | .mwidth = 2, | |
271 | .pshift = 16, | |
272 | .pwidth = 2, | |
273 | }; | |
274 | ||
6a721db1 MR |
275 | static struct clk_factors_config sun6i_a31_pll1_config = { |
276 | .nshift = 8, | |
277 | .nwidth = 5, | |
278 | .kshift = 4, | |
279 | .kwidth = 2, | |
280 | .mshift = 0, | |
281 | .mwidth = 2, | |
282 | }; | |
283 | ||
81ba6c5e | 284 | static struct clk_factors_config sun4i_apb1_config = { |
e874a669 EL |
285 | .mshift = 0, |
286 | .mwidth = 5, | |
287 | .pshift = 16, | |
288 | .pwidth = 2, | |
289 | }; | |
290 | ||
52be7cc8 | 291 | static const struct factors_data sun4i_pll1_data __initconst = { |
81ba6c5e MR |
292 | .table = &sun4i_pll1_config, |
293 | .getter = sun4i_get_pll1_factors, | |
e874a669 EL |
294 | }; |
295 | ||
52be7cc8 | 296 | static const struct factors_data sun6i_a31_pll1_data __initconst = { |
6a721db1 MR |
297 | .table = &sun6i_a31_pll1_config, |
298 | .getter = sun6i_a31_get_pll1_factors, | |
299 | }; | |
300 | ||
52be7cc8 | 301 | static const struct factors_data sun4i_apb1_data __initconst = { |
81ba6c5e MR |
302 | .table = &sun4i_apb1_config, |
303 | .getter = sun4i_get_apb1_factors, | |
e874a669 EL |
304 | }; |
305 | ||
306 | static void __init sunxi_factors_clk_setup(struct device_node *node, | |
307 | struct factors_data *data) | |
308 | { | |
309 | struct clk *clk; | |
310 | const char *clk_name = node->name; | |
311 | const char *parent; | |
312 | void *reg; | |
313 | ||
314 | reg = of_iomap(node, 0); | |
315 | ||
316 | parent = of_clk_get_parent_name(node, 0); | |
317 | ||
5a4fe9b5 EL |
318 | clk = clk_register_factors(NULL, clk_name, parent, 0, reg, |
319 | data->table, data->getter, &clk_lock); | |
e874a669 | 320 | |
ee85e9bd | 321 | if (!IS_ERR(clk)) { |
e874a669 EL |
322 | of_clk_add_provider(node, of_clk_src_simple_get, clk); |
323 | clk_register_clkdev(clk, clk_name, NULL); | |
324 | } | |
325 | } | |
326 | ||
327 | ||
328 | ||
329 | /** | |
330 | * sunxi_mux_clk_setup() - Setup function for muxes | |
331 | */ | |
332 | ||
333 | #define SUNXI_MUX_GATE_WIDTH 2 | |
334 | ||
335 | struct mux_data { | |
336 | u8 shift; | |
337 | }; | |
338 | ||
52be7cc8 | 339 | static const struct mux_data sun4i_cpu_mux_data __initconst = { |
e874a669 EL |
340 | .shift = 16, |
341 | }; | |
342 | ||
52be7cc8 | 343 | static const struct mux_data sun6i_a31_ahb1_mux_data __initconst = { |
6a721db1 MR |
344 | .shift = 12, |
345 | }; | |
346 | ||
52be7cc8 | 347 | static const struct mux_data sun4i_apb1_mux_data __initconst = { |
e874a669 EL |
348 | .shift = 24, |
349 | }; | |
350 | ||
351 | static void __init sunxi_mux_clk_setup(struct device_node *node, | |
352 | struct mux_data *data) | |
353 | { | |
354 | struct clk *clk; | |
355 | const char *clk_name = node->name; | |
918d7f6f | 356 | const char *parents[5]; |
e874a669 EL |
357 | void *reg; |
358 | int i = 0; | |
359 | ||
360 | reg = of_iomap(node, 0); | |
361 | ||
362 | while (i < 5 && (parents[i] = of_clk_get_parent_name(node, i)) != NULL) | |
363 | i++; | |
364 | ||
819c1de3 JH |
365 | clk = clk_register_mux(NULL, clk_name, parents, i, |
366 | CLK_SET_RATE_NO_REPARENT, reg, | |
e874a669 EL |
367 | data->shift, SUNXI_MUX_GATE_WIDTH, |
368 | 0, &clk_lock); | |
369 | ||
370 | if (clk) { | |
371 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | |
372 | clk_register_clkdev(clk, clk_name, NULL); | |
373 | } | |
374 | } | |
375 | ||
376 | ||
377 | ||
378 | /** | |
379 | * sunxi_divider_clk_setup() - Setup function for simple divider clocks | |
380 | */ | |
381 | ||
e874a669 | 382 | struct div_data { |
70855bb5 MR |
383 | u8 shift; |
384 | u8 pow; | |
385 | u8 width; | |
e874a669 EL |
386 | }; |
387 | ||
52be7cc8 | 388 | static const struct div_data sun4i_axi_data __initconst = { |
70855bb5 MR |
389 | .shift = 0, |
390 | .pow = 0, | |
391 | .width = 2, | |
e874a669 EL |
392 | }; |
393 | ||
52be7cc8 | 394 | static const struct div_data sun4i_ahb_data __initconst = { |
70855bb5 MR |
395 | .shift = 4, |
396 | .pow = 1, | |
397 | .width = 2, | |
e874a669 EL |
398 | }; |
399 | ||
52be7cc8 | 400 | static const struct div_data sun4i_apb0_data __initconst = { |
70855bb5 MR |
401 | .shift = 8, |
402 | .pow = 1, | |
403 | .width = 2, | |
e874a669 EL |
404 | }; |
405 | ||
52be7cc8 | 406 | static const struct div_data sun6i_a31_apb2_div_data __initconst = { |
6a721db1 MR |
407 | .shift = 0, |
408 | .pow = 0, | |
409 | .width = 4, | |
410 | }; | |
411 | ||
e874a669 EL |
412 | static void __init sunxi_divider_clk_setup(struct device_node *node, |
413 | struct div_data *data) | |
414 | { | |
415 | struct clk *clk; | |
416 | const char *clk_name = node->name; | |
417 | const char *clk_parent; | |
418 | void *reg; | |
419 | ||
420 | reg = of_iomap(node, 0); | |
421 | ||
422 | clk_parent = of_clk_get_parent_name(node, 0); | |
423 | ||
424 | clk = clk_register_divider(NULL, clk_name, clk_parent, 0, | |
70855bb5 | 425 | reg, data->shift, data->width, |
e874a669 EL |
426 | data->pow ? CLK_DIVIDER_POWER_OF_TWO : 0, |
427 | &clk_lock); | |
428 | if (clk) { | |
429 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | |
430 | clk_register_clkdev(clk, clk_name, NULL); | |
431 | } | |
432 | } | |
433 | ||
434 | ||
13569a70 EL |
435 | |
436 | /** | |
437 | * sunxi_gates_clk_setup() - Setup function for leaf gates on clocks | |
438 | */ | |
439 | ||
440 | #define SUNXI_GATES_MAX_SIZE 64 | |
441 | ||
442 | struct gates_data { | |
443 | DECLARE_BITMAP(mask, SUNXI_GATES_MAX_SIZE); | |
444 | }; | |
445 | ||
52be7cc8 | 446 | static const struct gates_data sun4i_axi_gates_data __initconst = { |
13569a70 EL |
447 | .mask = {1}, |
448 | }; | |
449 | ||
52be7cc8 | 450 | static const struct gates_data sun4i_ahb_gates_data __initconst = { |
13569a70 EL |
451 | .mask = {0x7F77FFF, 0x14FB3F}, |
452 | }; | |
453 | ||
52be7cc8 | 454 | static const struct gates_data sun5i_a10s_ahb_gates_data __initconst = { |
2371dd88 MR |
455 | .mask = {0x147667e7, 0x185915}, |
456 | }; | |
457 | ||
52be7cc8 | 458 | static const struct gates_data sun5i_a13_ahb_gates_data __initconst = { |
4f985b4c MR |
459 | .mask = {0x107067e7, 0x185111}, |
460 | }; | |
461 | ||
52be7cc8 | 462 | static const struct gates_data sun6i_a31_ahb1_gates_data __initconst = { |
6a721db1 MR |
463 | .mask = {0xEDFE7F62, 0x794F931}, |
464 | }; | |
465 | ||
52be7cc8 | 466 | static const struct gates_data sun7i_a20_ahb_gates_data __initconst = { |
1fb2e4aa MR |
467 | .mask = { 0x12f77fff, 0x16ff3f }, |
468 | }; | |
469 | ||
52be7cc8 | 470 | static const struct gates_data sun4i_apb0_gates_data __initconst = { |
13569a70 EL |
471 | .mask = {0x4EF}, |
472 | }; | |
473 | ||
52be7cc8 | 474 | static const struct gates_data sun5i_a10s_apb0_gates_data __initconst = { |
2371dd88 MR |
475 | .mask = {0x469}, |
476 | }; | |
477 | ||
52be7cc8 | 478 | static const struct gates_data sun5i_a13_apb0_gates_data __initconst = { |
4f985b4c MR |
479 | .mask = {0x61}, |
480 | }; | |
481 | ||
52be7cc8 | 482 | static const struct gates_data sun7i_a20_apb0_gates_data __initconst = { |
1fb2e4aa MR |
483 | .mask = { 0x4ff }, |
484 | }; | |
485 | ||
52be7cc8 | 486 | static const struct gates_data sun4i_apb1_gates_data __initconst = { |
13569a70 EL |
487 | .mask = {0xFF00F7}, |
488 | }; | |
489 | ||
52be7cc8 | 490 | static const struct gates_data sun5i_a10s_apb1_gates_data __initconst = { |
2371dd88 MR |
491 | .mask = {0xf0007}, |
492 | }; | |
493 | ||
52be7cc8 | 494 | static const struct gates_data sun5i_a13_apb1_gates_data __initconst = { |
4f985b4c MR |
495 | .mask = {0xa0007}, |
496 | }; | |
497 | ||
52be7cc8 | 498 | static const struct gates_data sun6i_a31_apb1_gates_data __initconst = { |
6a721db1 MR |
499 | .mask = {0x3031}, |
500 | }; | |
501 | ||
52be7cc8 | 502 | static const struct gates_data sun6i_a31_apb2_gates_data __initconst = { |
6a721db1 MR |
503 | .mask = {0x3F000F}, |
504 | }; | |
505 | ||
52be7cc8 | 506 | static const struct gates_data sun7i_a20_apb1_gates_data __initconst = { |
1fb2e4aa MR |
507 | .mask = { 0xff80ff }, |
508 | }; | |
509 | ||
13569a70 EL |
510 | static void __init sunxi_gates_clk_setup(struct device_node *node, |
511 | struct gates_data *data) | |
512 | { | |
513 | struct clk_onecell_data *clk_data; | |
514 | const char *clk_parent; | |
515 | const char *clk_name; | |
516 | void *reg; | |
517 | int qty; | |
518 | int i = 0; | |
519 | int j = 0; | |
520 | int ignore; | |
521 | ||
522 | reg = of_iomap(node, 0); | |
523 | ||
524 | clk_parent = of_clk_get_parent_name(node, 0); | |
525 | ||
526 | /* Worst-case size approximation and memory allocation */ | |
527 | qty = find_last_bit(data->mask, SUNXI_GATES_MAX_SIZE); | |
528 | clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL); | |
529 | if (!clk_data) | |
530 | return; | |
531 | clk_data->clks = kzalloc((qty+1) * sizeof(struct clk *), GFP_KERNEL); | |
532 | if (!clk_data->clks) { | |
533 | kfree(clk_data); | |
534 | return; | |
535 | } | |
536 | ||
537 | for_each_set_bit(i, data->mask, SUNXI_GATES_MAX_SIZE) { | |
538 | of_property_read_string_index(node, "clock-output-names", | |
539 | j, &clk_name); | |
540 | ||
541 | /* No driver claims this clock, but it should remain gated */ | |
542 | ignore = !strcmp("ahb_sdram", clk_name) ? CLK_IGNORE_UNUSED : 0; | |
543 | ||
544 | clk_data->clks[i] = clk_register_gate(NULL, clk_name, | |
545 | clk_parent, ignore, | |
546 | reg + 4 * (i/32), i % 32, | |
547 | 0, &clk_lock); | |
548 | WARN_ON(IS_ERR(clk_data->clks[i])); | |
549 | ||
550 | j++; | |
551 | } | |
552 | ||
553 | /* Adjust to the real max */ | |
554 | clk_data->clk_num = i; | |
555 | ||
556 | of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); | |
557 | } | |
558 | ||
e874a669 | 559 | /* Matches for factors clocks */ |
52be7cc8 | 560 | static const struct of_device_id clk_factors_match[] __initconst = { |
81ba6c5e | 561 | {.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,}, |
6a721db1 | 562 | {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,}, |
81ba6c5e | 563 | {.compatible = "allwinner,sun4i-apb1-clk", .data = &sun4i_apb1_data,}, |
e874a669 EL |
564 | {} |
565 | }; | |
566 | ||
567 | /* Matches for divider clocks */ | |
52be7cc8 | 568 | static const struct of_device_id clk_div_match[] __initconst = { |
81ba6c5e MR |
569 | {.compatible = "allwinner,sun4i-axi-clk", .data = &sun4i_axi_data,}, |
570 | {.compatible = "allwinner,sun4i-ahb-clk", .data = &sun4i_ahb_data,}, | |
571 | {.compatible = "allwinner,sun4i-apb0-clk", .data = &sun4i_apb0_data,}, | |
6a721db1 | 572 | {.compatible = "allwinner,sun6i-a31-apb2-div-clk", .data = &sun6i_a31_apb2_div_data,}, |
e874a669 EL |
573 | {} |
574 | }; | |
575 | ||
576 | /* Matches for mux clocks */ | |
52be7cc8 | 577 | static const struct of_device_id clk_mux_match[] __initconst = { |
81ba6c5e MR |
578 | {.compatible = "allwinner,sun4i-cpu-clk", .data = &sun4i_cpu_mux_data,}, |
579 | {.compatible = "allwinner,sun4i-apb1-mux-clk", .data = &sun4i_apb1_mux_data,}, | |
6a721db1 | 580 | {.compatible = "allwinner,sun6i-a31-ahb1-mux-clk", .data = &sun6i_a31_ahb1_mux_data,}, |
e874a669 EL |
581 | {} |
582 | }; | |
583 | ||
13569a70 | 584 | /* Matches for gate clocks */ |
52be7cc8 | 585 | static const struct of_device_id clk_gates_match[] __initconst = { |
4f985b4c MR |
586 | {.compatible = "allwinner,sun4i-axi-gates-clk", .data = &sun4i_axi_gates_data,}, |
587 | {.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &sun4i_ahb_gates_data,}, | |
2371dd88 | 588 | {.compatible = "allwinner,sun5i-a10s-ahb-gates-clk", .data = &sun5i_a10s_ahb_gates_data,}, |
4f985b4c | 589 | {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,}, |
6a721db1 | 590 | {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,}, |
1fb2e4aa | 591 | {.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,}, |
4f985b4c | 592 | {.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &sun4i_apb0_gates_data,}, |
2371dd88 | 593 | {.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,}, |
4f985b4c | 594 | {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,}, |
1fb2e4aa | 595 | {.compatible = "allwinner,sun7i-a20-apb0-gates-clk", .data = &sun7i_a20_apb0_gates_data,}, |
4f985b4c | 596 | {.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &sun4i_apb1_gates_data,}, |
2371dd88 | 597 | {.compatible = "allwinner,sun5i-a10s-apb1-gates-clk", .data = &sun5i_a10s_apb1_gates_data,}, |
4f985b4c | 598 | {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,}, |
6a721db1 | 599 | {.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,}, |
1fb2e4aa | 600 | {.compatible = "allwinner,sun7i-a20-apb1-gates-clk", .data = &sun7i_a20_apb1_gates_data,}, |
6a721db1 | 601 | {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,}, |
13569a70 EL |
602 | {} |
603 | }; | |
604 | ||
e874a669 EL |
605 | static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_match, |
606 | void *function) | |
607 | { | |
608 | struct device_node *np; | |
609 | const struct div_data *data; | |
610 | const struct of_device_id *match; | |
611 | void (*setup_function)(struct device_node *, const void *) = function; | |
612 | ||
613 | for_each_matching_node(np, clk_match) { | |
614 | match = of_match_node(clk_match, np); | |
615 | data = match->data; | |
616 | setup_function(np, data); | |
617 | } | |
618 | } | |
619 | ||
620 | void __init sunxi_init_clocks(void) | |
621 | { | |
431807f0 EL |
622 | /* Register all the simple and basic clocks on DT */ |
623 | of_clk_init(NULL); | |
e874a669 EL |
624 | |
625 | /* Register factor clocks */ | |
626 | of_sunxi_table_clock_setup(clk_factors_match, sunxi_factors_clk_setup); | |
627 | ||
628 | /* Register divider clocks */ | |
629 | of_sunxi_table_clock_setup(clk_div_match, sunxi_divider_clk_setup); | |
630 | ||
631 | /* Register mux clocks */ | |
632 | of_sunxi_table_clock_setup(clk_mux_match, sunxi_mux_clk_setup); | |
13569a70 EL |
633 | |
634 | /* Register gate clocks */ | |
635 | of_sunxi_table_clock_setup(clk_gates_match, sunxi_gates_clk_setup); | |
e874a669 | 636 | } |