File Index
Files and directories
Sign in
FILE

sam9x7.c

File preview with syntax highlighting.

linux-6.19.14/drivers/clk/at91/sam9x7.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * SAM9X7 PMC code.
  4 *
  5 * Copyright (C) 2023 Microchip Technology Inc. and its subsidiaries
  6 *
  7 * Author: Varshini Rajendran <varshini.rajendran@microchip.com>
  8 *
  9 */
 10#include <linux/clk.h>
 11#include <linux/clk-provider.h>
 12#include <linux/mfd/syscon.h>
 13#include <linux/slab.h>
 14
 15#include <dt-bindings/clock/at91.h>
 16
 17#include "pmc.h"
 18
 19static DEFINE_SPINLOCK(pmc_pll_lock);
 20static DEFINE_SPINLOCK(mck_lock);
 21
 22/**
 23 * enum pll_ids - PLL clocks identifiers
 24 * @PLL_ID_PLLA:	PLLA identifier
 25 * @PLL_ID_UPLL:	UPLL identifier
 26 * @PLL_ID_AUDIO:	Audio PLL identifier
 27 * @PLL_ID_LVDS:	LVDS PLL identifier
 28 * @PLL_ID_PLLA_DIV2:	PLLA DIV2 identifier
 29 * @PLL_ID_MAX:		Max PLL Identifier
 30 */
 31enum pll_ids {
 32	PLL_ID_PLLA,
 33	PLL_ID_UPLL,
 34	PLL_ID_AUDIO,
 35	PLL_ID_LVDS,
 36	PLL_ID_PLLA_DIV2,
 37	PLL_ID_MAX,
 38};
 39
 40/**
 41 * enum pll_type - PLL type identifiers
 42 * @PLL_TYPE_FRAC:	fractional PLL identifier
 43 * @PLL_TYPE_DIV:	divider PLL identifier
 44 */
 45enum pll_type {
 46	PLL_TYPE_FRAC,
 47	PLL_TYPE_DIV,
 48};
 49
 50static const struct clk_master_characteristics mck_characteristics = {
 51	.output = { .min = 32000000, .max = 266666667 },
 52	.divisors = { 1, 2, 4, 3, 5},
 53	.have_div3_pres = 1,
 54};
 55
 56static const struct clk_master_layout sam9x7_master_layout = {
 57	.mask = 0x373,
 58	.pres_shift = 4,
 59	.offset = 0x28,
 60};
 61
 62/* Fractional PLL core output range. */
 63static const struct clk_range plla_core_outputs[] = {
 64	{ .min = 800000000, .max = 1600000000 },
 65};
 66
 67static const struct clk_range upll_core_outputs[] = {
 68	{ .min = 600000000, .max = 960000000 },
 69};
 70
 71static const struct clk_range lvdspll_core_outputs[] = {
 72	{ .min = 600000000, .max = 1200000000 },
 73};
 74
 75static const struct clk_range audiopll_core_outputs[] = {
 76	{ .min = 600000000, .max = 1200000000 },
 77};
 78
 79static const struct clk_range plladiv2_core_outputs[] = {
 80	{ .min = 800000000, .max = 1600000000 },
 81};
 82
 83/* Fractional PLL output range. */
 84static const struct clk_range plla_outputs[] = {
 85	{ .min = 400000000, .max = 800000000 },
 86};
 87
 88static const struct clk_range upll_outputs[] = {
 89	{ .min = 300000000, .max = 480000000 },
 90};
 91
 92static const struct clk_range lvdspll_outputs[] = {
 93	{ .min = 175000000, .max = 550000000 },
 94};
 95
 96static const struct clk_range audiopll_outputs[] = {
 97	{ .min = 0, .max = 300000000 },
 98};
 99
