2 * drivers/clk/at91/sckc.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/delay.h>
17 #include <linux/of_address.h>
20 #define SLOW_CLOCK_FREQ 32768
21 #define SLOWCK_SW_CYCLES 5
22 #define SLOWCK_SW_TIME_USEC ((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \
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)
34 unsigned long startup_usec
;
37 #define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw)
39 struct clk_sama5d4_slow_osc
{
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 unsigned long frequency
;
52 unsigned long accuracy
;
53 unsigned long startup_usec
;
56 #define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw)
58 struct clk_sam9x5_slow
{
64 #define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
66 static int clk_slow_osc_prepare(struct clk_hw
*hw
)
68 struct clk_slow_osc
*osc
= to_clk_slow_osc(hw
);
69 void __iomem
*sckcr
= osc
->sckcr
;
70 u32 tmp
= readl(sckcr
);
72 if (tmp
& (AT91_SCKC_OSC32BYP
| AT91_SCKC_OSC32EN
))
75 writel(tmp
| AT91_SCKC_OSC32EN
, sckcr
);
77 usleep_range(osc
->startup_usec
, osc
->startup_usec
+ 1);
82 static void clk_slow_osc_unprepare(struct clk_hw
*hw
)
84 struct clk_slow_osc
*osc
= to_clk_slow_osc(hw
);
85 void __iomem
*sckcr
= osc
->sckcr
;
86 u32 tmp
= readl(sckcr
);
88 if (tmp
& AT91_SCKC_OSC32BYP
)
91 writel(tmp
& ~AT91_SCKC_OSC32EN
, sckcr
);
94 static int clk_slow_osc_is_prepared(struct clk_hw
*hw
)
96 struct clk_slow_osc
*osc
= to_clk_slow_osc(hw
);
97 void __iomem
*sckcr
= osc
->sckcr
;
98 u32 tmp
= readl(sckcr
);
100 if (tmp
& AT91_SCKC_OSC32BYP
)
103 return !!(tmp
& AT91_SCKC_OSC32EN
);
106 static const struct clk_ops slow_osc_ops
= {
107 .prepare
= clk_slow_osc_prepare
,
108 .unprepare
= clk_slow_osc_unprepare
,
109 .is_prepared
= clk_slow_osc_is_prepared
,
112 static struct clk_hw
* __init
113 at91_clk_register_slow_osc(void __iomem
*sckcr
,
115 const char *parent_name
,
116 unsigned long startup
,
119 struct clk_slow_osc
*osc
;
121 struct clk_init_data init
;
124 if (!sckcr
|| !name
|| !parent_name
)
125 return ERR_PTR(-EINVAL
);
127 osc
= kzalloc(sizeof(*osc
), GFP_KERNEL
);
129 return ERR_PTR(-ENOMEM
);
132 init
.ops
= &slow_osc_ops
;
133 init
.parent_names
= &parent_name
;
134 init
.num_parents
= 1;
135 init
.flags
= CLK_IGNORE_UNUSED
;
137 osc
->hw
.init
= &init
;
139 osc
->startup_usec
= startup
;
142 writel((readl(sckcr
) & ~AT91_SCKC_OSC32EN
) | AT91_SCKC_OSC32BYP
,
146 ret
= clk_hw_register(NULL
, &osc
->hw
);
156 of_at91sam9x5_clk_slow_osc_setup(struct device_node
*np
, void __iomem
*sckcr
)
159 const char *parent_name
;
160 const char *name
= np
->name
;
164 parent_name
= of_clk_get_parent_name(np
, 0);
165 of_property_read_string(np
, "clock-output-names", &name
);
166 of_property_read_u32(np
, "atmel,startup-time-usec", &startup
);
167 bypass
= of_property_read_bool(np
, "atmel,osc-bypass");
169 hw
= at91_clk_register_slow_osc(sckcr
, name
, parent_name
, startup
,
174 of_clk_add_hw_provider(np
, of_clk_hw_simple_get
, hw
);
177 static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw
*hw
,
178 unsigned long parent_rate
)
180 struct clk_slow_rc_osc
*osc
= to_clk_slow_rc_osc(hw
);
182 return osc
->frequency
;
185 static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw
*hw
,
186 unsigned long parent_acc
)
188 struct clk_slow_rc_osc
*osc
= to_clk_slow_rc_osc(hw
);
190 return osc
->accuracy
;
193 static int clk_slow_rc_osc_prepare(struct clk_hw
*hw
)
195 struct clk_slow_rc_osc
*osc
= to_clk_slow_rc_osc(hw
);
196 void __iomem
*sckcr
= osc
->sckcr
;
198 writel(readl(sckcr
) | AT91_SCKC_RCEN
, sckcr
);
200 usleep_range(osc
->startup_usec
, osc
->startup_usec
+ 1);
205 static void clk_slow_rc_osc_unprepare(struct clk_hw
*hw
)
207 struct clk_slow_rc_osc
*osc
= to_clk_slow_rc_osc(hw
);
208 void __iomem
*sckcr
= osc
->sckcr
;
210 writel(readl(sckcr
) & ~AT91_SCKC_RCEN
, sckcr
);
213 static int clk_slow_rc_osc_is_prepared(struct clk_hw
*hw
)
215 struct clk_slow_rc_osc
*osc
= to_clk_slow_rc_osc(hw
);
217 return !!(readl(osc
->sckcr
) & AT91_SCKC_RCEN
);
220 static const struct clk_ops slow_rc_osc_ops
= {
221 .prepare
= clk_slow_rc_osc_prepare
,
222 .unprepare
= clk_slow_rc_osc_unprepare
,
223 .is_prepared
= clk_slow_rc_osc_is_prepared
,
224 .recalc_rate
= clk_slow_rc_osc_recalc_rate
,
225 .recalc_accuracy
= clk_slow_rc_osc_recalc_accuracy
,
228 static struct clk_hw
* __init
229 at91_clk_register_slow_rc_osc(void __iomem
*sckcr
,
231 unsigned long frequency
,
232 unsigned long accuracy
,
233 unsigned long startup
)
235 struct clk_slow_rc_osc
*osc
;
237 struct clk_init_data init
;
241 return ERR_PTR(-EINVAL
);
243 osc
= kzalloc(sizeof(*osc
), GFP_KERNEL
);
245 return ERR_PTR(-ENOMEM
);
248 init
.ops
= &slow_rc_osc_ops
;
249 init
.parent_names
= NULL
;
250 init
.num_parents
= 0;
251 init
.flags
= CLK_IGNORE_UNUSED
;
253 osc
->hw
.init
= &init
;
255 osc
->frequency
= frequency
;
256 osc
->accuracy
= accuracy
;
257 osc
->startup_usec
= startup
;
260 ret
= clk_hw_register(NULL
, &osc
->hw
);
270 of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node
*np
, void __iomem
*sckcr
)
276 const char *name
= np
->name
;
278 of_property_read_string(np
, "clock-output-names", &name
);
279 of_property_read_u32(np
, "clock-frequency", &frequency
);
280 of_property_read_u32(np
, "clock-accuracy", &accuracy
);
281 of_property_read_u32(np
, "atmel,startup-time-usec", &startup
);
283 hw
= at91_clk_register_slow_rc_osc(sckcr
, name
, frequency
, accuracy
,
288 of_clk_add_hw_provider(np
, of_clk_hw_simple_get
, hw
);
291 static int clk_sam9x5_slow_set_parent(struct clk_hw
*hw
, u8 index
)
293 struct clk_sam9x5_slow
*slowck
= to_clk_sam9x5_slow(hw
);
294 void __iomem
*sckcr
= slowck
->sckcr
;
302 if ((!index
&& !(tmp
& AT91_SCKC_OSCSEL
)) ||
303 (index
&& (tmp
& AT91_SCKC_OSCSEL
)))
307 tmp
|= AT91_SCKC_OSCSEL
;
309 tmp
&= ~AT91_SCKC_OSCSEL
;
313 usleep_range(SLOWCK_SW_TIME_USEC
, SLOWCK_SW_TIME_USEC
+ 1);
318 static u8
clk_sam9x5_slow_get_parent(struct clk_hw
*hw
)
320 struct clk_sam9x5_slow
*slowck
= to_clk_sam9x5_slow(hw
);
322 return !!(readl(slowck
->sckcr
) & AT91_SCKC_OSCSEL
);
325 static const struct clk_ops sam9x5_slow_ops
= {
326 .set_parent
= clk_sam9x5_slow_set_parent
,
327 .get_parent
= clk_sam9x5_slow_get_parent
,
330 static struct clk_hw
* __init
331 at91_clk_register_sam9x5_slow(void __iomem
*sckcr
,
333 const char **parent_names
,
336 struct clk_sam9x5_slow
*slowck
;
338 struct clk_init_data init
;
341 if (!sckcr
|| !name
|| !parent_names
|| !num_parents
)
342 return ERR_PTR(-EINVAL
);
344 slowck
= kzalloc(sizeof(*slowck
), GFP_KERNEL
);
346 return ERR_PTR(-ENOMEM
);
349 init
.ops
= &sam9x5_slow_ops
;
350 init
.parent_names
= parent_names
;
351 init
.num_parents
= num_parents
;
354 slowck
->hw
.init
= &init
;
355 slowck
->sckcr
= sckcr
;
356 slowck
->parent
= !!(readl(sckcr
) & AT91_SCKC_OSCSEL
);
359 ret
= clk_hw_register(NULL
, &slowck
->hw
);
369 of_at91sam9x5_clk_slow_setup(struct device_node
*np
, void __iomem
*sckcr
)
372 const char *parent_names
[2];
373 unsigned int num_parents
;
374 const char *name
= np
->name
;
376 num_parents
= of_clk_get_parent_count(np
);
377 if (num_parents
== 0 || num_parents
> 2)
380 of_clk_parent_fill(np
, parent_names
, num_parents
);
382 of_property_read_string(np
, "clock-output-names", &name
);
384 hw
= at91_clk_register_sam9x5_slow(sckcr
, name
, parent_names
,
389 of_clk_add_hw_provider(np
, of_clk_hw_simple_get
, hw
);
392 static const struct of_device_id sckc_clk_ids
[] __initconst
= {
395 .compatible
= "atmel,at91sam9x5-clk-slow-osc",
396 .data
= of_at91sam9x5_clk_slow_osc_setup
,
399 .compatible
= "atmel,at91sam9x5-clk-slow-rc-osc",
400 .data
= of_at91sam9x5_clk_slow_rc_osc_setup
,
403 .compatible
= "atmel,at91sam9x5-clk-slow",
404 .data
= of_at91sam9x5_clk_slow_setup
,
409 static void __init
of_at91sam9x5_sckc_setup(struct device_node
*np
)
411 struct device_node
*childnp
;
412 void (*clk_setup
)(struct device_node
*, void __iomem
*);
413 const struct of_device_id
*clk_id
;
414 void __iomem
*regbase
= of_iomap(np
, 0);
419 for_each_child_of_node(np
, childnp
) {
420 clk_id
= of_match_node(sckc_clk_ids
, childnp
);
423 clk_setup
= clk_id
->data
;
424 clk_setup(childnp
, regbase
);
427 CLK_OF_DECLARE(at91sam9x5_clk_sckc
, "atmel,at91sam9x5-sckc",
428 of_at91sam9x5_sckc_setup
);
430 static int clk_sama5d4_slow_osc_prepare(struct clk_hw
*hw
)
432 struct clk_sama5d4_slow_osc
*osc
= to_clk_sama5d4_slow_osc(hw
);
438 * Assume that if it has already been selected (for example by the
439 * bootloader), enough time has aready passed.
441 if ((readl(osc
->sckcr
) & AT91_SCKC_OSCSEL
)) {
442 osc
->prepared
= true;
446 usleep_range(osc
->startup_usec
, osc
->startup_usec
+ 1);
447 osc
->prepared
= true;
452 static int clk_sama5d4_slow_osc_is_prepared(struct clk_hw
*hw
)
454 struct clk_sama5d4_slow_osc
*osc
= to_clk_sama5d4_slow_osc(hw
);
456 return osc
->prepared
;
459 static const struct clk_ops sama5d4_slow_osc_ops
= {
460 .prepare
= clk_sama5d4_slow_osc_prepare
,
461 .is_prepared
= clk_sama5d4_slow_osc_is_prepared
,
464 static void __init
of_sama5d4_sckc_setup(struct device_node
*np
)
466 void __iomem
*regbase
= of_iomap(np
, 0);
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" };
478 hw
= clk_hw_register_fixed_rate_with_accuracy(NULL
, parent_names
[0],
484 xtal_name
= of_clk_get_parent_name(np
, 0);
486 bypass
= of_property_read_bool(np
, "atmel,osc-bypass");
488 osc
= kzalloc(sizeof(*osc
), GFP_KERNEL
);
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
;
498 osc
->hw
.init
= &init
;
499 osc
->sckcr
= regbase
;
500 osc
->startup_usec
= 1200000;
503 writel((readl(regbase
) | AT91_SCKC_OSC32BYP
), regbase
);
506 ret
= clk_hw_register(NULL
, &osc
->hw
);
512 hw
= at91_clk_register_sam9x5_slow(regbase
, "slowck", parent_names
, 2);
516 of_clk_add_hw_provider(np
, of_clk_hw_simple_get
, hw
);
518 CLK_OF_DECLARE(sama5d4_clk_sckc
, "atmel,sama5d4-sckc",
519 of_sama5d4_sckc_setup
);