180eded6cSBoris BREZILLON /* 280eded6cSBoris BREZILLON * drivers/clk/at91/clk-slow.c 380eded6cSBoris BREZILLON * 480eded6cSBoris BREZILLON * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> 580eded6cSBoris BREZILLON * 680eded6cSBoris BREZILLON * This program is free software; you can redistribute it and/or modify 780eded6cSBoris BREZILLON * it under the terms of the GNU General Public License as published by 880eded6cSBoris BREZILLON * the Free Software Foundation; either version 2 of the License, or 980eded6cSBoris BREZILLON * (at your option) any later version. 1080eded6cSBoris BREZILLON * 1180eded6cSBoris BREZILLON */ 1280eded6cSBoris BREZILLON 1380eded6cSBoris BREZILLON #include <linux/clk-provider.h> 1480eded6cSBoris BREZILLON #include <linux/clkdev.h> 156a8ce8c9SStephen Boyd #include <linux/slab.h> 1680eded6cSBoris BREZILLON #include <linux/clk/at91_pmc.h> 1780eded6cSBoris BREZILLON #include <linux/delay.h> 1880eded6cSBoris BREZILLON #include <linux/of.h> 1980eded6cSBoris BREZILLON #include <linux/of_address.h> 2080eded6cSBoris BREZILLON #include <linux/of_irq.h> 2180eded6cSBoris BREZILLON #include <linux/io.h> 2280eded6cSBoris BREZILLON #include <linux/interrupt.h> 2380eded6cSBoris BREZILLON #include <linux/irq.h> 24*1bdf0232SBoris Brezillon #include <linux/mfd/syscon.h> 25*1bdf0232SBoris Brezillon #include <linux/regmap.h> 2680eded6cSBoris BREZILLON #include <linux/sched.h> 2780eded6cSBoris BREZILLON #include <linux/wait.h> 2880eded6cSBoris BREZILLON 2980eded6cSBoris BREZILLON #include "pmc.h" 3080eded6cSBoris BREZILLON #include "sckc.h" 3180eded6cSBoris BREZILLON 3280eded6cSBoris BREZILLON #define SLOW_CLOCK_FREQ 32768 3380eded6cSBoris BREZILLON #define SLOWCK_SW_CYCLES 5 3480eded6cSBoris BREZILLON #define SLOWCK_SW_TIME_USEC ((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \ 3580eded6cSBoris BREZILLON SLOW_CLOCK_FREQ) 3680eded6cSBoris BREZILLON 3780eded6cSBoris BREZILLON #define AT91_SCKC_CR 0x00 3880eded6cSBoris BREZILLON #define AT91_SCKC_RCEN (1 << 0) 3980eded6cSBoris BREZILLON #define AT91_SCKC_OSC32EN (1 << 1) 4080eded6cSBoris BREZILLON #define AT91_SCKC_OSC32BYP (1 << 2) 4180eded6cSBoris BREZILLON #define AT91_SCKC_OSCSEL (1 << 3) 4280eded6cSBoris BREZILLON 4380eded6cSBoris BREZILLON struct clk_slow_osc { 4480eded6cSBoris BREZILLON struct clk_hw hw; 4580eded6cSBoris BREZILLON void __iomem *sckcr; 4680eded6cSBoris BREZILLON unsigned long startup_usec; 4780eded6cSBoris BREZILLON }; 4880eded6cSBoris BREZILLON 4980eded6cSBoris BREZILLON #define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw) 5080eded6cSBoris BREZILLON 5180eded6cSBoris BREZILLON struct clk_slow_rc_osc { 5280eded6cSBoris BREZILLON struct clk_hw hw; 5380eded6cSBoris BREZILLON void __iomem *sckcr; 5480eded6cSBoris BREZILLON unsigned long frequency; 5580eded6cSBoris BREZILLON unsigned long accuracy; 5680eded6cSBoris BREZILLON unsigned long startup_usec; 5780eded6cSBoris BREZILLON }; 5880eded6cSBoris BREZILLON 5980eded6cSBoris BREZILLON #define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw) 6080eded6cSBoris BREZILLON 6180eded6cSBoris BREZILLON struct clk_sam9260_slow { 6280eded6cSBoris BREZILLON struct clk_hw hw; 63*1bdf0232SBoris Brezillon struct regmap *regmap; 6480eded6cSBoris BREZILLON }; 6580eded6cSBoris BREZILLON 6680eded6cSBoris BREZILLON #define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw) 6780eded6cSBoris BREZILLON 6880eded6cSBoris BREZILLON struct clk_sam9x5_slow { 6980eded6cSBoris BREZILLON struct clk_hw hw; 7080eded6cSBoris BREZILLON void __iomem *sckcr; 7180eded6cSBoris BREZILLON u8 parent; 7280eded6cSBoris BREZILLON }; 7380eded6cSBoris BREZILLON 7480eded6cSBoris BREZILLON #define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw) 7580eded6cSBoris BREZILLON 7680eded6cSBoris BREZILLON static int clk_slow_osc_prepare(struct clk_hw *hw) 7780eded6cSBoris BREZILLON { 7880eded6cSBoris BREZILLON struct clk_slow_osc *osc = to_clk_slow_osc(hw); 7980eded6cSBoris BREZILLON void __iomem *sckcr = osc->sckcr; 8080eded6cSBoris BREZILLON u32 tmp = readl(sckcr); 8180eded6cSBoris BREZILLON 8280eded6cSBoris BREZILLON if (tmp & AT91_SCKC_OSC32BYP) 8380eded6cSBoris BREZILLON return 0; 8480eded6cSBoris BREZILLON 8580eded6cSBoris BREZILLON writel(tmp | AT91_SCKC_OSC32EN, sckcr); 8680eded6cSBoris BREZILLON 8780eded6cSBoris BREZILLON usleep_range(osc->startup_usec, osc->startup_usec + 1); 8880eded6cSBoris BREZILLON 8980eded6cSBoris BREZILLON return 0; 9080eded6cSBoris BREZILLON } 9180eded6cSBoris BREZILLON 9280eded6cSBoris BREZILLON static void clk_slow_osc_unprepare(struct clk_hw *hw) 9380eded6cSBoris BREZILLON { 9480eded6cSBoris BREZILLON struct clk_slow_osc *osc = to_clk_slow_osc(hw); 9580eded6cSBoris BREZILLON void __iomem *sckcr = osc->sckcr; 9680eded6cSBoris BREZILLON u32 tmp = readl(sckcr); 9780eded6cSBoris BREZILLON 9880eded6cSBoris BREZILLON if (tmp & AT91_SCKC_OSC32BYP) 9980eded6cSBoris BREZILLON return; 10080eded6cSBoris BREZILLON 10180eded6cSBoris BREZILLON writel(tmp & ~AT91_SCKC_OSC32EN, sckcr); 10280eded6cSBoris BREZILLON } 10380eded6cSBoris BREZILLON 10480eded6cSBoris BREZILLON static int clk_slow_osc_is_prepared(struct clk_hw *hw) 10580eded6cSBoris BREZILLON { 10680eded6cSBoris BREZILLON struct clk_slow_osc *osc = to_clk_slow_osc(hw); 10780eded6cSBoris BREZILLON void __iomem *sckcr = osc->sckcr; 10880eded6cSBoris BREZILLON u32 tmp = readl(sckcr); 10980eded6cSBoris BREZILLON 11080eded6cSBoris BREZILLON if (tmp & AT91_SCKC_OSC32BYP) 11180eded6cSBoris BREZILLON return 1; 11280eded6cSBoris BREZILLON 11380eded6cSBoris BREZILLON return !!(tmp & AT91_SCKC_OSC32EN); 11480eded6cSBoris BREZILLON } 11580eded6cSBoris BREZILLON 11680eded6cSBoris BREZILLON static const struct clk_ops slow_osc_ops = { 11780eded6cSBoris BREZILLON .prepare = clk_slow_osc_prepare, 11880eded6cSBoris BREZILLON .unprepare = clk_slow_osc_unprepare, 11980eded6cSBoris BREZILLON .is_prepared = clk_slow_osc_is_prepared, 12080eded6cSBoris BREZILLON }; 12180eded6cSBoris BREZILLON 12280eded6cSBoris BREZILLON static struct clk * __init 12380eded6cSBoris BREZILLON at91_clk_register_slow_osc(void __iomem *sckcr, 12480eded6cSBoris BREZILLON const char *name, 12580eded6cSBoris BREZILLON const char *parent_name, 12680eded6cSBoris BREZILLON unsigned long startup, 12780eded6cSBoris BREZILLON bool bypass) 12880eded6cSBoris BREZILLON { 12980eded6cSBoris BREZILLON struct clk_slow_osc *osc; 13080eded6cSBoris BREZILLON struct clk *clk = NULL; 13180eded6cSBoris BREZILLON struct clk_init_data init; 13280eded6cSBoris BREZILLON 13380eded6cSBoris BREZILLON if (!sckcr || !name || !parent_name) 13480eded6cSBoris BREZILLON return ERR_PTR(-EINVAL); 13580eded6cSBoris BREZILLON 13680eded6cSBoris BREZILLON osc = kzalloc(sizeof(*osc), GFP_KERNEL); 13780eded6cSBoris BREZILLON if (!osc) 13880eded6cSBoris BREZILLON return ERR_PTR(-ENOMEM); 13980eded6cSBoris BREZILLON 14080eded6cSBoris BREZILLON init.name = name; 14180eded6cSBoris BREZILLON init.ops = &slow_osc_ops; 14280eded6cSBoris BREZILLON init.parent_names = &parent_name; 14380eded6cSBoris BREZILLON init.num_parents = 1; 14480eded6cSBoris BREZILLON init.flags = CLK_IGNORE_UNUSED; 14580eded6cSBoris BREZILLON 14680eded6cSBoris BREZILLON osc->hw.init = &init; 14780eded6cSBoris BREZILLON osc->sckcr = sckcr; 14880eded6cSBoris BREZILLON osc->startup_usec = startup; 14980eded6cSBoris BREZILLON 15080eded6cSBoris BREZILLON if (bypass) 15180eded6cSBoris BREZILLON writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP, 15280eded6cSBoris BREZILLON sckcr); 15380eded6cSBoris BREZILLON 15480eded6cSBoris BREZILLON clk = clk_register(NULL, &osc->hw); 15580eded6cSBoris BREZILLON if (IS_ERR(clk)) 15680eded6cSBoris BREZILLON kfree(osc); 15780eded6cSBoris BREZILLON 15880eded6cSBoris BREZILLON return clk; 15980eded6cSBoris BREZILLON } 16080eded6cSBoris BREZILLON 16180eded6cSBoris BREZILLON void __init of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, 16280eded6cSBoris BREZILLON void __iomem *sckcr) 16380eded6cSBoris BREZILLON { 16480eded6cSBoris BREZILLON struct clk *clk; 16580eded6cSBoris BREZILLON const char *parent_name; 16680eded6cSBoris BREZILLON const char *name = np->name; 16780eded6cSBoris BREZILLON u32 startup; 16880eded6cSBoris BREZILLON bool bypass; 16980eded6cSBoris BREZILLON 17080eded6cSBoris BREZILLON parent_name = of_clk_get_parent_name(np, 0); 17180eded6cSBoris BREZILLON of_property_read_string(np, "clock-output-names", &name); 17280eded6cSBoris BREZILLON of_property_read_u32(np, "atmel,startup-time-usec", &startup); 17380eded6cSBoris BREZILLON bypass = of_property_read_bool(np, "atmel,osc-bypass"); 17480eded6cSBoris BREZILLON 17580eded6cSBoris BREZILLON clk = at91_clk_register_slow_osc(sckcr, name, parent_name, startup, 17680eded6cSBoris BREZILLON bypass); 17780eded6cSBoris BREZILLON if (IS_ERR(clk)) 17880eded6cSBoris BREZILLON return; 17980eded6cSBoris BREZILLON 18080eded6cSBoris BREZILLON of_clk_add_provider(np, of_clk_src_simple_get, clk); 18180eded6cSBoris BREZILLON } 18280eded6cSBoris BREZILLON 18380eded6cSBoris BREZILLON static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw, 18480eded6cSBoris BREZILLON unsigned long parent_rate) 18580eded6cSBoris BREZILLON { 18680eded6cSBoris BREZILLON struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); 18780eded6cSBoris BREZILLON 18880eded6cSBoris BREZILLON return osc->frequency; 18980eded6cSBoris BREZILLON } 19080eded6cSBoris BREZILLON 19180eded6cSBoris BREZILLON static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw, 19280eded6cSBoris BREZILLON unsigned long parent_acc) 19380eded6cSBoris BREZILLON { 19480eded6cSBoris BREZILLON struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); 19580eded6cSBoris BREZILLON 19680eded6cSBoris BREZILLON return osc->accuracy; 19780eded6cSBoris BREZILLON } 19880eded6cSBoris BREZILLON 19980eded6cSBoris BREZILLON static int clk_slow_rc_osc_prepare(struct clk_hw *hw) 20080eded6cSBoris BREZILLON { 20180eded6cSBoris BREZILLON struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); 20280eded6cSBoris BREZILLON void __iomem *sckcr = osc->sckcr; 20380eded6cSBoris BREZILLON 20480eded6cSBoris BREZILLON writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr); 20580eded6cSBoris BREZILLON 20680eded6cSBoris BREZILLON usleep_range(osc->startup_usec, osc->startup_usec + 1); 20780eded6cSBoris BREZILLON 20880eded6cSBoris BREZILLON return 0; 20980eded6cSBoris BREZILLON } 21080eded6cSBoris BREZILLON 21180eded6cSBoris BREZILLON static void clk_slow_rc_osc_unprepare(struct clk_hw *hw) 21280eded6cSBoris BREZILLON { 21380eded6cSBoris BREZILLON struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); 21480eded6cSBoris BREZILLON void __iomem *sckcr = osc->sckcr; 21580eded6cSBoris BREZILLON 21680eded6cSBoris BREZILLON writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr); 21780eded6cSBoris BREZILLON } 21880eded6cSBoris BREZILLON 21980eded6cSBoris BREZILLON static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw) 22080eded6cSBoris BREZILLON { 22180eded6cSBoris BREZILLON struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); 22280eded6cSBoris BREZILLON 22380eded6cSBoris BREZILLON return !!(readl(osc->sckcr) & AT91_SCKC_RCEN); 22480eded6cSBoris BREZILLON } 22580eded6cSBoris BREZILLON 22680eded6cSBoris BREZILLON static const struct clk_ops slow_rc_osc_ops = { 22780eded6cSBoris BREZILLON .prepare = clk_slow_rc_osc_prepare, 22880eded6cSBoris BREZILLON .unprepare = clk_slow_rc_osc_unprepare, 22980eded6cSBoris BREZILLON .is_prepared = clk_slow_rc_osc_is_prepared, 23080eded6cSBoris BREZILLON .recalc_rate = clk_slow_rc_osc_recalc_rate, 23180eded6cSBoris BREZILLON .recalc_accuracy = clk_slow_rc_osc_recalc_accuracy, 23280eded6cSBoris BREZILLON }; 23380eded6cSBoris BREZILLON 23480eded6cSBoris BREZILLON static struct clk * __init 23580eded6cSBoris BREZILLON at91_clk_register_slow_rc_osc(void __iomem *sckcr, 23680eded6cSBoris BREZILLON const char *name, 23780eded6cSBoris BREZILLON unsigned long frequency, 23880eded6cSBoris BREZILLON unsigned long accuracy, 23980eded6cSBoris BREZILLON unsigned long startup) 24080eded6cSBoris BREZILLON { 24180eded6cSBoris BREZILLON struct clk_slow_rc_osc *osc; 24280eded6cSBoris BREZILLON struct clk *clk = NULL; 24380eded6cSBoris BREZILLON struct clk_init_data init; 24480eded6cSBoris BREZILLON 24580eded6cSBoris BREZILLON if (!sckcr || !name) 24680eded6cSBoris BREZILLON return ERR_PTR(-EINVAL); 24780eded6cSBoris BREZILLON 24880eded6cSBoris BREZILLON osc = kzalloc(sizeof(*osc), GFP_KERNEL); 24980eded6cSBoris BREZILLON if (!osc) 25080eded6cSBoris BREZILLON return ERR_PTR(-ENOMEM); 25180eded6cSBoris BREZILLON 25280eded6cSBoris BREZILLON init.name = name; 25380eded6cSBoris BREZILLON init.ops = &slow_rc_osc_ops; 25480eded6cSBoris BREZILLON init.parent_names = NULL; 25580eded6cSBoris BREZILLON init.num_parents = 0; 25680eded6cSBoris BREZILLON init.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED; 25780eded6cSBoris BREZILLON 25880eded6cSBoris BREZILLON osc->hw.init = &init; 25980eded6cSBoris BREZILLON osc->sckcr = sckcr; 26080eded6cSBoris BREZILLON osc->frequency = frequency; 26180eded6cSBoris BREZILLON osc->accuracy = accuracy; 26280eded6cSBoris BREZILLON osc->startup_usec = startup; 26380eded6cSBoris BREZILLON 26480eded6cSBoris BREZILLON clk = clk_register(NULL, &osc->hw); 26580eded6cSBoris BREZILLON if (IS_ERR(clk)) 26680eded6cSBoris BREZILLON kfree(osc); 26780eded6cSBoris BREZILLON 26880eded6cSBoris BREZILLON return clk; 26980eded6cSBoris BREZILLON } 27080eded6cSBoris BREZILLON 27180eded6cSBoris BREZILLON void __init of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, 27280eded6cSBoris BREZILLON void __iomem *sckcr) 27380eded6cSBoris BREZILLON { 27480eded6cSBoris BREZILLON struct clk *clk; 27580eded6cSBoris BREZILLON u32 frequency = 0; 27680eded6cSBoris BREZILLON u32 accuracy = 0; 27780eded6cSBoris BREZILLON u32 startup = 0; 27880eded6cSBoris BREZILLON const char *name = np->name; 27980eded6cSBoris BREZILLON 28080eded6cSBoris BREZILLON of_property_read_string(np, "clock-output-names", &name); 28180eded6cSBoris BREZILLON of_property_read_u32(np, "clock-frequency", &frequency); 28280eded6cSBoris BREZILLON of_property_read_u32(np, "clock-accuracy", &accuracy); 28380eded6cSBoris BREZILLON of_property_read_u32(np, "atmel,startup-time-usec", &startup); 28480eded6cSBoris BREZILLON 28580eded6cSBoris BREZILLON clk = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy, 28680eded6cSBoris BREZILLON startup); 28780eded6cSBoris BREZILLON if (IS_ERR(clk)) 28880eded6cSBoris BREZILLON return; 28980eded6cSBoris BREZILLON 29080eded6cSBoris BREZILLON of_clk_add_provider(np, of_clk_src_simple_get, clk); 29180eded6cSBoris BREZILLON } 29280eded6cSBoris BREZILLON 29380eded6cSBoris BREZILLON static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index) 29480eded6cSBoris BREZILLON { 29580eded6cSBoris BREZILLON struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw); 29680eded6cSBoris BREZILLON void __iomem *sckcr = slowck->sckcr; 29780eded6cSBoris BREZILLON u32 tmp; 29880eded6cSBoris BREZILLON 29980eded6cSBoris BREZILLON if (index > 1) 30080eded6cSBoris BREZILLON return -EINVAL; 30180eded6cSBoris BREZILLON 30280eded6cSBoris BREZILLON tmp = readl(sckcr); 30380eded6cSBoris BREZILLON 30480eded6cSBoris BREZILLON if ((!index && !(tmp & AT91_SCKC_OSCSEL)) || 30580eded6cSBoris BREZILLON (index && (tmp & AT91_SCKC_OSCSEL))) 30680eded6cSBoris BREZILLON return 0; 30780eded6cSBoris BREZILLON 30880eded6cSBoris BREZILLON if (index) 30980eded6cSBoris BREZILLON tmp |= AT91_SCKC_OSCSEL; 31080eded6cSBoris BREZILLON else 31180eded6cSBoris BREZILLON tmp &= ~AT91_SCKC_OSCSEL; 31280eded6cSBoris BREZILLON 31380eded6cSBoris BREZILLON writel(tmp, sckcr); 31480eded6cSBoris BREZILLON 31580eded6cSBoris BREZILLON usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1); 31680eded6cSBoris BREZILLON 31780eded6cSBoris BREZILLON return 0; 31880eded6cSBoris BREZILLON } 31980eded6cSBoris BREZILLON 32080eded6cSBoris BREZILLON static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw) 32180eded6cSBoris BREZILLON { 32280eded6cSBoris BREZILLON struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw); 32380eded6cSBoris BREZILLON 32480eded6cSBoris BREZILLON return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL); 32580eded6cSBoris BREZILLON } 32680eded6cSBoris BREZILLON 32780eded6cSBoris BREZILLON static const struct clk_ops sam9x5_slow_ops = { 32880eded6cSBoris BREZILLON .set_parent = clk_sam9x5_slow_set_parent, 32980eded6cSBoris BREZILLON .get_parent = clk_sam9x5_slow_get_parent, 33080eded6cSBoris BREZILLON }; 33180eded6cSBoris BREZILLON 33280eded6cSBoris BREZILLON static struct clk * __init 33380eded6cSBoris BREZILLON at91_clk_register_sam9x5_slow(void __iomem *sckcr, 33480eded6cSBoris BREZILLON const char *name, 33580eded6cSBoris BREZILLON const char **parent_names, 33680eded6cSBoris BREZILLON int num_parents) 33780eded6cSBoris BREZILLON { 33880eded6cSBoris BREZILLON struct clk_sam9x5_slow *slowck; 33980eded6cSBoris BREZILLON struct clk *clk = NULL; 34080eded6cSBoris BREZILLON struct clk_init_data init; 34180eded6cSBoris BREZILLON 34280eded6cSBoris BREZILLON if (!sckcr || !name || !parent_names || !num_parents) 34380eded6cSBoris BREZILLON return ERR_PTR(-EINVAL); 34480eded6cSBoris BREZILLON 34580eded6cSBoris BREZILLON slowck = kzalloc(sizeof(*slowck), GFP_KERNEL); 34680eded6cSBoris BREZILLON if (!slowck) 34780eded6cSBoris BREZILLON return ERR_PTR(-ENOMEM); 34880eded6cSBoris BREZILLON 34980eded6cSBoris BREZILLON init.name = name; 35080eded6cSBoris BREZILLON init.ops = &sam9x5_slow_ops; 35180eded6cSBoris BREZILLON init.parent_names = parent_names; 35280eded6cSBoris BREZILLON init.num_parents = num_parents; 35380eded6cSBoris BREZILLON init.flags = 0; 35480eded6cSBoris BREZILLON 35580eded6cSBoris BREZILLON slowck->hw.init = &init; 35680eded6cSBoris BREZILLON slowck->sckcr = sckcr; 35780eded6cSBoris BREZILLON slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL); 35880eded6cSBoris BREZILLON 35980eded6cSBoris BREZILLON clk = clk_register(NULL, &slowck->hw); 36080eded6cSBoris BREZILLON if (IS_ERR(clk)) 36180eded6cSBoris BREZILLON kfree(slowck); 36280eded6cSBoris BREZILLON 36380eded6cSBoris BREZILLON return clk; 36480eded6cSBoris BREZILLON } 36580eded6cSBoris BREZILLON 36680eded6cSBoris BREZILLON void __init of_at91sam9x5_clk_slow_setup(struct device_node *np, 36780eded6cSBoris BREZILLON void __iomem *sckcr) 36880eded6cSBoris BREZILLON { 36980eded6cSBoris BREZILLON struct clk *clk; 37080eded6cSBoris BREZILLON const char *parent_names[2]; 37180eded6cSBoris BREZILLON int num_parents; 37280eded6cSBoris BREZILLON const char *name = np->name; 37380eded6cSBoris BREZILLON 37451a43be9SGeert Uytterhoeven num_parents = of_clk_get_parent_count(np); 37580eded6cSBoris BREZILLON if (num_parents <= 0 || num_parents > 2) 37680eded6cSBoris BREZILLON return; 37780eded6cSBoris BREZILLON 378f0557fbeSDinh Nguyen of_clk_parent_fill(np, parent_names, num_parents); 37980eded6cSBoris BREZILLON 38080eded6cSBoris BREZILLON of_property_read_string(np, "clock-output-names", &name); 38180eded6cSBoris BREZILLON 38280eded6cSBoris BREZILLON clk = at91_clk_register_sam9x5_slow(sckcr, name, parent_names, 38380eded6cSBoris BREZILLON num_parents); 38480eded6cSBoris BREZILLON if (IS_ERR(clk)) 38580eded6cSBoris BREZILLON return; 38680eded6cSBoris BREZILLON 38780eded6cSBoris BREZILLON of_clk_add_provider(np, of_clk_src_simple_get, clk); 38880eded6cSBoris BREZILLON } 38980eded6cSBoris BREZILLON 39080eded6cSBoris BREZILLON static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw) 39180eded6cSBoris BREZILLON { 39280eded6cSBoris BREZILLON struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw); 393*1bdf0232SBoris Brezillon unsigned int status; 39480eded6cSBoris BREZILLON 395*1bdf0232SBoris Brezillon regmap_read(slowck->regmap, AT91_PMC_SR, &status); 396*1bdf0232SBoris Brezillon 397*1bdf0232SBoris Brezillon return status & AT91_PMC_OSCSEL ? 1 : 0; 39880eded6cSBoris BREZILLON } 39980eded6cSBoris BREZILLON 40080eded6cSBoris BREZILLON static const struct clk_ops sam9260_slow_ops = { 40180eded6cSBoris BREZILLON .get_parent = clk_sam9260_slow_get_parent, 40280eded6cSBoris BREZILLON }; 40380eded6cSBoris BREZILLON 40480eded6cSBoris BREZILLON static struct clk * __init 405*1bdf0232SBoris Brezillon at91_clk_register_sam9260_slow(struct regmap *regmap, 40680eded6cSBoris BREZILLON const char *name, 40780eded6cSBoris BREZILLON const char **parent_names, 40880eded6cSBoris BREZILLON int num_parents) 40980eded6cSBoris BREZILLON { 41080eded6cSBoris BREZILLON struct clk_sam9260_slow *slowck; 41180eded6cSBoris BREZILLON struct clk *clk = NULL; 41280eded6cSBoris BREZILLON struct clk_init_data init; 41380eded6cSBoris BREZILLON 414*1bdf0232SBoris Brezillon if (!name) 41580eded6cSBoris BREZILLON return ERR_PTR(-EINVAL); 41680eded6cSBoris BREZILLON 41780eded6cSBoris BREZILLON if (!parent_names || !num_parents) 41880eded6cSBoris BREZILLON return ERR_PTR(-EINVAL); 41980eded6cSBoris BREZILLON 42080eded6cSBoris BREZILLON slowck = kzalloc(sizeof(*slowck), GFP_KERNEL); 42180eded6cSBoris BREZILLON if (!slowck) 42280eded6cSBoris BREZILLON return ERR_PTR(-ENOMEM); 42380eded6cSBoris BREZILLON 42480eded6cSBoris BREZILLON init.name = name; 42580eded6cSBoris BREZILLON init.ops = &sam9260_slow_ops; 42680eded6cSBoris BREZILLON init.parent_names = parent_names; 42780eded6cSBoris BREZILLON init.num_parents = num_parents; 42880eded6cSBoris BREZILLON init.flags = 0; 42980eded6cSBoris BREZILLON 43080eded6cSBoris BREZILLON slowck->hw.init = &init; 431*1bdf0232SBoris Brezillon slowck->regmap = regmap; 43280eded6cSBoris BREZILLON 43380eded6cSBoris BREZILLON clk = clk_register(NULL, &slowck->hw); 43480eded6cSBoris BREZILLON if (IS_ERR(clk)) 43580eded6cSBoris BREZILLON kfree(slowck); 43680eded6cSBoris BREZILLON 43780eded6cSBoris BREZILLON return clk; 43880eded6cSBoris BREZILLON } 43980eded6cSBoris BREZILLON 440*1bdf0232SBoris Brezillon static void __init of_at91sam9260_clk_slow_setup(struct device_node *np) 44180eded6cSBoris BREZILLON { 44280eded6cSBoris BREZILLON struct clk *clk; 44380eded6cSBoris BREZILLON const char *parent_names[2]; 44480eded6cSBoris BREZILLON int num_parents; 44580eded6cSBoris BREZILLON const char *name = np->name; 446*1bdf0232SBoris Brezillon struct regmap *regmap; 44780eded6cSBoris BREZILLON 44851a43be9SGeert Uytterhoeven num_parents = of_clk_get_parent_count(np); 449e8531ac8SBoris BREZILLON if (num_parents != 2) 45080eded6cSBoris BREZILLON return; 45180eded6cSBoris BREZILLON 452f0557fbeSDinh Nguyen of_clk_parent_fill(np, parent_names, num_parents); 453*1bdf0232SBoris Brezillon regmap = syscon_node_to_regmap(of_get_parent(np)); 454*1bdf0232SBoris Brezillon if (IS_ERR(regmap)) 455*1bdf0232SBoris Brezillon return; 45680eded6cSBoris BREZILLON 45780eded6cSBoris BREZILLON of_property_read_string(np, "clock-output-names", &name); 45880eded6cSBoris BREZILLON 459*1bdf0232SBoris Brezillon clk = at91_clk_register_sam9260_slow(regmap, name, parent_names, 46080eded6cSBoris BREZILLON num_parents); 46180eded6cSBoris BREZILLON if (IS_ERR(clk)) 46280eded6cSBoris BREZILLON return; 46380eded6cSBoris BREZILLON 46480eded6cSBoris BREZILLON of_clk_add_provider(np, of_clk_src_simple_get, clk); 46580eded6cSBoris BREZILLON } 466*1bdf0232SBoris Brezillon 467*1bdf0232SBoris Brezillon CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow", 468*1bdf0232SBoris Brezillon of_at91sam9260_clk_slow_setup); 469