4 * Copyright (C) ST-Microelectronics SA 2013
5 * Author: Maxime Coquelin <maxime.coquelin@st.com> for ST-Microelectronics.
6 * License terms: GNU General Public License (GPL), version 2 */
9 #include <linux/clk-provider.h>
10 #include <linux/module.h>
11 #include <linux/slab.h>
13 #include <linux/err.h>
14 #include <linux/string.h>
16 #include <linux/of_address.h>
28 /* Pre-divisor's gate */
29 struct clk_gate pgate
;
31 struct clk_divider pdiv
;
32 /* Final divisor's gate */
33 struct clk_gate fgate
;
35 struct clk_divider fdiv
;
36 /* Asynchronous mode control */
38 /* hw control flags */
42 #define to_flexgen(_hw) container_of(_hw, struct flexgen, hw)
43 #define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
45 static int flexgen_enable(struct clk_hw
*hw
)
47 struct flexgen
*flexgen
= to_flexgen(hw
);
48 struct clk_hw
*pgate_hw
= &flexgen
->pgate
.hw
;
49 struct clk_hw
*fgate_hw
= &flexgen
->fgate
.hw
;
51 __clk_hw_set_clk(pgate_hw
, hw
);
52 __clk_hw_set_clk(fgate_hw
, hw
);
54 clk_gate_ops
.enable(pgate_hw
);
56 clk_gate_ops
.enable(fgate_hw
);
58 pr_debug("%s: flexgen output enabled\n", clk_hw_get_name(hw
));
62 static void flexgen_disable(struct clk_hw
*hw
)
64 struct flexgen
*flexgen
= to_flexgen(hw
);
65 struct clk_hw
*fgate_hw
= &flexgen
->fgate
.hw
;
67 /* disable only the final gate */
68 __clk_hw_set_clk(fgate_hw
, hw
);
70 clk_gate_ops
.disable(fgate_hw
);
72 pr_debug("%s: flexgen output disabled\n", clk_hw_get_name(hw
));
75 static int flexgen_is_enabled(struct clk_hw
*hw
)
77 struct flexgen
*flexgen
= to_flexgen(hw
);
78 struct clk_hw
*fgate_hw
= &flexgen
->fgate
.hw
;
80 __clk_hw_set_clk(fgate_hw
, hw
);
82 if (!clk_gate_ops
.is_enabled(fgate_hw
))
88 static u8
flexgen_get_parent(struct clk_hw
*hw
)
90 struct flexgen
*flexgen
= to_flexgen(hw
);
91 struct clk_hw
*mux_hw
= &flexgen
->mux
.hw
;
93 __clk_hw_set_clk(mux_hw
, hw
);
95 return clk_mux_ops
.get_parent(mux_hw
);
98 static int flexgen_set_parent(struct clk_hw
*hw
, u8 index
)
100 struct flexgen
*flexgen
= to_flexgen(hw
);
101 struct clk_hw
*mux_hw
= &flexgen
->mux
.hw
;
103 __clk_hw_set_clk(mux_hw
, hw
);
105 return clk_mux_ops
.set_parent(mux_hw
, index
);
108 static inline unsigned long
109 clk_best_div(unsigned long parent_rate
, unsigned long rate
)
111 return parent_rate
/ rate
+ ((rate
> (2*(parent_rate
% rate
))) ? 0 : 1);
114 static long flexgen_round_rate(struct clk_hw
*hw
, unsigned long rate
,
115 unsigned long *prate
)
119 /* Round div according to exact prate and wished rate */
120 div
= clk_best_div(*prate
, rate
);
122 if (clk_hw_get_flags(hw
) & CLK_SET_RATE_PARENT
) {
130 static unsigned long flexgen_recalc_rate(struct clk_hw
*hw
,
131 unsigned long parent_rate
)
133 struct flexgen
*flexgen
= to_flexgen(hw
);
134 struct clk_hw
*pdiv_hw
= &flexgen
->pdiv
.hw
;
135 struct clk_hw
*fdiv_hw
= &flexgen
->fdiv
.hw
;
136 unsigned long mid_rate
;
138 __clk_hw_set_clk(pdiv_hw
, hw
);
139 __clk_hw_set_clk(fdiv_hw
, hw
);
141 mid_rate
= clk_divider_ops
.recalc_rate(pdiv_hw
, parent_rate
);
143 return clk_divider_ops
.recalc_rate(fdiv_hw
, mid_rate
);
146 static int flexgen_set_rate(struct clk_hw
*hw
, unsigned long rate
,
147 unsigned long parent_rate
)
149 struct flexgen
*flexgen
= to_flexgen(hw
);
150 struct clk_hw
*pdiv_hw
= &flexgen
->pdiv
.hw
;
151 struct clk_hw
*fdiv_hw
= &flexgen
->fdiv
.hw
;
152 struct clk_hw
*sync_hw
= &flexgen
->sync
.hw
;
153 struct clk_gate
*config
= to_clk_gate(sync_hw
);
154 unsigned long div
= 0;
158 __clk_hw_set_clk(pdiv_hw
, hw
);
159 __clk_hw_set_clk(fdiv_hw
, hw
);
161 if (flexgen
->control_mode
) {
162 reg
= readl(config
->reg
);
163 reg
&= ~BIT(config
->bit_idx
);
164 writel(reg
, config
->reg
);
167 div
= clk_best_div(parent_rate
, rate
);
170 * pdiv is mainly targeted for low freq results, while fdiv
171 * should be used for div <= 64. The other way round can
172 * lead to 'duty cycle' issues.
176 clk_divider_ops
.set_rate(pdiv_hw
, parent_rate
, parent_rate
);
177 ret
= clk_divider_ops
.set_rate(fdiv_hw
, rate
, rate
* div
);
179 clk_divider_ops
.set_rate(fdiv_hw
, parent_rate
, parent_rate
);
180 ret
= clk_divider_ops
.set_rate(pdiv_hw
, rate
, rate
* div
);
186 static const struct clk_ops flexgen_ops
= {
187 .enable
= flexgen_enable
,
188 .disable
= flexgen_disable
,
189 .is_enabled
= flexgen_is_enabled
,
190 .get_parent
= flexgen_get_parent
,
191 .set_parent
= flexgen_set_parent
,
192 .round_rate
= flexgen_round_rate
,
193 .recalc_rate
= flexgen_recalc_rate
,
194 .set_rate
= flexgen_set_rate
,
197 static struct clk
*clk_register_flexgen(const char *name
,
198 const char **parent_names
, u8 num_parents
,
199 void __iomem
*reg
, spinlock_t
*lock
, u32 idx
,
200 unsigned long flexgen_flags
, bool mode
) {
201 struct flexgen
*fgxbar
;
203 struct clk_init_data init
;
205 void __iomem
*xbar_reg
, *fdiv_reg
;
207 fgxbar
= kzalloc(sizeof(struct flexgen
), GFP_KERNEL
);
209 return ERR_PTR(-ENOMEM
);
212 init
.ops
= &flexgen_ops
;
213 init
.flags
= CLK_IS_BASIC
| CLK_GET_RATE_NOCACHE
| flexgen_flags
;
214 init
.parent_names
= parent_names
;
215 init
.num_parents
= num_parents
;
217 xbar_reg
= reg
+ 0x18 + (idx
& ~0x3);
218 xbar_shift
= (idx
% 4) * 0x8;
219 fdiv_reg
= reg
+ 0x164 + idx
* 4;
221 /* Crossbar element config */
222 fgxbar
->mux
.lock
= lock
;
223 fgxbar
->mux
.mask
= BIT(6) - 1;
224 fgxbar
->mux
.reg
= xbar_reg
;
225 fgxbar
->mux
.shift
= xbar_shift
;
226 fgxbar
->mux
.table
= NULL
;
229 /* Pre-divider's gate config (in xbar register)*/
230 fgxbar
->pgate
.lock
= lock
;
231 fgxbar
->pgate
.reg
= xbar_reg
;
232 fgxbar
->pgate
.bit_idx
= xbar_shift
+ 6;
234 /* Pre-divider config */
235 fgxbar
->pdiv
.lock
= lock
;
236 fgxbar
->pdiv
.reg
= reg
+ 0x58 + idx
* 4;
237 fgxbar
->pdiv
.width
= 10;
239 /* Final divider's gate config */
240 fgxbar
->fgate
.lock
= lock
;
241 fgxbar
->fgate
.reg
= fdiv_reg
;
242 fgxbar
->fgate
.bit_idx
= 6;
244 /* Final divider config */
245 fgxbar
->fdiv
.lock
= lock
;
246 fgxbar
->fdiv
.reg
= fdiv_reg
;
247 fgxbar
->fdiv
.width
= 6;
249 /* Final divider sync config */
250 fgxbar
->sync
.lock
= lock
;
251 fgxbar
->sync
.reg
= fdiv_reg
;
252 fgxbar
->sync
.bit_idx
= 7;
254 fgxbar
->control_mode
= mode
;
256 fgxbar
->hw
.init
= &init
;
258 clk
= clk_register(NULL
, &fgxbar
->hw
);
262 pr_debug("%s: parent %s rate %u\n",
264 __clk_get_name(clk_get_parent(clk
)),
265 (unsigned int)clk_get_rate(clk
));
269 static const char ** __init
flexgen_get_parents(struct device_node
*np
,
272 const char **parents
;
273 unsigned int nparents
;
275 nparents
= of_clk_get_parent_count(np
);
276 if (WARN_ON(!nparents
))
279 parents
= kcalloc(nparents
, sizeof(const char *), GFP_KERNEL
);
283 *num_parents
= of_clk_parent_fill(np
, parents
, nparents
);
288 static const struct clkgen_data clkgen_audio
= {
289 .flags
= CLK_SET_RATE_PARENT
,
292 static const struct clkgen_data clkgen_video
= {
293 .flags
= CLK_SET_RATE_PARENT
,
297 static const struct of_device_id flexgen_of_match
[] = {
299 .compatible
= "st,flexgen-audio",
300 .data
= &clkgen_audio
,
303 .compatible
= "st,flexgen-video",
304 .data
= &clkgen_video
,
309 static void __init
st_of_flexgen_setup(struct device_node
*np
)
311 struct device_node
*pnode
;
313 struct clk_onecell_data
*clk_data
;
314 const char **parents
;
316 spinlock_t
*rlock
= NULL
;
317 const struct of_device_id
*match
;
318 struct clkgen_data
*data
= NULL
;
319 unsigned long flex_flags
= 0;
323 pnode
= of_get_parent(np
);
327 reg
= of_iomap(pnode
, 0);
331 parents
= flexgen_get_parents(np
, &num_parents
);
337 match
= of_match_node(flexgen_of_match
, np
);
339 data
= (struct clkgen_data
*)match
->data
;
340 flex_flags
= data
->flags
;
341 clk_mode
= data
->mode
;
344 clk_data
= kzalloc(sizeof(*clk_data
), GFP_KERNEL
);
348 ret
= of_property_count_strings(np
, "clock-output-names");
350 pr_err("%s: Failed to get number of output clocks (%d)",
351 __func__
, clk_data
->clk_num
);
354 clk_data
->clk_num
= ret
;
356 clk_data
->clks
= kcalloc(clk_data
->clk_num
, sizeof(struct clk
*),
361 rlock
= kzalloc(sizeof(spinlock_t
), GFP_KERNEL
);
365 spin_lock_init(rlock
);
367 for (i
= 0; i
< clk_data
->clk_num
; i
++) {
369 const char *clk_name
;
371 if (of_property_read_string_index(np
, "clock-output-names",
376 flex_flags
&= ~CLK_IS_CRITICAL
;
377 of_clk_detect_critical(np
, i
, &flex_flags
);
380 * If we read an empty clock name then the output is unused
382 if (*clk_name
== '\0')
385 clk
= clk_register_flexgen(clk_name
, parents
, num_parents
,
386 reg
, rlock
, i
, flex_flags
, clk_mode
);
391 clk_data
->clks
[i
] = clk
;
395 of_clk_add_provider(np
, of_clk_src_onecell_get
, clk_data
);
402 kfree(clk_data
->clks
);
407 CLK_OF_DECLARE(flexgen
, "st,flexgen", st_of_flexgen_setup
);