xref: /openbmc/linux/drivers/clk/at91/sckc.c (revision 8e8e69d6)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * drivers/clk/at91/sckc.c
4  *
5  *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
6  */
7 
8 #include <linux/clk-provider.h>
9 #include <linux/clkdev.h>
10 #include <linux/delay.h>
11 #include <linux/of.h>
12 #include <linux/of_address.h>
13 #include <linux/io.h>
14 
15 #define SLOW_CLOCK_FREQ		32768
16 #define SLOWCK_SW_CYCLES	5
17 #define SLOWCK_SW_TIME_USEC	((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \
18 				 SLOW_CLOCK_FREQ)
19 
20 #define	AT91_SCKC_CR			0x00
21 #define		AT91_SCKC_RCEN		(1 << 0)
22 #define		AT91_SCKC_OSC32EN	(1 << 1)
23 #define		AT91_SCKC_OSC32BYP	(1 << 2)
24 #define		AT91_SCKC_OSCSEL	(1 << 3)
25 
26 struct clk_slow_osc {
27 	struct clk_hw hw;
28 	void __iomem *sckcr;
29 	unsigned long startup_usec;
30 };
31 
32 #define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw)
33 
34 struct clk_sama5d4_slow_osc {
35 	struct clk_hw hw;
36 	void __iomem *sckcr;
37 	unsigned long startup_usec;
38 	bool prepared;
39 };
40 
41 #define to_clk_sama5d4_slow_osc(hw) container_of(hw, struct clk_sama5d4_slow_osc, hw)
42 
43 struct clk_slow_rc_osc {
44 	struct clk_hw hw;
45 	void __iomem *sckcr;
46 	unsigned long frequency;
47 	unsigned long accuracy;
48 	unsigned long startup_usec;
49 };
50 
51 #define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw)
52 
53 struct clk_sam9x5_slow {
54 	struct clk_hw hw;
55 	void __iomem *sckcr;
56 	u8 parent;
57 };
58 
59 #define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
60 
61 static int clk_slow_osc_prepare(struct clk_hw *hw)
62 {
63 	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
64 	void __iomem *sckcr = osc->sckcr;
65 	u32 tmp = readl(sckcr);
66 
67 	if (tmp & (AT91_SCKC_OSC32BYP | AT91_SCKC_OSC32EN))
68 		return 0;
69 
70 	writel(tmp | AT91_SCKC_OSC32EN, sckcr);
71 
72 	usleep_range(osc->startup_usec, osc->startup_usec + 1);
73 
74 	return 0;
75 }
76 
77 static void clk_slow_osc_unprepare(struct clk_hw *hw)
78 {
79 	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
80 	void __iomem *sckcr = osc->sckcr;
81 	u32 tmp = readl(sckcr);
82 
83 	if (tmp & AT91_SCKC_OSC32BYP)
84 		return;
85 
86 	writel(tmp & ~AT91_SCKC_OSC32EN, sckcr);
87 }
88 
89 static int clk_slow_osc_is_prepared(struct clk_hw *hw)
90 {
91 	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
92 	void __iomem *sckcr = osc->sckcr;
93 	u32 tmp = readl(sckcr);
94 
95 	if (tmp & AT91_SCKC_OSC32BYP)
96 		return 1;
97 
98 	return !!(tmp & AT91_SCKC_OSC32EN);
99 }
100 
101 static const struct clk_ops slow_osc_ops = {
102 	.prepare = clk_slow_osc_prepare,
103 	.unprepare = clk_slow_osc_unprepare,
104 	.is_prepared = clk_slow_osc_is_prepared,
105 };
106 
107 static struct clk_hw * __init
108 at91_clk_register_slow_osc(void __iomem *sckcr,
109 			   const char *name,
110 			   const char *parent_name,
111 			   unsigned long startup,
112 			   bool bypass)
113 {
114 	struct clk_slow_osc *osc;
115 	struct clk_hw *hw;
116 	struct clk_init_data init;
117 	int ret;
118 
119 	if (!sckcr || !name || !parent_name)
120 		return ERR_PTR(-EINVAL);
121 
122 	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
123 	if (!osc)
124 		return ERR_PTR(-ENOMEM);
125 
126 	init.name = name;
127 	init.ops = &slow_osc_ops;
128 	init.parent_names = &parent_name;
129 	init.num_parents = 1;
130 	init.flags = CLK_IGNORE_UNUSED;
131 
132 	osc->hw.init = &init;
133 	osc->sckcr = sckcr;
134 	osc->startup_usec = startup;
135 
136 	if (bypass)
137 		writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP,
138 		       sckcr);
139 
140 	hw = &osc->hw;
141 	ret = clk_hw_register(NULL, &osc->hw);
142 	if (ret) {
143 		kfree(osc);
144 		hw = ERR_PTR(ret);
145 	}
146 
147 	return hw;
148 }
149 
150 static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
151 						 unsigned long parent_rate)
152 {
153 	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
154 
155 	return osc->frequency;
156 }
157 
158 static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw,
159 						     unsigned long parent_acc)
160 {
161 	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
162 
163 	return osc->accuracy;
164 }
165 
166 static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
167 {
168 	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
169 	void __iomem *sckcr = osc->sckcr;
170 
171 	writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr);
172 
173 	usleep_range(osc->startup_usec, osc->startup_usec + 1);
174 
175 	return 0;
176 }
177 
178 static void clk_slow_rc_osc_unprepare(struct clk_hw *hw)
179 {
180 	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
181 	void __iomem *sckcr = osc->sckcr;
182 
183 	writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr);
184 }
185 
186 static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw)
187 {
188 	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
189 
190 	return !!(readl(osc->sckcr) & AT91_SCKC_RCEN);
191 }
192 
193 static const struct clk_ops slow_rc_osc_ops = {
194 	.prepare = clk_slow_rc_osc_prepare,
195 	.unprepare = clk_slow_rc_osc_unprepare,
196 	.is_prepared = clk_slow_rc_osc_is_prepared,
197 	.recalc_rate = clk_slow_rc_osc_recalc_rate,
198 	.recalc_accuracy = clk_slow_rc_osc_recalc_accuracy,
199 };
200 
201 static struct clk_hw * __init
202 at91_clk_register_slow_rc_osc(void __iomem *sckcr,
203 			      const char *name,
204 			      unsigned long frequency,
205 			      unsigned long accuracy,
206 			      unsigned long startup)
207 {
208 	struct clk_slow_rc_osc *osc;
209 	struct clk_hw *hw;
210 	struct clk_init_data init;
211 	int ret;
212 
213 	if (!sckcr || !name)
214 		return ERR_PTR(-EINVAL);
215 
216 	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
217 	if (!osc)
218 		return ERR_PTR(-ENOMEM);
219 
220 	init.name = name;
221 	init.ops = &slow_rc_osc_ops;
222 	init.parent_names = NULL;
223 	init.num_parents = 0;
224 	init.flags = CLK_IGNORE_UNUSED;
225 
226 	osc->hw.init = &init;
227 	osc->sckcr = sckcr;
228 	osc->frequency = frequency;
229 	osc->accuracy = accuracy;
230 	osc->startup_usec = startup;
231 
232 	hw = &osc->hw;
233 	ret = clk_hw_register(NULL, &osc->hw);
234 	if (ret) {
235 		kfree(osc);
236 		hw = ERR_PTR(ret);
237 	}
238 
239 	return hw;
240 }
241 
242 static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
243 {
244 	struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
245 	void __iomem *sckcr = slowck->sckcr;
246 	u32 tmp;
247 
248 	if (index > 1)
249 		return -EINVAL;
250 
251 	tmp = readl(sckcr);
252 
253 	if ((!index && !(tmp & AT91_SCKC_OSCSEL)) ||
254 	    (index && (tmp & AT91_SCKC_OSCSEL)))
255 		return 0;
256 
257 	if (index)
258 		tmp |= AT91_SCKC_OSCSEL;
259 	else
260 		tmp &= ~AT91_SCKC_OSCSEL;
261 
262 	writel(tmp, sckcr);
263 
264 	usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1);
265 
266 	return 0;
267 }
268 
269 static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
270 {
271 	struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
272 
273 	return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL);
274 }
275 
276 static const struct clk_ops sam9x5_slow_ops = {
277 	.set_parent = clk_sam9x5_slow_set_parent,
278 	.get_parent = clk_sam9x5_slow_get_parent,
279 };
280 
281 static struct clk_hw * __init
282 at91_clk_register_sam9x5_slow(void __iomem *sckcr,
283 			      const char *name,
284 			      const char **parent_names,
285 			      int num_parents)
286 {
287 	struct clk_sam9x5_slow *slowck;
288 	struct clk_hw *hw;
289 	struct clk_init_data init;
290 	int ret;
291 
292 	if (!sckcr || !name || !parent_names || !num_parents)
293 		return ERR_PTR(-EINVAL);
294 
295 	slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
296 	if (!slowck)
297 		return ERR_PTR(-ENOMEM);
298 
299 	init.name = name;
300 	init.ops = &sam9x5_slow_ops;
301 	init.parent_names = parent_names;
302 	init.num_parents = num_parents;
303 	init.flags = 0;
304 
305 	slowck->hw.init = &init;
306 	slowck->sckcr = sckcr;
307 	slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL);
308 
309 	hw = &slowck->hw;
310 	ret = clk_hw_register(NULL, &slowck->hw);
311 	if (ret) {
312 		kfree(slowck);
313 		hw = ERR_PTR(ret);
314 	}
315 
316 	return hw;
317 }
318 
319 static void __init at91sam9x5_sckc_register(struct device_node *np,
320 					    unsigned int rc_osc_startup_us)
321 {
322 	const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
323 	void __iomem *regbase = of_iomap(np, 0);
324 	struct device_node *child = NULL;
325 	const char *xtal_name;
326 	struct clk_hw *hw;
327 	bool bypass;
328 
329 	if (!regbase)
330 		return;
331 
332 	hw = at91_clk_register_slow_rc_osc(regbase, parent_names[0], 32768,
333 					   50000000, rc_osc_startup_us);
334 	if (IS_ERR(hw))
335 		return;
336 
337 	xtal_name = of_clk_get_parent_name(np, 0);
338 	if (!xtal_name) {
339 		/* DT backward compatibility */
340 		child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow-osc");
341 		if (!child)
342 			return;
343 
344 		xtal_name = of_clk_get_parent_name(child, 0);
345 		bypass = of_property_read_bool(child, "atmel,osc-bypass");
346 
347 		child =  of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow");
348 	} else {
349 		bypass = of_property_read_bool(np, "atmel,osc-bypass");
350 	}
351 
352 	if (!xtal_name)
353 		return;
354 
355 	hw = at91_clk_register_slow_osc(regbase, parent_names[1], xtal_name,
356 					1200000, bypass);
357 	if (IS_ERR(hw))
358 		return;
359 
360 	hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2);
361 	if (IS_ERR(hw))
362 		return;
363 
364 	of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
365 
366 	/* DT backward compatibility */
367 	if (child)
368 		of_clk_add_hw_provider(child, of_clk_hw_simple_get, hw);
369 }
370 
371 static void __init of_at91sam9x5_sckc_setup(struct device_node *np)
372 {
373 	at91sam9x5_sckc_register(np, 75);
374 }
375 CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc",
376 	       of_at91sam9x5_sckc_setup);
377 
378 static void __init of_sama5d3_sckc_setup(struct device_node *np)
379 {
380 	at91sam9x5_sckc_register(np, 500);
381 }
382 CLK_OF_DECLARE(sama5d3_clk_sckc, "atmel,sama5d3-sckc",
383 	       of_sama5d3_sckc_setup);
384 
385 static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
386 {
387 	struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
388 
389 	if (osc->prepared)
390 		return 0;
391 
392 	/*
393 	 * Assume that if it has already been selected (for example by the
394 	 * bootloader), enough time has aready passed.
395 	 */
396 	if ((readl(osc->sckcr) & AT91_SCKC_OSCSEL)) {
397 		osc->prepared = true;
398 		return 0;
399 	}
400 
401 	usleep_range(osc->startup_usec, osc->startup_usec + 1);
402 	osc->prepared = true;
403 
404 	return 0;
405 }
406 
407 static int clk_sama5d4_slow_osc_is_prepared(struct clk_hw *hw)
408 {
409 	struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
410 
411 	return osc->prepared;
412 }
413 
414 static const struct clk_ops sama5d4_slow_osc_ops = {
415 	.prepare = clk_sama5d4_slow_osc_prepare,
416 	.is_prepared = clk_sama5d4_slow_osc_is_prepared,
417 };
418 
419 static void __init of_sama5d4_sckc_setup(struct device_node *np)
420 {
421 	void __iomem *regbase = of_iomap(np, 0);
422 	struct clk_hw *hw;
423 	struct clk_sama5d4_slow_osc *osc;
424 	struct clk_init_data init;
425 	const char *xtal_name;
426 	const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
427 	bool bypass;
428 	int ret;
429 
430 	if (!regbase)
431 		return;
432 
433 	hw = clk_hw_register_fixed_rate_with_accuracy(NULL, parent_names[0],
434 						      NULL, 0, 32768,
435 						      250000000);
436 	if (IS_ERR(hw))
437 		return;
438 
439 	xtal_name = of_clk_get_parent_name(np, 0);
440 
441 	bypass = of_property_read_bool(np, "atmel,osc-bypass");
442 
443 	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
444 	if (!osc)
445 		return;
446 
447 	init.name = parent_names[1];
448 	init.ops = &sama5d4_slow_osc_ops;
449 	init.parent_names = &xtal_name;
450 	init.num_parents = 1;
451 	init.flags = CLK_IGNORE_UNUSED;
452 
453 	osc->hw.init = &init;
454 	osc->sckcr = regbase;
455 	osc->startup_usec = 1200000;
456 
457 	if (bypass)
458 		writel((readl(regbase) | AT91_SCKC_OSC32BYP), regbase);
459 
460 	hw = &osc->hw;
461 	ret = clk_hw_register(NULL, &osc->hw);
462 	if (ret) {
463 		kfree(osc);
464 		return;
465 	}
466 
467 	hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2);
468 	if (IS_ERR(hw))
469 		return;
470 
471 	of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
472 }
473 CLK_OF_DECLARE(sama5d4_clk_sckc, "atmel,sama5d4-sckc",
474 	       of_sama5d4_sckc_setup);
475