2 * Copyright (C) 2015 Atmel Corporation,
3 * Nicolas Ferre <nicolas.ferre@atmel.com>
5 * Based on clk-programmable & clk-peripheral drivers by Boris BREZILLON.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
14 #include <linux/clk-provider.h>
15 #include <linux/clkdev.h>
16 #include <linux/clk/at91_pmc.h>
18 #include <linux/of_address.h>
23 #define PERIPHERAL_MAX 64
24 #define PERIPHERAL_ID_MIN 2
26 #define GENERATED_SOURCE_MAX 6
27 #define GENERATED_MAX_DIV 255
29 struct clk_generated
{
32 struct clk_range range
;
38 #define to_clk_generated(hw) \
39 container_of(hw, struct clk_generated, hw)
41 static int clk_generated_enable(struct clk_hw
*hw
)
43 struct clk_generated
*gck
= to_clk_generated(hw
);
44 struct at91_pmc
*pmc
= gck
->pmc
;
47 pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n",
48 __func__
, gck
->gckdiv
, gck
->parent_id
);
51 pmc_write(pmc
, AT91_PMC_PCR
, (gck
->id
& AT91_PMC_PCR_PID_MASK
));
52 tmp
= pmc_read(pmc
, AT91_PMC_PCR
) &
53 ~(AT91_PMC_PCR_GCKDIV_MASK
| AT91_PMC_PCR_GCKCSS_MASK
);
54 pmc_write(pmc
, AT91_PMC_PCR
, tmp
| AT91_PMC_PCR_GCKCSS(gck
->parent_id
)
56 | AT91_PMC_PCR_GCKDIV(gck
->gckdiv
)
57 | AT91_PMC_PCR_GCKEN
);
62 static void clk_generated_disable(struct clk_hw
*hw
)
64 struct clk_generated
*gck
= to_clk_generated(hw
);
65 struct at91_pmc
*pmc
= gck
->pmc
;
69 pmc_write(pmc
, AT91_PMC_PCR
, (gck
->id
& AT91_PMC_PCR_PID_MASK
));
70 tmp
= pmc_read(pmc
, AT91_PMC_PCR
) & ~AT91_PMC_PCR_GCKEN
;
71 pmc_write(pmc
, AT91_PMC_PCR
, tmp
| AT91_PMC_PCR_CMD
);
75 static int clk_generated_is_enabled(struct clk_hw
*hw
)
77 struct clk_generated
*gck
= to_clk_generated(hw
);
78 struct at91_pmc
*pmc
= gck
->pmc
;
82 pmc_write(pmc
, AT91_PMC_PCR
, (gck
->id
& AT91_PMC_PCR_PID_MASK
));
83 ret
= !!(pmc_read(pmc
, AT91_PMC_PCR
) & AT91_PMC_PCR_GCKEN
);
90 clk_generated_recalc_rate(struct clk_hw
*hw
,
91 unsigned long parent_rate
)
93 struct clk_generated
*gck
= to_clk_generated(hw
);
95 return DIV_ROUND_CLOSEST(parent_rate
, gck
->gckdiv
+ 1);
98 static int clk_generated_determine_rate(struct clk_hw
*hw
,
99 struct clk_rate_request
*req
)
101 struct clk_generated
*gck
= to_clk_generated(hw
);
102 struct clk_hw
*parent
= NULL
;
103 long best_rate
= -EINVAL
;
104 unsigned long tmp_rate
, min_rate
;
109 for (i
= 0; i
< clk_hw_get_num_parents(hw
); i
++) {
111 unsigned long parent_rate
;
113 parent
= clk_hw_get_parent_by_index(hw
, i
);
117 parent_rate
= clk_hw_get_rate(parent
);
118 min_rate
= DIV_ROUND_CLOSEST(parent_rate
, GENERATED_MAX_DIV
+ 1);
120 (gck
->range
.max
&& min_rate
> gck
->range
.max
))
123 for (div
= 1; div
< GENERATED_MAX_DIV
+ 2; div
++) {
124 tmp_rate
= DIV_ROUND_CLOSEST(parent_rate
, div
);
125 tmp_diff
= abs(req
->rate
- tmp_rate
);
127 if (best_diff
< 0 || best_diff
> tmp_diff
) {
128 best_rate
= tmp_rate
;
129 best_diff
= tmp_diff
;
130 req
->best_parent_rate
= parent_rate
;
131 req
->best_parent_hw
= parent
;
134 if (!best_diff
|| tmp_rate
< req
->rate
)
142 pr_debug("GCLK: %s, best_rate = %ld, parent clk: %s @ %ld\n",
144 __clk_get_name((req
->best_parent_hw
)->clk
),
145 req
->best_parent_rate
);
150 req
->rate
= best_rate
;
154 /* No modification of hardware as we have the flag CLK_SET_PARENT_GATE set */
155 static int clk_generated_set_parent(struct clk_hw
*hw
, u8 index
)
157 struct clk_generated
*gck
= to_clk_generated(hw
);
159 if (index
>= clk_hw_get_num_parents(hw
))
162 gck
->parent_id
= index
;
166 static u8
clk_generated_get_parent(struct clk_hw
*hw
)
168 struct clk_generated
*gck
= to_clk_generated(hw
);
170 return gck
->parent_id
;
173 /* No modification of hardware as we have the flag CLK_SET_RATE_GATE set */
174 static int clk_generated_set_rate(struct clk_hw
*hw
,
176 unsigned long parent_rate
)
178 struct clk_generated
*gck
= to_clk_generated(hw
);
184 if (gck
->range
.max
&& rate
> gck
->range
.max
)
187 div
= DIV_ROUND_CLOSEST(parent_rate
, rate
);
188 if (div
> GENERATED_MAX_DIV
+ 1 || !div
)
191 gck
->gckdiv
= div
- 1;
195 static const struct clk_ops generated_ops
= {
196 .enable
= clk_generated_enable
,
197 .disable
= clk_generated_disable
,
198 .is_enabled
= clk_generated_is_enabled
,
199 .recalc_rate
= clk_generated_recalc_rate
,
200 .determine_rate
= clk_generated_determine_rate
,
201 .get_parent
= clk_generated_get_parent
,
202 .set_parent
= clk_generated_set_parent
,
203 .set_rate
= clk_generated_set_rate
,
207 * clk_generated_startup - Initialize a given clock to its default parent and
210 * @gck: Generated clock to set the startup parameters for.
212 * Take parameters from the hardware and update local clock configuration
215 static void clk_generated_startup(struct clk_generated
*gck
)
217 struct at91_pmc
*pmc
= gck
->pmc
;
221 pmc_write(pmc
, AT91_PMC_PCR
, (gck
->id
& AT91_PMC_PCR_PID_MASK
));
222 tmp
= pmc_read(pmc
, AT91_PMC_PCR
);
225 gck
->parent_id
= (tmp
& AT91_PMC_PCR_GCKCSS_MASK
)
226 >> AT91_PMC_PCR_GCKCSS_OFFSET
;
227 gck
->gckdiv
= (tmp
& AT91_PMC_PCR_GCKDIV_MASK
)
228 >> AT91_PMC_PCR_GCKDIV_OFFSET
;
231 static struct clk
* __init
232 at91_clk_register_generated(struct at91_pmc
*pmc
, const char *name
,
233 const char **parent_names
, u8 num_parents
,
234 u8 id
, const struct clk_range
*range
)
236 struct clk_generated
*gck
;
237 struct clk
*clk
= NULL
;
238 struct clk_init_data init
;
240 gck
= kzalloc(sizeof(*gck
), GFP_KERNEL
);
242 return ERR_PTR(-ENOMEM
);
245 init
.ops
= &generated_ops
;
246 init
.parent_names
= parent_names
;
247 init
.num_parents
= num_parents
;
248 init
.flags
= CLK_SET_RATE_GATE
| CLK_SET_PARENT_GATE
;
251 gck
->hw
.init
= &init
;
255 clk
= clk_register(NULL
, &gck
->hw
);
259 clk_generated_startup(gck
);
264 void __init
of_sama5d2_clk_generated_setup(struct device_node
*np
,
265 struct at91_pmc
*pmc
)
272 const char *parent_names
[GENERATED_SOURCE_MAX
];
273 struct device_node
*gcknp
;
274 struct clk_range range
= CLK_RANGE(0, 0);
276 num_parents
= of_clk_get_parent_count(np
);
277 if (num_parents
<= 0 || num_parents
> GENERATED_SOURCE_MAX
)
280 of_clk_parent_fill(np
, parent_names
, num_parents
);
282 num
= of_get_child_count(np
);
283 if (!num
|| num
> PERIPHERAL_MAX
)
286 for_each_child_of_node(np
, gcknp
) {
287 if (of_property_read_u32(gcknp
, "reg", &id
))
290 if (id
< PERIPHERAL_ID_MIN
|| id
>= PERIPHERAL_MAX
)
293 if (of_property_read_string(np
, "clock-output-names", &name
))
296 of_at91_get_clk_range(gcknp
, "atmel,clk-output-range",
299 clk
= at91_clk_register_generated(pmc
, name
, parent_names
,
300 num_parents
, id
, &range
);
304 of_clk_add_provider(gcknp
, of_clk_src_simple_get
, clk
);