Lines Matching +full:mix +full:-

1 // SPDX-License-Identifier: GPL-2.0-only
3 * mmp mix(div and mux) clock operation source file
9 #include <linux/clk-provider.h>
17 * The mix clock is a clock combined mux and div type clock.
24 static unsigned int _get_maxdiv(struct mmp_clk_mix *mix) in _get_maxdiv() argument
26 unsigned int div_mask = (1 << mix->reg_info.width_div) - 1; in _get_maxdiv()
30 if (mix->div_flags & CLK_DIVIDER_ONE_BASED) in _get_maxdiv()
32 if (mix->div_flags & CLK_DIVIDER_POWER_OF_TWO) in _get_maxdiv()
34 if (mix->div_table) { in _get_maxdiv()
35 for (clkt = mix->div_table; clkt->div; clkt++) in _get_maxdiv()
36 if (clkt->div > maxdiv) in _get_maxdiv()
37 maxdiv = clkt->div; in _get_maxdiv()
43 static unsigned int _get_div(struct mmp_clk_mix *mix, unsigned int val) in _get_div() argument
47 if (mix->div_flags & CLK_DIVIDER_ONE_BASED) in _get_div()
49 if (mix->div_flags & CLK_DIVIDER_POWER_OF_TWO) in _get_div()
51 if (mix->div_table) { in _get_div()
52 for (clkt = mix->div_table; clkt->div; clkt++) in _get_div()
53 if (clkt->val == val) in _get_div()
54 return clkt->div; in _get_div()
55 if (clkt->div == 0) in _get_div()
61 static unsigned int _get_mux(struct mmp_clk_mix *mix, unsigned int val) in _get_mux() argument
63 int num_parents = clk_hw_get_num_parents(&mix->hw); in _get_mux()
66 if (mix->mux_flags & CLK_MUX_INDEX_BIT) in _get_mux()
67 return ffs(val) - 1; in _get_mux()
68 if (mix->mux_flags & CLK_MUX_INDEX_ONE) in _get_mux()
69 return val - 1; in _get_mux()
70 if (mix->mux_table) { in _get_mux()
72 if (mix->mux_table[i] == val) in _get_mux()
80 static unsigned int _get_div_val(struct mmp_clk_mix *mix, unsigned int div) in _get_div_val() argument
84 if (mix->div_flags & CLK_DIVIDER_ONE_BASED) in _get_div_val()
86 if (mix->div_flags & CLK_DIVIDER_POWER_OF_TWO) in _get_div_val()
88 if (mix->div_table) { in _get_div_val()
89 for (clkt = mix->div_table; clkt->div; clkt++) in _get_div_val()
90 if (clkt->div == div) in _get_div_val()
91 return clkt->val; in _get_div_val()
92 if (clkt->div == 0) in _get_div_val()
96 return div - 1; in _get_div_val()
99 static unsigned int _get_mux_val(struct mmp_clk_mix *mix, unsigned int mux) in _get_mux_val() argument
101 if (mix->mux_table) in _get_mux_val()
102 return mix->mux_table[mux]; in _get_mux_val()
107 static void _filter_clk_table(struct mmp_clk_mix *mix, in _filter_clk_table() argument
116 hw = &mix->hw; in _filter_clk_table()
120 parent = clk_hw_get_parent_by_index(hw, item->parent_index); in _filter_clk_table()
122 if (parent_rate % item->rate) { in _filter_clk_table()
123 item->valid = 0; in _filter_clk_table()
125 item->divisor = parent_rate / item->rate; in _filter_clk_table()
126 item->valid = 1; in _filter_clk_table()
131 static int _set_rate(struct mmp_clk_mix *mix, u32 mux_val, u32 div_val, in _set_rate() argument
134 struct mmp_clk_mix_reg_info *ri = &mix->reg_info; in _set_rate()
141 return -EINVAL; in _set_rate()
143 if (mix->lock) in _set_rate()
144 spin_lock_irqsave(mix->lock, flags); in _set_rate()
146 if (mix->type == MMP_CLK_MIX_TYPE_V1 in _set_rate()
147 || mix->type == MMP_CLK_MIX_TYPE_V2) in _set_rate()
148 mux_div = readl(ri->reg_clk_ctrl); in _set_rate()
150 mux_div = readl(ri->reg_clk_sel); in _set_rate()
153 width = ri->width_div; in _set_rate()
154 shift = ri->shift_div; in _set_rate()
160 width = ri->width_mux; in _set_rate()
161 shift = ri->shift_mux; in _set_rate()
166 if (mix->type == MMP_CLK_MIX_TYPE_V1) { in _set_rate()
167 writel(mux_div, ri->reg_clk_ctrl); in _set_rate()
168 } else if (mix->type == MMP_CLK_MIX_TYPE_V2) { in _set_rate()
169 mux_div |= (1 << ri->bit_fc); in _set_rate()
170 writel(mux_div, ri->reg_clk_ctrl); in _set_rate()
173 fc_req = readl(ri->reg_clk_ctrl); in _set_rate()
174 timeout--; in _set_rate()
175 if (!(fc_req & (1 << ri->bit_fc))) in _set_rate()
181 __func__, clk_hw_get_name(&mix->hw)); in _set_rate()
182 ret = -EBUSY; in _set_rate()
186 fc_req = readl(ri->reg_clk_ctrl); in _set_rate()
187 fc_req |= 1 << ri->bit_fc; in _set_rate()
188 writel(fc_req, ri->reg_clk_ctrl); in _set_rate()
189 writel(mux_div, ri->reg_clk_sel); in _set_rate()
190 fc_req &= ~(1 << ri->bit_fc); in _set_rate()
195 if (mix->lock) in _set_rate()
196 spin_unlock_irqrestore(mix->lock, flags); in _set_rate()
204 struct mmp_clk_mix *mix = to_clk_mix(hw); in mmp_clk_mix_determine_rate() local
219 if (mix->table) { in mmp_clk_mix_determine_rate()
220 for (i = 0; i < mix->table_size; i++) { in mmp_clk_mix_determine_rate()
221 item = &mix->table[i]; in mmp_clk_mix_determine_rate()
222 if (item->valid == 0) in mmp_clk_mix_determine_rate()
225 item->parent_index); in mmp_clk_mix_determine_rate()
227 mix_rate = parent_rate / item->divisor; in mmp_clk_mix_determine_rate()
228 gap = abs(mix_rate - req->rate); in mmp_clk_mix_determine_rate()
242 div_val_max = _get_maxdiv(mix); in mmp_clk_mix_determine_rate()
244 div = _get_div(mix, j); in mmp_clk_mix_determine_rate()
246 gap = abs(mix_rate - req->rate); in mmp_clk_mix_determine_rate()
261 return -EINVAL; in mmp_clk_mix_determine_rate()
263 req->best_parent_rate = parent_rate_best; in mmp_clk_mix_determine_rate()
264 req->best_parent_hw = parent_best; in mmp_clk_mix_determine_rate()
265 req->rate = mix_rate_best; in mmp_clk_mix_determine_rate()
275 struct mmp_clk_mix *mix = to_clk_mix(hw); in mmp_clk_mix_set_rate_and_parent() local
280 div_val = _get_div_val(mix, div); in mmp_clk_mix_set_rate_and_parent()
281 mux_val = _get_mux_val(mix, index); in mmp_clk_mix_set_rate_and_parent()
283 return _set_rate(mix, mux_val, div_val, 1, 1); in mmp_clk_mix_set_rate_and_parent()
288 struct mmp_clk_mix *mix = to_clk_mix(hw); in mmp_clk_mix_get_parent() local
289 struct mmp_clk_mix_reg_info *ri = &mix->reg_info; in mmp_clk_mix_get_parent()
295 if (mix->lock) in mmp_clk_mix_get_parent()
296 spin_lock_irqsave(mix->lock, flags); in mmp_clk_mix_get_parent()
298 if (mix->type == MMP_CLK_MIX_TYPE_V1 in mmp_clk_mix_get_parent()
299 || mix->type == MMP_CLK_MIX_TYPE_V2) in mmp_clk_mix_get_parent()
300 mux_div = readl(ri->reg_clk_ctrl); in mmp_clk_mix_get_parent()
302 mux_div = readl(ri->reg_clk_sel); in mmp_clk_mix_get_parent()
304 if (mix->lock) in mmp_clk_mix_get_parent()
305 spin_unlock_irqrestore(mix->lock, flags); in mmp_clk_mix_get_parent()
307 width = mix->reg_info.width_mux; in mmp_clk_mix_get_parent()
308 shift = mix->reg_info.shift_mux; in mmp_clk_mix_get_parent()
312 return _get_mux(mix, mux_val); in mmp_clk_mix_get_parent()
318 struct mmp_clk_mix *mix = to_clk_mix(hw); in mmp_clk_mix_recalc_rate() local
319 struct mmp_clk_mix_reg_info *ri = &mix->reg_info; in mmp_clk_mix_recalc_rate()
325 if (mix->lock) in mmp_clk_mix_recalc_rate()
326 spin_lock_irqsave(mix->lock, flags); in mmp_clk_mix_recalc_rate()
328 if (mix->type == MMP_CLK_MIX_TYPE_V1 in mmp_clk_mix_recalc_rate()
329 || mix->type == MMP_CLK_MIX_TYPE_V2) in mmp_clk_mix_recalc_rate()
330 mux_div = readl(ri->reg_clk_ctrl); in mmp_clk_mix_recalc_rate()
332 mux_div = readl(ri->reg_clk_sel); in mmp_clk_mix_recalc_rate()
334 if (mix->lock) in mmp_clk_mix_recalc_rate()
335 spin_unlock_irqrestore(mix->lock, flags); in mmp_clk_mix_recalc_rate()
337 width = mix->reg_info.width_div; in mmp_clk_mix_recalc_rate()
338 shift = mix->reg_info.shift_div; in mmp_clk_mix_recalc_rate()
340 div = _get_div(mix, MMP_CLK_BITS_GET_VAL(mux_div, width, shift)); in mmp_clk_mix_recalc_rate()
347 struct mmp_clk_mix *mix = to_clk_mix(hw); in mmp_clk_set_parent() local
352 if (mix->table) { in mmp_clk_set_parent()
353 for (i = 0; i < mix->table_size; i++) { in mmp_clk_set_parent()
354 item = &mix->table[i]; in mmp_clk_set_parent()
355 if (item->valid == 0) in mmp_clk_set_parent()
357 if (item->parent_index == index) in mmp_clk_set_parent()
360 if (i < mix->table_size) { in mmp_clk_set_parent()
361 div_val = _get_div_val(mix, item->divisor); in mmp_clk_set_parent()
362 mux_val = _get_mux_val(mix, item->parent_index); in mmp_clk_set_parent()
364 return -EINVAL; in mmp_clk_set_parent()
366 mux_val = _get_mux_val(mix, index); in mmp_clk_set_parent()
370 return _set_rate(mix, mux_val, div_val, 1, div_val ? 1 : 0); in mmp_clk_set_parent()
376 struct mmp_clk_mix *mix = to_clk_mix(hw); in mmp_clk_set_rate() local
385 if (mix->table) { in mmp_clk_set_rate()
386 for (i = 0; i < mix->table_size; i++) { in mmp_clk_set_rate()
387 item = &mix->table[i]; in mmp_clk_set_rate()
388 if (item->valid == 0) in mmp_clk_set_rate()
391 item->parent_index); in mmp_clk_set_rate()
394 && item->divisor == best_divisor) in mmp_clk_set_rate()
397 if (i < mix->table_size) in mmp_clk_set_rate()
398 return _set_rate(mix, in mmp_clk_set_rate()
399 _get_mux_val(mix, item->parent_index), in mmp_clk_set_rate()
400 _get_div_val(mix, item->divisor), in mmp_clk_set_rate()
403 return -EINVAL; in mmp_clk_set_rate()
412 return _set_rate(mix, _get_mux_val(mix, i), in mmp_clk_set_rate()
413 _get_div_val(mix, best_divisor), 1, 1); in mmp_clk_set_rate()
415 return -EINVAL; in mmp_clk_set_rate()
421 struct mmp_clk_mix *mix = to_clk_mix(hw); in mmp_clk_mix_init() local
423 if (mix->table) in mmp_clk_mix_init()
424 _filter_clk_table(mix, mix->table, mix->table_size); in mmp_clk_mix_init()
447 struct mmp_clk_mix *mix; in mmp_clk_register_mix() local
451 mix = kzalloc(sizeof(*mix), GFP_KERNEL); in mmp_clk_register_mix()
452 if (!mix) in mmp_clk_register_mix()
453 return ERR_PTR(-ENOMEM); in mmp_clk_register_mix()
461 memcpy(&mix->reg_info, &config->reg_info, sizeof(config->reg_info)); in mmp_clk_register_mix()
462 if (config->table) { in mmp_clk_register_mix()
463 mix->table = kmemdup_array(config->table, config->table_size, in mmp_clk_register_mix()
464 sizeof(*mix->table), GFP_KERNEL); in mmp_clk_register_mix()
465 if (!mix->table) in mmp_clk_register_mix()
468 mix->table_size = config->table_size; in mmp_clk_register_mix()
471 if (config->mux_table) { in mmp_clk_register_mix()
472 mix->mux_table = kmemdup_array(config->mux_table, num_parents, in mmp_clk_register_mix()
473 sizeof(*mix->mux_table), GFP_KERNEL); in mmp_clk_register_mix()
474 if (!mix->mux_table) { in mmp_clk_register_mix()
475 kfree(mix->table); in mmp_clk_register_mix()
480 mix->div_flags = config->div_flags; in mmp_clk_register_mix()
481 mix->mux_flags = config->mux_flags; in mmp_clk_register_mix()
482 mix->lock = lock; in mmp_clk_register_mix()
483 mix->hw.init = &init; in mmp_clk_register_mix()
485 if (config->reg_info.bit_fc >= 32) in mmp_clk_register_mix()
486 mix->type = MMP_CLK_MIX_TYPE_V1; in mmp_clk_register_mix()
487 else if (config->reg_info.reg_clk_sel) in mmp_clk_register_mix()
488 mix->type = MMP_CLK_MIX_TYPE_V3; in mmp_clk_register_mix()
490 mix->type = MMP_CLK_MIX_TYPE_V2; in mmp_clk_register_mix()
491 clk = clk_register(dev, &mix->hw); in mmp_clk_register_mix()
494 kfree(mix->mux_table); in mmp_clk_register_mix()
495 kfree(mix->table); in mmp_clk_register_mix()
496 kfree(mix); in mmp_clk_register_mix()
502 kfree(mix); in mmp_clk_register_mix()
503 return ERR_PTR(-ENOMEM); in mmp_clk_register_mix()