100static const struct clk_range plladiv2_outputs[] = {
101	{ .min = 200000000, .max = 400000000 },
102};
103
104/* PLL characteristics. */
105static const struct clk_pll_characteristics plla_characteristics = {
106	.input = { .min = 20000000, .max = 50000000 },
107	.num_output = ARRAY_SIZE(plla_outputs),
108	.output = plla_outputs,
109	.core_output = plla_core_outputs,
110	.acr = UL(0x00020010), /* Old ACR_DEFAULT_PLLA value */
111};
112
113static const struct clk_pll_characteristics upll_characteristics = {
114	.input = { .min = 20000000, .max = 50000000 },
115	.num_output = ARRAY_SIZE(upll_outputs),
116	.output = upll_outputs,
117	.core_output = upll_core_outputs,
118	.upll = true,
119	.acr = UL(0x12023010), /* fIN=[20 MHz, 32 MHz] */
120};
121
122static const struct clk_pll_characteristics lvdspll_characteristics = {
123	.input = { .min = 20000000, .max = 50000000 },
124	.num_output = ARRAY_SIZE(lvdspll_outputs),
125	.output = lvdspll_outputs,
126	.core_output = lvdspll_core_outputs,
127	.acr = UL(0x12023010), /* fIN=[20 MHz, 32 MHz] */
128};
129
130static const struct clk_pll_characteristics audiopll_characteristics = {
131	.input = { .min = 20000000, .max = 50000000 },
132	.num_output = ARRAY_SIZE(audiopll_outputs),
133	.output = audiopll_outputs,
134	.core_output = audiopll_core_outputs,
135	.acr = UL(0x12023010), /* fIN=[20 MHz, 32 MHz] */
136};
137
138static const struct clk_pll_characteristics plladiv2_characteristics = {
139	.input = { .min = 20000000, .max = 50000000 },
140	.num_output = ARRAY_SIZE(plladiv2_outputs),
141	.output = plladiv2_outputs,
142	.core_output = plladiv2_core_outputs,
143	.acr = UL(0x00020010),  /* Old ACR_DEFAULT_PLLA value */
144};
145
146/* Layout for fractional PLL ID PLLA. */
147static const struct clk_pll_layout plla_frac_layout = {
148	.mul_mask = GENMASK(31, 24),
149	.frac_mask = GENMASK(21, 0),
150	.mul_shift = 24,
151	.frac_shift = 0,
152	.div2 = 1,
153};
154
155/* Layout for fractional PLLs. */
156static const struct clk_pll_layout pll_frac_layout = {
157	.mul_mask = GENMASK(31, 24),
158	.frac_mask = GENMASK(21, 0),
159	.mul_shift = 24,
160	.frac_shift = 0,
161};
162
163/* Layout for DIV PLLs. */
164static const struct clk_pll_layout pll_divpmc_layout = {
165	.div_mask = GENMASK(7, 0),
166	.endiv_mask = BIT(29),
167	.div_shift = 0,
168	.endiv_shift = 29,
169};
170
171/* Layout for DIV PLL ID PLLADIV2. */
172static const struct clk_pll_layout plladiv2_divpmc_layout = {
173	.div_mask = GENMASK(7, 0),
174	.endiv_mask = BIT(29),
175	.div_shift = 0,
176	.endiv_shift = 29,
177	.div2 = 1,
178};
179
180/* Layout for DIVIO dividers. */
181static const struct clk_pll_layout pll_divio_layout = {
182	.div_mask	= GENMASK(19, 12),
183	.endiv_mask	= BIT(30),
184	.div_shift	= 12,
185	.endiv_shift	= 30,
186};
187
188/*
189 * PLL clocks description
190 * @n:		clock name
191 * @p:		clock parent
192 * @l:		clock layout
193 * @t:		clock type
194 * @c:		pll characteristics
195 * @f:		clock flags
196 * @eid:	export index in sam9x7->chws[] array
197 */
198static const struct {
199	const char *n;
200	const char *p;
201	const struct clk_pll_layout *l;
202	u8 t;
203	const struct clk_pll_characteristics *c;
204	unsigned long f;
205	u8 eid;
206} sam9x7_plls[][3] = {
207	[PLL_ID_PLLA] = {
208		{
209			.n = "plla_fracck",
210			.p = "mainck",
211			.l = &plla_frac_layout,
212			.t = PLL_TYPE_FRAC,
213			/*
214			 * This feeds plla_divpmcck which feeds CPU. It should
215			 * not be disabled.
216			 */
217			.f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
218			.c = &plla_characteristics,
219		},
220
221		{
222			.n = "plla_divpmcck",
223			.p = "plla_fracck",
224			.l = &pll_divpmc_layout,
225			.t = PLL_TYPE_DIV,
226			/* This feeds CPU. It should not be disabled */
227			.f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
228			.eid = PMC_PLLACK,
229			.c = &plla_characteristics,
230		},
231	},
232
233	[PLL_ID_UPLL] = {
234		{
235			.n = "upll_fracck",
236			.p = "main_osc",
237			.l = &pll_frac_layout,
238			.t = PLL_TYPE_FRAC,
239			.f = CLK_SET_RATE_GATE,
240			.c = &upll_characteristics,
241		},
242
243		{
244			.n = "upll_divpmcck",
245			.p = "upll_fracck",
246			.l = &pll_divpmc_layout,
247			.t = PLL_TYPE_DIV,
248			.f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
249			     CLK_SET_RATE_PARENT,
250			.eid = PMC_UTMI,
251			.c = &upll_characteristics,
252		},
253	},
254
255	[PLL_ID_AUDIO] = {
256		{
257			.n = "audiopll_fracck",
258			.p = "main_osc",
259			.l = &pll_frac_layout,
260			.f = CLK_SET_RATE_GATE,
261			.c = &audiopll_characteristics,
262			.t = PLL_TYPE_FRAC,
263		},
264
265		{
266			.n = "audiopll_divpmcck",
267			.p = "audiopll_fracck",
268			.l = &pll_divpmc_layout,
269			.f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
270			     CLK_SET_RATE_PARENT,
271			.c = &audiopll_characteristics,
272			.eid = PMC_AUDIOPMCPLL,
273			.t = PLL_TYPE_DIV,
274		},
275
276		{
277			.n = "audiopll_diviock",
278			.p = "audiopll_fracck",
279			.l = &pll_divio_layout,
280			.f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
281			     CLK_SET_RATE_PARENT,
282			.c = &audiopll_characteristics,
283			.eid = PMC_AUDIOIOPLL,
284			.t = PLL_TYPE_DIV,
285		},
286	},
287
288	[PLL_ID_LVDS] = {
289		{
290			.n = "lvdspll_fracck",
291			.p = "main_osc",
292			.l = &pll_frac_layout,
293			.f = CLK_SET_RATE_GATE,
294			.c = &lvdspll_characteristics,
295			.t = PLL_TYPE_FRAC,
296		},
297
298		{
299			.n = "lvdspll_divpmcck",
300			.p = "lvdspll_fracck",
301			.l = &pll_divpmc_layout,
302			.f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
303			     CLK_SET_RATE_PARENT,
304			.c = &lvdspll_characteristics,
305			.eid = PMC_LVDSPLL,
306			.t = PLL_TYPE_DIV,
307		},
308	},
309
310	[PLL_ID_PLLA_DIV2] = {
311		{
312			.n = "plla_div2pmcck",
313			.p = "plla_fracck",
314			.l = &plladiv2_divpmc_layout,
315			/*
316			 * This may feed critical parts of the system like timers.
317			 * It should not be disabled.
318			 */
319			.f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
320			.c = &plladiv2_characteristics,
321			.eid = PMC_PLLADIV2,
322			.t = PLL_TYPE_DIV,
323		},
324	},
325};
326
327static const struct clk_programmable_layout sam9x7_programmable_layout = {
328	.pres_mask = 0xff,
329	.pres_shift = 8,
330	.css_mask = 0x1f,
331	.have_slck_mck = 0,
332	.is_pres_direct = 1,
333};
334
335static const struct clk_pcr_layout sam9x7_pcr_layout = {
336	.offset = 0x88,
337	.cmd = BIT(31),
338	.gckcss_mask = GENMASK(12, 8),
339	.pid_mask = GENMASK(6, 0),
340};
341
342static const struct {
343	char *n;
344	char *p;
345	u8 id;
346	unsigned long flags;
347} sam9x7_systemck[] = {
348	/*
349	 * ddrck feeds DDR controller and is enabled by bootloader thus we need
350	 * to keep it enabled in case there is no Linux consumer for it.
351	 */
352	{ .n = "ddrck",		.p = "masterck_div",	.id = 2,	.flags = CLK_IS_CRITICAL },
353	{ .n = "uhpck",		.p = "usbck",		.id = 6 },
354	{ .n = "pck0",		.p = "prog0",		.id = 8 },
355	{ .n = "pck1",		.p = "prog1",		.id = 9 },
356};
357
358/*
359 * Peripheral clocks description
360 * @n:		clock name
361 * @f:		clock flags
362 * @id:		peripheral id
363 */
364static const struct {
365	char *n;
366	unsigned long f;
367	u8 id;
368} sam9x7_periphck[] = {
369	{ .n = "pioA_clk",	.id = 2, },
370	{ .n = "pioB_clk",	.id = 3, },
371	{ .n = "pioC_clk",	.id = 4, },
372	{ .n = "flex0_clk",	.id = 5, },
373	{ .n = "flex1_clk",	.id = 6, },
374	{ .n = "flex2_clk",	.id = 7, },
375	{ .n = "flex3_clk",	.id = 8, },
376	{ .n = "flex6_clk",	.id = 9, },
377	{ .n = "flex7_clk",	.id = 10, },
378	{ .n = "flex8_clk",	.id = 11, },
379	{ .n = "sdmmc0_clk",	.id = 12, },
380	{ .n = "flex4_clk",	.id = 13, },
381	{ .n = "flex5_clk",	.id = 14, },
382	{ .n = "flex9_clk",	.id = 15, },
383	{ .n = "flex10_clk",	.id = 16, },
384	{ .n = "tcb0_clk",	.id = 17, },
385	{ .n = "pwm_clk",	.id = 18, },
386	{ .n = "adc_clk",	.id = 19, },
387	{ .n = "dma0_clk",	.id = 20, },
388	{ .n = "uhphs_clk",	.id = 22, },
389	{ .n = "udphs_clk",	.id = 23, },
390	{ .n = "macb0_clk",	.id = 24, },
391	{ .n = "lcd_clk",	.id = 25, },
392	{ .n = "sdmmc1_clk",	.id = 26, },
393	{ .n = "ssc_clk",	.id = 28, },
394	{ .n = "can0_clk",	.id = 29, },
395	{ .n = "can1_clk",	.id = 30, },
396	{ .n = "flex11_clk",	.id = 32, },
397	{ .n = "flex12_clk",	.id = 33, },
398	{ .n = "i2s_clk",	.id = 34, },
399	{ .n = "qspi_clk",	.id = 35, },
400	{ .n = "gfx2d_clk",	.id = 36, },
401	{ .n = "pit64b0_clk",	.id = 37, },
402	{ .n = "trng_clk",	.id = 38, },
403	{ .n = "aes_clk",	.id = 39, },
404	{ .n = "tdes_clk",	.id = 40, },
405	{ .n = "sha_clk",	.id = 41, },
406	{ .n = "classd_clk",	.id = 42, },
407	{ .n = "isi_clk",	.id = 43, },
408	{ .n = "pioD_clk",	.id = 44, },
409	{ .n = "tcb1_clk",	.id = 45, },
410	{ .n = "dbgu_clk",	.id = 47, },
411	{ .n = "pmecc_clk",	.id = 48, },
412	/*
413	 * mpddr_clk feeds DDR controller and is enabled by bootloader thus we
414	 * need to keep it enabled in case there is no Linux consumer for it.
415	 */
416	{ .n = "mpddr_clk",	.id = 49,	.f = CLK_IS_CRITICAL },
417	{ .n = "csi2dc_clk",	.id = 52, },
418	{ .n = "csi4l_clk",	.id = 53, },
419	{ .n = "dsi4l_clk",	.id = 54, },
420	{ .n = "lvdsc_clk",	.id = 56, },
421	{ .n = "pit64b1_clk",	.id = 58, },
422	{ .n = "puf_clk",	.id = 59, },
423	{ .n = "gmactsu_clk",	.id = 67, },
424};
425
426/*
427 * Generic clock description
428 * @n:			clock name
429 * @pp:			PLL parents
430 * @pp_mux_table:	PLL parents mux table
431 * @r:			clock output range
432 * @pp_chg_id:		id in parent array of changeable PLL parent
433 * @pp_count:		PLL parents count
434 * @id:			clock id
435 */
436static const struct {
437	const char *n;
438	const char *pp[8];
439	const char pp_mux_table[8];
440	struct clk_range r;
441	int pp_chg_id;
442	u8 pp_count;
443	u8 id;
444} sam9x7_gck[] = {
445	{
446		.n = "flex0_gclk",
447		.id = 5,
448		.pp = { "plla_div2pmcck", },
449		.pp_mux_table = { 8, },
450		.pp_count = 1,
451		.pp_chg_id = INT_MIN,
452	},
453
454	{
455		.n = "flex1_gclk",
456		.id = 6,
457		.pp = { "plla_div2pmcck", },
458		.pp_mux_table = { 8, },
459		.pp_count = 1,
460		.pp_chg_id = INT_MIN,
461	},
462
463	{
464		.n = "flex2_gclk",
465		.id = 7,
466		.pp = { "plla_div2pmcck", },
467		.pp_mux_table = { 8, },
468		.pp_count = 1,
469		.pp_chg_id = INT_MIN,
470	},
471
472	{
473		.n = "flex3_gclk",
474		.id = 8,
475		.pp = { "plla_div2pmcck", },
476		.pp_mux_table = { 8, },
477		.pp_count = 1,
478		.pp_chg_id = INT_MIN,
479	},
480
481	{
482		.n = "flex6_gclk",
483		.id = 9,
484		.pp = { "plla_div2pmcck", },
485		.pp_mux_table = { 8, },
486		.pp_count = 1,
487		.pp_chg_id = INT_MIN,
488	},
489
490	{
491		.n = "flex7_gclk",
492		.id = 10,
493		.pp = { "plla_div2pmcck", },
494		.pp_mux_table = { 8, },
495		.pp_count = 1,
496		.pp_chg_id = INT_MIN,
497	},
498
499	{
500		.n = "flex8_gclk",
501		.id = 11,
502		.pp = { "plla_div2pmcck", },
503		.pp_mux_table = { 8, },
504		.pp_count = 1,
505		.pp_chg_id = INT_MIN,
506	},
507
508	{
509		.n = "sdmmc0_gclk",
510		.id = 12,
511		.r = { .max = 105000000 },
512		.pp = { "audiopll_divpmcck", "plla_div2pmcck", },
513		.pp_mux_table = { 6, 8, },
514		.pp_count = 2,
515		.pp_chg_id = INT_MIN,
516	},
517
518	{
519		.n = "flex4_gclk",
520		.id = 13,
521		.pp = { "plla_div2pmcck", },
522		.pp_mux_table = { 8, },
523		.pp_count = 1,
524		.pp_chg_id = INT_MIN,
525	},
526
527	{
528		.n = "flex5_gclk",
529		.id = 14,
530		.pp = { "plla_div2pmcck", },
531		.pp_mux_table = { 8, },
532		.pp_count = 1,
533		.pp_chg_id = INT_MIN,
534	},
535
536	{
537		.n = "flex9_gclk",
538		.id = 15,
539		.pp = { "plla_div2pmcck", },
540		.pp_mux_table = { 8, },
541		.pp_count = 1,
542		.pp_chg_id = INT_MIN,
543	},
544
545	{
546		.n = "flex10_gclk",
547		.id = 16,
548		.pp = { "plla_div2pmcck", },
549		.pp_mux_table = { 8, },
550		.pp_count = 1,
551		.pp_chg_id = INT_MIN,
552	},
553
554	{
555		.n = "tcb0_gclk",
556		.id = 17,
557		.pp = { "audiopll_divpmcck", "plla_div2pmcck", },
558		.pp_mux_table = { 6, 8, },
559		.pp_count = 2,
560		.pp_chg_id = INT_MIN,
561	},
562
563	{
564		.n = "adc_gclk",
565		.id = 19,
566		.pp = { "upll_divpmcck", "plla_div2pmcck", },
567		.pp_mux_table = { 5, 8, },
568		.pp_count = 2,
569		.pp_chg_id = INT_MIN,
570	},
571
572	{
573		.n = "lcd_gclk",
574		.id = 25,
575		.r = { .max = 75000000 },
576		.pp = { "audiopll_divpmcck", "plla_div2pmcck", },
577		.pp_mux_table = { 6, 8, },
578		.pp_count = 2,
579		.pp_chg_id = INT_MIN,
580	},
581
582	{
583		.n = "sdmmc1_gclk",
584		.id = 26,
585		.r = { .max = 105000000 },
586		.pp = { "audiopll_divpmcck", "plla_div2pmcck", },
587		.pp_mux_table = { 6, 8, },
588		.pp_count = 2,
589		.pp_chg_id = INT_MIN,
590	},
591
592	{
593		.n = "mcan0_gclk",
594		.id = 29,
595		.r = { .max = 80000000 },
596		.pp = { "upll_divpmcck", "plla_div2pmcck", },
597		.pp_mux_table = { 5, 8, },
598		.pp_count = 2,
599		.pp_chg_id = INT_MIN,
600	},
601
602	{
603		.n = "mcan1_gclk",
604		.id = 30,
605		.r = { .max = 80000000 },
606		.pp = { "upll_divpmcck", "plla_div2pmcck", },
607		.pp_mux_table = { 5, 8, },
608		.pp_count = 2,
609		.pp_chg_id = INT_MIN,
610	},
611
612	{
613		.n = "flex11_gclk",
614		.id = 32,
615		.pp = { "plla_div2pmcck", },
616		.pp_mux_table = { 8, },
617		.pp_count = 1,
618		.pp_chg_id = INT_MIN,
619	},
620
621	{
622		.n = "flex12_gclk",
623		.id = 33,
624		.pp = { "plla_div2pmcck", },
625		.pp_mux_table = { 8, },
626		.pp_count = 1,
627		.pp_chg_id = INT_MIN,
628	},
629
630	{
631		.n = "i2s_gclk",
632		.id = 34,
633		.r = { .max = 100000000 },
634		.pp = { "audiopll_divpmcck", "plla_div2pmcck", },
635		.pp_mux_table = { 6, 8, },
636		.pp_count = 2,
637		.pp_chg_id = INT_MIN,
638	},
639
640	{
641		.n = "qspi_gclk",
642		.id = 35,
643		.r = { .max = 200000000 },
644		.pp = { "audiopll_divpmcck", "plla_div2pmcck", },
645		.pp_mux_table = { 6, 8, },
646		.pp_count = 2,
647		.pp_chg_id = INT_MIN,
648	},
649
650	{
651		.n = "pit64b0_gclk",
652		.id = 37,
653		.pp = { "plla_div2pmcck", },
654		.pp_mux_table = { 8, },
655		.pp_count = 1,
656		.pp_chg_id = INT_MIN,
657	},
658
659	{
660		.n = "classd_gclk",
661		.id = 42,
662		.r = { .max = 100000000 },
663		.pp = { "audiopll_divpmcck", "plla_div2pmcck", },
664		.pp_mux_table = { 6, 8, },
665		.pp_count = 2,
666		.pp_chg_id = INT_MIN,
667	},
668
669	{
670		.n = "tcb1_gclk",
671		.id = 45,
672		.pp = { "audiopll_divpmcck", "plla_div2pmcck", },
673		.pp_mux_table = { 6, 8, },
674		.pp_count = 2,
675		.pp_chg_id = INT_MIN,
676	},
677
678	{
679		.n = "dbgu_gclk",
680		.id = 47,
681		.pp = { "plla_div2pmcck", },
682		.pp_mux_table = { 8, },
683		.pp_count = 1,
684		.pp_chg_id = INT_MIN,
685	},
686
687	{
688		.n = "mipiphy_gclk",
689		.id = 55,
690		.r = { .max = 27000000 },
691		.pp = { "plla_div2pmcck", },
692		.pp_mux_table = { 8, },
693		.pp_count = 1,
694		.pp_chg_id = INT_MIN,
695	},
696
697	{
698		.n = "pit64b1_gclk",
699		.id = 58,
700		.pp = { "plla_div2pmcck", },
701		.pp_mux_table = { 8, },
702		.pp_count = 1,
703		.pp_chg_id = INT_MIN,
704	},
705
706	{
707		.n = "gmac_gclk",
708		.id = 67,
709		.pp = { "audiopll_divpmcck", "plla_div2pmcck", },
710		.pp_mux_table = { 6, 8, },
711		.pp_count = 2,
712		.pp_chg_id = INT_MIN,
713	},
714};
715
716static void __init sam9x7_pmc_setup(struct device_node *np)
717{
718	struct clk_range range = CLK_RANGE(0, 0);
719	const char *td_slck_name, *md_slck_name, *mainxtal_name;
720	struct pmc_data *sam9x7_pmc;
721	const char *parent_names[9];
722	void **clk_mux_buffer = NULL;
723	int clk_mux_buffer_size = 0;
724	struct clk_hw *main_osc_hw;
725	struct regmap *regmap;
726	struct clk_hw *hw;
727	int i, j;
728
729	i = of_property_match_string(np, "clock-names", "td_slck");
730	if (i < 0)
731		return;
732
733	td_slck_name = of_clk_get_parent_name(np, i);
734
735	i = of_property_match_string(np, "clock-names", "md_slck");
736	if (i < 0)
737		return;
738
739	md_slck_name = of_clk_get_parent_name(np, i);
740
741	i = of_property_match_string(np, "clock-names", "main_xtal");
742	if (i < 0)
743		return;
744	mainxtal_name = of_clk_get_parent_name(np, i);
745
746	regmap = device_node_to_regmap(np);
747	if (IS_ERR(regmap))
748		return;
749
750	sam9x7_pmc = pmc_data_allocate(PMC_LVDSPLL + 1,
751				       nck(sam9x7_systemck),
752				       nck(sam9x7_periphck),
753				       nck(sam9x7_gck), 8);
754	if (!sam9x7_pmc)
755		return;
756
757	clk_mux_buffer = kmalloc(sizeof(void *) *
758				 (ARRAY_SIZE(sam9x7_gck)),
759				 GFP_KERNEL);
760	if (!clk_mux_buffer)
761		goto err_free;
762
763	hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
764					   50000000);
765	if (IS_ERR(hw))
766		goto err_free;
767
768	hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, NULL, 0);
769	if (IS_ERR(hw))
770		goto err_free;
771	main_osc_hw = hw;
772
773	parent_names[0] = "main_rc_osc";
774	parent_names[1] = "main_osc";
775	hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, NULL, 2);
776	if (IS_ERR(hw))
777		goto err_free;
778
779	sam9x7_pmc->chws[PMC_MAIN] = hw;
780
781	for (i = 0; i < PLL_ID_MAX; i++) {
782		for (j = 0; j < 3; j++) {
783			struct clk_hw *parent_hw;
784
785			if (!sam9x7_plls[i][j].n)
786				continue;
787
788			switch (sam9x7_plls[i][j].t) {
789			case PLL_TYPE_FRAC:
790				if (!strcmp(sam9x7_plls[i][j].p, "mainck"))
791					parent_hw = sam9x7_pmc->chws[PMC_MAIN];
792				else if (!strcmp(sam9x7_plls[i][j].p, "main_osc"))
793					parent_hw = main_osc_hw;
794				else
795					parent_hw = __clk_get_hw(of_clk_get_by_name
796								 (np, sam9x7_plls[i][j].p));
797
798				hw = sam9x60_clk_register_frac_pll(regmap,
799								   &pmc_pll_lock,
800								   sam9x7_plls[i][j].n,
801								   sam9x7_plls[i][j].p,
802								   parent_hw, i,
803								   sam9x7_plls[i][j].c,
804								   sam9x7_plls[i][j].l,
805								   sam9x7_plls[i][j].f);
806				break;
807
808			case PLL_TYPE_DIV:
809				hw = sam9x60_clk_register_div_pll(regmap,
810								  &pmc_pll_lock,
811								  sam9x7_plls[i][j].n,
812								  sam9x7_plls[i][j].p, NULL, i,
813								  sam9x7_plls[i][j].c,
814								  sam9x7_plls[i][j].l,
815								  sam9x7_plls[i][j].f, 0);
816				break;
817
818			default:
819				continue;
820			}
821
822			if (IS_ERR(hw))
823				goto err_free;
824
825			if (sam9x7_plls[i][j].eid)
826				sam9x7_pmc->chws[sam9x7_plls[i][j].eid] = hw;
827		}
828	}
829
830	parent_names[0] = md_slck_name;
831	parent_names[1] = "mainck";
832	parent_names[2] = "plla_divpmcck";
833	parent_names[3] = "upll_divpmcck";
834	hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
835					   parent_names, NULL, &sam9x7_master_layout,
836					   &mck_characteristics, &mck_lock);
837	if (IS_ERR(hw))
838		goto err_free;
839
840	hw = at91_clk_register_master_div(regmap, "masterck_div",
841					  "masterck_pres", NULL, &sam9x7_master_layout,
842					  &mck_characteristics, &mck_lock,
843					  CLK_SET_RATE_GATE, 0);
844	if (IS_ERR(hw))
845		goto err_free;
846
847	sam9x7_pmc->chws[PMC_MCK] = hw;
848
849	parent_names[0] = "plla_divpmcck";
850	parent_names[1] = "upll_divpmcck";
851	parent_names[2] = "main_osc";
852	hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 3);
853	if (IS_ERR(hw))
854		goto err_free;
855
856	parent_names[0] = md_slck_name;
857	parent_names[1] = td_slck_name;
858	parent_names[2] = "mainck";
859	parent_names[3] = "masterck_div";
860	parent_names[4] = "plla_divpmcck";
861	parent_names[5] = "upll_divpmcck";
862	parent_names[6] = "audiopll_divpmcck";
863	for (i = 0; i < 2; i++) {
864		char name[6];
865
866		snprintf(name, sizeof(name), "prog%d", i);
867
868		hw = at91_clk_register_programmable(regmap, name,
869						    parent_names, NULL, 7, i,
870						    &sam9x7_programmable_layout,
871						    NULL);
872		if (IS_ERR(hw))
873			goto err_free;
874
875		sam9x7_pmc->pchws[i] = hw;
876	}
877
878	for (i = 0; i < ARRAY_SIZE(sam9x7_systemck); i++) {
879		hw = at91_clk_register_system(regmap, sam9x7_systemck[i].n,
880					      sam9x7_systemck[i].p, NULL,
881					      sam9x7_systemck[i].id,
882					      sam9x7_systemck[i].flags);
883		if (IS_ERR(hw))
884			goto err_free;
885
886		sam9x7_pmc->shws[sam9x7_systemck[i].id] = hw;
887	}
888
889	for (i = 0; i < ARRAY_SIZE(sam9x7_periphck); i++) {
890		hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
891							 &sam9x7_pcr_layout,
892							 sam9x7_periphck[i].n,
893							 "masterck_div", NULL,
894							 sam9x7_periphck[i].id,
895							 &range, INT_MIN,
896							 sam9x7_periphck[i].f);
897		if (IS_ERR(hw))
898			goto err_free;
899
900		sam9x7_pmc->phws[sam9x7_periphck[i].id] = hw;
901	}
902
903	parent_names[0] = md_slck_name;
904	parent_names[1] = td_slck_name;
905	parent_names[2] = "mainck";
906	parent_names[3] = "masterck_div";
907	for (i = 0; i < ARRAY_SIZE(sam9x7_gck); i++) {
908		u8 num_parents = 4 + sam9x7_gck[i].pp_count;
909		u32 *mux_table;
910
911		mux_table = kmalloc_array(num_parents, sizeof(*mux_table),
912					  GFP_KERNEL);
913		if (!mux_table)
914			goto err_free;
915
916		PMC_INIT_TABLE(mux_table, 4);
917		PMC_FILL_TABLE(&mux_table[4], sam9x7_gck[i].pp_mux_table,
918			       sam9x7_gck[i].pp_count);
919		PMC_FILL_TABLE(&parent_names[4], sam9x7_gck[i].pp,
920			       sam9x7_gck[i].pp_count);
921
922		hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
923						 &sam9x7_pcr_layout,
924						 sam9x7_gck[i].n,
925						 parent_names, NULL, mux_table,
926						 num_parents,
927						 sam9x7_gck[i].id,
928						 &sam9x7_gck[i].r,
929						 sam9x7_gck[i].pp_chg_id);
930		if (IS_ERR(hw))
931			goto err_free;
932
933		sam9x7_pmc->ghws[sam9x7_gck[i].id] = hw;
934		clk_mux_buffer[clk_mux_buffer_size++] = mux_table;
935	}
936
937	of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sam9x7_pmc);
938	kfree(clk_mux_buffer);
939
940	return;
941
942err_free:
943	if (clk_mux_buffer) {
944		for (i = 0; i < clk_mux_buffer_size; i++)
945			kfree(clk_mux_buffer[i]);
946		kfree(clk_mux_buffer);
947	}
948	kfree(sam9x7_pmc);
949}
950
951/* Some clks are used for a clocksource */
952CLK_OF_DECLARE(sam9x7_pmc, "microchip,sam9x7-pmc", sam9x7_pmc_setup);
~/ Read-only file preview.