1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * drivers/clk/at91/sckc.c
5 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
8 #include <linux/clk-provider.h>
9 #include <linux/clkdev.h>
10 #include <linux/delay.h>
12 #include <linux/of_address.h>
15 #define SLOW_CLOCK_FREQ 32768
16 #define SLOWCK_SW_CYCLES 5
17 #define SLOWCK_SW_TIME_USEC ((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \
20 #define AT91_SCKC_CR 0x00
22 struct clk_slow_bits {
32 const struct clk_slow_bits *bits;
33 unsigned long startup_usec;
36 #define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw)
38 struct clk_sama5d4_slow_osc {
41 const struct clk_slow_bits *bits;
42 unsigned long startup_usec;
46 #define to_clk_sama5d4_slow_osc(hw) container_of(hw, struct clk_sama5d4_slow_osc, hw)
48 struct clk_slow_rc_osc {
51 const struct clk_slow_bits *bits;
52 unsigned long frequency;
53 unsigned long accuracy;
54 unsigned long startup_usec;
57 #define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw)
59 struct clk_sam9x5_slow {
62 const struct clk_slow_bits *bits;
66 #define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
68 static int clk_slow_osc_prepare(struct clk_hw *hw)
70 struct clk_slow_osc *osc = to_clk_slow_osc(hw);
71 void __iomem *sckcr = osc->sckcr;
72 u32 tmp = readl(sckcr);
74 if (tmp & (osc->bits->cr_osc32byp | osc->bits->cr_osc32en))
77 writel(tmp | osc->bits->cr_osc32en, sckcr);
79 usleep_range(osc->startup_usec, osc->startup_usec + 1);
84 static void clk_slow_osc_unprepare(struct clk_hw *hw)
86 struct clk_slow_osc *osc = to_clk_slow_osc(hw);
87 void __iomem *sckcr = osc->sckcr;
88 u32 tmp = readl(sckcr);
90 if (tmp & osc->bits->cr_osc32byp)
93 writel(tmp & ~osc->bits->cr_osc32en, sckcr);
96 static int clk_slow_osc_is_prepared(struct clk_hw *hw)
98 struct clk_slow_osc *osc = to_clk_slow_osc(hw);
99 void __iomem *sckcr = osc->sckcr;
100 u32 tmp = readl(sckcr);
102 if (tmp & osc->bits->cr_osc32byp)
105 return !!(tmp & osc->bits->cr_osc32en);
108 static const struct clk_ops slow_osc_ops = {
109 .prepare = clk_slow_osc_prepare,
110 .unprepare = clk_slow_osc_unprepare,
111 .is_prepared = clk_slow_osc_is_prepared,
114 static struct clk_hw * __init
115 at91_clk_register_slow_osc(void __iomem *sckcr,
117 const char *parent_name,
118 unsigned long startup,
120 const struct clk_slow_bits *bits)
122 struct clk_slow_osc *osc;
124 struct clk_init_data init;
127 if (!sckcr || !name || !parent_name)
128 return ERR_PTR(-EINVAL);
130 osc = kzalloc(sizeof(*osc), GFP_KERNEL);
132 return ERR_PTR(-ENOMEM);
135 init.ops = &slow_osc_ops;
136 init.parent_names = &parent_name;
137 init.num_parents = 1;
138 init.flags = CLK_IGNORE_UNUSED;
140 osc->hw.init = &init;
142 osc->startup_usec = startup;
146 writel((readl(sckcr) & ~osc->bits->cr_osc32en) |
147 osc->bits->cr_osc32byp, sckcr);
150 ret = clk_hw_register(NULL, &osc->hw);
159 static void at91_clk_unregister_slow_osc(struct clk_hw *hw)
161 struct clk_slow_osc *osc = to_clk_slow_osc(hw);
163 clk_hw_unregister(hw);
167 static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
168 unsigned long parent_rate)
170 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
172 return osc->frequency;
175 static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw,
176 unsigned long parent_acc)
178 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
180 return osc->accuracy;
183 static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
185 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
186 void __iomem *sckcr = osc->sckcr;
188 writel(readl(sckcr) | osc->bits->cr_rcen, sckcr);
190 usleep_range(osc->startup_usec, osc->startup_usec + 1);
195 static void clk_slow_rc_osc_unprepare(struct clk_hw *hw)
197 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
198 void __iomem *sckcr = osc->sckcr;
200 writel(readl(sckcr) & ~osc->bits->cr_rcen, sckcr);
203 static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw)
205 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
207 return !!(readl(osc->sckcr) & osc->bits->cr_rcen);
210 static const struct clk_ops slow_rc_osc_ops = {
211 .prepare = clk_slow_rc_osc_prepare,
212 .unprepare = clk_slow_rc_osc_unprepare,
213 .is_prepared = clk_slow_rc_osc_is_prepared,
214 .recalc_rate = clk_slow_rc_osc_recalc_rate,
215 .recalc_accuracy = clk_slow_rc_osc_recalc_accuracy,
218 static struct clk_hw * __init
219 at91_clk_register_slow_rc_osc(void __iomem *sckcr,
221 unsigned long frequency,
222 unsigned long accuracy,
223 unsigned long startup,
224 const struct clk_slow_bits *bits)
226 struct clk_slow_rc_osc *osc;
228 struct clk_init_data init;
232 return ERR_PTR(-EINVAL);
234 osc = kzalloc(sizeof(*osc), GFP_KERNEL);
236 return ERR_PTR(-ENOMEM);
239 init.ops = &slow_rc_osc_ops;
240 init.parent_names = NULL;
241 init.num_parents = 0;
242 init.flags = CLK_IGNORE_UNUSED;
244 osc->hw.init = &init;
247 osc->frequency = frequency;
248 osc->accuracy = accuracy;
249 osc->startup_usec = startup;
252 ret = clk_hw_register(NULL, &osc->hw);
261 static void at91_clk_unregister_slow_rc_osc(struct clk_hw *hw)
263 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
265 clk_hw_unregister(hw);
269 static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
271 struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
272 void __iomem *sckcr = slowck->sckcr;
280 if ((!index && !(tmp & slowck->bits->cr_oscsel)) ||
281 (index && (tmp & slowck->bits->cr_oscsel)))
285 tmp |= slowck->bits->cr_oscsel;
287 tmp &= ~slowck->bits->cr_oscsel;
291 usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1);
296 static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
298 struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
300 return !!(readl(slowck->sckcr) & slowck->bits->cr_oscsel);
303 static const struct clk_ops sam9x5_slow_ops = {
304 .set_parent = clk_sam9x5_slow_set_parent,
305 .get_parent = clk_sam9x5_slow_get_parent,
308 static struct clk_hw * __init
309 at91_clk_register_sam9x5_slow(void __iomem *sckcr,
311 const char **parent_names,
313 const struct clk_slow_bits *bits)
315 struct clk_sam9x5_slow *slowck;
317 struct clk_init_data init;
320 if (!sckcr || !name || !parent_names || !num_parents)
321 return ERR_PTR(-EINVAL);
323 slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
325 return ERR_PTR(-ENOMEM);
328 init.ops = &sam9x5_slow_ops;
329 init.parent_names = parent_names;
330 init.num_parents = num_parents;
333 slowck->hw.init = &init;
334 slowck->sckcr = sckcr;
336 slowck->parent = !!(readl(sckcr) & slowck->bits->cr_oscsel);
339 ret = clk_hw_register(NULL, &slowck->hw);
348 static void at91_clk_unregister_sam9x5_slow(struct clk_hw *hw)
350 struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
352 clk_hw_unregister(hw);
356 static void __init at91sam9x5_sckc_register(struct device_node *np,
357 unsigned int rc_osc_startup_us,
358 const struct clk_slow_bits *bits)
360 const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
361 void __iomem *regbase = of_iomap(np, 0);
362 struct device_node *child = NULL;
363 const char *xtal_name;
364 struct clk_hw *slow_rc, *slow_osc, *slowck;
371 slow_rc = at91_clk_register_slow_rc_osc(regbase, parent_names[0],
373 rc_osc_startup_us, bits);
377 xtal_name = of_clk_get_parent_name(np, 0);
379 /* DT backward compatibility */
380 child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow-osc");
382 goto unregister_slow_rc;
384 xtal_name = of_clk_get_parent_name(child, 0);
385 bypass = of_property_read_bool(child, "atmel,osc-bypass");
387 child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow");
389 bypass = of_property_read_bool(np, "atmel,osc-bypass");
393 goto unregister_slow_rc;
395 slow_osc = at91_clk_register_slow_osc(regbase, parent_names[1],
396 xtal_name, 1200000, bypass, bits);
397 if (IS_ERR(slow_osc))
398 goto unregister_slow_rc;
400 slowck = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names,
403 goto unregister_slow_osc;
405 /* DT backward compatibility */
407 ret = of_clk_add_hw_provider(child, of_clk_hw_simple_get,
410 ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck);
413 goto unregister_slowck;
418 at91_clk_unregister_sam9x5_slow(slowck);
420 at91_clk_unregister_slow_osc(slow_osc);
422 at91_clk_unregister_slow_rc_osc(slow_rc);
425 static const struct clk_slow_bits at91sam9x5_bits = {
427 .cr_osc32en = BIT(1),
428 .cr_osc32byp = BIT(2),
432 static void __init of_at91sam9x5_sckc_setup(struct device_node *np)
434 at91sam9x5_sckc_register(np, 75, &at91sam9x5_bits);
436 CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc",
437 of_at91sam9x5_sckc_setup);
439 static void __init of_sama5d3_sckc_setup(struct device_node *np)
441 at91sam9x5_sckc_register(np, 500, &at91sam9x5_bits);
443 CLK_OF_DECLARE(sama5d3_clk_sckc, "atmel,sama5d3-sckc",
444 of_sama5d3_sckc_setup);
446 static const struct clk_slow_bits at91sam9x60_bits = {
447 .cr_osc32en = BIT(1),
448 .cr_osc32byp = BIT(2),
449 .cr_oscsel = BIT(24),
452 static void __init of_sam9x60_sckc_setup(struct device_node *np)
454 void __iomem *regbase = of_iomap(np, 0);
455 struct clk_hw_onecell_data *clk_data;
456 struct clk_hw *slow_rc, *slow_osc;
457 const char *xtal_name;
458 const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
465 slow_rc = clk_hw_register_fixed_rate(NULL, parent_names[0], NULL, 0,
470 xtal_name = of_clk_get_parent_name(np, 0);
472 goto unregister_slow_rc;
474 bypass = of_property_read_bool(np, "atmel,osc-bypass");
475 slow_osc = at91_clk_register_slow_osc(regbase, parent_names[1],
476 xtal_name, 5000000, bypass,
478 if (IS_ERR(slow_osc))
479 goto unregister_slow_rc;
481 clk_data = kzalloc(sizeof(*clk_data) + (2 * sizeof(struct clk_hw *)),
484 goto unregister_slow_osc;
486 /* MD_SLCK and TD_SLCK. */
488 clk_data->hws[0] = clk_hw_register_fixed_rate(NULL, "md_slck",
491 if (IS_ERR(clk_data->hws[0]))
494 clk_data->hws[1] = at91_clk_register_sam9x5_slow(regbase, "td_slck",
497 if (IS_ERR(clk_data->hws[1]))
498 goto unregister_md_slck;
500 ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
502 goto unregister_td_slck;
507 at91_clk_unregister_sam9x5_slow(clk_data->hws[1]);
509 clk_hw_unregister(clk_data->hws[0]);
513 at91_clk_unregister_slow_osc(slow_osc);
515 clk_hw_unregister(slow_rc);
517 CLK_OF_DECLARE(sam9x60_clk_sckc, "microchip,sam9x60-sckc",
518 of_sam9x60_sckc_setup);
520 static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
522 struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
528 * Assume that if it has already been selected (for example by the
529 * bootloader), enough time has aready passed.
531 if ((readl(osc->sckcr) & osc->bits->cr_oscsel)) {
532 osc->prepared = true;
536 usleep_range(osc->startup_usec, osc->startup_usec + 1);
537 osc->prepared = true;
542 static int clk_sama5d4_slow_osc_is_prepared(struct clk_hw *hw)
544 struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
546 return osc->prepared;
549 static const struct clk_ops sama5d4_slow_osc_ops = {
550 .prepare = clk_sama5d4_slow_osc_prepare,
551 .is_prepared = clk_sama5d4_slow_osc_is_prepared,
554 static const struct clk_slow_bits at91sama5d4_bits = {
558 static void __init of_sama5d4_sckc_setup(struct device_node *np)
560 void __iomem *regbase = of_iomap(np, 0);
561 struct clk_hw *slow_rc, *slowck;
562 struct clk_sama5d4_slow_osc *osc;
563 struct clk_init_data init;
564 const char *xtal_name;
565 const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
571 slow_rc = clk_hw_register_fixed_rate_with_accuracy(NULL,
578 xtal_name = of_clk_get_parent_name(np, 0);
580 osc = kzalloc(sizeof(*osc), GFP_KERNEL);
582 goto unregister_slow_rc;
584 init.name = parent_names[1];
585 init.ops = &sama5d4_slow_osc_ops;
586 init.parent_names = &xtal_name;
587 init.num_parents = 1;
588 init.flags = CLK_IGNORE_UNUSED;
590 osc->hw.init = &init;
591 osc->sckcr = regbase;
592 osc->startup_usec = 1200000;
593 osc->bits = &at91sama5d4_bits;
595 ret = clk_hw_register(NULL, &osc->hw);
597 goto free_slow_osc_data;
599 slowck = at91_clk_register_sam9x5_slow(regbase, "slowck",
603 goto unregister_slow_osc;
605 ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck);
607 goto unregister_slowck;
612 at91_clk_unregister_sam9x5_slow(slowck);
614 clk_hw_unregister(&osc->hw);
618 clk_hw_unregister(slow_rc);
620 CLK_OF_DECLARE(sama5d4_clk_sckc, "atmel,sama5d4-sckc",
621 of_sama5d4_sckc_setup);