1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/clk-provider.h> |
3 | #include <linux/clk/at91_pmc.h> |
4 | #include <linux/of.h> |
5 | #include <linux/mfd/syscon.h> |
6 | #include <linux/regmap.h> |
7 | #include <linux/slab.h> |
8 | |
9 | #include "pmc.h" |
10 | |
11 | #define MASTER_SOURCE_MAX 4 |
12 | |
13 | #define PERIPHERAL_AT91RM9200 0 |
14 | #define PERIPHERAL_AT91SAM9X5 1 |
15 | |
16 | #define PERIPHERAL_MAX 64 |
17 | |
18 | #define PERIPHERAL_ID_MIN 2 |
19 | |
20 | #define PROG_SOURCE_MAX 5 |
21 | #define PROG_ID_MAX 7 |
22 | |
23 | #define SYSTEM_MAX_ID 31 |
24 | |
25 | #define GCK_INDEX_DT_AUDIO_PLL 5 |
26 | |
27 | static DEFINE_SPINLOCK(mck_lock); |
28 | |
29 | #ifdef CONFIG_HAVE_AT91_AUDIO_PLL |
30 | static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np) |
31 | { |
32 | struct clk_hw *hw; |
33 | const char *name = np->name; |
34 | const char *parent_name; |
35 | struct regmap *regmap; |
36 | struct device_node *parent_np; |
37 | |
38 | parent_np = of_get_parent(np); |
39 | regmap = syscon_node_to_regmap(parent_np); |
40 | of_node_put(parent_np); |
41 | if (IS_ERR(regmap)) |
42 | return; |
43 | |
44 | parent_name = of_clk_get_parent_name(np, 0); |
45 | |
46 | hw = at91_clk_register_audio_pll_frac(regmap, name, parent_name); |
47 | if (IS_ERR(hw)) |
48 | return; |
49 | |
50 | of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); |
51 | } |
52 | CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_frac_setup, |
53 | "atmel,sama5d2-clk-audio-pll-frac" , |
54 | of_sama5d2_clk_audio_pll_frac_setup); |
55 | |
56 | static void __init of_sama5d2_clk_audio_pll_pad_setup(struct device_node *np) |
57 | { |
58 | struct clk_hw *hw; |
59 | const char *name = np->name; |
60 | const char *parent_name; |
61 | struct regmap *regmap; |
62 | struct device_node *parent_np; |
63 | |
64 | parent_np = of_get_parent(np); |
65 | regmap = syscon_node_to_regmap(parent_np); |
66 | of_node_put(parent_np); |
67 | if (IS_ERR(regmap)) |
68 | return; |
69 | |
70 | parent_name = of_clk_get_parent_name(np, 0); |
71 | |
72 | hw = at91_clk_register_audio_pll_pad(regmap, name, parent_name); |
73 | if (IS_ERR(hw)) |
74 | return; |
75 | |
76 | of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); |
77 | } |
78 | CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pad_setup, |
79 | "atmel,sama5d2-clk-audio-pll-pad" , |
80 | of_sama5d2_clk_audio_pll_pad_setup); |
81 | |
82 | static void __init of_sama5d2_clk_audio_pll_pmc_setup(struct device_node *np) |
83 | { |
84 | struct clk_hw *hw; |
85 | const char *name = np->name; |
86 | const char *parent_name; |
87 | struct regmap *regmap; |
88 | struct device_node *parent_np; |
89 | |
90 | parent_np = of_get_parent(np); |
91 | regmap = syscon_node_to_regmap(parent_np); |
92 | of_node_put(parent_np); |
93 | if (IS_ERR(regmap)) |
94 | return; |
95 | |
96 | parent_name = of_clk_get_parent_name(np, 0); |
97 | |
98 | hw = at91_clk_register_audio_pll_pmc(regmap, name, parent_name); |
99 | if (IS_ERR(hw)) |
100 | return; |
101 | |
102 | of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); |
103 | } |
104 | CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup, |
105 | "atmel,sama5d2-clk-audio-pll-pmc" , |
106 | of_sama5d2_clk_audio_pll_pmc_setup); |
107 | #endif /* CONFIG_HAVE_AT91_AUDIO_PLL */ |
108 | |
109 | static const struct clk_pcr_layout dt_pcr_layout = { |
110 | .offset = 0x10c, |
111 | .cmd = BIT(12), |
112 | .pid_mask = GENMASK(5, 0), |
113 | .div_mask = GENMASK(17, 16), |
114 | .gckcss_mask = GENMASK(10, 8), |
115 | }; |
116 | |
117 | #ifdef CONFIG_HAVE_AT91_GENERATED_CLK |
118 | #define GENERATED_SOURCE_MAX 6 |
119 | |
120 | #define GCK_ID_I2S0 54 |
121 | #define GCK_ID_I2S1 55 |
122 | #define GCK_ID_CLASSD 59 |
123 | |
124 | static void __init of_sama5d2_clk_generated_setup(struct device_node *np) |
125 | { |
126 | int num; |
127 | u32 id; |
128 | const char *name; |
129 | struct clk_hw *hw; |
130 | unsigned int num_parents; |
131 | const char *parent_names[GENERATED_SOURCE_MAX]; |
132 | struct device_node *gcknp, *parent_np; |
133 | struct clk_range range = CLK_RANGE(0, 0); |
134 | struct regmap *regmap; |
135 | |
136 | num_parents = of_clk_get_parent_count(np); |
137 | if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX) |
138 | return; |
139 | |
140 | of_clk_parent_fill(np, parent_names, num_parents); |
141 | |
142 | num = of_get_child_count(np); |
143 | if (!num || num > PERIPHERAL_MAX) |
144 | return; |
145 | |
146 | parent_np = of_get_parent(np); |
147 | regmap = syscon_node_to_regmap(parent_np); |
148 | of_node_put(parent_np); |
149 | if (IS_ERR(regmap)) |
150 | return; |
151 | |
152 | for_each_child_of_node(np, gcknp) { |
153 | int chg_pid = INT_MIN; |
154 | |
155 | if (of_property_read_u32(gcknp, "reg" , &id)) |
156 | continue; |
157 | |
158 | if (id < PERIPHERAL_ID_MIN || id >= PERIPHERAL_MAX) |
159 | continue; |
160 | |
161 | if (of_property_read_string(np, "clock-output-names" , &name)) |
162 | name = gcknp->name; |
163 | |
164 | of_at91_get_clk_range(gcknp, "atmel,clk-output-range" , |
165 | &range); |
166 | |
167 | if (of_device_is_compatible(np, "atmel,sama5d2-clk-generated" ) && |
168 | (id == GCK_ID_I2S0 || id == GCK_ID_I2S1 || |
169 | id == GCK_ID_CLASSD)) |
170 | chg_pid = GCK_INDEX_DT_AUDIO_PLL; |
171 | |
172 | hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, |
173 | &dt_pcr_layout, name, |
174 | parent_names, NULL, NULL, |
175 | num_parents, id, &range, |
176 | chg_pid); |
177 | if (IS_ERR(hw)) |
178 | continue; |
179 | |
180 | of_clk_add_hw_provider(gcknp, of_clk_hw_simple_get, hw); |
181 | } |
182 | } |
183 | CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated" , |
184 | of_sama5d2_clk_generated_setup); |
185 | #endif /* CONFIG_HAVE_AT91_GENERATED_CLK */ |
186 | |
187 | #ifdef CONFIG_HAVE_AT91_H32MX |
188 | static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np) |
189 | { |
190 | struct clk_hw *hw; |
191 | const char *name = np->name; |
192 | const char *parent_name; |
193 | struct regmap *regmap; |
194 | struct device_node *parent_np; |
195 | |
196 | parent_np = of_get_parent(np); |
197 | regmap = syscon_node_to_regmap(parent_np); |
198 | of_node_put(parent_np); |
199 | if (IS_ERR(regmap)) |
200 | return; |
201 | |
202 | parent_name = of_clk_get_parent_name(np, 0); |
203 | |
204 | hw = at91_clk_register_h32mx(regmap, name, parent_name); |
205 | if (IS_ERR(hw)) |
206 | return; |
207 | |
208 | of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); |
209 | } |
210 | CLK_OF_DECLARE(of_sama5d4_clk_h32mx_setup, "atmel,sama5d4-clk-h32mx" , |
211 | of_sama5d4_clk_h32mx_setup); |
212 | #endif /* CONFIG_HAVE_AT91_H32MX */ |
213 | |
214 | #ifdef CONFIG_HAVE_AT91_I2S_MUX_CLK |
215 | #define I2S_BUS_NR 2 |
216 | |
217 | static void __init of_sama5d2_clk_i2s_mux_setup(struct device_node *np) |
218 | { |
219 | struct regmap *regmap_sfr; |
220 | u8 bus_id; |
221 | const char *parent_names[2]; |
222 | struct device_node *i2s_mux_np; |
223 | struct clk_hw *hw; |
224 | int ret; |
225 | |
226 | regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr" ); |
227 | if (IS_ERR(regmap_sfr)) |
228 | return; |
229 | |
230 | for_each_child_of_node(np, i2s_mux_np) { |
231 | if (of_property_read_u8(i2s_mux_np, "reg" , &bus_id)) |
232 | continue; |
233 | |
234 | if (bus_id > I2S_BUS_NR) |
235 | continue; |
236 | |
237 | ret = of_clk_parent_fill(i2s_mux_np, parent_names, 2); |
238 | if (ret != 2) |
239 | continue; |
240 | |
241 | hw = at91_clk_i2s_mux_register(regmap_sfr, i2s_mux_np->name, |
242 | parent_names, 2, bus_id); |
243 | if (IS_ERR(hw)) |
244 | continue; |
245 | |
246 | of_clk_add_hw_provider(i2s_mux_np, of_clk_hw_simple_get, hw); |
247 | } |
248 | } |
249 | CLK_OF_DECLARE(sama5d2_clk_i2s_mux, "atmel,sama5d2-clk-i2s-mux" , |
250 | of_sama5d2_clk_i2s_mux_setup); |
251 | #endif /* CONFIG_HAVE_AT91_I2S_MUX_CLK */ |
252 | |
253 | static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np) |
254 | { |
255 | struct clk_hw *hw; |
256 | const char *name = np->name; |
257 | const char *parent_name; |
258 | struct regmap *regmap; |
259 | bool bypass; |
260 | struct device_node *parent_np; |
261 | |
262 | of_property_read_string(np, propname: "clock-output-names" , out_string: &name); |
263 | bypass = of_property_read_bool(np, propname: "atmel,osc-bypass" ); |
264 | parent_name = of_clk_get_parent_name(np, index: 0); |
265 | |
266 | parent_np = of_get_parent(node: np); |
267 | regmap = syscon_node_to_regmap(np: parent_np); |
268 | of_node_put(node: parent_np); |
269 | if (IS_ERR(ptr: regmap)) |
270 | return; |
271 | |
272 | hw = at91_clk_register_main_osc(regmap, name, parent_name, NULL, bypass); |
273 | if (IS_ERR(ptr: hw)) |
274 | return; |
275 | |
276 | of_clk_add_hw_provider(np, get: of_clk_hw_simple_get, data: hw); |
277 | } |
278 | CLK_OF_DECLARE(at91rm9200_clk_main_osc, "atmel,at91rm9200-clk-main-osc" , |
279 | of_at91rm9200_clk_main_osc_setup); |
280 | |
281 | static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np) |
282 | { |
283 | struct clk_hw *hw; |
284 | u32 frequency = 0; |
285 | u32 accuracy = 0; |
286 | const char *name = np->name; |
287 | struct regmap *regmap; |
288 | struct device_node *parent_np; |
289 | |
290 | of_property_read_string(np, propname: "clock-output-names" , out_string: &name); |
291 | of_property_read_u32(np, propname: "clock-frequency" , out_value: &frequency); |
292 | of_property_read_u32(np, propname: "clock-accuracy" , out_value: &accuracy); |
293 | |
294 | parent_np = of_get_parent(node: np); |
295 | regmap = syscon_node_to_regmap(np: parent_np); |
296 | of_node_put(node: parent_np); |
297 | if (IS_ERR(ptr: regmap)) |
298 | return; |
299 | |
300 | hw = at91_clk_register_main_rc_osc(regmap, name, frequency, accuracy); |
301 | if (IS_ERR(ptr: hw)) |
302 | return; |
303 | |
304 | of_clk_add_hw_provider(np, get: of_clk_hw_simple_get, data: hw); |
305 | } |
306 | CLK_OF_DECLARE(at91sam9x5_clk_main_rc_osc, "atmel,at91sam9x5-clk-main-rc-osc" , |
307 | of_at91sam9x5_clk_main_rc_osc_setup); |
308 | |
309 | static void __init of_at91rm9200_clk_main_setup(struct device_node *np) |
310 | { |
311 | struct clk_hw *hw; |
312 | const char *parent_name; |
313 | const char *name = np->name; |
314 | struct regmap *regmap; |
315 | struct device_node *parent_np; |
316 | |
317 | parent_name = of_clk_get_parent_name(np, index: 0); |
318 | of_property_read_string(np, propname: "clock-output-names" , out_string: &name); |
319 | |
320 | parent_np = of_get_parent(node: np); |
321 | regmap = syscon_node_to_regmap(np: parent_np); |
322 | of_node_put(node: parent_np); |
323 | if (IS_ERR(ptr: regmap)) |
324 | return; |
325 | |
326 | hw = at91_clk_register_rm9200_main(regmap, name, parent_name, NULL); |
327 | if (IS_ERR(ptr: hw)) |
328 | return; |
329 | |
330 | of_clk_add_hw_provider(np, get: of_clk_hw_simple_get, data: hw); |
331 | } |
332 | CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-clk-main" , |
333 | of_at91rm9200_clk_main_setup); |
334 | |
335 | static void __init of_at91sam9x5_clk_main_setup(struct device_node *np) |
336 | { |
337 | struct clk_hw *hw; |
338 | const char *parent_names[2]; |
339 | unsigned int num_parents; |
340 | const char *name = np->name; |
341 | struct regmap *regmap; |
342 | struct device_node *parent_np; |
343 | |
344 | num_parents = of_clk_get_parent_count(np); |
345 | if (num_parents == 0 || num_parents > 2) |
346 | return; |
347 | |
348 | of_clk_parent_fill(np, parents: parent_names, size: num_parents); |
349 | parent_np = of_get_parent(node: np); |
350 | regmap = syscon_node_to_regmap(np: parent_np); |
351 | of_node_put(node: parent_np); |
352 | if (IS_ERR(ptr: regmap)) |
353 | return; |
354 | |
355 | of_property_read_string(np, propname: "clock-output-names" , out_string: &name); |
356 | |
357 | hw = at91_clk_register_sam9x5_main(regmap, name, parent_names, NULL, |
358 | num_parents); |
359 | if (IS_ERR(ptr: hw)) |
360 | return; |
361 | |
362 | of_clk_add_hw_provider(np, get: of_clk_hw_simple_get, data: hw); |
363 | } |
364 | CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-clk-main" , |
365 | of_at91sam9x5_clk_main_setup); |
366 | |
367 | static struct clk_master_characteristics * __init |
368 | of_at91_clk_master_get_characteristics(struct device_node *np) |
369 | { |
370 | struct clk_master_characteristics *characteristics; |
371 | |
372 | characteristics = kzalloc(size: sizeof(*characteristics), GFP_KERNEL); |
373 | if (!characteristics) |
374 | return NULL; |
375 | |
376 | if (of_at91_get_clk_range(np, propname: "atmel,clk-output-range" , range: &characteristics->output)) |
377 | goto out_free_characteristics; |
378 | |
379 | of_property_read_u32_array(np, propname: "atmel,clk-divisors" , |
380 | out_values: characteristics->divisors, sz: 4); |
381 | |
382 | characteristics->have_div3_pres = |
383 | of_property_read_bool(np, propname: "atmel,master-clk-have-div3-pres" ); |
384 | |
385 | return characteristics; |
386 | |
387 | out_free_characteristics: |
388 | kfree(objp: characteristics); |
389 | return NULL; |
390 | } |
391 | |
392 | static void __init |
393 | of_at91_clk_master_setup(struct device_node *np, |
394 | const struct clk_master_layout *layout) |
395 | { |
396 | struct clk_hw *hw; |
397 | unsigned int num_parents; |
398 | const char *parent_names[MASTER_SOURCE_MAX]; |
399 | const char *name = np->name; |
400 | struct clk_master_characteristics *characteristics; |
401 | struct regmap *regmap; |
402 | struct device_node *parent_np; |
403 | |
404 | num_parents = of_clk_get_parent_count(np); |
405 | if (num_parents == 0 || num_parents > MASTER_SOURCE_MAX) |
406 | return; |
407 | |
408 | of_clk_parent_fill(np, parents: parent_names, size: num_parents); |
409 | |
410 | of_property_read_string(np, propname: "clock-output-names" , out_string: &name); |
411 | |
412 | characteristics = of_at91_clk_master_get_characteristics(np); |
413 | if (!characteristics) |
414 | return; |
415 | |
416 | parent_np = of_get_parent(node: np); |
417 | regmap = syscon_node_to_regmap(np: parent_np); |
418 | of_node_put(node: parent_np); |
419 | if (IS_ERR(ptr: regmap)) |
420 | return; |
421 | |
422 | hw = at91_clk_register_master_pres(regmap, name: "masterck_pres" , num_parents, |
423 | parent_names, NULL, layout, |
424 | characteristics, lock: &mck_lock); |
425 | if (IS_ERR(ptr: hw)) |
426 | goto out_free_characteristics; |
427 | |
428 | hw = at91_clk_register_master_div(regmap, name, parent_names: "masterck_pres" , NULL, |
429 | layout, characteristics, |
430 | lock: &mck_lock, CLK_SET_RATE_GATE, safe_div: 0); |
431 | if (IS_ERR(ptr: hw)) |
432 | goto out_free_characteristics; |
433 | |
434 | of_clk_add_hw_provider(np, get: of_clk_hw_simple_get, data: hw); |
435 | return; |
436 | |
437 | out_free_characteristics: |
438 | kfree(objp: characteristics); |
439 | } |
440 | |
441 | static void __init of_at91rm9200_clk_master_setup(struct device_node *np) |
442 | { |
443 | of_at91_clk_master_setup(np, layout: &at91rm9200_master_layout); |
444 | } |
445 | CLK_OF_DECLARE(at91rm9200_clk_master, "atmel,at91rm9200-clk-master" , |
446 | of_at91rm9200_clk_master_setup); |
447 | |
448 | static void __init of_at91sam9x5_clk_master_setup(struct device_node *np) |
449 | { |
450 | of_at91_clk_master_setup(np, layout: &at91sam9x5_master_layout); |
451 | } |
452 | CLK_OF_DECLARE(at91sam9x5_clk_master, "atmel,at91sam9x5-clk-master" , |
453 | of_at91sam9x5_clk_master_setup); |
454 | |
455 | static void __init |
456 | of_at91_clk_periph_setup(struct device_node *np, u8 type) |
457 | { |
458 | int num; |
459 | u32 id; |
460 | struct clk_hw *hw; |
461 | const char *parent_name; |
462 | const char *name; |
463 | struct device_node *periphclknp; |
464 | struct regmap *regmap; |
465 | struct device_node *parent_np; |
466 | |
467 | parent_name = of_clk_get_parent_name(np, index: 0); |
468 | if (!parent_name) |
469 | return; |
470 | |
471 | num = of_get_child_count(np); |
472 | if (!num || num > PERIPHERAL_MAX) |
473 | return; |
474 | |
475 | parent_np = of_get_parent(node: np); |
476 | regmap = syscon_node_to_regmap(np: parent_np); |
477 | of_node_put(node: parent_np); |
478 | if (IS_ERR(ptr: regmap)) |
479 | return; |
480 | |
481 | for_each_child_of_node(np, periphclknp) { |
482 | if (of_property_read_u32(np: periphclknp, propname: "reg" , out_value: &id)) |
483 | continue; |
484 | |
485 | if (id >= PERIPHERAL_MAX) |
486 | continue; |
487 | |
488 | if (of_property_read_string(np, propname: "clock-output-names" , out_string: &name)) |
489 | name = periphclknp->name; |
490 | |
491 | if (type == PERIPHERAL_AT91RM9200) { |
492 | hw = at91_clk_register_peripheral(regmap, name, |
493 | parent_name, NULL, id); |
494 | } else { |
495 | struct clk_range range = CLK_RANGE(0, 0); |
496 | unsigned long flags = 0; |
497 | |
498 | of_at91_get_clk_range(np: periphclknp, |
499 | propname: "atmel,clk-output-range" , |
500 | range: &range); |
501 | |
502 | /* |
503 | * mpddr_clk feed DDR controller and is enabled by |
504 | * bootloader thus we need to keep it enabled in case |
505 | * there is no Linux consumer for it. |
506 | */ |
507 | if (!strcmp(periphclknp->name, "mpddr_clk" )) |
508 | flags = CLK_IS_CRITICAL; |
509 | |
510 | hw = at91_clk_register_sam9x5_peripheral(regmap, |
511 | lock: &pmc_pcr_lock, |
512 | layout: &dt_pcr_layout, |
513 | name, |
514 | parent_name, |
515 | NULL, |
516 | id, range: &range, |
517 | INT_MIN, |
518 | flags); |
519 | } |
520 | |
521 | if (IS_ERR(ptr: hw)) |
522 | continue; |
523 | |
524 | of_clk_add_hw_provider(np: periphclknp, get: of_clk_hw_simple_get, data: hw); |
525 | } |
526 | } |
527 | |
528 | static void __init of_at91rm9200_clk_periph_setup(struct device_node *np) |
529 | { |
530 | of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200); |
531 | } |
532 | CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral" , |
533 | of_at91rm9200_clk_periph_setup); |
534 | |
535 | static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np) |
536 | { |
537 | of_at91_clk_periph_setup(np, PERIPHERAL_AT91SAM9X5); |
538 | } |
539 | CLK_OF_DECLARE(at91sam9x5_clk_periph, "atmel,at91sam9x5-clk-peripheral" , |
540 | of_at91sam9x5_clk_periph_setup); |
541 | |
542 | static struct clk_pll_characteristics * __init |
543 | of_at91_clk_pll_get_characteristics(struct device_node *np) |
544 | { |
545 | int i; |
546 | int offset; |
547 | u32 tmp; |
548 | int num_output; |
549 | u32 num_cells; |
550 | struct clk_range input; |
551 | struct clk_range *output; |
552 | u8 *out = NULL; |
553 | u16 *icpll = NULL; |
554 | struct clk_pll_characteristics *characteristics; |
555 | |
556 | if (of_at91_get_clk_range(np, propname: "atmel,clk-input-range" , range: &input)) |
557 | return NULL; |
558 | |
559 | if (of_property_read_u32(np, propname: "#atmel,pll-clk-output-range-cells" , |
560 | out_value: &num_cells)) |
561 | return NULL; |
562 | |
563 | if (num_cells < 2 || num_cells > 4) |
564 | return NULL; |
565 | |
566 | if (!of_get_property(node: np, name: "atmel,pll-clk-output-ranges" , lenp: &tmp)) |
567 | return NULL; |
568 | num_output = tmp / (sizeof(u32) * num_cells); |
569 | |
570 | characteristics = kzalloc(size: sizeof(*characteristics), GFP_KERNEL); |
571 | if (!characteristics) |
572 | return NULL; |
573 | |
574 | output = kcalloc(n: num_output, size: sizeof(*output), GFP_KERNEL); |
575 | if (!output) |
576 | goto out_free_characteristics; |
577 | |
578 | if (num_cells > 2) { |
579 | out = kcalloc(n: num_output, size: sizeof(*out), GFP_KERNEL); |
580 | if (!out) |
581 | goto out_free_output; |
582 | } |
583 | |
584 | if (num_cells > 3) { |
585 | icpll = kcalloc(n: num_output, size: sizeof(*icpll), GFP_KERNEL); |
586 | if (!icpll) |
587 | goto out_free_output; |
588 | } |
589 | |
590 | for (i = 0; i < num_output; i++) { |
591 | offset = i * num_cells; |
592 | if (of_property_read_u32_index(np, |
593 | propname: "atmel,pll-clk-output-ranges" , |
594 | index: offset, out_value: &tmp)) |
595 | goto out_free_output; |
596 | output[i].min = tmp; |
597 | if (of_property_read_u32_index(np, |
598 | propname: "atmel,pll-clk-output-ranges" , |
599 | index: offset + 1, out_value: &tmp)) |
600 | goto out_free_output; |
601 | output[i].max = tmp; |
602 | |
603 | if (num_cells == 2) |
604 | continue; |
605 | |
606 | if (of_property_read_u32_index(np, |
607 | propname: "atmel,pll-clk-output-ranges" , |
608 | index: offset + 2, out_value: &tmp)) |
609 | goto out_free_output; |
610 | out[i] = tmp; |
611 | |
612 | if (num_cells == 3) |
613 | continue; |
614 | |
615 | if (of_property_read_u32_index(np, |
616 | propname: "atmel,pll-clk-output-ranges" , |
617 | index: offset + 3, out_value: &tmp)) |
618 | goto out_free_output; |
619 | icpll[i] = tmp; |
620 | } |
621 | |
622 | characteristics->input = input; |
623 | characteristics->num_output = num_output; |
624 | characteristics->output = output; |
625 | characteristics->out = out; |
626 | characteristics->icpll = icpll; |
627 | return characteristics; |
628 | |
629 | out_free_output: |
630 | kfree(objp: icpll); |
631 | kfree(objp: out); |
632 | kfree(objp: output); |
633 | out_free_characteristics: |
634 | kfree(objp: characteristics); |
635 | return NULL; |
636 | } |
637 | |
638 | static void __init |
639 | of_at91_clk_pll_setup(struct device_node *np, |
640 | const struct clk_pll_layout *layout) |
641 | { |
642 | u32 id; |
643 | struct clk_hw *hw; |
644 | struct regmap *regmap; |
645 | const char *parent_name; |
646 | const char *name = np->name; |
647 | struct device_node *parent_np; |
648 | struct clk_pll_characteristics *characteristics; |
649 | |
650 | if (of_property_read_u32(np, propname: "reg" , out_value: &id)) |
651 | return; |
652 | |
653 | parent_name = of_clk_get_parent_name(np, index: 0); |
654 | |
655 | of_property_read_string(np, propname: "clock-output-names" , out_string: &name); |
656 | |
657 | parent_np = of_get_parent(node: np); |
658 | regmap = syscon_node_to_regmap(np: parent_np); |
659 | of_node_put(node: parent_np); |
660 | if (IS_ERR(ptr: regmap)) |
661 | return; |
662 | |
663 | characteristics = of_at91_clk_pll_get_characteristics(np); |
664 | if (!characteristics) |
665 | return; |
666 | |
667 | hw = at91_clk_register_pll(regmap, name, parent_name, id, layout, |
668 | characteristics); |
669 | if (IS_ERR(ptr: hw)) |
670 | goto out_free_characteristics; |
671 | |
672 | of_clk_add_hw_provider(np, get: of_clk_hw_simple_get, data: hw); |
673 | return; |
674 | |
675 | out_free_characteristics: |
676 | kfree(objp: characteristics); |
677 | } |
678 | |
679 | static void __init of_at91rm9200_clk_pll_setup(struct device_node *np) |
680 | { |
681 | of_at91_clk_pll_setup(np, layout: &at91rm9200_pll_layout); |
682 | } |
683 | CLK_OF_DECLARE(at91rm9200_clk_pll, "atmel,at91rm9200-clk-pll" , |
684 | of_at91rm9200_clk_pll_setup); |
685 | |
686 | static void __init of_at91sam9g45_clk_pll_setup(struct device_node *np) |
687 | { |
688 | of_at91_clk_pll_setup(np, layout: &at91sam9g45_pll_layout); |
689 | } |
690 | CLK_OF_DECLARE(at91sam9g45_clk_pll, "atmel,at91sam9g45-clk-pll" , |
691 | of_at91sam9g45_clk_pll_setup); |
692 | |
693 | static void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np) |
694 | { |
695 | of_at91_clk_pll_setup(np, layout: &at91sam9g20_pllb_layout); |
696 | } |
697 | CLK_OF_DECLARE(at91sam9g20_clk_pllb, "atmel,at91sam9g20-clk-pllb" , |
698 | of_at91sam9g20_clk_pllb_setup); |
699 | |
700 | static void __init of_sama5d3_clk_pll_setup(struct device_node *np) |
701 | { |
702 | of_at91_clk_pll_setup(np, layout: &sama5d3_pll_layout); |
703 | } |
704 | CLK_OF_DECLARE(sama5d3_clk_pll, "atmel,sama5d3-clk-pll" , |
705 | of_sama5d3_clk_pll_setup); |
706 | |
707 | static void __init |
708 | of_at91sam9x5_clk_plldiv_setup(struct device_node *np) |
709 | { |
710 | struct clk_hw *hw; |
711 | const char *parent_name; |
712 | const char *name = np->name; |
713 | struct regmap *regmap; |
714 | struct device_node *parent_np; |
715 | |
716 | parent_name = of_clk_get_parent_name(np, index: 0); |
717 | |
718 | of_property_read_string(np, propname: "clock-output-names" , out_string: &name); |
719 | |
720 | parent_np = of_get_parent(node: np); |
721 | regmap = syscon_node_to_regmap(np: parent_np); |
722 | of_node_put(node: parent_np); |
723 | if (IS_ERR(ptr: regmap)) |
724 | return; |
725 | |
726 | hw = at91_clk_register_plldiv(regmap, name, parent_name); |
727 | if (IS_ERR(ptr: hw)) |
728 | return; |
729 | |
730 | of_clk_add_hw_provider(np, get: of_clk_hw_simple_get, data: hw); |
731 | } |
732 | CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv" , |
733 | of_at91sam9x5_clk_plldiv_setup); |
734 | |
735 | static void __init |
736 | of_at91_clk_prog_setup(struct device_node *np, |
737 | const struct clk_programmable_layout *layout, |
738 | u32 *mux_table) |
739 | { |
740 | int num; |
741 | u32 id; |
742 | struct clk_hw *hw; |
743 | unsigned int num_parents; |
744 | const char *parent_names[PROG_SOURCE_MAX]; |
745 | const char *name; |
746 | struct device_node *progclknp, *parent_np; |
747 | struct regmap *regmap; |
748 | |
749 | num_parents = of_clk_get_parent_count(np); |
750 | if (num_parents == 0 || num_parents > PROG_SOURCE_MAX) |
751 | return; |
752 | |
753 | of_clk_parent_fill(np, parents: parent_names, size: num_parents); |
754 | |
755 | num = of_get_child_count(np); |
756 | if (!num || num > (PROG_ID_MAX + 1)) |
757 | return; |
758 | |
759 | parent_np = of_get_parent(node: np); |
760 | regmap = syscon_node_to_regmap(np: parent_np); |
761 | of_node_put(node: parent_np); |
762 | if (IS_ERR(ptr: regmap)) |
763 | return; |
764 | |
765 | for_each_child_of_node(np, progclknp) { |
766 | if (of_property_read_u32(np: progclknp, propname: "reg" , out_value: &id)) |
767 | continue; |
768 | |
769 | if (of_property_read_string(np, propname: "clock-output-names" , out_string: &name)) |
770 | name = progclknp->name; |
771 | |
772 | hw = at91_clk_register_programmable(regmap, name, |
773 | parent_names, NULL, num_parents, |
774 | id, layout, mux_table); |
775 | if (IS_ERR(ptr: hw)) |
776 | continue; |
777 | |
778 | of_clk_add_hw_provider(np: progclknp, get: of_clk_hw_simple_get, data: hw); |
779 | } |
780 | } |
781 | |
782 | static void __init of_at91rm9200_clk_prog_setup(struct device_node *np) |
783 | { |
784 | of_at91_clk_prog_setup(np, layout: &at91rm9200_programmable_layout, NULL); |
785 | } |
786 | CLK_OF_DECLARE(at91rm9200_clk_prog, "atmel,at91rm9200-clk-programmable" , |
787 | of_at91rm9200_clk_prog_setup); |
788 | |
789 | static void __init of_at91sam9g45_clk_prog_setup(struct device_node *np) |
790 | { |
791 | of_at91_clk_prog_setup(np, layout: &at91sam9g45_programmable_layout, NULL); |
792 | } |
793 | CLK_OF_DECLARE(at91sam9g45_clk_prog, "atmel,at91sam9g45-clk-programmable" , |
794 | of_at91sam9g45_clk_prog_setup); |
795 | |
796 | static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np) |
797 | { |
798 | of_at91_clk_prog_setup(np, layout: &at91sam9x5_programmable_layout, NULL); |
799 | } |
800 | CLK_OF_DECLARE(at91sam9x5_clk_prog, "atmel,at91sam9x5-clk-programmable" , |
801 | of_at91sam9x5_clk_prog_setup); |
802 | |
803 | static void __init of_at91sam9260_clk_slow_setup(struct device_node *np) |
804 | { |
805 | struct clk_hw *hw; |
806 | const char *parent_names[2]; |
807 | unsigned int num_parents; |
808 | const char *name = np->name; |
809 | struct regmap *regmap; |
810 | struct device_node *parent_np; |
811 | |
812 | num_parents = of_clk_get_parent_count(np); |
813 | if (num_parents != 2) |
814 | return; |
815 | |
816 | of_clk_parent_fill(np, parents: parent_names, size: num_parents); |
817 | parent_np = of_get_parent(node: np); |
818 | regmap = syscon_node_to_regmap(np: parent_np); |
819 | of_node_put(node: parent_np); |
820 | if (IS_ERR(ptr: regmap)) |
821 | return; |
822 | |
823 | of_property_read_string(np, propname: "clock-output-names" , out_string: &name); |
824 | |
825 | hw = at91_clk_register_sam9260_slow(regmap, name, parent_names, |
826 | num_parents); |
827 | if (IS_ERR(ptr: hw)) |
828 | return; |
829 | |
830 | of_clk_add_hw_provider(np, get: of_clk_hw_simple_get, data: hw); |
831 | } |
832 | CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow" , |
833 | of_at91sam9260_clk_slow_setup); |
834 | |
835 | #ifdef CONFIG_HAVE_AT91_SMD |
836 | #define SMD_SOURCE_MAX 2 |
837 | |
838 | static void __init of_at91sam9x5_clk_smd_setup(struct device_node *np) |
839 | { |
840 | struct clk_hw *hw; |
841 | unsigned int num_parents; |
842 | const char *parent_names[SMD_SOURCE_MAX]; |
843 | const char *name = np->name; |
844 | struct regmap *regmap; |
845 | struct device_node *parent_np; |
846 | |
847 | num_parents = of_clk_get_parent_count(np); |
848 | if (num_parents == 0 || num_parents > SMD_SOURCE_MAX) |
849 | return; |
850 | |
851 | of_clk_parent_fill(np, parent_names, num_parents); |
852 | |
853 | of_property_read_string(np, "clock-output-names" , &name); |
854 | |
855 | parent_np = of_get_parent(np); |
856 | regmap = syscon_node_to_regmap(parent_np); |
857 | of_node_put(parent_np); |
858 | if (IS_ERR(regmap)) |
859 | return; |
860 | |
861 | hw = at91sam9x5_clk_register_smd(regmap, name, parent_names, |
862 | num_parents); |
863 | if (IS_ERR(hw)) |
864 | return; |
865 | |
866 | of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); |
867 | } |
868 | CLK_OF_DECLARE(at91sam9x5_clk_smd, "atmel,at91sam9x5-clk-smd" , |
869 | of_at91sam9x5_clk_smd_setup); |
870 | #endif /* CONFIG_HAVE_AT91_SMD */ |
871 | |
872 | static void __init of_at91rm9200_clk_sys_setup(struct device_node *np) |
873 | { |
874 | int num; |
875 | u32 id; |
876 | struct clk_hw *hw; |
877 | const char *name; |
878 | struct device_node *sysclknp, *parent_np; |
879 | const char *parent_name; |
880 | struct regmap *regmap; |
881 | |
882 | num = of_get_child_count(np); |
883 | if (num > (SYSTEM_MAX_ID + 1)) |
884 | return; |
885 | |
886 | parent_np = of_get_parent(node: np); |
887 | regmap = syscon_node_to_regmap(np: parent_np); |
888 | of_node_put(node: parent_np); |
889 | if (IS_ERR(ptr: regmap)) |
890 | return; |
891 | |
892 | for_each_child_of_node(np, sysclknp) { |
893 | unsigned long flags = 0; |
894 | |
895 | if (of_property_read_u32(np: sysclknp, propname: "reg" , out_value: &id)) |
896 | continue; |
897 | |
898 | if (of_property_read_string(np, propname: "clock-output-names" , out_string: &name)) |
899 | name = sysclknp->name; |
900 | |
901 | parent_name = of_clk_get_parent_name(np: sysclknp, index: 0); |
902 | |
903 | /* |
904 | * ddrck feeds DDR controller and is enabled by bootloader thus |
905 | * we need to keep it enabled in case there is no Linux consumer |
906 | * for it. |
907 | */ |
908 | if (!strcmp(sysclknp->name, "ddrck" )) |
909 | flags = CLK_IS_CRITICAL; |
910 | |
911 | hw = at91_clk_register_system(regmap, name, parent_name, NULL, |
912 | id, flags); |
913 | if (IS_ERR(ptr: hw)) |
914 | continue; |
915 | |
916 | of_clk_add_hw_provider(np: sysclknp, get: of_clk_hw_simple_get, data: hw); |
917 | } |
918 | } |
919 | CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system" , |
920 | of_at91rm9200_clk_sys_setup); |
921 | |
922 | #ifdef CONFIG_HAVE_AT91_USB_CLK |
923 | #define USB_SOURCE_MAX 2 |
924 | |
925 | static void __init of_at91sam9x5_clk_usb_setup(struct device_node *np) |
926 | { |
927 | struct clk_hw *hw; |
928 | unsigned int num_parents; |
929 | const char *parent_names[USB_SOURCE_MAX]; |
930 | const char *name = np->name; |
931 | struct regmap *regmap; |
932 | struct device_node *parent_np; |
933 | |
934 | num_parents = of_clk_get_parent_count(np); |
935 | if (num_parents == 0 || num_parents > USB_SOURCE_MAX) |
936 | return; |
937 | |
938 | of_clk_parent_fill(np, parent_names, num_parents); |
939 | |
940 | of_property_read_string(np, "clock-output-names" , &name); |
941 | |
942 | parent_np = of_get_parent(np); |
943 | regmap = syscon_node_to_regmap(parent_np); |
944 | of_node_put(parent_np); |
945 | if (IS_ERR(regmap)) |
946 | return; |
947 | |
948 | hw = at91sam9x5_clk_register_usb(regmap, name, parent_names, |
949 | num_parents); |
950 | if (IS_ERR(hw)) |
951 | return; |
952 | |
953 | of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); |
954 | } |
955 | CLK_OF_DECLARE(at91sam9x5_clk_usb, "atmel,at91sam9x5-clk-usb" , |
956 | of_at91sam9x5_clk_usb_setup); |
957 | |
958 | static void __init of_at91sam9n12_clk_usb_setup(struct device_node *np) |
959 | { |
960 | struct clk_hw *hw; |
961 | const char *parent_name; |
962 | const char *name = np->name; |
963 | struct regmap *regmap; |
964 | struct device_node *parent_np; |
965 | |
966 | parent_name = of_clk_get_parent_name(np, 0); |
967 | if (!parent_name) |
968 | return; |
969 | |
970 | of_property_read_string(np, "clock-output-names" , &name); |
971 | |
972 | parent_np = of_get_parent(np); |
973 | regmap = syscon_node_to_regmap(parent_np); |
974 | of_node_put(parent_np); |
975 | if (IS_ERR(regmap)) |
976 | return; |
977 | |
978 | hw = at91sam9n12_clk_register_usb(regmap, name, parent_name); |
979 | if (IS_ERR(hw)) |
980 | return; |
981 | |
982 | of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); |
983 | } |
984 | CLK_OF_DECLARE(at91sam9n12_clk_usb, "atmel,at91sam9n12-clk-usb" , |
985 | of_at91sam9n12_clk_usb_setup); |
986 | |
987 | static void __init of_at91rm9200_clk_usb_setup(struct device_node *np) |
988 | { |
989 | struct clk_hw *hw; |
990 | const char *parent_name; |
991 | const char *name = np->name; |
992 | u32 divisors[4] = {0, 0, 0, 0}; |
993 | struct regmap *regmap; |
994 | struct device_node *parent_np; |
995 | |
996 | parent_name = of_clk_get_parent_name(np, 0); |
997 | if (!parent_name) |
998 | return; |
999 | |
1000 | of_property_read_u32_array(np, "atmel,clk-divisors" , divisors, 4); |
1001 | if (!divisors[0]) |
1002 | return; |
1003 | |
1004 | of_property_read_string(np, "clock-output-names" , &name); |
1005 | |
1006 | parent_np = of_get_parent(np); |
1007 | regmap = syscon_node_to_regmap(parent_np); |
1008 | of_node_put(parent_np); |
1009 | if (IS_ERR(regmap)) |
1010 | return; |
1011 | hw = at91rm9200_clk_register_usb(regmap, name, parent_name, divisors); |
1012 | if (IS_ERR(hw)) |
1013 | return; |
1014 | |
1015 | of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); |
1016 | } |
1017 | CLK_OF_DECLARE(at91rm9200_clk_usb, "atmel,at91rm9200-clk-usb" , |
1018 | of_at91rm9200_clk_usb_setup); |
1019 | #endif /* CONFIG_HAVE_AT91_USB_CLK */ |
1020 | |
1021 | #ifdef CONFIG_HAVE_AT91_UTMI |
1022 | static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np) |
1023 | { |
1024 | struct clk_hw *hw; |
1025 | const char *parent_name; |
1026 | const char *name = np->name; |
1027 | struct regmap *regmap_pmc, *regmap_sfr; |
1028 | struct device_node *parent_np; |
1029 | |
1030 | parent_name = of_clk_get_parent_name(np, 0); |
1031 | |
1032 | of_property_read_string(np, "clock-output-names" , &name); |
1033 | |
1034 | parent_np = of_get_parent(np); |
1035 | regmap_pmc = syscon_node_to_regmap(parent_np); |
1036 | of_node_put(parent_np); |
1037 | if (IS_ERR(regmap_pmc)) |
1038 | return; |
1039 | |
1040 | /* |
1041 | * If the device supports different mainck rates, this value has to be |
1042 | * set in the UTMI Clock Trimming register. |
1043 | * - 9x5: mainck supports several rates but it is indicated that a |
1044 | * 12 MHz is needed in case of USB. |
1045 | * - sama5d3 and sama5d2: mainck supports several rates. Configuring |
1046 | * the FREQ field of the UTMI Clock Trimming register is mandatory. |
1047 | * - sama5d4: mainck is at 12 MHz. |
1048 | * |
1049 | * We only need to retrieve sama5d3 or sama5d2 sfr regmap. |
1050 | */ |
1051 | regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d3-sfr" ); |
1052 | if (IS_ERR(regmap_sfr)) { |
1053 | regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr" ); |
1054 | if (IS_ERR(regmap_sfr)) |
1055 | regmap_sfr = NULL; |
1056 | } |
1057 | |
1058 | hw = at91_clk_register_utmi(regmap_pmc, regmap_sfr, name, parent_name, NULL); |
1059 | if (IS_ERR(hw)) |
1060 | return; |
1061 | |
1062 | of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); |
1063 | } |
1064 | CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi" , |
1065 | of_at91sam9x5_clk_utmi_setup); |
1066 | #endif /* CONFIG_HAVE_AT91_UTMI */ |
1067 | |