1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
7 * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
10 #include <linux/clk.h>
11 #include <linux/clk-provider.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/slab.h>
15 #include <dt-bindings/clock/at91.h>
19 #define SAMA7G5_INIT_TABLE(_table, _count) \
22 for (_i = 0; _i < (_count); _i++) \
26 #define SAMA7G5_FILL_TABLE(_to, _from, _count) \
29 for (_i = 0; _i < (_count); _i++) { \
30 (_to)[_i] = (_from)[_i]; \
34 static DEFINE_SPINLOCK(pmc_pll_lock);
35 static DEFINE_SPINLOCK(pmc_mckX_lock);
38 * PLL clocks identifiers
39 * @PLL_ID_CPU: CPU PLL identifier
40 * @PLL_ID_SYS: System PLL identifier
41 * @PLL_ID_DDR: DDR PLL identifier
42 * @PLL_ID_IMG: Image subsystem PLL identifier
43 * @PLL_ID_BAUD: Baud PLL identifier
44 * @PLL_ID_AUDIO: Audio PLL identifier
45 * @PLL_ID_ETH: Ethernet PLL identifier
59 * PLL type identifiers
60 * @PLL_TYPE_FRAC: fractional PLL identifier
61 * @PLL_TYPE_DIV: divider PLL identifier
68 /* Layout for fractional PLLs. */
69 static const struct clk_pll_layout pll_layout_frac = {
70 .mul_mask = GENMASK(31, 24),
71 .frac_mask = GENMASK(21, 0),
76 /* Layout for DIVPMC dividers. */
77 static const struct clk_pll_layout pll_layout_divpmc = {
78 .div_mask = GENMASK(7, 0),
79 .endiv_mask = BIT(29),
84 /* Layout for DIVIO dividers. */
85 static const struct clk_pll_layout pll_layout_divio = {
86 .div_mask = GENMASK(19, 12),
87 .endiv_mask = BIT(30),
93 * PLL clocks description
98 * @f: true if clock is critical and cannot be disabled
99 * @eid: export index in sama7g5->chws[] array
101 static const struct {
104 const struct clk_pll_layout *l;
108 } sama7g5_plls[][PLL_ID_MAX] = {
110 { .n = "cpupll_fracck",
112 .l = &pll_layout_frac,
116 { .n = "cpupll_divpmcck",
117 .p = "cpupll_fracck",
118 .l = &pll_layout_divpmc,
121 .eid = PMC_CPUPLL, },
125 { .n = "syspll_fracck",
127 .l = &pll_layout_frac,
131 { .n = "syspll_divpmcck",
132 .p = "syspll_fracck",
133 .l = &pll_layout_divpmc,
136 .eid = PMC_SYSPLL, },
140 { .n = "ddrpll_fracck",
142 .l = &pll_layout_frac,
146 { .n = "ddrpll_divpmcck",
147 .p = "ddrpll_fracck",
148 .l = &pll_layout_divpmc,
154 { .n = "imgpll_fracck",
156 .l = &pll_layout_frac,
157 .t = PLL_TYPE_FRAC, },
159 { .n = "imgpll_divpmcck",
160 .p = "imgpll_fracck",
161 .l = &pll_layout_divpmc,
162 .t = PLL_TYPE_DIV, },
166 { .n = "baudpll_fracck",
168 .l = &pll_layout_frac,
169 .t = PLL_TYPE_FRAC, },
171 { .n = "baudpll_divpmcck",
172 .p = "baudpll_fracck",
173 .l = &pll_layout_divpmc,
174 .t = PLL_TYPE_DIV, },
178 { .n = "audiopll_fracck",
180 .l = &pll_layout_frac,
181 .t = PLL_TYPE_FRAC, },
183 { .n = "audiopll_divpmcck",
184 .p = "audiopll_fracck",
185 .l = &pll_layout_divpmc,
187 .eid = PMC_AUDIOPMCPLL, },
189 { .n = "audiopll_diviock",
190 .p = "audiopll_fracck",
191 .l = &pll_layout_divio,
193 .eid = PMC_AUDIOIOPLL, },
197 { .n = "ethpll_fracck",
199 .l = &pll_layout_frac,
200 .t = PLL_TYPE_FRAC, },
202 { .n = "ethpll_divpmcck",
203 .p = "ethpll_fracck",
204 .l = &pll_layout_divpmc,
205 .t = PLL_TYPE_DIV, },
210 * Master clock (MCK[1..4]) description
212 * @ep: extra parents names array
213 * @ep_chg_chg_id: index in parents array that specifies the changeable
215 * @ep_count: extra parents count
216 * @ep_mux_table: mux table for extra parents
218 * @c: true if clock is critical and cannot be disabled
220 static const struct {
231 .ep = { "syspll_divpmcck", },
232 .ep_mux_table = { 5, },
234 .ep_chg_id = INT_MIN,
239 .ep = { "ddrpll_divpmcck", },
240 .ep_mux_table = { 6, },
242 .ep_chg_id = INT_MIN,
247 .ep = { "syspll_divpmcck", "ddrpll_divpmcck", "imgpll_divpmcck", },
248 .ep_mux_table = { 5, 6, 7, },
254 .ep = { "syspll_divpmcck", },
255 .ep_mux_table = { 5, },
257 .ep_chg_id = INT_MIN,
262 * System clock description
264 * @p: clock parent name
267 static const struct {
271 } sama7g5_systemck[] = {
272 { .n = "pck0", .p = "prog0", .id = 8, },
273 { .n = "pck1", .p = "prog1", .id = 9, },
274 { .n = "pck2", .p = "prog2", .id = 10, },
275 { .n = "pck3", .p = "prog3", .id = 11, },
276 { .n = "pck4", .p = "prog4", .id = 12, },
277 { .n = "pck5", .p = "prog5", .id = 13, },
278 { .n = "pck6", .p = "prog6", .id = 14, },
279 { .n = "pck7", .p = "prog7", .id = 15, },
282 /* Mux table for programmable clocks. */
283 static u32 sama7g5_prog_mux_table[] = { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, };
286 * Peripheral clock description
288 * @p: clock parent name
289 * @r: clock range values
291 * @chgp: index in parent array of the changeable parent
293 static const struct {
299 } sama7g5_periphck[] = {
300 { .n = "pioA_clk", .p = "mck0", .id = 11, },
301 { .n = "sfr_clk", .p = "mck1", .id = 19, },
302 { .n = "hsmc_clk", .p = "mck1", .id = 21, },
303 { .n = "xdmac0_clk", .p = "mck1", .id = 22, },
304 { .n = "xdmac1_clk", .p = "mck1", .id = 23, },
305 { .n = "xdmac2_clk", .p = "mck1", .id = 24, },
306 { .n = "acc_clk", .p = "mck1", .id = 25, },
307 { .n = "aes_clk", .p = "mck1", .id = 27, },
308 { .n = "tzaesbasc_clk", .p = "mck1", .id = 28, },
309 { .n = "asrc_clk", .p = "mck1", .id = 30, .r = { .max = 200000000, }, },
310 { .n = "cpkcc_clk", .p = "mck0", .id = 32, },
311 { .n = "csi_clk", .p = "mck3", .id = 33, .r = { .max = 266000000, }, .chgp = 1, },
312 { .n = "csi2dc_clk", .p = "mck3", .id = 34, .r = { .max = 266000000, }, .chgp = 1, },
313 { .n = "eic_clk", .p = "mck1", .id = 37, },
314 { .n = "flex0_clk", .p = "mck1", .id = 38, },
315 { .n = "flex1_clk", .p = "mck1", .id = 39, },
316 { .n = "flex2_clk", .p = "mck1", .id = 40, },
317 { .n = "flex3_clk", .p = "mck1", .id = 41, },
318 { .n = "flex4_clk", .p = "mck1", .id = 42, },
319 { .n = "flex5_clk", .p = "mck1", .id = 43, },
320 { .n = "flex6_clk", .p = "mck1", .id = 44, },
321 { .n = "flex7_clk", .p = "mck1", .id = 45, },
322 { .n = "flex8_clk", .p = "mck1", .id = 46, },
323 { .n = "flex9_clk", .p = "mck1", .id = 47, },
324 { .n = "flex10_clk", .p = "mck1", .id = 48, },
325 { .n = "flex11_clk", .p = "mck1", .id = 49, },
326 { .n = "gmac0_clk", .p = "mck1", .id = 51, },
327 { .n = "gmac1_clk", .p = "mck1", .id = 52, },
328 { .n = "icm_clk", .p = "mck1", .id = 55, },
329 { .n = "isc_clk", .p = "mck3", .id = 56, .r = { .max = 266000000, }, .chgp = 1, },
330 { .n = "i2smcc0_clk", .p = "mck1", .id = 57, .r = { .max = 200000000, }, },
331 { .n = "i2smcc1_clk", .p = "mck1", .id = 58, .r = { .max = 200000000, }, },
332 { .n = "matrix_clk", .p = "mck1", .id = 60, },
333 { .n = "mcan0_clk", .p = "mck1", .id = 61, .r = { .max = 200000000, }, },
334 { .n = "mcan1_clk", .p = "mck1", .id = 62, .r = { .max = 200000000, }, },
335 { .n = "mcan2_clk", .p = "mck1", .id = 63, .r = { .max = 200000000, }, },
336 { .n = "mcan3_clk", .p = "mck1", .id = 64, .r = { .max = 200000000, }, },
337 { .n = "mcan4_clk", .p = "mck1", .id = 65, .r = { .max = 200000000, }, },
338 { .n = "mcan5_clk", .p = "mck1", .id = 66, .r = { .max = 200000000, }, },
339 { .n = "pdmc0_clk", .p = "mck1", .id = 68, .r = { .max = 200000000, }, },
340 { .n = "pdmc1_clk", .p = "mck1", .id = 69, .r = { .max = 200000000, }, },
341 { .n = "pit64b0_clk", .p = "mck1", .id = 70, },
342 { .n = "pit64b1_clk", .p = "mck1", .id = 71, },
343 { .n = "pit64b2_clk", .p = "mck1", .id = 72, },
344 { .n = "pit64b3_clk", .p = "mck1", .id = 73, },
345 { .n = "pit64b4_clk", .p = "mck1", .id = 74, },
346 { .n = "pit64b5_clk", .p = "mck1", .id = 75, },
347 { .n = "pwm_clk", .p = "mck1", .id = 77, },
348 { .n = "qspi0_clk", .p = "mck1", .id = 78, },
349 { .n = "qspi1_clk", .p = "mck1", .id = 79, },
350 { .n = "sdmmc0_clk", .p = "mck1", .id = 80, },
351 { .n = "sdmmc1_clk", .p = "mck1", .id = 81, },
352 { .n = "sdmmc2_clk", .p = "mck1", .id = 82, },
353 { .n = "sha_clk", .p = "mck1", .id = 83, },
354 { .n = "spdifrx_clk", .p = "mck1", .id = 84, .r = { .max = 200000000, }, },
355 { .n = "spdiftx_clk", .p = "mck1", .id = 85, .r = { .max = 200000000, }, },
356 { .n = "ssc0_clk", .p = "mck1", .id = 86, .r = { .max = 200000000, }, },
357 { .n = "ssc1_clk", .p = "mck1", .id = 87, .r = { .max = 200000000, }, },
358 { .n = "tcb0_ch0_clk", .p = "mck1", .id = 88, .r = { .max = 200000000, }, },
359 { .n = "tcb0_ch1_clk", .p = "mck1", .id = 89, .r = { .max = 200000000, }, },
360 { .n = "tcb0_ch2_clk", .p = "mck1", .id = 90, .r = { .max = 200000000, }, },
361 { .n = "tcb1_ch0_clk", .p = "mck1", .id = 91, .r = { .max = 200000000, }, },
362 { .n = "tcb1_ch1_clk", .p = "mck1", .id = 92, .r = { .max = 200000000, }, },
363 { .n = "tcb1_ch2_clk", .p = "mck1", .id = 93, .r = { .max = 200000000, }, },
364 { .n = "tcpca_clk", .p = "mck1", .id = 94, },
365 { .n = "tcpcb_clk", .p = "mck1", .id = 95, },
366 { .n = "tdes_clk", .p = "mck1", .id = 96, },
367 { .n = "trng_clk", .p = "mck1", .id = 97, },
368 { .n = "udphsa_clk", .p = "mck1", .id = 104, },
369 { .n = "udphsb_clk", .p = "mck1", .id = 105, },
370 { .n = "uhphs_clk", .p = "mck1", .id = 106, },
374 * Generic clock description
377 * @pp_mux_table: PLL parents mux table
378 * @r: clock output range
379 * @pp_chg_id: id in parrent array of changeable PLL parent
380 * @pp_count: PLL parents count
383 static const struct {
386 const char pp_mux_table[8];
394 .r = { .max = 100000000, },
395 .pp = { "syspll_divpmcck", "imgpll_divpmcck", "audiopll_divpmcck", },
396 .pp_mux_table = { 5, 7, 9, },
398 .pp_chg_id = INT_MIN, },
402 .r = { .max = 200000000 },
403 .pp = { "audiopll_divpmcck", },
404 .pp_mux_table = { 9, },
410 .r = { .max = 27000000 },
411 .pp = { "ddrpll_divpmcck", "imgpll_divpmcck", },
412 .pp_mux_table = { 6, 7, },
414 .pp_chg_id = INT_MIN, },
418 .r = { .max = 200000000 },
419 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
420 .pp_mux_table = { 5, 8, },
422 .pp_chg_id = INT_MIN, },
426 .r = { .max = 200000000 },
427 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
428 .pp_mux_table = { 5, 8, },
430 .pp_chg_id = INT_MIN, },
434 .r = { .max = 200000000 },
435 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
436 .pp_mux_table = { 5, 8, },
438 .pp_chg_id = INT_MIN, },
442 .r = { .max = 200000000 },
443 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
444 .pp_mux_table = { 5, 8, },
446 .pp_chg_id = INT_MIN, },
450 .r = { .max = 200000000 },
451 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
452 .pp_mux_table = { 5, 8, },
454 .pp_chg_id = INT_MIN, },
458 .r = { .max = 200000000 },
459 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
460 .pp_mux_table = { 5, 8, },
462 .pp_chg_id = INT_MIN, },
466 .r = { .max = 200000000 },
467 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
468 .pp_mux_table = { 5, 8, },
470 .pp_chg_id = INT_MIN, },
474 .r = { .max = 200000000 },
475 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
476 .pp_mux_table = { 5, 8, },
478 .pp_chg_id = INT_MIN, },
482 .r = { .max = 200000000 },
483 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
484 .pp_mux_table = { 5, 8, },
486 .pp_chg_id = INT_MIN, },
490 .r = { .max = 200000000 },
491 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
492 .pp_mux_table = { 5, 8, },
494 .pp_chg_id = INT_MIN, },
496 { .n = "flex10_gclk",
498 .r = { .max = 200000000 },
499 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
500 .pp_mux_table = { 5, 8, },
502 .pp_chg_id = INT_MIN, },
504 { .n = "flex11_gclk",
506 .r = { .max = 200000000 },
507 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
508 .pp_mux_table = { 5, 8, },
510 .pp_chg_id = INT_MIN, },
514 .r = { .max = 125000000 },
515 .pp = { "ethpll_divpmcck", },
516 .pp_mux_table = { 10, },
522 .r = { .max = 50000000 },
523 .pp = { "ethpll_divpmcck", },
524 .pp_mux_table = { 10, },
526 .pp_chg_id = INT_MIN, },
528 { .n = "gmac0_tsu_gclk",
530 .r = { .max = 300000000 },
531 .pp = { "audiopll_divpmcck", "ethpll_divpmcck", },
532 .pp_mux_table = { 9, 10, },
534 .pp_chg_id = INT_MIN, },
536 { .n = "gmac1_tsu_gclk",
538 .r = { .max = 300000000 },
539 .pp = { "audiopll_divpmcck", "ethpll_divpmcck", },
540 .pp_mux_table = { 9, 10, },
542 .pp_chg_id = INT_MIN, },
544 { .n = "i2smcc0_gclk",
546 .r = { .max = 100000000 },
547 .pp = { "syspll_divpmcck", "audiopll_divpmcck", },
548 .pp_mux_table = { 5, 9, },
552 { .n = "i2smcc1_gclk",
554 .r = { .max = 100000000 },
555 .pp = { "syspll_divpmcck", "audiopll_divpmcck", },
556 .pp_mux_table = { 5, 9, },
562 .r = { .max = 200000000 },
563 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
564 .pp_mux_table = { 5, 8, },
566 .pp_chg_id = INT_MIN, },
570 .r = { .max = 200000000 },
571 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
572 .pp_mux_table = { 5, 8, },
574 .pp_chg_id = INT_MIN, },
578 .r = { .max = 200000000 },
579 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
580 .pp_mux_table = { 5, 8, },
582 .pp_chg_id = INT_MIN, },
586 .r = { .max = 200000000 },
587 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
588 .pp_mux_table = { 5, 8, },
590 .pp_chg_id = INT_MIN, },
594 .r = { .max = 200000000 },
595 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
596 .pp_mux_table = { 5, 8, },
598 .pp_chg_id = INT_MIN, },
602 .r = { .max = 200000000 },
603 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
604 .pp_mux_table = { 5, 8, },
606 .pp_chg_id = INT_MIN, },
610 .r = { .max = 50000000 },
611 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
612 .pp_mux_table = { 5, 8, },
614 .pp_chg_id = INT_MIN, },
618 .r = { .max = 50000000, },
619 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
620 .pp_mux_table = { 5, 8, },
622 .pp_chg_id = INT_MIN, },
624 { .n = "pit64b0_gclk",
626 .r = { .max = 200000000 },
627 .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
628 "audiopll_divpmcck", "ethpll_divpmcck", },
629 .pp_mux_table = { 5, 7, 8, 9, 10, },
631 .pp_chg_id = INT_MIN, },
633 { .n = "pit64b1_gclk",
635 .r = { .max = 200000000 },
636 .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
637 "audiopll_divpmcck", "ethpll_divpmcck", },
638 .pp_mux_table = { 5, 7, 8, 9, 10, },
640 .pp_chg_id = INT_MIN, },
642 { .n = "pit64b2_gclk",
644 .r = { .max = 200000000 },
645 .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
646 "audiopll_divpmcck", "ethpll_divpmcck", },
647 .pp_mux_table = { 5, 7, 8, 9, 10, },
649 .pp_chg_id = INT_MIN, },
651 { .n = "pit64b3_gclk",
653 .r = { .max = 200000000 },
654 .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
655 "audiopll_divpmcck", "ethpll_divpmcck", },
656 .pp_mux_table = { 5, 7, 8, 9, 10, },
658 .pp_chg_id = INT_MIN, },
660 { .n = "pit64b4_gclk",
662 .r = { .max = 200000000 },
663 .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
664 "audiopll_divpmcck", "ethpll_divpmcck", },
665 .pp_mux_table = { 5, 7, 8, 9, 10, },
667 .pp_chg_id = INT_MIN, },
669 { .n = "pit64b5_gclk",
671 .r = { .max = 200000000 },
672 .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
673 "audiopll_divpmcck", "ethpll_divpmcck", },
674 .pp_mux_table = { 5, 7, 8, 9, 10, },
676 .pp_chg_id = INT_MIN, },
680 .r = { .max = 200000000 },
681 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
682 .pp_mux_table = { 5, 8, },
684 .pp_chg_id = INT_MIN, },
688 .r = { .max = 200000000 },
689 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
690 .pp_mux_table = { 5, 8, },
692 .pp_chg_id = INT_MIN, },
694 { .n = "sdmmc0_gclk",
696 .r = { .max = 208000000 },
697 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
698 .pp_mux_table = { 5, 8, },
702 { .n = "sdmmc1_gclk",
704 .r = { .max = 208000000 },
705 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
706 .pp_mux_table = { 5, 8, },
710 { .n = "sdmmc2_gclk",
712 .r = { .max = 208000000 },
713 .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
714 .pp_mux_table = { 5, 8, },
718 { .n = "spdifrx_gclk",
720 .r = { .max = 150000000 },
721 .pp = { "syspll_divpmcck", "audiopll_divpmcck", },
722 .pp_mux_table = { 5, 9, },
726 { .n = "spdiftx_gclk",
728 .r = { .max = 25000000 },
729 .pp = { "syspll_divpmcck", "audiopll_divpmcck", },
730 .pp_mux_table = { 5, 9, },
734 { .n = "tcb0_ch0_gclk",
736 .r = { .max = 200000000 },
737 .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
738 "audiopll_divpmcck", "ethpll_divpmcck", },
739 .pp_mux_table = { 5, 7, 8, 9, 10, },
741 .pp_chg_id = INT_MIN, },
743 { .n = "tcb1_ch0_gclk",
745 .r = { .max = 200000000 },
746 .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
747 "audiopll_divpmcck", "ethpll_divpmcck", },
748 .pp_mux_table = { 5, 7, 8, 9, 10, },
750 .pp_chg_id = INT_MIN, },
754 .r = { .max = 32768, },
755 .pp_chg_id = INT_MIN, },
759 .r = { .max = 32768, },
760 .pp_chg_id = INT_MIN, },
763 /* PLL output range. */
764 static const struct clk_range pll_outputs[] = {
765 { .min = 2343750, .max = 1200000000 },
768 /* PLL characteristics. */
769 static const struct clk_pll_characteristics pll_characteristics = {
770 .input = { .min = 12000000, .max = 50000000 },
771 .num_output = ARRAY_SIZE(pll_outputs),
772 .output = pll_outputs,
775 /* MCK0 characteristics. */
776 static const struct clk_master_characteristics mck0_characteristics = {
777 .output = { .min = 140000000, .max = 200000000 },
778 .divisors = { 1, 2, 4, 3 },
783 static const struct clk_master_layout mck0_layout = {
789 /* Programmable clock layout. */
790 static const struct clk_programmable_layout programmable_layout = {
798 /* Peripheral clock layout. */
799 static const struct clk_pcr_layout sama7g5_pcr_layout = {
802 .gckcss_mask = GENMASK(12, 8),
803 .pid_mask = GENMASK(6, 0),
806 static void __init sama7g5_pmc_setup(struct device_node *np)
808 const char *td_slck_name, *md_slck_name, *mainxtal_name;
809 struct pmc_data *sama7g5_pmc;
810 const char *parent_names[10];
811 void **alloc_mem = NULL;
812 int alloc_mem_size = 0;
813 struct regmap *regmap;
818 i = of_property_match_string(np, "clock-names", "td_slck");
822 td_slck_name = of_clk_get_parent_name(np, i);
824 i = of_property_match_string(np, "clock-names", "md_slck");
828 md_slck_name = of_clk_get_parent_name(np, i);
830 i = of_property_match_string(np, "clock-names", "main_xtal");
834 mainxtal_name = of_clk_get_parent_name(np, i);
836 regmap = device_node_to_regmap(np);
840 sama7g5_pmc = pmc_data_allocate(PMC_ETHPLL + 1,
841 nck(sama7g5_systemck),
842 nck(sama7g5_periphck),
843 nck(sama7g5_gck), 8);
847 alloc_mem = kmalloc(sizeof(void *) *
848 (ARRAY_SIZE(sama7g5_mckx) + ARRAY_SIZE(sama7g5_gck)),
853 hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
858 bypass = of_property_read_bool(np, "atmel,osc-bypass");
860 hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
865 parent_names[0] = "main_rc_osc";
866 parent_names[1] = "main_osc";
867 hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2);
871 sama7g5_pmc->chws[PMC_MAIN] = hw;
873 for (i = 0; i < PLL_ID_MAX; i++) {
874 for (j = 0; j < 3; j++) {
875 struct clk_hw *parent_hw;
877 if (!sama7g5_plls[i][j].n)
880 switch (sama7g5_plls[i][j].t) {
882 if (!strcmp(sama7g5_plls[i][j].p, "mainck"))
883 parent_hw = sama7g5_pmc->chws[PMC_MAIN];
885 parent_hw = __clk_get_hw(of_clk_get_by_name(np,
886 sama7g5_plls[i][j].p));
888 hw = sam9x60_clk_register_frac_pll(regmap,
889 &pmc_pll_lock, sama7g5_plls[i][j].n,
890 sama7g5_plls[i][j].p, parent_hw, i,
891 &pll_characteristics,
892 sama7g5_plls[i][j].l,
893 sama7g5_plls[i][j].c);
897 hw = sam9x60_clk_register_div_pll(regmap,
898 &pmc_pll_lock, sama7g5_plls[i][j].n,
899 sama7g5_plls[i][j].p, i,
900 &pll_characteristics,
901 sama7g5_plls[i][j].l,
902 sama7g5_plls[i][j].c);
912 if (sama7g5_plls[i][j].eid)
913 sama7g5_pmc->chws[sama7g5_plls[i][j].eid] = hw;
917 parent_names[0] = md_slck_name;
918 parent_names[1] = "mainck";
919 parent_names[2] = "cpupll_divpmcck";
920 parent_names[3] = "syspll_divpmcck";
921 hw = at91_clk_register_master(regmap, "mck0", 4, parent_names,
922 &mck0_layout, &mck0_characteristics);
926 sama7g5_pmc->chws[PMC_MCK] = hw;
928 parent_names[0] = md_slck_name;
929 parent_names[1] = td_slck_name;
930 parent_names[2] = "mainck";
931 parent_names[3] = "mck0";
932 for (i = 0; i < ARRAY_SIZE(sama7g5_mckx); i++) {
933 u8 num_parents = 4 + sama7g5_mckx[i].ep_count;
936 mux_table = kmalloc_array(num_parents, sizeof(*mux_table),
941 SAMA7G5_INIT_TABLE(mux_table, 4);
942 SAMA7G5_FILL_TABLE(&mux_table[4], sama7g5_mckx[i].ep_mux_table,
943 sama7g5_mckx[i].ep_count);
944 SAMA7G5_FILL_TABLE(&parent_names[4], sama7g5_mckx[i].ep,
945 sama7g5_mckx[i].ep_count);
947 hw = at91_clk_sama7g5_register_master(regmap, sama7g5_mckx[i].n,
948 num_parents, parent_names, mux_table,
949 &pmc_mckX_lock, sama7g5_mckx[i].id,
951 sama7g5_mckx[i].ep_chg_id);
955 alloc_mem[alloc_mem_size++] = mux_table;
958 hw = at91_clk_sama7g5_register_utmi(regmap, "utmick", "main_xtal");
962 sama7g5_pmc->chws[PMC_UTMI] = hw;
964 parent_names[0] = md_slck_name;
965 parent_names[1] = td_slck_name;
966 parent_names[2] = "mainck";
967 parent_names[3] = "mck0";
968 parent_names[4] = "syspll_divpmcck";
969 parent_names[5] = "ddrpll_divpmcck";
970 parent_names[6] = "imgpll_divpmcck";
971 parent_names[7] = "baudpll_divpmcck";
972 parent_names[8] = "audiopll_divpmcck";
973 parent_names[9] = "ethpll_divpmcck";
974 for (i = 0; i < 8; i++) {
977 snprintf(name, sizeof(name), "prog%d", i);
979 hw = at91_clk_register_programmable(regmap, name, parent_names,
981 &programmable_layout,
982 sama7g5_prog_mux_table);
986 sama7g5_pmc->pchws[i] = hw;
989 for (i = 0; i < ARRAY_SIZE(sama7g5_systemck); i++) {
990 hw = at91_clk_register_system(regmap, sama7g5_systemck[i].n,
991 sama7g5_systemck[i].p,
992 sama7g5_systemck[i].id);
996 sama7g5_pmc->shws[sama7g5_systemck[i].id] = hw;
999 for (i = 0; i < ARRAY_SIZE(sama7g5_periphck); i++) {
1000 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
1001 &sama7g5_pcr_layout,
1002 sama7g5_periphck[i].n,
1003 sama7g5_periphck[i].p,
1004 sama7g5_periphck[i].id,
1005 &sama7g5_periphck[i].r,
1006 sama7g5_periphck[i].chgp ? 0 :
1011 sama7g5_pmc->phws[sama7g5_periphck[i].id] = hw;
1014 parent_names[0] = md_slck_name;
1015 parent_names[1] = td_slck_name;
1016 parent_names[2] = "mainck";
1017 parent_names[3] = "mck0";
1018 for (i = 0; i < ARRAY_SIZE(sama7g5_gck); i++) {
1019 u8 num_parents = 4 + sama7g5_gck[i].pp_count;
1022 mux_table = kmalloc_array(num_parents, sizeof(*mux_table),
1027 SAMA7G5_INIT_TABLE(mux_table, 4);
1028 SAMA7G5_FILL_TABLE(&mux_table[4], sama7g5_gck[i].pp_mux_table,
1029 sama7g5_gck[i].pp_count);
1030 SAMA7G5_FILL_TABLE(&parent_names[4], sama7g5_gck[i].pp,
1031 sama7g5_gck[i].pp_count);
1033 hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
1034 &sama7g5_pcr_layout,
1036 parent_names, mux_table,
1040 sama7g5_gck[i].pp_chg_id);
1044 sama7g5_pmc->ghws[sama7g5_gck[i].id] = hw;
1045 alloc_mem[alloc_mem_size++] = mux_table;
1048 of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sama7g5_pmc);
1054 for (i = 0; i < alloc_mem_size; i++)
1055 kfree(alloc_mem[i]);
1062 /* Some clks are used for a clocksource */
1063 CLK_OF_DECLARE(sama7g5_pmc, "microchip,sama7g5-pmc", sama7g5_pmc_setup);