Lines Matching +full:divider +full:- +full:clock
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>
20 * DOC: basic adjustable divider clock that cannot gate
22 * Traits of this clock:
23 * prepare - clk_prepare only ensures that parents are prepared
24 * enable - clk_enable only ensures that parents are enabled
25 * rate - rate is adjustable. clk->rate = ceiling(parent->rate / divisor)
26 * parent - fixed parent. No clk_set_parent support
29 static inline u32 clk_div_readl(struct clk_divider *divider) in clk_div_readl() argument
31 if (divider->flags & CLK_DIVIDER_BIG_ENDIAN) in clk_div_readl()
32 return ioread32be(divider->reg); in clk_div_readl()
34 return readl(divider->reg); in clk_div_readl()
37 static inline void clk_div_writel(struct clk_divider *divider, u32 val) in clk_div_writel() argument
39 if (divider->flags & CLK_DIVIDER_BIG_ENDIAN) in clk_div_writel()
40 iowrite32be(val, divider->reg); in clk_div_writel()
42 writel(val, divider->reg); in clk_div_writel()
51 for (clkt = table; clkt->div; clkt++) in _get_table_maxdiv()
52 if (clkt->div > maxdiv && clkt->val <= mask) in _get_table_maxdiv()
53 maxdiv = clkt->div; in _get_table_maxdiv()
62 for (clkt = table; clkt->div; clkt++) in _get_table_mindiv()
63 if (clkt->div < mindiv) in _get_table_mindiv()
64 mindiv = clkt->div; in _get_table_mindiv()
87 for (clkt = table; clkt->div; clkt++) in _get_table_div()
88 if (clkt->val == val) in _get_table_div()
89 return clkt->div; in _get_table_div()
114 for (clkt = table; clkt->div; clkt++) in _get_table_val()
115 if (clkt->div == div) in _get_table_val()
116 return clkt->val; in _get_table_val()
130 return (div >> 1) - 1; in _get_val()
133 return div - 1; in _get_val()
158 struct clk_divider *divider = to_clk_divider(hw); in clk_divider_recalc_rate() local
161 val = clk_div_readl(divider) >> divider->shift; in clk_divider_recalc_rate()
162 val &= clk_div_mask(divider->width); in clk_divider_recalc_rate()
164 return divider_recalc_rate(hw, parent_rate, val, divider->table, in clk_divider_recalc_rate()
165 divider->flags, divider->width); in clk_divider_recalc_rate()
173 for (clkt = table; clkt->div; clkt++) in _is_valid_table_div()
174 if (clkt->div == div) in _is_valid_table_div()
194 for (clkt = table; clkt->div; clkt++) { in _round_up_table()
195 if (clkt->div == div) in _round_up_table()
196 return clkt->div; in _round_up_table()
197 else if (clkt->div < div) in _round_up_table()
200 if ((clkt->div - div) < (up - div)) in _round_up_table()
201 up = clkt->div; in _round_up_table()
212 for (clkt = table; clkt->div; clkt++) { in _round_down_table()
213 if (clkt->div == div) in _round_down_table()
214 return clkt->div; in _round_down_table()
215 else if (clkt->div > div) in _round_down_table()
218 if ((div - clkt->div) < (div - down)) in _round_down_table()
219 down = clkt->div; in _round_down_table()
260 return (rate - up_rate) <= (down_rate - rate) ? up : down; in _div_round_closest()
277 return abs(rate - now) < abs(rate - best); in _is_best_div()
319 * The maximum divider we can use without overflowing in clk_divider_bestdiv()
329 * divided from parent clock without needing to change in clk_divider_bestdiv()
330 * parent rate, so return the divider immediately. in clk_divider_bestdiv()
358 div = clk_divider_bestdiv(hw, req->best_parent_hw, req->rate, in divider_determine_rate()
359 &req->best_parent_rate, table, width, flags); in divider_determine_rate()
361 req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div); in divider_determine_rate()
375 /* Even a read-only clock can propagate a rate change */ in divider_ro_determine_rate()
377 if (!req->best_parent_hw) in divider_ro_determine_rate()
378 return -EINVAL; in divider_ro_determine_rate()
380 req->best_parent_rate = clk_hw_round_rate(req->best_parent_hw, in divider_ro_determine_rate()
381 req->rate * div); in divider_ro_determine_rate()
384 req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div); in divider_ro_determine_rate()
437 struct clk_divider *divider = to_clk_divider(hw); in clk_divider_round_rate() local
440 if (divider->flags & CLK_DIVIDER_READ_ONLY) { in clk_divider_round_rate()
443 val = clk_div_readl(divider) >> divider->shift; in clk_divider_round_rate()
444 val &= clk_div_mask(divider->width); in clk_divider_round_rate()
446 return divider_ro_round_rate(hw, rate, prate, divider->table, in clk_divider_round_rate()
447 divider->width, divider->flags, in clk_divider_round_rate()
451 return divider_round_rate(hw, rate, prate, divider->table, in clk_divider_round_rate()
452 divider->width, divider->flags); in clk_divider_round_rate()
458 struct clk_divider *divider = to_clk_divider(hw); in clk_divider_determine_rate() local
461 if (divider->flags & CLK_DIVIDER_READ_ONLY) { in clk_divider_determine_rate()
464 val = clk_div_readl(divider) >> divider->shift; in clk_divider_determine_rate()
465 val &= clk_div_mask(divider->width); in clk_divider_determine_rate()
467 return divider_ro_determine_rate(hw, req, divider->table, in clk_divider_determine_rate()
468 divider->width, in clk_divider_determine_rate()
469 divider->flags, val); in clk_divider_determine_rate()
472 return divider_determine_rate(hw, req, divider->table, divider->width, in clk_divider_determine_rate()
473 divider->flags); in clk_divider_determine_rate()
485 return -EINVAL; in divider_get_val()
496 struct clk_divider *divider = to_clk_divider(hw); in clk_divider_set_rate() local
501 value = divider_get_val(rate, parent_rate, divider->table, in clk_divider_set_rate()
502 divider->width, divider->flags); in clk_divider_set_rate()
506 if (divider->lock) in clk_divider_set_rate()
507 spin_lock_irqsave(divider->lock, flags); in clk_divider_set_rate()
509 __acquire(divider->lock); in clk_divider_set_rate()
511 if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { in clk_divider_set_rate()
512 val = clk_div_mask(divider->width) << (divider->shift + 16); in clk_divider_set_rate()
514 val = clk_div_readl(divider); in clk_divider_set_rate()
515 val &= ~(clk_div_mask(divider->width) << divider->shift); in clk_divider_set_rate()
517 val |= (u32)value << divider->shift; in clk_divider_set_rate()
518 clk_div_writel(divider, val); in clk_divider_set_rate()
520 if (divider->lock) in clk_divider_set_rate()
521 spin_unlock_irqrestore(divider->lock, flags); in clk_divider_set_rate()
523 __release(divider->lock); in clk_divider_set_rate()
558 pr_warn("divider value exceeds LOWORD field\n"); in __clk_hw_register_divider()
559 return ERR_PTR(-EINVAL); in __clk_hw_register_divider()
563 /* allocate the divider */ in __clk_hw_register_divider()
566 return ERR_PTR(-ENOMEM); in __clk_hw_register_divider()
583 div->reg = reg; in __clk_hw_register_divider()
584 div->shift = shift; in __clk_hw_register_divider()
585 div->width = width; in __clk_hw_register_divider()
586 div->flags = clk_divider_flags; in __clk_hw_register_divider()
587 div->lock = lock; in __clk_hw_register_divider()
588 div->hw.init = &init; in __clk_hw_register_divider()
589 div->table = table; in __clk_hw_register_divider()
591 /* register the clock */ in __clk_hw_register_divider()
592 hw = &div->hw; in __clk_hw_register_divider()
604 * clk_register_divider_table - register a table based divider clock with
605 * the clock framework
606 * @dev: device registering this clock
607 * @name: name of this clock
608 * @parent_name: name of clock's parent
609 * @flags: framework-specific flags
610 * @reg: register address to adjust divider
613 * @clk_divider_flags: divider-specific flags for this clock
614 * @table: array of divider/value pairs ending with a div set to 0
615 * @lock: shared register lock for this clock
630 return hw->clk; in clk_register_divider_table()
651 * clk_hw_unregister_divider - unregister a clk divider
652 * @hw: hardware-specific clock data to unregister
682 return ERR_PTR(-ENOMEM); in __devm_clk_hw_register_divider()