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