xref: /OK3568_Linux_fs/kernel/drivers/clk/at91/sckc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * drivers/clk/at91/sckc.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/clk-provider.h>
9*4882a593Smuzhiyun #include <linux/clkdev.h>
10*4882a593Smuzhiyun #include <linux/delay.h>
11*4882a593Smuzhiyun #include <linux/of.h>
12*4882a593Smuzhiyun #include <linux/of_address.h>
13*4882a593Smuzhiyun #include <linux/io.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #define SLOW_CLOCK_FREQ		32768
16*4882a593Smuzhiyun #define SLOWCK_SW_CYCLES	5
17*4882a593Smuzhiyun #define SLOWCK_SW_TIME_USEC	((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \
18*4882a593Smuzhiyun 				 SLOW_CLOCK_FREQ)
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #define	AT91_SCKC_CR			0x00
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun struct clk_slow_bits {
23*4882a593Smuzhiyun 	u32 cr_rcen;
24*4882a593Smuzhiyun 	u32 cr_osc32en;
25*4882a593Smuzhiyun 	u32 cr_osc32byp;
26*4882a593Smuzhiyun 	u32 cr_oscsel;
27*4882a593Smuzhiyun };
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun struct clk_slow_osc {
30*4882a593Smuzhiyun 	struct clk_hw hw;
31*4882a593Smuzhiyun 	void __iomem *sckcr;
32*4882a593Smuzhiyun 	const struct clk_slow_bits *bits;
33*4882a593Smuzhiyun 	unsigned long startup_usec;
34*4882a593Smuzhiyun };
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun #define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw)
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun struct clk_sama5d4_slow_osc {
39*4882a593Smuzhiyun 	struct clk_hw hw;
40*4882a593Smuzhiyun 	void __iomem *sckcr;
41*4882a593Smuzhiyun 	const struct clk_slow_bits *bits;
42*4882a593Smuzhiyun 	unsigned long startup_usec;
43*4882a593Smuzhiyun 	bool prepared;
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #define to_clk_sama5d4_slow_osc(hw) container_of(hw, struct clk_sama5d4_slow_osc, hw)
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun struct clk_slow_rc_osc {
49*4882a593Smuzhiyun 	struct clk_hw hw;
50*4882a593Smuzhiyun 	void __iomem *sckcr;
51*4882a593Smuzhiyun 	const struct clk_slow_bits *bits;
52*4882a593Smuzhiyun 	unsigned long frequency;
53*4882a593Smuzhiyun 	unsigned long accuracy;
54*4882a593Smuzhiyun 	unsigned long startup_usec;
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun #define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw)
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun struct clk_sam9x5_slow {
60*4882a593Smuzhiyun 	struct clk_hw hw;
61*4882a593Smuzhiyun 	void __iomem *sckcr;
62*4882a593Smuzhiyun 	const struct clk_slow_bits *bits;
63*4882a593Smuzhiyun 	u8 parent;
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
67*4882a593Smuzhiyun 
clk_slow_osc_prepare(struct clk_hw * hw)68*4882a593Smuzhiyun static int clk_slow_osc_prepare(struct clk_hw *hw)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun 	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
71*4882a593Smuzhiyun 	void __iomem *sckcr = osc->sckcr;
72*4882a593Smuzhiyun 	u32 tmp = readl(sckcr);
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	if (tmp & (osc->bits->cr_osc32byp | osc->bits->cr_osc32en))
75*4882a593Smuzhiyun 		return 0;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	writel(tmp | osc->bits->cr_osc32en, sckcr);
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	if (system_state < SYSTEM_RUNNING)
80*4882a593Smuzhiyun 		udelay(osc->startup_usec);
81*4882a593Smuzhiyun 	else
82*4882a593Smuzhiyun 		usleep_range(osc->startup_usec, osc->startup_usec + 1);
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	return 0;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
clk_slow_osc_unprepare(struct clk_hw * hw)87*4882a593Smuzhiyun static void clk_slow_osc_unprepare(struct clk_hw *hw)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun 	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
90*4882a593Smuzhiyun 	void __iomem *sckcr = osc->sckcr;
91*4882a593Smuzhiyun 	u32 tmp = readl(sckcr);
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	if (tmp & osc->bits->cr_osc32byp)
94*4882a593Smuzhiyun 		return;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	writel(tmp & ~osc->bits->cr_osc32en, sckcr);
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun 
clk_slow_osc_is_prepared(struct clk_hw * hw)99*4882a593Smuzhiyun static int clk_slow_osc_is_prepared(struct clk_hw *hw)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun 	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
102*4882a593Smuzhiyun 	void __iomem *sckcr = osc->sckcr;
103*4882a593Smuzhiyun 	u32 tmp = readl(sckcr);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	if (tmp & osc->bits->cr_osc32byp)
106*4882a593Smuzhiyun 		return 1;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	return !!(tmp & osc->bits->cr_osc32en);
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun static const struct clk_ops slow_osc_ops = {
112*4882a593Smuzhiyun 	.prepare = clk_slow_osc_prepare,
113*4882a593Smuzhiyun 	.unprepare = clk_slow_osc_unprepare,
114*4882a593Smuzhiyun 	.is_prepared = clk_slow_osc_is_prepared,
115*4882a593Smuzhiyun };
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun static struct clk_hw * __init
at91_clk_register_slow_osc(void __iomem * sckcr,const char * name,const char * parent_name,unsigned long startup,bool bypass,const struct clk_slow_bits * bits)118*4882a593Smuzhiyun at91_clk_register_slow_osc(void __iomem *sckcr,
119*4882a593Smuzhiyun 			   const char *name,
120*4882a593Smuzhiyun 			   const char *parent_name,
121*4882a593Smuzhiyun 			   unsigned long startup,
122*4882a593Smuzhiyun 			   bool bypass,
123*4882a593Smuzhiyun 			   const struct clk_slow_bits *bits)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	struct clk_slow_osc *osc;
126*4882a593Smuzhiyun 	struct clk_hw *hw;
127*4882a593Smuzhiyun 	struct clk_init_data init;
128*4882a593Smuzhiyun 	int ret;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	if (!sckcr || !name || !parent_name)
131*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
134*4882a593Smuzhiyun 	if (!osc)
135*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	init.name = name;
138*4882a593Smuzhiyun 	init.ops = &slow_osc_ops;
139*4882a593Smuzhiyun 	init.parent_names = &parent_name;
140*4882a593Smuzhiyun 	init.num_parents = 1;
141*4882a593Smuzhiyun 	init.flags = CLK_IGNORE_UNUSED;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	osc->hw.init = &init;
144*4882a593Smuzhiyun 	osc->sckcr = sckcr;
145*4882a593Smuzhiyun 	osc->startup_usec = startup;
146*4882a593Smuzhiyun 	osc->bits = bits;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	if (bypass)
149*4882a593Smuzhiyun 		writel((readl(sckcr) & ~osc->bits->cr_osc32en) |
150*4882a593Smuzhiyun 					osc->bits->cr_osc32byp, sckcr);
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	hw = &osc->hw;
153*4882a593Smuzhiyun 	ret = clk_hw_register(NULL, &osc->hw);
154*4882a593Smuzhiyun 	if (ret) {
155*4882a593Smuzhiyun 		kfree(osc);
156*4882a593Smuzhiyun 		hw = ERR_PTR(ret);
157*4882a593Smuzhiyun 	}
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	return hw;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun 
at91_clk_unregister_slow_osc(struct clk_hw * hw)162*4882a593Smuzhiyun static void at91_clk_unregister_slow_osc(struct clk_hw *hw)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun 	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	clk_hw_unregister(hw);
167*4882a593Smuzhiyun 	kfree(osc);
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun 
clk_slow_rc_osc_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)170*4882a593Smuzhiyun static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
171*4882a593Smuzhiyun 						 unsigned long parent_rate)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun 	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	return osc->frequency;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun 
clk_slow_rc_osc_recalc_accuracy(struct clk_hw * hw,unsigned long parent_acc)178*4882a593Smuzhiyun static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw,
179*4882a593Smuzhiyun 						     unsigned long parent_acc)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun 	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	return osc->accuracy;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun 
clk_slow_rc_osc_prepare(struct clk_hw * hw)186*4882a593Smuzhiyun static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun 	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
189*4882a593Smuzhiyun 	void __iomem *sckcr = osc->sckcr;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	writel(readl(sckcr) | osc->bits->cr_rcen, sckcr);
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	if (system_state < SYSTEM_RUNNING)
194*4882a593Smuzhiyun 		udelay(osc->startup_usec);
195*4882a593Smuzhiyun 	else
196*4882a593Smuzhiyun 		usleep_range(osc->startup_usec, osc->startup_usec + 1);
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	return 0;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
clk_slow_rc_osc_unprepare(struct clk_hw * hw)201*4882a593Smuzhiyun static void clk_slow_rc_osc_unprepare(struct clk_hw *hw)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
204*4882a593Smuzhiyun 	void __iomem *sckcr = osc->sckcr;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	writel(readl(sckcr) & ~osc->bits->cr_rcen, sckcr);
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun 
clk_slow_rc_osc_is_prepared(struct clk_hw * hw)209*4882a593Smuzhiyun static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun 	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	return !!(readl(osc->sckcr) & osc->bits->cr_rcen);
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun static const struct clk_ops slow_rc_osc_ops = {
217*4882a593Smuzhiyun 	.prepare = clk_slow_rc_osc_prepare,
218*4882a593Smuzhiyun 	.unprepare = clk_slow_rc_osc_unprepare,
219*4882a593Smuzhiyun 	.is_prepared = clk_slow_rc_osc_is_prepared,
220*4882a593Smuzhiyun 	.recalc_rate = clk_slow_rc_osc_recalc_rate,
221*4882a593Smuzhiyun 	.recalc_accuracy = clk_slow_rc_osc_recalc_accuracy,
222*4882a593Smuzhiyun };
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun static struct clk_hw * __init
at91_clk_register_slow_rc_osc(void __iomem * sckcr,const char * name,unsigned long frequency,unsigned long accuracy,unsigned long startup,const struct clk_slow_bits * bits)225*4882a593Smuzhiyun at91_clk_register_slow_rc_osc(void __iomem *sckcr,
226*4882a593Smuzhiyun 			      const char *name,
227*4882a593Smuzhiyun 			      unsigned long frequency,
228*4882a593Smuzhiyun 			      unsigned long accuracy,
229*4882a593Smuzhiyun 			      unsigned long startup,
230*4882a593Smuzhiyun 			      const struct clk_slow_bits *bits)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun 	struct clk_slow_rc_osc *osc;
233*4882a593Smuzhiyun 	struct clk_hw *hw;
234*4882a593Smuzhiyun 	struct clk_init_data init;
235*4882a593Smuzhiyun 	int ret;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	if (!sckcr || !name)
238*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
241*4882a593Smuzhiyun 	if (!osc)
242*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	init.name = name;
245*4882a593Smuzhiyun 	init.ops = &slow_rc_osc_ops;
246*4882a593Smuzhiyun 	init.parent_names = NULL;
247*4882a593Smuzhiyun 	init.num_parents = 0;
248*4882a593Smuzhiyun 	init.flags = CLK_IGNORE_UNUSED;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	osc->hw.init = &init;
251*4882a593Smuzhiyun 	osc->sckcr = sckcr;
252*4882a593Smuzhiyun 	osc->bits = bits;
253*4882a593Smuzhiyun 	osc->frequency = frequency;
254*4882a593Smuzhiyun 	osc->accuracy = accuracy;
255*4882a593Smuzhiyun 	osc->startup_usec = startup;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	hw = &osc->hw;
258*4882a593Smuzhiyun 	ret = clk_hw_register(NULL, &osc->hw);
259*4882a593Smuzhiyun 	if (ret) {
260*4882a593Smuzhiyun 		kfree(osc);
261*4882a593Smuzhiyun 		hw = ERR_PTR(ret);
262*4882a593Smuzhiyun 	}
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	return hw;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun 
at91_clk_unregister_slow_rc_osc(struct clk_hw * hw)267*4882a593Smuzhiyun static void at91_clk_unregister_slow_rc_osc(struct clk_hw *hw)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun 	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	clk_hw_unregister(hw);
272*4882a593Smuzhiyun 	kfree(osc);
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun 
clk_sam9x5_slow_set_parent(struct clk_hw * hw,u8 index)275*4882a593Smuzhiyun static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun 	struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
278*4882a593Smuzhiyun 	void __iomem *sckcr = slowck->sckcr;
279*4882a593Smuzhiyun 	u32 tmp;
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	if (index > 1)
282*4882a593Smuzhiyun 		return -EINVAL;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	tmp = readl(sckcr);
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	if ((!index && !(tmp & slowck->bits->cr_oscsel)) ||
287*4882a593Smuzhiyun 	    (index && (tmp & slowck->bits->cr_oscsel)))
288*4882a593Smuzhiyun 		return 0;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	if (index)
291*4882a593Smuzhiyun 		tmp |= slowck->bits->cr_oscsel;
292*4882a593Smuzhiyun 	else
293*4882a593Smuzhiyun 		tmp &= ~slowck->bits->cr_oscsel;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	writel(tmp, sckcr);
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	if (system_state < SYSTEM_RUNNING)
298*4882a593Smuzhiyun 		udelay(SLOWCK_SW_TIME_USEC);
299*4882a593Smuzhiyun 	else
300*4882a593Smuzhiyun 		usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1);
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	return 0;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun 
clk_sam9x5_slow_get_parent(struct clk_hw * hw)305*4882a593Smuzhiyun static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun 	struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	return !!(readl(slowck->sckcr) & slowck->bits->cr_oscsel);
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun static const struct clk_ops sam9x5_slow_ops = {
313*4882a593Smuzhiyun 	.set_parent = clk_sam9x5_slow_set_parent,
314*4882a593Smuzhiyun 	.get_parent = clk_sam9x5_slow_get_parent,
315*4882a593Smuzhiyun };
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun static struct clk_hw * __init
at91_clk_register_sam9x5_slow(void __iomem * sckcr,const char * name,const char ** parent_names,int num_parents,const struct clk_slow_bits * bits)318*4882a593Smuzhiyun at91_clk_register_sam9x5_slow(void __iomem *sckcr,
319*4882a593Smuzhiyun 			      const char *name,
320*4882a593Smuzhiyun 			      const char **parent_names,
321*4882a593Smuzhiyun 			      int num_parents,
322*4882a593Smuzhiyun 			      const struct clk_slow_bits *bits)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun 	struct clk_sam9x5_slow *slowck;
325*4882a593Smuzhiyun 	struct clk_hw *hw;
326*4882a593Smuzhiyun 	struct clk_init_data init;
327*4882a593Smuzhiyun 	int ret;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	if (!sckcr || !name || !parent_names || !num_parents)
330*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
333*4882a593Smuzhiyun 	if (!slowck)
334*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	init.name = name;
337*4882a593Smuzhiyun 	init.ops = &sam9x5_slow_ops;
338*4882a593Smuzhiyun 	init.parent_names = parent_names;
339*4882a593Smuzhiyun 	init.num_parents = num_parents;
340*4882a593Smuzhiyun 	init.flags = 0;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	slowck->hw.init = &init;
343*4882a593Smuzhiyun 	slowck->sckcr = sckcr;
344*4882a593Smuzhiyun 	slowck->bits = bits;
345*4882a593Smuzhiyun 	slowck->parent = !!(readl(sckcr) & slowck->bits->cr_oscsel);
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	hw = &slowck->hw;
348*4882a593Smuzhiyun 	ret = clk_hw_register(NULL, &slowck->hw);
349*4882a593Smuzhiyun 	if (ret) {
350*4882a593Smuzhiyun 		kfree(slowck);
351*4882a593Smuzhiyun 		hw = ERR_PTR(ret);
352*4882a593Smuzhiyun 	}
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	return hw;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun 
at91_clk_unregister_sam9x5_slow(struct clk_hw * hw)357*4882a593Smuzhiyun static void at91_clk_unregister_sam9x5_slow(struct clk_hw *hw)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun 	struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	clk_hw_unregister(hw);
362*4882a593Smuzhiyun 	kfree(slowck);
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun 
at91sam9x5_sckc_register(struct device_node * np,unsigned int rc_osc_startup_us,const struct clk_slow_bits * bits)365*4882a593Smuzhiyun static void __init at91sam9x5_sckc_register(struct device_node *np,
366*4882a593Smuzhiyun 					    unsigned int rc_osc_startup_us,
367*4882a593Smuzhiyun 					    const struct clk_slow_bits *bits)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun 	const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
370*4882a593Smuzhiyun 	void __iomem *regbase = of_iomap(np, 0);
371*4882a593Smuzhiyun 	struct device_node *child = NULL;
372*4882a593Smuzhiyun 	const char *xtal_name;
373*4882a593Smuzhiyun 	struct clk_hw *slow_rc, *slow_osc, *slowck;
374*4882a593Smuzhiyun 	bool bypass;
375*4882a593Smuzhiyun 	int ret;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	if (!regbase)
378*4882a593Smuzhiyun 		return;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	slow_rc = at91_clk_register_slow_rc_osc(regbase, parent_names[0],
381*4882a593Smuzhiyun 						32768, 50000000,
382*4882a593Smuzhiyun 						rc_osc_startup_us, bits);
383*4882a593Smuzhiyun 	if (IS_ERR(slow_rc))
384*4882a593Smuzhiyun 		return;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	xtal_name = of_clk_get_parent_name(np, 0);
387*4882a593Smuzhiyun 	if (!xtal_name) {
388*4882a593Smuzhiyun 		/* DT backward compatibility */
389*4882a593Smuzhiyun 		child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow-osc");
390*4882a593Smuzhiyun 		if (!child)
391*4882a593Smuzhiyun 			goto unregister_slow_rc;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 		xtal_name = of_clk_get_parent_name(child, 0);
394*4882a593Smuzhiyun 		bypass = of_property_read_bool(child, "atmel,osc-bypass");
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 		child =  of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow");
397*4882a593Smuzhiyun 	} else {
398*4882a593Smuzhiyun 		bypass = of_property_read_bool(np, "atmel,osc-bypass");
399*4882a593Smuzhiyun 	}
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	if (!xtal_name)
402*4882a593Smuzhiyun 		goto unregister_slow_rc;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	slow_osc = at91_clk_register_slow_osc(regbase, parent_names[1],
405*4882a593Smuzhiyun 					      xtal_name, 1200000, bypass, bits);
406*4882a593Smuzhiyun 	if (IS_ERR(slow_osc))
407*4882a593Smuzhiyun 		goto unregister_slow_rc;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	slowck = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names,
410*4882a593Smuzhiyun 					       2, bits);
411*4882a593Smuzhiyun 	if (IS_ERR(slowck))
412*4882a593Smuzhiyun 		goto unregister_slow_osc;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	/* DT backward compatibility */
415*4882a593Smuzhiyun 	if (child)
416*4882a593Smuzhiyun 		ret = of_clk_add_hw_provider(child, of_clk_hw_simple_get,
417*4882a593Smuzhiyun 					     slowck);
418*4882a593Smuzhiyun 	else
419*4882a593Smuzhiyun 		ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck);
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	if (WARN_ON(ret))
422*4882a593Smuzhiyun 		goto unregister_slowck;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	return;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun unregister_slowck:
427*4882a593Smuzhiyun 	at91_clk_unregister_sam9x5_slow(slowck);
428*4882a593Smuzhiyun unregister_slow_osc:
429*4882a593Smuzhiyun 	at91_clk_unregister_slow_osc(slow_osc);
430*4882a593Smuzhiyun unregister_slow_rc:
431*4882a593Smuzhiyun 	at91_clk_unregister_slow_rc_osc(slow_rc);
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun static const struct clk_slow_bits at91sam9x5_bits = {
435*4882a593Smuzhiyun 	.cr_rcen = BIT(0),
436*4882a593Smuzhiyun 	.cr_osc32en = BIT(1),
437*4882a593Smuzhiyun 	.cr_osc32byp = BIT(2),
438*4882a593Smuzhiyun 	.cr_oscsel = BIT(3),
439*4882a593Smuzhiyun };
440*4882a593Smuzhiyun 
of_at91sam9x5_sckc_setup(struct device_node * np)441*4882a593Smuzhiyun static void __init of_at91sam9x5_sckc_setup(struct device_node *np)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun 	at91sam9x5_sckc_register(np, 75, &at91sam9x5_bits);
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc",
446*4882a593Smuzhiyun 	       of_at91sam9x5_sckc_setup);
447*4882a593Smuzhiyun 
of_sama5d3_sckc_setup(struct device_node * np)448*4882a593Smuzhiyun static void __init of_sama5d3_sckc_setup(struct device_node *np)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun 	at91sam9x5_sckc_register(np, 500, &at91sam9x5_bits);
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun CLK_OF_DECLARE(sama5d3_clk_sckc, "atmel,sama5d3-sckc",
453*4882a593Smuzhiyun 	       of_sama5d3_sckc_setup);
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun static const struct clk_slow_bits at91sam9x60_bits = {
456*4882a593Smuzhiyun 	.cr_osc32en = BIT(1),
457*4882a593Smuzhiyun 	.cr_osc32byp = BIT(2),
458*4882a593Smuzhiyun 	.cr_oscsel = BIT(24),
459*4882a593Smuzhiyun };
460*4882a593Smuzhiyun 
of_sam9x60_sckc_setup(struct device_node * np)461*4882a593Smuzhiyun static void __init of_sam9x60_sckc_setup(struct device_node *np)
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun 	void __iomem *regbase = of_iomap(np, 0);
464*4882a593Smuzhiyun 	struct clk_hw_onecell_data *clk_data;
465*4882a593Smuzhiyun 	struct clk_hw *slow_rc, *slow_osc;
466*4882a593Smuzhiyun 	const char *xtal_name;
467*4882a593Smuzhiyun 	const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
468*4882a593Smuzhiyun 	bool bypass;
469*4882a593Smuzhiyun 	int ret;
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	if (!regbase)
472*4882a593Smuzhiyun 		return;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	slow_rc = clk_hw_register_fixed_rate_with_accuracy(NULL, parent_names[0],
475*4882a593Smuzhiyun 							   NULL, 0, 32768,
476*4882a593Smuzhiyun 							   93750000);
477*4882a593Smuzhiyun 	if (IS_ERR(slow_rc))
478*4882a593Smuzhiyun 		return;
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	xtal_name = of_clk_get_parent_name(np, 0);
481*4882a593Smuzhiyun 	if (!xtal_name)
482*4882a593Smuzhiyun 		goto unregister_slow_rc;
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	bypass = of_property_read_bool(np, "atmel,osc-bypass");
485*4882a593Smuzhiyun 	slow_osc = at91_clk_register_slow_osc(regbase, parent_names[1],
486*4882a593Smuzhiyun 					      xtal_name, 5000000, bypass,
487*4882a593Smuzhiyun 					      &at91sam9x60_bits);
488*4882a593Smuzhiyun 	if (IS_ERR(slow_osc))
489*4882a593Smuzhiyun 		goto unregister_slow_rc;
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	clk_data = kzalloc(struct_size(clk_data, hws, 2), GFP_KERNEL);
492*4882a593Smuzhiyun 	if (!clk_data)
493*4882a593Smuzhiyun 		goto unregister_slow_osc;
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	/* MD_SLCK and TD_SLCK. */
496*4882a593Smuzhiyun 	clk_data->num = 2;
497*4882a593Smuzhiyun 	clk_data->hws[0] = clk_hw_register_fixed_rate(NULL, "md_slck",
498*4882a593Smuzhiyun 						      parent_names[0],
499*4882a593Smuzhiyun 						      0, 32768);
500*4882a593Smuzhiyun 	if (IS_ERR(clk_data->hws[0]))
501*4882a593Smuzhiyun 		goto clk_data_free;
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	clk_data->hws[1] = at91_clk_register_sam9x5_slow(regbase, "td_slck",
504*4882a593Smuzhiyun 							 parent_names, 2,
505*4882a593Smuzhiyun 							 &at91sam9x60_bits);
506*4882a593Smuzhiyun 	if (IS_ERR(clk_data->hws[1]))
507*4882a593Smuzhiyun 		goto unregister_md_slck;
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
510*4882a593Smuzhiyun 	if (WARN_ON(ret))
511*4882a593Smuzhiyun 		goto unregister_td_slck;
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	return;
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun unregister_td_slck:
516*4882a593Smuzhiyun 	at91_clk_unregister_sam9x5_slow(clk_data->hws[1]);
517*4882a593Smuzhiyun unregister_md_slck:
518*4882a593Smuzhiyun 	clk_hw_unregister(clk_data->hws[0]);
519*4882a593Smuzhiyun clk_data_free:
520*4882a593Smuzhiyun 	kfree(clk_data);
521*4882a593Smuzhiyun unregister_slow_osc:
522*4882a593Smuzhiyun 	at91_clk_unregister_slow_osc(slow_osc);
523*4882a593Smuzhiyun unregister_slow_rc:
524*4882a593Smuzhiyun 	clk_hw_unregister(slow_rc);
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun CLK_OF_DECLARE(sam9x60_clk_sckc, "microchip,sam9x60-sckc",
527*4882a593Smuzhiyun 	       of_sam9x60_sckc_setup);
528*4882a593Smuzhiyun 
clk_sama5d4_slow_osc_prepare(struct clk_hw * hw)529*4882a593Smuzhiyun static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
530*4882a593Smuzhiyun {
531*4882a593Smuzhiyun 	struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	if (osc->prepared)
534*4882a593Smuzhiyun 		return 0;
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	/*
537*4882a593Smuzhiyun 	 * Assume that if it has already been selected (for example by the
538*4882a593Smuzhiyun 	 * bootloader), enough time has aready passed.
539*4882a593Smuzhiyun 	 */
540*4882a593Smuzhiyun 	if ((readl(osc->sckcr) & osc->bits->cr_oscsel)) {
541*4882a593Smuzhiyun 		osc->prepared = true;
542*4882a593Smuzhiyun 		return 0;
543*4882a593Smuzhiyun 	}
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	if (system_state < SYSTEM_RUNNING)
546*4882a593Smuzhiyun 		udelay(osc->startup_usec);
547*4882a593Smuzhiyun 	else
548*4882a593Smuzhiyun 		usleep_range(osc->startup_usec, osc->startup_usec + 1);
549*4882a593Smuzhiyun 	osc->prepared = true;
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	return 0;
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun 
clk_sama5d4_slow_osc_is_prepared(struct clk_hw * hw)554*4882a593Smuzhiyun static int clk_sama5d4_slow_osc_is_prepared(struct clk_hw *hw)
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun 	struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 	return osc->prepared;
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun static const struct clk_ops sama5d4_slow_osc_ops = {
562*4882a593Smuzhiyun 	.prepare = clk_sama5d4_slow_osc_prepare,
563*4882a593Smuzhiyun 	.is_prepared = clk_sama5d4_slow_osc_is_prepared,
564*4882a593Smuzhiyun };
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun static const struct clk_slow_bits at91sama5d4_bits = {
567*4882a593Smuzhiyun 	.cr_oscsel = BIT(3),
568*4882a593Smuzhiyun };
569*4882a593Smuzhiyun 
of_sama5d4_sckc_setup(struct device_node * np)570*4882a593Smuzhiyun static void __init of_sama5d4_sckc_setup(struct device_node *np)
571*4882a593Smuzhiyun {
572*4882a593Smuzhiyun 	void __iomem *regbase = of_iomap(np, 0);
573*4882a593Smuzhiyun 	struct clk_hw *slow_rc, *slowck;
574*4882a593Smuzhiyun 	struct clk_sama5d4_slow_osc *osc;
575*4882a593Smuzhiyun 	struct clk_init_data init;
576*4882a593Smuzhiyun 	const char *xtal_name;
577*4882a593Smuzhiyun 	const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
578*4882a593Smuzhiyun 	int ret;
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	if (!regbase)
581*4882a593Smuzhiyun 		return;
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	slow_rc = clk_hw_register_fixed_rate_with_accuracy(NULL,
584*4882a593Smuzhiyun 							   parent_names[0],
585*4882a593Smuzhiyun 							   NULL, 0, 32768,
586*4882a593Smuzhiyun 							   250000000);
587*4882a593Smuzhiyun 	if (IS_ERR(slow_rc))
588*4882a593Smuzhiyun 		return;
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	xtal_name = of_clk_get_parent_name(np, 0);
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
593*4882a593Smuzhiyun 	if (!osc)
594*4882a593Smuzhiyun 		goto unregister_slow_rc;
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	init.name = parent_names[1];
597*4882a593Smuzhiyun 	init.ops = &sama5d4_slow_osc_ops;
598*4882a593Smuzhiyun 	init.parent_names = &xtal_name;
599*4882a593Smuzhiyun 	init.num_parents = 1;
600*4882a593Smuzhiyun 	init.flags = CLK_IGNORE_UNUSED;
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	osc->hw.init = &init;
603*4882a593Smuzhiyun 	osc->sckcr = regbase;
604*4882a593Smuzhiyun 	osc->startup_usec = 1200000;
605*4882a593Smuzhiyun 	osc->bits = &at91sama5d4_bits;
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	ret = clk_hw_register(NULL, &osc->hw);
608*4882a593Smuzhiyun 	if (ret)
609*4882a593Smuzhiyun 		goto free_slow_osc_data;
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	slowck = at91_clk_register_sam9x5_slow(regbase, "slowck",
612*4882a593Smuzhiyun 					       parent_names, 2,
613*4882a593Smuzhiyun 					       &at91sama5d4_bits);
614*4882a593Smuzhiyun 	if (IS_ERR(slowck))
615*4882a593Smuzhiyun 		goto unregister_slow_osc;
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck);
618*4882a593Smuzhiyun 	if (WARN_ON(ret))
619*4882a593Smuzhiyun 		goto unregister_slowck;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	return;
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun unregister_slowck:
624*4882a593Smuzhiyun 	at91_clk_unregister_sam9x5_slow(slowck);
625*4882a593Smuzhiyun unregister_slow_osc:
626*4882a593Smuzhiyun 	clk_hw_unregister(&osc->hw);
627*4882a593Smuzhiyun free_slow_osc_data:
628*4882a593Smuzhiyun 	kfree(osc);
629*4882a593Smuzhiyun unregister_slow_rc:
630*4882a593Smuzhiyun 	clk_hw_unregister(slow_rc);
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun CLK_OF_DECLARE(sama5d4_clk_sckc, "atmel,sama5d4-sckc",
633*4882a593Smuzhiyun 	       of_sama5d4_sckc_setup);
634