2 * drivers/clk/at91/clk-slow.c
4 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
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.
13 #include <linux/clk-provider.h>
14 #include <linux/clkdev.h>
15 #include <linux/clk/at91_pmc.h>
16 #include <linux/delay.h>
18 #include <linux/mfd/syscon.h>
19 #include <linux/regmap.h>
24 #define SLOW_CLOCK_FREQ 32768
25 #define SLOWCK_SW_CYCLES 5
26 #define SLOWCK_SW_TIME_USEC ((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \
29 #define AT91_SCKC_CR 0x00
30 #define AT91_SCKC_RCEN (1 << 0)
31 #define AT91_SCKC_OSC32EN (1 << 1)
32 #define AT91_SCKC_OSC32BYP (1 << 2)
33 #define AT91_SCKC_OSCSEL (1 << 3)
38 unsigned long startup_usec;
41 #define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw)
43 struct clk_slow_rc_osc {
46 unsigned long frequency;
47 unsigned long accuracy;
48 unsigned long startup_usec;
51 #define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw)
53 struct clk_sam9260_slow {
55 struct regmap *regmap;
58 #define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw)
60 struct clk_sam9x5_slow {
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 & AT91_SCKC_OSC32BYP)
77 writel(tmp | AT91_SCKC_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 & AT91_SCKC_OSC32BYP)
93 writel(tmp & ~AT91_SCKC_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 & AT91_SCKC_OSC32BYP)
105 return !!(tmp & AT91_SCKC_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 * __init
115 at91_clk_register_slow_osc(void __iomem *sckcr,
117 const char *parent_name,
118 unsigned long startup,
121 struct clk_slow_osc *osc;
122 struct clk *clk = NULL;
123 struct clk_init_data init;
125 if (!sckcr || !name || !parent_name)
126 return ERR_PTR(-EINVAL);
128 osc = kzalloc(sizeof(*osc), GFP_KERNEL);
130 return ERR_PTR(-ENOMEM);
133 init.ops = &slow_osc_ops;
134 init.parent_names = &parent_name;
135 init.num_parents = 1;
136 init.flags = CLK_IGNORE_UNUSED;
138 osc->hw.init = &init;
140 osc->startup_usec = startup;
143 writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP,
146 clk = clk_register(NULL, &osc->hw);
153 void __init of_at91sam9x5_clk_slow_osc_setup(struct device_node *np,
157 const char *parent_name;
158 const char *name = np->name;
162 parent_name = of_clk_get_parent_name(np, 0);
163 of_property_read_string(np, "clock-output-names", &name);
164 of_property_read_u32(np, "atmel,startup-time-usec", &startup);
165 bypass = of_property_read_bool(np, "atmel,osc-bypass");
167 clk = at91_clk_register_slow_osc(sckcr, name, parent_name, startup,
172 of_clk_add_provider(np, of_clk_src_simple_get, clk);
175 static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
176 unsigned long parent_rate)
178 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
180 return osc->frequency;
183 static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw,
184 unsigned long parent_acc)
186 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
188 return osc->accuracy;
191 static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
193 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
194 void __iomem *sckcr = osc->sckcr;
196 writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr);
198 usleep_range(osc->startup_usec, osc->startup_usec + 1);
203 static void clk_slow_rc_osc_unprepare(struct clk_hw *hw)
205 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
206 void __iomem *sckcr = osc->sckcr;
208 writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr);
211 static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw)
213 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
215 return !!(readl(osc->sckcr) & AT91_SCKC_RCEN);
218 static const struct clk_ops slow_rc_osc_ops = {
219 .prepare = clk_slow_rc_osc_prepare,
220 .unprepare = clk_slow_rc_osc_unprepare,
221 .is_prepared = clk_slow_rc_osc_is_prepared,
222 .recalc_rate = clk_slow_rc_osc_recalc_rate,
223 .recalc_accuracy = clk_slow_rc_osc_recalc_accuracy,
226 static struct clk * __init
227 at91_clk_register_slow_rc_osc(void __iomem *sckcr,
229 unsigned long frequency,
230 unsigned long accuracy,
231 unsigned long startup)
233 struct clk_slow_rc_osc *osc;
234 struct clk *clk = NULL;
235 struct clk_init_data init;
238 return ERR_PTR(-EINVAL);
240 osc = kzalloc(sizeof(*osc), GFP_KERNEL);
242 return ERR_PTR(-ENOMEM);
245 init.ops = &slow_rc_osc_ops;
246 init.parent_names = NULL;
247 init.num_parents = 0;
248 init.flags = CLK_IGNORE_UNUSED;
250 osc->hw.init = &init;
252 osc->frequency = frequency;
253 osc->accuracy = accuracy;
254 osc->startup_usec = startup;
256 clk = clk_register(NULL, &osc->hw);
263 void __init of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np,
270 const char *name = np->name;
272 of_property_read_string(np, "clock-output-names", &name);
273 of_property_read_u32(np, "clock-frequency", &frequency);
274 of_property_read_u32(np, "clock-accuracy", &accuracy);
275 of_property_read_u32(np, "atmel,startup-time-usec", &startup);
277 clk = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy,
282 of_clk_add_provider(np, of_clk_src_simple_get, clk);
285 static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
287 struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
288 void __iomem *sckcr = slowck->sckcr;
296 if ((!index && !(tmp & AT91_SCKC_OSCSEL)) ||
297 (index && (tmp & AT91_SCKC_OSCSEL)))
301 tmp |= AT91_SCKC_OSCSEL;
303 tmp &= ~AT91_SCKC_OSCSEL;
307 usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1);
312 static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
314 struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
316 return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL);
319 static const struct clk_ops sam9x5_slow_ops = {
320 .set_parent = clk_sam9x5_slow_set_parent,
321 .get_parent = clk_sam9x5_slow_get_parent,
324 static struct clk * __init
325 at91_clk_register_sam9x5_slow(void __iomem *sckcr,
327 const char **parent_names,
330 struct clk_sam9x5_slow *slowck;
331 struct clk *clk = NULL;
332 struct clk_init_data init;
334 if (!sckcr || !name || !parent_names || !num_parents)
335 return ERR_PTR(-EINVAL);
337 slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
339 return ERR_PTR(-ENOMEM);
342 init.ops = &sam9x5_slow_ops;
343 init.parent_names = parent_names;
344 init.num_parents = num_parents;
347 slowck->hw.init = &init;
348 slowck->sckcr = sckcr;
349 slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL);
351 clk = clk_register(NULL, &slowck->hw);
358 void __init of_at91sam9x5_clk_slow_setup(struct device_node *np,
362 const char *parent_names[2];
363 unsigned int num_parents;
364 const char *name = np->name;
366 num_parents = of_clk_get_parent_count(np);
367 if (num_parents == 0 || num_parents > 2)
370 of_clk_parent_fill(np, parent_names, num_parents);
372 of_property_read_string(np, "clock-output-names", &name);
374 clk = at91_clk_register_sam9x5_slow(sckcr, name, parent_names,
379 of_clk_add_provider(np, of_clk_src_simple_get, clk);
382 static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw)
384 struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw);
387 regmap_read(slowck->regmap, AT91_PMC_SR, &status);
389 return status & AT91_PMC_OSCSEL ? 1 : 0;
392 static const struct clk_ops sam9260_slow_ops = {
393 .get_parent = clk_sam9260_slow_get_parent,
396 static struct clk * __init
397 at91_clk_register_sam9260_slow(struct regmap *regmap,
399 const char **parent_names,
402 struct clk_sam9260_slow *slowck;
403 struct clk *clk = NULL;
404 struct clk_init_data init;
407 return ERR_PTR(-EINVAL);
409 if (!parent_names || !num_parents)
410 return ERR_PTR(-EINVAL);
412 slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
414 return ERR_PTR(-ENOMEM);
417 init.ops = &sam9260_slow_ops;
418 init.parent_names = parent_names;
419 init.num_parents = num_parents;
422 slowck->hw.init = &init;
423 slowck->regmap = regmap;
425 clk = clk_register(NULL, &slowck->hw);
432 static void __init of_at91sam9260_clk_slow_setup(struct device_node *np)
435 const char *parent_names[2];
436 unsigned int num_parents;
437 const char *name = np->name;
438 struct regmap *regmap;
440 num_parents = of_clk_get_parent_count(np);
441 if (num_parents != 2)
444 of_clk_parent_fill(np, parent_names, num_parents);
445 regmap = syscon_node_to_regmap(of_get_parent(np));
449 of_property_read_string(np, "clock-output-names", &name);
451 clk = at91_clk_register_sam9260_slow(regmap, name, parent_names,
456 of_clk_add_provider(np, of_clk_src_simple_get, clk);
459 CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow",
460 of_at91sam9260_clk_slow_setup);