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
*parent
, *clk
;
117 unsigned long parent_rate
;
121 for (i
= 0; i
< table_size
; i
++) {
123 parent
= clk_get_parent_by_index(clk
, item
->parent_index
);
124 parent_rate
= __clk_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_get_name(mix
->hw
.clk
));
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
*parent
, *parent_best
, *mix_clk
;
210 unsigned long parent_rate
, mix_rate
, mix_rate_best
, parent_rate_best
;
211 unsigned long gap
, gap_best
;
220 parent_rate_best
= 0;
221 gap_best
= ULONG_MAX
;
225 for (i
= 0; i
< mix
->table_size
; i
++) {
226 item
= &mix
->table
[i
];
227 if (item
->valid
== 0)
229 parent
= clk_get_parent_by_index(mix_clk
,
231 parent_rate
= __clk_get_rate(parent
);
232 mix_rate
= parent_rate
/ item
->divisor
;
233 gap
= abs(mix_rate
- req
->rate
);
234 if (parent_best
== NULL
|| gap
< gap_best
) {
235 parent_best
= parent
;
236 parent_rate_best
= parent_rate
;
237 mix_rate_best
= mix_rate
;
244 for (i
= 0; i
< clk_hw_get_num_parents(hw
); i
++) {
245 parent
= clk_get_parent_by_index(mix_clk
, i
);
246 parent_rate
= __clk_get_rate(parent
);
247 div_val_max
= _get_maxdiv(mix
);
248 for (j
= 0; j
< div_val_max
; j
++) {
249 div
= _get_div(mix
, j
);
250 mix_rate
= parent_rate
/ div
;
251 gap
= abs(mix_rate
- req
->rate
);
252 if (parent_best
== NULL
|| gap
< gap_best
) {
253 parent_best
= parent
;
254 parent_rate_best
= parent_rate
;
255 mix_rate_best
= mix_rate
;
268 req
->best_parent_rate
= parent_rate_best
;
269 req
->best_parent_hw
= __clk_get_hw(parent_best
);
270 req
->rate
= mix_rate_best
;
275 static int mmp_clk_mix_set_rate_and_parent(struct clk_hw
*hw
,
277 unsigned long parent_rate
,
280 struct mmp_clk_mix
*mix
= to_clk_mix(hw
);
282 u32 div_val
, mux_val
;
284 div
= parent_rate
/ rate
;
285 div_val
= _get_div_val(mix
, div
);
286 mux_val
= _get_mux_val(mix
, index
);
288 return _set_rate(mix
, mux_val
, div_val
, 1, 1);
291 static u8
mmp_clk_mix_get_parent(struct clk_hw
*hw
)
293 struct mmp_clk_mix
*mix
= to_clk_mix(hw
);
294 struct mmp_clk_mix_reg_info
*ri
= &mix
->reg_info
;
295 unsigned long flags
= 0;
301 spin_lock_irqsave(mix
->lock
, flags
);
303 if (mix
->type
== MMP_CLK_MIX_TYPE_V1
304 || mix
->type
== MMP_CLK_MIX_TYPE_V2
)
305 mux_div
= readl(ri
->reg_clk_ctrl
);
307 mux_div
= readl(ri
->reg_clk_sel
);
310 spin_unlock_irqrestore(mix
->lock
, flags
);
312 width
= mix
->reg_info
.width_mux
;
313 shift
= mix
->reg_info
.shift_mux
;
315 mux_val
= MMP_CLK_BITS_GET_VAL(mux_div
, width
, shift
);
317 return _get_mux(mix
, mux_val
);
320 static unsigned long mmp_clk_mix_recalc_rate(struct clk_hw
*hw
,
321 unsigned long parent_rate
)
323 struct mmp_clk_mix
*mix
= to_clk_mix(hw
);
324 struct mmp_clk_mix_reg_info
*ri
= &mix
->reg_info
;
325 unsigned long flags
= 0;
331 spin_lock_irqsave(mix
->lock
, flags
);
333 if (mix
->type
== MMP_CLK_MIX_TYPE_V1
334 || mix
->type
== MMP_CLK_MIX_TYPE_V2
)
335 mux_div
= readl(ri
->reg_clk_ctrl
);
337 mux_div
= readl(ri
->reg_clk_sel
);
340 spin_unlock_irqrestore(mix
->lock
, flags
);
342 width
= mix
->reg_info
.width_div
;
343 shift
= mix
->reg_info
.shift_div
;
345 div
= _get_div(mix
, MMP_CLK_BITS_GET_VAL(mux_div
, width
, shift
));
347 return parent_rate
/ div
;
350 static int mmp_clk_set_parent(struct clk_hw
*hw
, u8 index
)
352 struct mmp_clk_mix
*mix
= to_clk_mix(hw
);
353 struct mmp_clk_mix_clk_table
*item
;
355 u32 div_val
, mux_val
;
358 for (i
= 0; i
< mix
->table_size
; i
++) {
359 item
= &mix
->table
[i
];
360 if (item
->valid
== 0)
362 if (item
->parent_index
== index
)
365 if (i
< mix
->table_size
) {
366 div_val
= _get_div_val(mix
, item
->divisor
);
367 mux_val
= _get_mux_val(mix
, item
->parent_index
);
371 mux_val
= _get_mux_val(mix
, index
);
375 return _set_rate(mix
, mux_val
, div_val
, 1, div_val
? 1 : 0);
378 static int mmp_clk_set_rate(struct clk_hw
*hw
, unsigned long rate
,
379 unsigned long best_parent_rate
)
381 struct mmp_clk_mix
*mix
= to_clk_mix(hw
);
382 struct mmp_clk_mix_clk_table
*item
;
383 unsigned long parent_rate
;
384 unsigned int best_divisor
;
385 struct clk
*mix_clk
, *parent
;
388 best_divisor
= best_parent_rate
/ rate
;
392 for (i
= 0; i
< mix
->table_size
; i
++) {
393 item
= &mix
->table
[i
];
394 if (item
->valid
== 0)
396 parent
= clk_get_parent_by_index(mix_clk
,
398 parent_rate
= __clk_get_rate(parent
);
399 if (parent_rate
== best_parent_rate
400 && item
->divisor
== best_divisor
)
403 if (i
< mix
->table_size
)
404 return _set_rate(mix
,
405 _get_mux_val(mix
, item
->parent_index
),
406 _get_div_val(mix
, item
->divisor
),
411 for (i
= 0; i
< clk_hw_get_num_parents(hw
); i
++) {
412 parent
= clk_get_parent_by_index(mix_clk
, i
);
413 parent_rate
= __clk_get_rate(parent
);
414 if (parent_rate
== best_parent_rate
)
417 if (i
< clk_hw_get_num_parents(hw
))
418 return _set_rate(mix
, _get_mux_val(mix
, i
),
419 _get_div_val(mix
, best_divisor
), 1, 1);
425 static void mmp_clk_mix_init(struct clk_hw
*hw
)
427 struct mmp_clk_mix
*mix
= to_clk_mix(hw
);
430 _filter_clk_table(mix
, mix
->table
, mix
->table_size
);
433 const struct clk_ops mmp_clk_mix_ops
= {
434 .determine_rate
= mmp_clk_mix_determine_rate
,
435 .set_rate_and_parent
= mmp_clk_mix_set_rate_and_parent
,
436 .set_rate
= mmp_clk_set_rate
,
437 .set_parent
= mmp_clk_set_parent
,
438 .get_parent
= mmp_clk_mix_get_parent
,
439 .recalc_rate
= mmp_clk_mix_recalc_rate
,
440 .init
= mmp_clk_mix_init
,
443 struct clk
*mmp_clk_register_mix(struct device
*dev
,
445 const char **parent_names
,
448 struct mmp_clk_mix_config
*config
,
451 struct mmp_clk_mix
*mix
;
453 struct clk_init_data init
;
456 mix
= kzalloc(sizeof(*mix
), GFP_KERNEL
);
458 pr_err("%s:%s: could not allocate mmp mix clk\n",
460 return ERR_PTR(-ENOMEM
);
464 init
.flags
= flags
| CLK_GET_RATE_NOCACHE
;
465 init
.parent_names
= parent_names
;
466 init
.num_parents
= num_parents
;
467 init
.ops
= &mmp_clk_mix_ops
;
469 memcpy(&mix
->reg_info
, &config
->reg_info
, sizeof(config
->reg_info
));
471 table_bytes
= sizeof(*config
->table
) * config
->table_size
;
472 mix
->table
= kmemdup(config
->table
, table_bytes
, GFP_KERNEL
);
474 pr_err("%s:%s: could not allocate mmp mix table\n",
477 return ERR_PTR(-ENOMEM
);
479 mix
->table_size
= config
->table_size
;
482 if (config
->mux_table
) {
483 table_bytes
= sizeof(u32
) * num_parents
;
484 mix
->mux_table
= kmemdup(config
->mux_table
, table_bytes
,
486 if (!mix
->mux_table
) {
487 pr_err("%s:%s: could not allocate mmp mix mux-table\n",
491 return ERR_PTR(-ENOMEM
);
495 mix
->div_flags
= config
->div_flags
;
496 mix
->mux_flags
= config
->mux_flags
;
498 mix
->hw
.init
= &init
;
500 if (config
->reg_info
.bit_fc
>= 32)
501 mix
->type
= MMP_CLK_MIX_TYPE_V1
;
502 else if (config
->reg_info
.reg_clk_sel
)
503 mix
->type
= MMP_CLK_MIX_TYPE_V3
;
505 mix
->type
= MMP_CLK_MIX_TYPE_V2
;
506 clk
= clk_register(dev
, &mix
->hw
);
509 kfree(mix
->mux_table
);