2 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
11 #include <linux/clk-provider.h>
12 #include <linux/clkdev.h>
13 #include <linux/clk/at91_pmc.h>
15 #include <linux/mfd/syscon.h>
16 #include <linux/regmap.h>
20 DEFINE_SPINLOCK(pmc_pcr_lock
);
22 #define PERIPHERAL_MAX 64
24 #define PERIPHERAL_AT91RM9200 0
25 #define PERIPHERAL_AT91SAM9X5 1
27 #define PERIPHERAL_ID_MIN 2
28 #define PERIPHERAL_ID_MAX 31
29 #define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX))
31 #define PERIPHERAL_RSHIFT_MASK 0x3
32 #define PERIPHERAL_RSHIFT(val) (((val) >> 16) & PERIPHERAL_RSHIFT_MASK)
34 #define PERIPHERAL_MAX_SHIFT 3
36 struct clk_peripheral
{
38 struct regmap
*regmap
;
42 #define to_clk_peripheral(hw) container_of(hw, struct clk_peripheral, hw)
44 struct clk_sam9x5_peripheral
{
46 struct regmap
*regmap
;
47 struct clk_range range
;
54 #define to_clk_sam9x5_peripheral(hw) \
55 container_of(hw, struct clk_sam9x5_peripheral, hw)
57 static int clk_peripheral_enable(struct clk_hw
*hw
)
59 struct clk_peripheral
*periph
= to_clk_peripheral(hw
);
60 int offset
= AT91_PMC_PCER
;
63 if (id
< PERIPHERAL_ID_MIN
)
65 if (id
> PERIPHERAL_ID_MAX
)
66 offset
= AT91_PMC_PCER1
;
67 regmap_write(periph
->regmap
, offset
, PERIPHERAL_MASK(id
));
72 static void clk_peripheral_disable(struct clk_hw
*hw
)
74 struct clk_peripheral
*periph
= to_clk_peripheral(hw
);
75 int offset
= AT91_PMC_PCDR
;
78 if (id
< PERIPHERAL_ID_MIN
)
80 if (id
> PERIPHERAL_ID_MAX
)
81 offset
= AT91_PMC_PCDR1
;
82 regmap_write(periph
->regmap
, offset
, PERIPHERAL_MASK(id
));
85 static int clk_peripheral_is_enabled(struct clk_hw
*hw
)
87 struct clk_peripheral
*periph
= to_clk_peripheral(hw
);
88 int offset
= AT91_PMC_PCSR
;
92 if (id
< PERIPHERAL_ID_MIN
)
94 if (id
> PERIPHERAL_ID_MAX
)
95 offset
= AT91_PMC_PCSR1
;
96 regmap_read(periph
->regmap
, offset
, &status
);
98 return status
& PERIPHERAL_MASK(id
) ? 1 : 0;
101 static const struct clk_ops peripheral_ops
= {
102 .enable
= clk_peripheral_enable
,
103 .disable
= clk_peripheral_disable
,
104 .is_enabled
= clk_peripheral_is_enabled
,
107 static struct clk
* __init
108 at91_clk_register_peripheral(struct regmap
*regmap
, const char *name
,
109 const char *parent_name
, u32 id
)
111 struct clk_peripheral
*periph
;
112 struct clk
*clk
= NULL
;
113 struct clk_init_data init
;
115 if (!name
|| !parent_name
|| id
> PERIPHERAL_ID_MAX
)
116 return ERR_PTR(-EINVAL
);
118 periph
= kzalloc(sizeof(*periph
), GFP_KERNEL
);
120 return ERR_PTR(-ENOMEM
);
123 init
.ops
= &peripheral_ops
;
124 init
.parent_names
= (parent_name
? &parent_name
: NULL
);
125 init
.num_parents
= (parent_name
? 1 : 0);
129 periph
->hw
.init
= &init
;
130 periph
->regmap
= regmap
;
132 clk
= clk_register(NULL
, &periph
->hw
);
139 static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral
*periph
)
141 struct clk_hw
*parent
;
142 unsigned long parent_rate
;
145 if (!periph
->auto_div
)
148 if (periph
->range
.max
) {
149 parent
= clk_hw_get_parent_by_index(&periph
->hw
, 0);
150 parent_rate
= clk_hw_get_rate(parent
);
154 for (; shift
< PERIPHERAL_MAX_SHIFT
; shift
++) {
155 if (parent_rate
>> shift
<= periph
->range
.max
)
160 periph
->auto_div
= false;
164 static int clk_sam9x5_peripheral_enable(struct clk_hw
*hw
)
166 struct clk_sam9x5_peripheral
*periph
= to_clk_sam9x5_peripheral(hw
);
169 if (periph
->id
< PERIPHERAL_ID_MIN
)
172 spin_lock_irqsave(periph
->lock
, flags
);
173 regmap_write(periph
->regmap
, AT91_PMC_PCR
,
174 (periph
->id
& AT91_PMC_PCR_PID_MASK
));
175 regmap_update_bits(periph
->regmap
, AT91_PMC_PCR
,
176 AT91_PMC_PCR_DIV_MASK
| AT91_PMC_PCR_CMD
|
178 AT91_PMC_PCR_DIV(periph
->div
) |
181 spin_unlock_irqrestore(periph
->lock
, flags
);
186 static void clk_sam9x5_peripheral_disable(struct clk_hw
*hw
)
188 struct clk_sam9x5_peripheral
*periph
= to_clk_sam9x5_peripheral(hw
);
191 if (periph
->id
< PERIPHERAL_ID_MIN
)
194 spin_lock_irqsave(periph
->lock
, flags
);
195 regmap_write(periph
->regmap
, AT91_PMC_PCR
,
196 (periph
->id
& AT91_PMC_PCR_PID_MASK
));
197 regmap_update_bits(periph
->regmap
, AT91_PMC_PCR
,
198 AT91_PMC_PCR_EN
| AT91_PMC_PCR_CMD
,
200 spin_unlock_irqrestore(periph
->lock
, flags
);
203 static int clk_sam9x5_peripheral_is_enabled(struct clk_hw
*hw
)
205 struct clk_sam9x5_peripheral
*periph
= to_clk_sam9x5_peripheral(hw
);
209 if (periph
->id
< PERIPHERAL_ID_MIN
)
212 spin_lock_irqsave(periph
->lock
, flags
);
213 regmap_write(periph
->regmap
, AT91_PMC_PCR
,
214 (periph
->id
& AT91_PMC_PCR_PID_MASK
));
215 regmap_read(periph
->regmap
, AT91_PMC_PCR
, &status
);
216 spin_unlock_irqrestore(periph
->lock
, flags
);
218 return status
& AT91_PMC_PCR_EN
? 1 : 0;
222 clk_sam9x5_peripheral_recalc_rate(struct clk_hw
*hw
,
223 unsigned long parent_rate
)
225 struct clk_sam9x5_peripheral
*periph
= to_clk_sam9x5_peripheral(hw
);
229 if (periph
->id
< PERIPHERAL_ID_MIN
)
232 spin_lock_irqsave(periph
->lock
, flags
);
233 regmap_write(periph
->regmap
, AT91_PMC_PCR
,
234 (periph
->id
& AT91_PMC_PCR_PID_MASK
));
235 regmap_read(periph
->regmap
, AT91_PMC_PCR
, &status
);
236 spin_unlock_irqrestore(periph
->lock
, flags
);
238 if (status
& AT91_PMC_PCR_EN
) {
239 periph
->div
= PERIPHERAL_RSHIFT(status
);
240 periph
->auto_div
= false;
242 clk_sam9x5_peripheral_autodiv(periph
);
245 return parent_rate
>> periph
->div
;
248 static long clk_sam9x5_peripheral_round_rate(struct clk_hw
*hw
,
250 unsigned long *parent_rate
)
253 unsigned long best_rate
;
254 unsigned long best_diff
;
255 unsigned long cur_rate
= *parent_rate
;
256 unsigned long cur_diff
;
257 struct clk_sam9x5_peripheral
*periph
= to_clk_sam9x5_peripheral(hw
);
259 if (periph
->id
< PERIPHERAL_ID_MIN
|| !periph
->range
.max
)
262 if (periph
->range
.max
) {
263 for (; shift
<= PERIPHERAL_MAX_SHIFT
; shift
++) {
264 cur_rate
= *parent_rate
>> shift
;
265 if (cur_rate
<= periph
->range
.max
)
270 if (rate
>= cur_rate
)
273 best_diff
= cur_rate
- rate
;
274 best_rate
= cur_rate
;
275 for (; shift
<= PERIPHERAL_MAX_SHIFT
; shift
++) {
276 cur_rate
= *parent_rate
>> shift
;
278 cur_diff
= rate
- cur_rate
;
280 cur_diff
= cur_rate
- rate
;
282 if (cur_diff
< best_diff
) {
283 best_diff
= cur_diff
;
284 best_rate
= cur_rate
;
287 if (!best_diff
|| cur_rate
< rate
)
294 static int clk_sam9x5_peripheral_set_rate(struct clk_hw
*hw
,
296 unsigned long parent_rate
)
299 struct clk_sam9x5_peripheral
*periph
= to_clk_sam9x5_peripheral(hw
);
300 if (periph
->id
< PERIPHERAL_ID_MIN
|| !periph
->range
.max
) {
301 if (parent_rate
== rate
)
307 if (periph
->range
.max
&& rate
> periph
->range
.max
)
310 for (shift
= 0; shift
<= PERIPHERAL_MAX_SHIFT
; shift
++) {
311 if (parent_rate
>> shift
== rate
) {
312 periph
->auto_div
= false;
321 static const struct clk_ops sam9x5_peripheral_ops
= {
322 .enable
= clk_sam9x5_peripheral_enable
,
323 .disable
= clk_sam9x5_peripheral_disable
,
324 .is_enabled
= clk_sam9x5_peripheral_is_enabled
,
325 .recalc_rate
= clk_sam9x5_peripheral_recalc_rate
,
326 .round_rate
= clk_sam9x5_peripheral_round_rate
,
327 .set_rate
= clk_sam9x5_peripheral_set_rate
,
330 static struct clk
* __init
331 at91_clk_register_sam9x5_peripheral(struct regmap
*regmap
, spinlock_t
*lock
,
332 const char *name
, const char *parent_name
,
333 u32 id
, const struct clk_range
*range
)
335 struct clk_sam9x5_peripheral
*periph
;
336 struct clk
*clk
= NULL
;
337 struct clk_init_data init
;
339 if (!name
|| !parent_name
)
340 return ERR_PTR(-EINVAL
);
342 periph
= kzalloc(sizeof(*periph
), GFP_KERNEL
);
344 return ERR_PTR(-ENOMEM
);
347 init
.ops
= &sam9x5_peripheral_ops
;
348 init
.parent_names
= (parent_name
? &parent_name
: NULL
);
349 init
.num_parents
= (parent_name
? 1 : 0);
353 periph
->hw
.init
= &init
;
355 periph
->regmap
= regmap
;
357 periph
->auto_div
= true;
358 periph
->range
= *range
;
360 clk
= clk_register(NULL
, &periph
->hw
);
364 clk_sam9x5_peripheral_autodiv(periph
);
370 of_at91_clk_periph_setup(struct device_node
*np
, u8 type
)
375 const char *parent_name
;
377 struct device_node
*periphclknp
;
378 struct regmap
*regmap
;
380 parent_name
= of_clk_get_parent_name(np
, 0);
384 num
= of_get_child_count(np
);
385 if (!num
|| num
> PERIPHERAL_MAX
)
388 regmap
= syscon_node_to_regmap(of_get_parent(np
));
392 for_each_child_of_node(np
, periphclknp
) {
393 if (of_property_read_u32(periphclknp
, "reg", &id
))
396 if (id
>= PERIPHERAL_MAX
)
399 if (of_property_read_string(np
, "clock-output-names", &name
))
400 name
= periphclknp
->name
;
402 if (type
== PERIPHERAL_AT91RM9200
) {
403 clk
= at91_clk_register_peripheral(regmap
, name
,
406 struct clk_range range
= CLK_RANGE(0, 0);
408 of_at91_get_clk_range(periphclknp
,
409 "atmel,clk-output-range",
412 clk
= at91_clk_register_sam9x5_peripheral(regmap
,
422 of_clk_add_provider(periphclknp
, of_clk_src_simple_get
, clk
);
426 static void __init
of_at91rm9200_clk_periph_setup(struct device_node
*np
)
428 of_at91_clk_periph_setup(np
, PERIPHERAL_AT91RM9200
);
430 CLK_OF_DECLARE(at91rm9200_clk_periph
, "atmel,at91rm9200-clk-peripheral",
431 of_at91rm9200_clk_periph_setup
);
433 static void __init
of_at91sam9x5_clk_periph_setup(struct device_node
*np
)
435 of_at91_clk_periph_setup(np
, PERIPHERAL_AT91SAM9X5
);
437 CLK_OF_DECLARE(at91sam9x5_clk_periph
, "atmel,at91sam9x5-clk-peripheral",
438 of_at91sam9x5_clk_periph_setup
);