Lines Matching +full:clock +full:- +full:div
1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
7 * Adjustable divider clock implementation
10 #include <linux/clk-provider.h>
19 * DOC: basic adjustable divider clock that cannot gate
21 * Traits of this clock:
22 * prepare - clk_prepare only ensures that parents are prepared
23 * enable - clk_enable only ensures that parents are enabled
24 * rate - rate is adjustable. clk->rate = ceiling(parent->rate / divisor)
25 * parent - fixed parent. No clk_set_parent support
30 if (divider->flags & CLK_DIVIDER_BIG_ENDIAN) in clk_div_readl()
31 return ioread32be(divider->reg); in clk_div_readl()
33 return readl(divider->reg); in clk_div_readl()
38 if (divider->flags & CLK_DIVIDER_BIG_ENDIAN) in clk_div_writel()
39 iowrite32be(val, divider->reg); in clk_div_writel()
41 writel(val, divider->reg); in clk_div_writel()
50 for (clkt = table; clkt->div; clkt++) in _get_table_maxdiv()
51 if (clkt->div > maxdiv && clkt->val <= mask) in _get_table_maxdiv()
52 maxdiv = clkt->div; in _get_table_maxdiv()
61 for (clkt = table; clkt->div; clkt++) in _get_table_mindiv()
62 if (clkt->div < mindiv) in _get_table_mindiv()
63 mindiv = clkt->div; in _get_table_mindiv()
84 for (clkt = table; clkt->div; clkt++) in _get_table_div()
85 if (clkt->val == val) in _get_table_div()
86 return clkt->div; in _get_table_div()
105 unsigned int div) in _get_table_val() argument
109 for (clkt = table; clkt->div; clkt++) in _get_table_val()
110 if (clkt->div == div) in _get_table_val()
111 return clkt->val; in _get_table_val()
116 unsigned int div, unsigned long flags, u8 width) in _get_val() argument
119 return div; in _get_val()
121 return __ffs(div); in _get_val()
123 return (div == clk_div_mask(width) + 1) ? 0 : div; in _get_val()
125 return _get_table_val(table, div); in _get_val()
126 return div - 1; in _get_val()
134 unsigned int div; in divider_recalc_rate() local
136 div = _get_div(table, val, flags, width); in divider_recalc_rate()
137 if (!div) { in divider_recalc_rate()
144 return DIV_ROUND_UP_ULL((u64)parent_rate, div); in divider_recalc_rate()
154 val = clk_div_readl(divider) >> divider->shift; in clk_divider_recalc_rate()
155 val &= clk_div_mask(divider->width); in clk_divider_recalc_rate()
157 return divider_recalc_rate(hw, parent_rate, val, divider->table, in clk_divider_recalc_rate()
158 divider->flags, divider->width); in clk_divider_recalc_rate()
162 unsigned int div) in _is_valid_table_div() argument
166 for (clkt = table; clkt->div; clkt++) in _is_valid_table_div()
167 if (clkt->div == div) in _is_valid_table_div()
172 static bool _is_valid_div(const struct clk_div_table *table, unsigned int div, in _is_valid_div() argument
176 return is_power_of_2(div); in _is_valid_div()
178 return _is_valid_table_div(table, div); in _is_valid_div()
182 static int _round_up_table(const struct clk_div_table *table, int div) in _round_up_table() argument
187 for (clkt = table; clkt->div; clkt++) { in _round_up_table()
188 if (clkt->div == div) in _round_up_table()
189 return clkt->div; in _round_up_table()
190 else if (clkt->div < div) in _round_up_table()
193 if ((clkt->div - div) < (up - div)) in _round_up_table()
194 up = clkt->div; in _round_up_table()
200 static int _round_down_table(const struct clk_div_table *table, int div) in _round_down_table() argument
205 for (clkt = table; clkt->div; clkt++) { in _round_down_table()
206 if (clkt->div == div) in _round_down_table()
207 return clkt->div; in _round_down_table()
208 else if (clkt->div > div) in _round_down_table()
211 if ((div - clkt->div) < (div - down)) in _round_down_table()
212 down = clkt->div; in _round_down_table()
222 int div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); in _div_round_up() local
225 div = __roundup_pow_of_two(div); in _div_round_up()
227 div = _round_up_table(table, div); in _div_round_up()
229 return div; in _div_round_up()
253 return (rate - up_rate) <= (down_rate - rate) ? up : down; in _div_round_closest()
270 return abs(rate - now) < abs(rate - best); in _is_best_div()
275 static int _next_div(const struct clk_div_table *table, int div, in _next_div() argument
278 div++; in _next_div()
281 return __roundup_pow_of_two(div); in _next_div()
283 return _round_up_table(table, div); in _next_div()
285 return div; in _next_div()
322 * divided from parent clock without needing to change in clk_divider_bestdiv()
350 int div; in divider_round_rate_parent() local
352 div = clk_divider_bestdiv(hw, parent, rate, prate, table, width, flags); in divider_round_rate_parent()
354 return DIV_ROUND_UP_ULL((u64)*prate, div); in divider_round_rate_parent()
363 int div; in divider_ro_round_rate_parent() local
365 div = _get_div(table, val, flags, width); in divider_ro_round_rate_parent()
367 /* Even a read-only clock can propagate a rate change */ in divider_ro_round_rate_parent()
370 return -EINVAL; in divider_ro_round_rate_parent()
372 *prate = clk_hw_round_rate(parent, rate * div); in divider_ro_round_rate_parent()
375 return DIV_ROUND_UP_ULL((u64)*prate, div); in divider_ro_round_rate_parent()
386 if (divider->flags & CLK_DIVIDER_READ_ONLY) { in clk_divider_round_rate()
389 val = clk_div_readl(divider) >> divider->shift; in clk_divider_round_rate()
390 val &= clk_div_mask(divider->width); in clk_divider_round_rate()
392 return divider_ro_round_rate(hw, rate, prate, divider->table, in clk_divider_round_rate()
393 divider->width, divider->flags, in clk_divider_round_rate()
397 return divider_round_rate(hw, rate, prate, divider->table, in clk_divider_round_rate()
398 divider->width, divider->flags); in clk_divider_round_rate()
405 unsigned int div, value; in divider_get_val() local
407 div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); in divider_get_val()
409 if (!_is_valid_div(table, div, flags)) in divider_get_val()
410 return -EINVAL; in divider_get_val()
412 value = _get_val(table, div, flags, width); in divider_get_val()
426 value = divider_get_val(rate, parent_rate, divider->table, in clk_divider_set_rate()
427 divider->width, divider->flags); in clk_divider_set_rate()
431 if (divider->lock) in clk_divider_set_rate()
432 spin_lock_irqsave(divider->lock, flags); in clk_divider_set_rate()
434 __acquire(divider->lock); in clk_divider_set_rate()
436 if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { in clk_divider_set_rate()
437 val = clk_div_mask(divider->width) << (divider->shift + 16); in clk_divider_set_rate()
440 val &= ~(clk_div_mask(divider->width) << divider->shift); in clk_divider_set_rate()
442 val |= (u32)value << divider->shift; in clk_divider_set_rate()
445 if (divider->lock) in clk_divider_set_rate()
446 spin_unlock_irqrestore(divider->lock, flags); in clk_divider_set_rate()
448 __release(divider->lock); in clk_divider_set_rate()
473 struct clk_divider *div; in __clk_hw_register_divider() local
481 return ERR_PTR(-EINVAL); in __clk_hw_register_divider()
486 div = kzalloc(sizeof(*div), GFP_KERNEL); in __clk_hw_register_divider()
487 if (!div) in __clk_hw_register_divider()
488 return ERR_PTR(-ENOMEM); in __clk_hw_register_divider()
500 div->reg = reg; in __clk_hw_register_divider()
501 div->shift = shift; in __clk_hw_register_divider()
502 div->width = width; in __clk_hw_register_divider()
503 div->flags = clk_divider_flags; in __clk_hw_register_divider()
504 div->lock = lock; in __clk_hw_register_divider()
505 div->hw.init = &init; in __clk_hw_register_divider()
506 div->table = table; in __clk_hw_register_divider()
508 /* register the clock */ in __clk_hw_register_divider()
509 hw = &div->hw; in __clk_hw_register_divider()
512 kfree(div); in __clk_hw_register_divider()
521 * clk_register_divider_table - register a table based divider clock with
522 * the clock framework
523 * @dev: device registering this clock
524 * @name: name of this clock
525 * @parent_name: name of clock's parent
526 * @flags: framework-specific flags
530 * @clk_divider_flags: divider-specific flags for this clock
531 * @table: array of divider/value pairs ending with a div set to 0
532 * @lock: shared register lock for this clock
547 return hw->clk; in clk_register_divider_table()
553 struct clk_divider *div; in clk_unregister_divider() local
560 div = to_clk_divider(hw); in clk_unregister_divider()
563 kfree(div); in clk_unregister_divider()
568 * clk_hw_unregister_divider - unregister a clk divider
569 * @hw: hardware-specific clock data to unregister
573 struct clk_divider *div; in clk_hw_unregister_divider() local
575 div = to_clk_divider(hw); in clk_hw_unregister_divider()
578 kfree(div); in clk_hw_unregister_divider()