2 * mmp mix(div and mux) clock operation source file
4 * Copyright (C) 2014 Marvell
5 * Chao Xie <chao.xie@marvell.com>
7 * This file is licensed under the terms of the GNU General Public
8 * License version 2. This program is licensed "as is" without any
9 * warranty of any kind, whether express or implied.
12 #include <linux/clk-provider.h>
13 #include <linux/slab.h>
15 #include <linux/err.h>
20 * The mix clock is a clock combined mux and div type clock.
21 * Because the div field and mux field need to be set at same
22 * time, we can not divide it into 2 types of clock
25 #define to_clk_mix(hw) container_of(hw, struct mmp_clk_mix, hw)
27 static unsigned int _get_maxdiv(struct mmp_clk_mix
*mix
)
29 unsigned int div_mask
= (1 << mix
->reg_info
.width_div
) - 1;
30 unsigned int maxdiv
= 0;
31 struct clk_div_table
*clkt
;
33 if (mix
->div_flags
& CLK_DIVIDER_ONE_BASED
)
35 if (mix
->div_flags
& CLK_DIVIDER_POWER_OF_TWO
)
38 for (clkt
= mix
->div_table
; clkt
->div
; clkt
++)
39 if (clkt
->div
> maxdiv
)
46 static unsigned int _get_div(struct mmp_clk_mix
*mix
, unsigned int val
)
48 struct clk_div_table
*clkt
;
50 if (mix
->div_flags
& CLK_DIVIDER_ONE_BASED
)
52 if (mix
->div_flags
& CLK_DIVIDER_POWER_OF_TWO
)
55 for (clkt
= mix
->div_table
; clkt
->div
; clkt
++)
64 static unsigned int _get_mux(struct mmp_clk_mix
*mix
, unsigned int val
)
66 int num_parents
= clk_hw_get_num_parents(&mix
->hw
);
69 if (mix
->mux_flags
& CLK_MUX_INDEX_BIT
)
71 if (mix
->mux_flags
& CLK_MUX_INDEX_ONE
)
74 for (i
= 0; i
< num_parents
; i
++)
75 if (mix
->mux_table
[i
] == val
)
83 static unsigned int _get_div_val(struct mmp_clk_mix
*mix
, unsigned int div
)
85 struct clk_div_table
*clkt
;
87 if (mix
->div_flags
& CLK_DIVIDER_ONE_BASED
)
89 if (mix
->div_flags
& CLK_DIVIDER_POWER_OF_TWO
)
92 for (clkt
= mix
->div_table
; clkt
->div
; clkt
++)
102 static unsigned int _get_mux_val(struct mmp_clk_mix
*mix
, unsigned int mux
)
105 return mix
->mux_table
[mux
];
110 static void _filter_clk_table(struct mmp_clk_mix
*mix
,
111 struct mmp_clk_mix_clk_table
*table
,
112 unsigned int table_size
)
115 struct mmp_clk_mix_clk_table
*item
;
116 struct clk_hw
*parent
, *hw
;
117 unsigned long parent_rate
;
121 for (i
= 0; i
< table_size
; i
++) {
123 parent
= clk_hw_get_parent_by_index(hw
, item
->parent_index
);
124 parent_rate
= clk_hw_get_rate(parent
);
125 if (parent_rate
% item
->rate
) {
128 item
->divisor
= parent_rate
/ item
->rate
;
134 static int _set_rate(struct mmp_clk_mix
*mix
, u32 mux_val
, u32 div_val
,
135 unsigned int change_mux
, unsigned int change_div
)
137 struct mmp_clk_mix_reg_info
*ri
= &mix
->reg_info
;
140 int ret
, timeout
= 50;
141 unsigned long flags
= 0;
143 if (!change_mux
&& !change_div
)
147 spin_lock_irqsave(mix
->lock
, flags
);
149 if (mix
->type
== MMP_CLK_MIX_TYPE_V1
150 || mix
->type
== MMP_CLK_MIX_TYPE_V2
)
151 mux_div
= readl(ri
->reg_clk_ctrl
);
153 mux_div
= readl(ri
->reg_clk_sel
);
156 width
= ri
->width_div
;
157 shift
= ri
->shift_div
;
158 mux_div
&= ~MMP_CLK_BITS_MASK(width
, shift
);
159 mux_div
|= MMP_CLK_BITS_SET_VAL(div_val
, width
, shift
);
163 width
= ri
->width_mux
;
164 shift
= ri
->shift_mux
;
165 mux_div
&= ~MMP_CLK_BITS_MASK(width
, shift
);
166 mux_div
|= MMP_CLK_BITS_SET_VAL(mux_val
, width
, shift
);
169 if (mix
->type
== MMP_CLK_MIX_TYPE_V1
) {
170 writel(mux_div
, ri
->reg_clk_ctrl
);
171 } else if (mix
->type
== MMP_CLK_MIX_TYPE_V2
) {
172 mux_div
|= (1 << ri
->bit_fc
);
173 writel(mux_div
, ri
->reg_clk_ctrl
);
176 fc_req
= readl(ri
->reg_clk_ctrl
);
178 if (!(fc_req
& (1 << ri
->bit_fc
)))
183 pr_err("%s:%s cannot do frequency change\n",
184 __func__
, clk_hw_get_name(&mix
->hw
));
189 fc_req
= readl(ri
->reg_clk_ctrl
);
190 fc_req
|= 1 << ri
->bit_fc
;
191 writel(fc_req
, ri
->reg_clk_ctrl
);
192 writel(mux_div
, ri
->reg_clk_sel
);
193 fc_req
&= ~(1 << ri
->bit_fc
);
199 spin_unlock_irqrestore(mix
->lock
, flags
);
204 static int mmp_clk_mix_determine_rate(struct clk_hw
*hw
,
205 struct clk_rate_request
*req
)
207 struct mmp_clk_mix
*mix
= to_clk_mix(hw
);
208 struct mmp_clk_mix_clk_table
*item
;
209 struct clk_hw
*parent
, *parent_best
;
210 unsigned long parent_rate
, mix_rate
, mix_rate_best
, parent_rate_best
;
211 unsigned long gap
, gap_best
;
218 parent_rate_best
= 0;
219 gap_best
= ULONG_MAX
;
223 for (i
= 0; i
< mix
->table_size
; i
++) {
224 item
= &mix
->table
[i
];
225 if (item
->valid
== 0)
227 parent
= clk_hw_get_parent_by_index(hw
,
229 parent_rate
= clk_hw_get_rate(parent
);
230 mix_rate
= parent_rate
/ item
->divisor
;
231 gap
= abs(mix_rate
- req
->rate
);
232 if (!parent_best
|| gap
< gap_best
) {
233 parent_best
= parent
;
234 parent_rate_best
= parent_rate
;
235 mix_rate_best
= mix_rate
;
242 for (i
= 0; i
< clk_hw_get_num_parents(hw
); i
++) {
243 parent
= clk_hw_get_parent_by_index(hw
, i
);
244 parent_rate
= clk_hw_get_rate(parent
);
245 div_val_max
= _get_maxdiv(mix
);
246 for (j
= 0; j
< div_val_max
; j
++) {
247 div
= _get_div(mix
, j
);
248 mix_rate
= parent_rate
/ div
;
249 gap
= abs(mix_rate
- req
->rate
);
250 if (!parent_best
|| gap
< gap_best
) {
251 parent_best
= parent
;
252 parent_rate_best
= parent_rate
;
253 mix_rate_best
= mix_rate
;
266 req
->best_parent_rate
= parent_rate_best
;
267 req
->best_parent_hw
= parent_best
;
268 req
->rate
= mix_rate_best
;
273 static int mmp_clk_mix_set_rate_and_parent(struct clk_hw
*hw
,
275 unsigned long parent_rate
,
278 struct mmp_clk_mix
*mix
= to_clk_mix(hw
);
280 u32 div_val
, mux_val
;
282 div
= parent_rate
/ rate
;
283 div_val
= _get_div_val(mix
, div
);
284 mux_val
= _get_mux_val(mix
, index
);
286 return _set_rate(mix
, mux_val
, div_val
, 1, 1);
289 static u8
mmp_clk_mix_get_parent(struct clk_hw
*hw
)
291 struct mmp_clk_mix
*mix
= to_clk_mix(hw
);
292 struct mmp_clk_mix_reg_info
*ri
= &mix
->reg_info
;
293 unsigned long flags
= 0;
299 spin_lock_irqsave(mix
->lock
, flags
);
301 if (mix
->type
== MMP_CLK_MIX_TYPE_V1
302 || mix
->type
== MMP_CLK_MIX_TYPE_V2
)
303 mux_div
= readl(ri
->reg_clk_ctrl
);
305 mux_div
= readl(ri
->reg_clk_sel
);
308 spin_unlock_irqrestore(mix
->lock
, flags
);
310 width
= mix
->reg_info
.width_mux
;
311 shift
= mix
->reg_info
.shift_mux
;
313 mux_val
= MMP_CLK_BITS_GET_VAL(mux_div
, width
, shift
);
315 return _get_mux(mix
, mux_val
);
318 static unsigned long mmp_clk_mix_recalc_rate(struct clk_hw
*hw
,
319 unsigned long parent_rate
)
321 struct mmp_clk_mix
*mix
= to_clk_mix(hw
);
322 struct mmp_clk_mix_reg_info
*ri
= &mix
->reg_info
;
323 unsigned long flags
= 0;
329 spin_lock_irqsave(mix
->lock
, flags
);
331 if (mix
->type
== MMP_CLK_MIX_TYPE_V1
332 || mix
->type
== MMP_CLK_MIX_TYPE_V2
)
333 mux_div
= readl(ri
->reg_clk_ctrl
);
335 mux_div
= readl(ri
->reg_clk_sel
);
338 spin_unlock_irqrestore(mix
->lock
, flags
);
340 width
= mix
->reg_info
.width_div
;
341 shift
= mix
->reg_info
.shift_div
;
343 div
= _get_div(mix
, MMP_CLK_BITS_GET_VAL(mux_div
, width
, shift
));
345 return parent_rate
/ div
;
348 static int mmp_clk_set_parent(struct clk_hw
*hw
, u8 index
)
350 struct mmp_clk_mix
*mix
= to_clk_mix(hw
);
351 struct mmp_clk_mix_clk_table
*item
;
353 u32 div_val
, mux_val
;
356 for (i
= 0; i
< mix
->table_size
; i
++) {
357 item
= &mix
->table
[i
];
358 if (item
->valid
== 0)
360 if (item
->parent_index
== index
)
363 if (i
< mix
->table_size
) {
364 div_val
= _get_div_val(mix
, item
->divisor
);
365 mux_val
= _get_mux_val(mix
, item
->parent_index
);
369 mux_val
= _get_mux_val(mix
, index
);
373 return _set_rate(mix
, mux_val
, div_val
, 1, div_val
? 1 : 0);
376 static int mmp_clk_set_rate(struct clk_hw
*hw
, unsigned long rate
,
377 unsigned long best_parent_rate
)
379 struct mmp_clk_mix
*mix
= to_clk_mix(hw
);
380 struct mmp_clk_mix_clk_table
*item
;
381 unsigned long parent_rate
;
382 unsigned int best_divisor
;
383 struct clk_hw
*parent
;
386 best_divisor
= best_parent_rate
/ rate
;
389 for (i
= 0; i
< mix
->table_size
; i
++) {
390 item
= &mix
->table
[i
];
391 if (item
->valid
== 0)
393 parent
= clk_hw_get_parent_by_index(hw
,
395 parent_rate
= clk_hw_get_rate(parent
);
396 if (parent_rate
== best_parent_rate
397 && item
->divisor
== best_divisor
)
400 if (i
< mix
->table_size
)
401 return _set_rate(mix
,
402 _get_mux_val(mix
, item
->parent_index
),
403 _get_div_val(mix
, item
->divisor
),
408 for (i
= 0; i
< clk_hw_get_num_parents(hw
); i
++) {
409 parent
= clk_hw_get_parent_by_index(hw
, i
);
410 parent_rate
= clk_hw_get_rate(parent
);
411 if (parent_rate
== best_parent_rate
)
414 if (i
< clk_hw_get_num_parents(hw
))
415 return _set_rate(mix
, _get_mux_val(mix
, i
),
416 _get_div_val(mix
, best_divisor
), 1, 1);
422 static void mmp_clk_mix_init(struct clk_hw
*hw
)
424 struct mmp_clk_mix
*mix
= to_clk_mix(hw
);
427 _filter_clk_table(mix
, mix
->table
, mix
->table_size
);
430 const struct clk_ops mmp_clk_mix_ops
= {
431 .determine_rate
= mmp_clk_mix_determine_rate
,
432 .set_rate_and_parent
= mmp_clk_mix_set_rate_and_parent
,
433 .set_rate
= mmp_clk_set_rate
,
434 .set_parent
= mmp_clk_set_parent
,
435 .get_parent
= mmp_clk_mix_get_parent
,
436 .recalc_rate
= mmp_clk_mix_recalc_rate
,
437 .init
= mmp_clk_mix_init
,
440 struct clk
*mmp_clk_register_mix(struct device
*dev
,
442 const char **parent_names
,
445 struct mmp_clk_mix_config
*config
,
448 struct mmp_clk_mix
*mix
;
450 struct clk_init_data init
;
453 mix
= kzalloc(sizeof(*mix
), GFP_KERNEL
);
455 return ERR_PTR(-ENOMEM
);
458 init
.flags
= flags
| CLK_GET_RATE_NOCACHE
;
459 init
.parent_names
= parent_names
;
460 init
.num_parents
= num_parents
;
461 init
.ops
= &mmp_clk_mix_ops
;
463 memcpy(&mix
->reg_info
, &config
->reg_info
, sizeof(config
->reg_info
));
465 table_bytes
= sizeof(*config
->table
) * config
->table_size
;
466 mix
->table
= kmemdup(config
->table
, table_bytes
, GFP_KERNEL
);
470 mix
->table_size
= config
->table_size
;
473 if (config
->mux_table
) {
474 table_bytes
= sizeof(u32
) * num_parents
;
475 mix
->mux_table
= kmemdup(config
->mux_table
, table_bytes
,
477 if (!mix
->mux_table
) {
483 mix
->div_flags
= config
->div_flags
;
484 mix
->mux_flags
= config
->mux_flags
;
486 mix
->hw
.init
= &init
;
488 if (config
->reg_info
.bit_fc
>= 32)
489 mix
->type
= MMP_CLK_MIX_TYPE_V1
;
490 else if (config
->reg_info
.reg_clk_sel
)
491 mix
->type
= MMP_CLK_MIX_TYPE_V3
;
493 mix
->type
= MMP_CLK_MIX_TYPE_V2
;
494 clk
= clk_register(dev
, &mix
->hw
);
497 kfree(mix
->mux_table
);
506 return ERR_PTR(-ENOMEM
);