xref: /OK3568_Linux_fs/u-boot/drivers/clk/clk_pic32.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (C) 2015 Purna Chandra Mandal <purna.mandal@microchip.com>
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <clk-uclass.h>
10*4882a593Smuzhiyun #include <dm.h>
11*4882a593Smuzhiyun #include <div64.h>
12*4882a593Smuzhiyun #include <wait_bit.h>
13*4882a593Smuzhiyun #include <dm/lists.h>
14*4882a593Smuzhiyun #include <asm/io.h>
15*4882a593Smuzhiyun #include <mach/pic32.h>
16*4882a593Smuzhiyun #include <dt-bindings/clock/microchip,clock.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /* Primary oscillator */
21*4882a593Smuzhiyun #define SYS_POSC_CLK_HZ	24000000
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun /* FRC clk rate */
24*4882a593Smuzhiyun #define SYS_FRC_CLK_HZ	8000000
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun /* Clock Registers */
27*4882a593Smuzhiyun #define OSCCON		0x0000
28*4882a593Smuzhiyun #define OSCTUNE		0x0010
29*4882a593Smuzhiyun #define SPLLCON		0x0020
30*4882a593Smuzhiyun #define REFO1CON	0x0080
31*4882a593Smuzhiyun #define REFO1TRIM	0x0090
32*4882a593Smuzhiyun #define PB1DIV		0x0140
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun /* SPLL */
35*4882a593Smuzhiyun #define ICLK_MASK	0x00000080
36*4882a593Smuzhiyun #define PLLIDIV_MASK	0x00000007
37*4882a593Smuzhiyun #define PLLODIV_MASK	0x00000007
38*4882a593Smuzhiyun #define CUROSC_MASK	0x00000007
39*4882a593Smuzhiyun #define PLLMUL_MASK	0x0000007F
40*4882a593Smuzhiyun #define FRCDIV_MASK	0x00000007
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun /* PBCLK */
43*4882a593Smuzhiyun #define PBDIV_MASK	0x00000007
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun /* SYSCLK MUX */
46*4882a593Smuzhiyun #define SCLK_SRC_FRC1	0
47*4882a593Smuzhiyun #define SCLK_SRC_SPLL	1
48*4882a593Smuzhiyun #define SCLK_SRC_POSC	2
49*4882a593Smuzhiyun #define SCLK_SRC_FRC2	7
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun /* Reference Oscillator Control Reg fields */
52*4882a593Smuzhiyun #define REFO_SEL_MASK	0x0f
53*4882a593Smuzhiyun #define REFO_SEL_SHIFT	0
54*4882a593Smuzhiyun #define REFO_ACTIVE	BIT(8)
55*4882a593Smuzhiyun #define REFO_DIVSW_EN	BIT(9)
56*4882a593Smuzhiyun #define REFO_OE		BIT(12)
57*4882a593Smuzhiyun #define REFO_ON		BIT(15)
58*4882a593Smuzhiyun #define REFO_DIV_SHIFT	16
59*4882a593Smuzhiyun #define REFO_DIV_MASK	0x7fff
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun /* Reference Oscillator Trim Register Fields */
62*4882a593Smuzhiyun #define REFO_TRIM_REG	0x10
63*4882a593Smuzhiyun #define REFO_TRIM_MASK	0x1ff
64*4882a593Smuzhiyun #define REFO_TRIM_SHIFT	23
65*4882a593Smuzhiyun #define REFO_TRIM_MAX	511
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun #define ROCLK_SRC_SCLK		0x0
68*4882a593Smuzhiyun #define ROCLK_SRC_SPLL		0x7
69*4882a593Smuzhiyun #define ROCLK_SRC_ROCLKI	0x8
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun /* Memory PLL */
72*4882a593Smuzhiyun #define MPLL_IDIV		0x3f
73*4882a593Smuzhiyun #define MPLL_MULT		0xff
74*4882a593Smuzhiyun #define MPLL_ODIV1		0x7
75*4882a593Smuzhiyun #define MPLL_ODIV2		0x7
76*4882a593Smuzhiyun #define MPLL_VREG_RDY		BIT(23)
77*4882a593Smuzhiyun #define MPLL_RDY		BIT(31)
78*4882a593Smuzhiyun #define MPLL_IDIV_SHIFT		0
79*4882a593Smuzhiyun #define MPLL_MULT_SHIFT		8
80*4882a593Smuzhiyun #define MPLL_ODIV1_SHIFT	24
81*4882a593Smuzhiyun #define MPLL_ODIV2_SHIFT	27
82*4882a593Smuzhiyun #define MPLL_IDIV_INIT		0x03
83*4882a593Smuzhiyun #define MPLL_MULT_INIT		0x32
84*4882a593Smuzhiyun #define MPLL_ODIV1_INIT		0x02
85*4882a593Smuzhiyun #define MPLL_ODIV2_INIT		0x01
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun struct pic32_clk_priv {
88*4882a593Smuzhiyun 	void __iomem *iobase;
89*4882a593Smuzhiyun 	void __iomem *syscfg_base;
90*4882a593Smuzhiyun };
91*4882a593Smuzhiyun 
pic32_get_pll_rate(struct pic32_clk_priv * priv)92*4882a593Smuzhiyun static ulong pic32_get_pll_rate(struct pic32_clk_priv *priv)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	u32 iclk, idiv, odiv, mult;
95*4882a593Smuzhiyun 	ulong plliclk, v;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	v = readl(priv->iobase + SPLLCON);
98*4882a593Smuzhiyun 	iclk = (v & ICLK_MASK);
99*4882a593Smuzhiyun 	idiv = ((v >> 8) & PLLIDIV_MASK) + 1;
100*4882a593Smuzhiyun 	odiv = ((v >> 24) & PLLODIV_MASK);
101*4882a593Smuzhiyun 	mult = ((v >> 16) & PLLMUL_MASK) + 1;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	plliclk = iclk ? SYS_FRC_CLK_HZ : SYS_POSC_CLK_HZ;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	if (odiv < 2)
106*4882a593Smuzhiyun 		odiv = 2;
107*4882a593Smuzhiyun 	else if (odiv < 5)
108*4882a593Smuzhiyun 		odiv = (1 << odiv);
109*4882a593Smuzhiyun 	else
110*4882a593Smuzhiyun 		odiv = 32;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	return ((plliclk / idiv) * mult) / odiv;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
pic32_get_sysclk(struct pic32_clk_priv * priv)115*4882a593Smuzhiyun static ulong pic32_get_sysclk(struct pic32_clk_priv *priv)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	ulong v;
118*4882a593Smuzhiyun 	ulong hz;
119*4882a593Smuzhiyun 	ulong div, frcdiv;
120*4882a593Smuzhiyun 	ulong curr_osc;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	/* get clk source */
123*4882a593Smuzhiyun 	v = readl(priv->iobase + OSCCON);
124*4882a593Smuzhiyun 	curr_osc = (v >> 12) & CUROSC_MASK;
125*4882a593Smuzhiyun 	switch (curr_osc) {
126*4882a593Smuzhiyun 	case SCLK_SRC_FRC1:
127*4882a593Smuzhiyun 	case SCLK_SRC_FRC2:
128*4882a593Smuzhiyun 		frcdiv = ((v >> 24) & FRCDIV_MASK);
129*4882a593Smuzhiyun 		div = ((1 << frcdiv) + 1) + (128 * (frcdiv == 7));
130*4882a593Smuzhiyun 		hz = SYS_FRC_CLK_HZ / div;
131*4882a593Smuzhiyun 		break;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	case SCLK_SRC_SPLL:
134*4882a593Smuzhiyun 		hz = pic32_get_pll_rate(priv);
135*4882a593Smuzhiyun 		break;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	case SCLK_SRC_POSC:
138*4882a593Smuzhiyun 		hz = SYS_POSC_CLK_HZ;
139*4882a593Smuzhiyun 		break;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	default:
142*4882a593Smuzhiyun 		hz = 0;
143*4882a593Smuzhiyun 		printf("clk: unknown sclk_src.\n");
144*4882a593Smuzhiyun 		break;
145*4882a593Smuzhiyun 	}
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	return hz;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun 
pic32_get_pbclk(struct pic32_clk_priv * priv,int periph)150*4882a593Smuzhiyun static ulong pic32_get_pbclk(struct pic32_clk_priv *priv, int periph)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun 	void __iomem *reg;
153*4882a593Smuzhiyun 	ulong div, clk_freq;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	WARN_ON((periph < PB1CLK) || (periph > PB7CLK));
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	clk_freq = pic32_get_sysclk(priv);
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	reg = priv->iobase + PB1DIV + (periph - PB1CLK) * 0x10;
160*4882a593Smuzhiyun 	div = (readl(reg) & PBDIV_MASK) + 1;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	return clk_freq / div;
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun 
pic32_get_cpuclk(struct pic32_clk_priv * priv)165*4882a593Smuzhiyun static ulong pic32_get_cpuclk(struct pic32_clk_priv *priv)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun 	return pic32_get_pbclk(priv, PB7CLK);
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun 
pic32_set_refclk(struct pic32_clk_priv * priv,int periph,int parent_rate,int rate,int parent_id)170*4882a593Smuzhiyun static ulong pic32_set_refclk(struct pic32_clk_priv *priv, int periph,
171*4882a593Smuzhiyun 			      int parent_rate, int rate, int parent_id)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun 	void __iomem *reg;
174*4882a593Smuzhiyun 	u32 div, trim, v;
175*4882a593Smuzhiyun 	u64 frac;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	WARN_ON((periph < REF1CLK) || (periph > REF5CLK));
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	/* calculate dividers,
180*4882a593Smuzhiyun 	 *   rate = parent_rate / [2 * (div + (trim / 512))]
181*4882a593Smuzhiyun 	 */
182*4882a593Smuzhiyun 	if (parent_rate <= rate) {
183*4882a593Smuzhiyun 		div = 0;
184*4882a593Smuzhiyun 		trim = 0;
185*4882a593Smuzhiyun 	} else {
186*4882a593Smuzhiyun 		div = parent_rate / (rate << 1);
187*4882a593Smuzhiyun 		frac = parent_rate;
188*4882a593Smuzhiyun 		frac <<= 8;
189*4882a593Smuzhiyun 		do_div(frac, rate);
190*4882a593Smuzhiyun 		frac -= (u64)(div << 9);
191*4882a593Smuzhiyun 		trim = (frac >= REFO_TRIM_MAX) ? REFO_TRIM_MAX : (u32)frac;
192*4882a593Smuzhiyun 	}
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	reg = priv->iobase + REFO1CON + (periph - REF1CLK) * 0x20;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	/* disable clk */
197*4882a593Smuzhiyun 	writel(REFO_ON | REFO_OE, reg + _CLR_OFFSET);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	/* wait till previous src change is active */
200*4882a593Smuzhiyun 	wait_for_bit_le32(reg, REFO_DIVSW_EN | REFO_ACTIVE,
201*4882a593Smuzhiyun 			  false, CONFIG_SYS_HZ, false);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	/* parent_id */
204*4882a593Smuzhiyun 	v = readl(reg);
205*4882a593Smuzhiyun 	v &= ~(REFO_SEL_MASK << REFO_SEL_SHIFT);
206*4882a593Smuzhiyun 	v |= (parent_id << REFO_SEL_SHIFT);
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	/* apply rodiv */
209*4882a593Smuzhiyun 	v &= ~(REFO_DIV_MASK << REFO_DIV_SHIFT);
210*4882a593Smuzhiyun 	v |= (div << REFO_DIV_SHIFT);
211*4882a593Smuzhiyun 	writel(v, reg);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	/* apply trim */
214*4882a593Smuzhiyun 	v = readl(reg + REFO_TRIM_REG);
215*4882a593Smuzhiyun 	v &= ~(REFO_TRIM_MASK << REFO_TRIM_SHIFT);
216*4882a593Smuzhiyun 	v |= (trim << REFO_TRIM_SHIFT);
217*4882a593Smuzhiyun 	writel(v, reg + REFO_TRIM_REG);
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	/* enable clk */
220*4882a593Smuzhiyun 	writel(REFO_ON | REFO_OE, reg + _SET_OFFSET);
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	/* switch divider */
223*4882a593Smuzhiyun 	writel(REFO_DIVSW_EN, reg + _SET_OFFSET);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	/* wait for divider switching to complete */
226*4882a593Smuzhiyun 	return wait_for_bit_le32(reg, REFO_DIVSW_EN, false,
227*4882a593Smuzhiyun 				 CONFIG_SYS_HZ, false);
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun 
pic32_get_refclk(struct pic32_clk_priv * priv,int periph)230*4882a593Smuzhiyun static ulong pic32_get_refclk(struct pic32_clk_priv *priv, int periph)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun 	u32 rodiv, rotrim, rosel, v, parent_rate;
233*4882a593Smuzhiyun 	void __iomem *reg;
234*4882a593Smuzhiyun 	u64 rate64;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	WARN_ON((periph < REF1CLK) || (periph > REF5CLK));
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	reg = priv->iobase + REFO1CON + (periph - REF1CLK) * 0x20;
239*4882a593Smuzhiyun 	v = readl(reg);
240*4882a593Smuzhiyun 	/* get rosel */
241*4882a593Smuzhiyun 	rosel = (v >> REFO_SEL_SHIFT) & REFO_SEL_MASK;
242*4882a593Smuzhiyun 	/* get div */
243*4882a593Smuzhiyun 	rodiv = (v >> REFO_DIV_SHIFT) & REFO_DIV_MASK;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	/* get trim */
246*4882a593Smuzhiyun 	v = readl(reg + REFO_TRIM_REG);
247*4882a593Smuzhiyun 	rotrim = (v >> REFO_TRIM_SHIFT) & REFO_TRIM_MASK;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	if (!rodiv)
250*4882a593Smuzhiyun 		return 0;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	/* get parent rate */
253*4882a593Smuzhiyun 	switch (rosel) {
254*4882a593Smuzhiyun 	case ROCLK_SRC_SCLK:
255*4882a593Smuzhiyun 		parent_rate = pic32_get_cpuclk(priv);
256*4882a593Smuzhiyun 		break;
257*4882a593Smuzhiyun 	case ROCLK_SRC_SPLL:
258*4882a593Smuzhiyun 		parent_rate = pic32_get_pll_rate(priv);
259*4882a593Smuzhiyun 		break;
260*4882a593Smuzhiyun 	default:
261*4882a593Smuzhiyun 		parent_rate = 0;
262*4882a593Smuzhiyun 		break;
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	/* Calculation
266*4882a593Smuzhiyun 	 * rate = parent_rate / [2 * (div + (trim / 512))]
267*4882a593Smuzhiyun 	 */
268*4882a593Smuzhiyun 	if (rotrim) {
269*4882a593Smuzhiyun 		rodiv <<= 9;
270*4882a593Smuzhiyun 		rodiv += rotrim;
271*4882a593Smuzhiyun 		rate64 = parent_rate;
272*4882a593Smuzhiyun 		rate64 <<= 8;
273*4882a593Smuzhiyun 		do_div(rate64, rodiv);
274*4882a593Smuzhiyun 		v = (u32)rate64;
275*4882a593Smuzhiyun 	} else {
276*4882a593Smuzhiyun 		v = parent_rate / (rodiv << 1);
277*4882a593Smuzhiyun 	}
278*4882a593Smuzhiyun 	return v;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun 
pic32_get_mpll_rate(struct pic32_clk_priv * priv)281*4882a593Smuzhiyun static ulong pic32_get_mpll_rate(struct pic32_clk_priv *priv)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun 	u32 v, idiv, mul;
284*4882a593Smuzhiyun 	u32 odiv1, odiv2;
285*4882a593Smuzhiyun 	u64 rate;
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	v = readl(priv->syscfg_base + CFGMPLL);
288*4882a593Smuzhiyun 	idiv = v & MPLL_IDIV;
289*4882a593Smuzhiyun 	mul = (v >> MPLL_MULT_SHIFT) & MPLL_MULT;
290*4882a593Smuzhiyun 	odiv1 = (v >> MPLL_ODIV1_SHIFT) & MPLL_ODIV1;
291*4882a593Smuzhiyun 	odiv2 = (v >> MPLL_ODIV2_SHIFT) & MPLL_ODIV2;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	rate = (SYS_POSC_CLK_HZ / idiv) * mul;
294*4882a593Smuzhiyun 	do_div(rate, odiv1);
295*4882a593Smuzhiyun 	do_div(rate, odiv2);
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	return (ulong)rate;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun 
pic32_mpll_init(struct pic32_clk_priv * priv)300*4882a593Smuzhiyun static int pic32_mpll_init(struct pic32_clk_priv *priv)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun 	u32 v, mask;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	/* initialize */
305*4882a593Smuzhiyun 	v = (MPLL_IDIV_INIT << MPLL_IDIV_SHIFT) |
306*4882a593Smuzhiyun 	    (MPLL_MULT_INIT << MPLL_MULT_SHIFT) |
307*4882a593Smuzhiyun 	    (MPLL_ODIV1_INIT << MPLL_ODIV1_SHIFT) |
308*4882a593Smuzhiyun 	    (MPLL_ODIV2_INIT << MPLL_ODIV2_SHIFT);
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	writel(v, priv->syscfg_base + CFGMPLL);
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	/* Wait for ready */
313*4882a593Smuzhiyun 	mask = MPLL_RDY | MPLL_VREG_RDY;
314*4882a593Smuzhiyun 	return wait_for_bit_le32(priv->syscfg_base + CFGMPLL, mask,
315*4882a593Smuzhiyun 				 true, get_tbclk(), false);
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun 
pic32_clk_init(struct udevice * dev)318*4882a593Smuzhiyun static void pic32_clk_init(struct udevice *dev)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun 	const void *blob = gd->fdt_blob;
321*4882a593Smuzhiyun 	struct pic32_clk_priv *priv;
322*4882a593Smuzhiyun 	ulong rate, pll_hz;
323*4882a593Smuzhiyun 	char propname[50];
324*4882a593Smuzhiyun 	int i;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	priv = dev_get_priv(dev);
327*4882a593Smuzhiyun 	pll_hz = pic32_get_pll_rate(priv);
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	/* Initialize REFOs as not initialized and enabled on reset. */
330*4882a593Smuzhiyun 	for (i = REF1CLK; i <= REF5CLK; i++) {
331*4882a593Smuzhiyun 		snprintf(propname, sizeof(propname),
332*4882a593Smuzhiyun 			 "microchip,refo%d-frequency", i - REF1CLK + 1);
333*4882a593Smuzhiyun 		rate = fdtdec_get_int(blob, dev_of_offset(dev), propname, 0);
334*4882a593Smuzhiyun 		if (rate)
335*4882a593Smuzhiyun 			pic32_set_refclk(priv, i, pll_hz, rate, ROCLK_SRC_SPLL);
336*4882a593Smuzhiyun 	}
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	/* Memory PLL */
339*4882a593Smuzhiyun 	pic32_mpll_init(priv);
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
pic32_get_rate(struct clk * clk)342*4882a593Smuzhiyun static ulong pic32_get_rate(struct clk *clk)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun 	struct pic32_clk_priv *priv = dev_get_priv(clk->dev);
345*4882a593Smuzhiyun 	ulong rate;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	switch (clk->id) {
348*4882a593Smuzhiyun 	case PB1CLK ... PB7CLK:
349*4882a593Smuzhiyun 		rate = pic32_get_pbclk(priv, clk->id);
350*4882a593Smuzhiyun 		break;
351*4882a593Smuzhiyun 	case REF1CLK ... REF5CLK:
352*4882a593Smuzhiyun 		rate = pic32_get_refclk(priv, clk->id);
353*4882a593Smuzhiyun 		break;
354*4882a593Smuzhiyun 	case PLLCLK:
355*4882a593Smuzhiyun 		rate = pic32_get_pll_rate(priv);
356*4882a593Smuzhiyun 		break;
357*4882a593Smuzhiyun 	case MPLL:
358*4882a593Smuzhiyun 		rate = pic32_get_mpll_rate(priv);
359*4882a593Smuzhiyun 		break;
360*4882a593Smuzhiyun 	default:
361*4882a593Smuzhiyun 		rate = 0;
362*4882a593Smuzhiyun 		break;
363*4882a593Smuzhiyun 	}
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	return rate;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun 
pic32_set_rate(struct clk * clk,ulong rate)368*4882a593Smuzhiyun static ulong pic32_set_rate(struct clk *clk, ulong rate)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun 	struct pic32_clk_priv *priv = dev_get_priv(clk->dev);
371*4882a593Smuzhiyun 	ulong pll_hz;
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	switch (clk->id) {
374*4882a593Smuzhiyun 	case REF1CLK ... REF5CLK:
375*4882a593Smuzhiyun 		pll_hz = pic32_get_pll_rate(priv);
376*4882a593Smuzhiyun 		pic32_set_refclk(priv, clk->id, pll_hz, rate, ROCLK_SRC_SPLL);
377*4882a593Smuzhiyun 		break;
378*4882a593Smuzhiyun 	default:
379*4882a593Smuzhiyun 		break;
380*4882a593Smuzhiyun 	}
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	return rate;
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun static struct clk_ops pic32_pic32_clk_ops = {
386*4882a593Smuzhiyun 	.set_rate = pic32_set_rate,
387*4882a593Smuzhiyun 	.get_rate = pic32_get_rate,
388*4882a593Smuzhiyun };
389*4882a593Smuzhiyun 
pic32_clk_probe(struct udevice * dev)390*4882a593Smuzhiyun static int pic32_clk_probe(struct udevice *dev)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun 	struct pic32_clk_priv *priv = dev_get_priv(dev);
393*4882a593Smuzhiyun 	fdt_addr_t addr;
394*4882a593Smuzhiyun 	fdt_size_t size;
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	addr = fdtdec_get_addr_size(gd->fdt_blob, dev_of_offset(dev), "reg",
397*4882a593Smuzhiyun 				    &size);
398*4882a593Smuzhiyun 	if (addr == FDT_ADDR_T_NONE)
399*4882a593Smuzhiyun 		return -EINVAL;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	priv->iobase = ioremap(addr, size);
402*4882a593Smuzhiyun 	if (!priv->iobase)
403*4882a593Smuzhiyun 		return -EINVAL;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	priv->syscfg_base = pic32_get_syscfg_base();
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	/* initialize clocks */
408*4882a593Smuzhiyun 	pic32_clk_init(dev);
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	return 0;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun static const struct udevice_id pic32_clk_ids[] = {
414*4882a593Smuzhiyun 	{ .compatible = "microchip,pic32mzda-clk"},
415*4882a593Smuzhiyun 	{}
416*4882a593Smuzhiyun };
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun U_BOOT_DRIVER(pic32_clk) = {
419*4882a593Smuzhiyun 	.name		= "pic32_clk",
420*4882a593Smuzhiyun 	.id		= UCLASS_CLK,
421*4882a593Smuzhiyun 	.of_match	= pic32_clk_ids,
422*4882a593Smuzhiyun 	.flags		= DM_FLAG_PRE_RELOC,
423*4882a593Smuzhiyun 	.ops		= &pic32_pic32_clk_ops,
424*4882a593Smuzhiyun 	.probe		= pic32_clk_probe,
425*4882a593Smuzhiyun 	.priv_auto_alloc_size = sizeof(struct pic32_clk_priv),
426*4882a593Smuzhiyun };
427