aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/at91/sckc.c
diff options
context:
space:
mode:
authorAlexandre Belloni <alexandre.belloni@free-electrons.com>2016-09-20 16:58:30 -0400
committerStephen Boyd <sboyd@codeaurora.org>2016-09-20 20:02:58 -0400
commit4b13b6451a9dce278881d236d33d4bb0cb28592b (patch)
tree65c8c7bfda88b2ff30ebf77628c2c4a1110e1b92 /drivers/clk/at91/sckc.c
parentec187ef0ce9880d9dc360261807c434e77783ac8 (diff)
clk: at91: Add sama5d4 sckc support
Starting with sama5d4, the crystal oscillator is always enabled at startup and the SCKC doesn't have an OSC32EN bit anymore. Add support for that new controller. Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Diffstat (limited to 'drivers/clk/at91/sckc.c')
-rw-r--r--drivers/clk/at91/sckc.c100
1 files changed, 100 insertions, 0 deletions
diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c
index 311956abf4aa..199d1b3f5ad3 100644
--- a/drivers/clk/at91/sckc.c
+++ b/drivers/clk/at91/sckc.c
@@ -36,6 +36,15 @@ struct clk_slow_osc {
36 36
37#define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw) 37#define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw)
38 38
39struct 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
39struct clk_slow_rc_osc { 48struct clk_slow_rc_osc {
40 struct clk_hw hw; 49 struct clk_hw hw;
41 void __iomem *sckcr; 50 void __iomem *sckcr;
@@ -417,3 +426,94 @@ static void __init of_at91sam9x5_sckc_setup(struct device_node *np)
417} 426}
418CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc", 427CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc",
419 of_at91sam9x5_sckc_setup); 428 of_at91sam9x5_sckc_setup);
429
430static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
431{
432 struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
433
434 if (osc->prepared)
435 return 0;
436
437 /*
438 * Assume that if it has already been selected (for example by the
439 * bootloader), enough time has aready passed.
440 */
441 if ((readl(osc->sckcr) & AT91_SCKC_OSCSEL)) {
442 osc->prepared = true;
443 return 0;
444 }
445
446 usleep_range(osc->startup_usec, osc->startup_usec + 1);
447 osc->prepared = true;
448
449 return 0;
450}
451
452static int clk_sama5d4_slow_osc_is_prepared(struct clk_hw *hw)
453{
454 struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
455
456 return osc->prepared;
457}
458
459static const struct clk_ops sama5d4_slow_osc_ops = {
460 .prepare = clk_sama5d4_slow_osc_prepare,
461 .is_prepared = clk_sama5d4_slow_osc_is_prepared,
462};
463
464static void __init of_sama5d4_sckc_setup(struct device_node *np)
465{
466 void __iomem *regbase = of_iomap(np, 0);
467 struct clk_hw *hw;
468 struct clk_sama5d4_slow_osc *osc;
469 struct clk_init_data init;
470 const char *xtal_name;
471 const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
472 bool bypass;
473 int ret;
474
475 if (!regbase)
476 return;
477
478 hw = clk_hw_register_fixed_rate_with_accuracy(NULL, parent_names[0],
479 NULL, 0, 32768,
480 250000000);
481 if (IS_ERR(hw))
482 return;
483
484 xtal_name = of_clk_get_parent_name(np, 0);
485
486 bypass = of_property_read_bool(np, "atmel,osc-bypass");
487
488 osc = kzalloc(sizeof(*osc), GFP_KERNEL);
489 if (!osc)
490 return;
491
492 init.name = parent_names[1];
493 init.ops = &sama5d4_slow_osc_ops;
494 init.parent_names = &xtal_name;
495 init.num_parents = 1;
496 init.flags = CLK_IGNORE_UNUSED;
497
498 osc->hw.init = &init;
499 osc->sckcr = regbase;
500 osc->startup_usec = 1200000;
501
502 if (bypass)
503 writel((readl(regbase) | AT91_SCKC_OSC32BYP), regbase);
504
505 hw = &osc->hw;
506 ret = clk_hw_register(NULL, &osc->hw);
507 if (ret) {
508 kfree(osc);
509 return;
510 }
511
512 hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2);
513 if (IS_ERR(hw))
514 return;
515
516 of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
517}
518CLK_OF_DECLARE(sama5d4_clk_sckc, "atmel,sama5d4-sckc",
519 of_sama5d4_sckc_setup);