Lines Matching +full:device +full:- +full:width
1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
10 #include <linux/clk-provider.h>
11 #include <linux/device.h>
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
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()
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()
46 u8 width) in _get_table_maxdiv() argument
48 unsigned int maxdiv = 0, mask = clk_div_mask(width); in _get_table_maxdiv()
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()
68 static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width, in _get_maxdiv() argument
72 return clk_div_mask(width); in _get_maxdiv()
74 return 1 << clk_div_mask(width); in _get_maxdiv()
76 return _get_table_maxdiv(table, width); in _get_maxdiv()
77 return clk_div_mask(width) + 1; in _get_maxdiv()
85 for (clkt = table; clkt->div; clkt++) in _get_table_div()
86 if (clkt->val == val) in _get_table_div()
87 return clkt->div; in _get_table_div()
92 unsigned int val, unsigned long flags, u8 width) in _get_div() argument
99 return val ? val : clk_div_mask(width) + 1; in _get_div()
110 for (clkt = table; clkt->div; clkt++) in _get_table_val()
111 if (clkt->div == div) in _get_table_val()
112 return clkt->val; in _get_table_val()
117 unsigned int div, unsigned long flags, u8 width) in _get_val() argument
124 return (div == clk_div_mask(width) + 1) ? 0 : div; in _get_val()
127 return div - 1; in _get_val()
133 unsigned long flags, unsigned long width) in divider_recalc_rate() argument
137 div = _get_div(table, val, flags, width); in divider_recalc_rate()
155 val = clk_div_readl(divider) >> divider->shift; in clk_divider_recalc_rate()
156 val &= clk_div_mask(divider->width); in clk_divider_recalc_rate()
158 return divider_recalc_rate(hw, parent_rate, val, divider->table, in clk_divider_recalc_rate()
159 divider->flags, divider->width); in clk_divider_recalc_rate()
167 for (clkt = table; clkt->div; clkt++) in _is_valid_table_div()
168 if (clkt->div == div) in _is_valid_table_div()
188 for (clkt = table; clkt->div; clkt++) { in _round_up_table()
189 if (clkt->div == div) in _round_up_table()
190 return clkt->div; in _round_up_table()
191 else if (clkt->div < div) in _round_up_table()
194 if ((clkt->div - div) < (up - div)) in _round_up_table()
195 up = clkt->div; in _round_up_table()
206 for (clkt = table; clkt->div; clkt++) { in _round_down_table()
207 if (clkt->div == div) in _round_down_table()
208 return clkt->div; in _round_down_table()
209 else if (clkt->div > div) in _round_down_table()
212 if ((div - clkt->div) < (div - down)) in _round_down_table()
213 down = clkt->div; in _round_down_table()
254 return (rate - up_rate) <= (down_rate - rate) ? up : down; in _div_round_closest()
271 return abs(rate - now) < abs(rate - best); in _is_best_div()
292 const struct clk_div_table *table, u8 width, in clk_divider_bestdiv() argument
302 maxdiv = _get_maxdiv(table, width, flags); in clk_divider_bestdiv()
339 bestdiv = _get_maxdiv(table, width, flags); in clk_divider_bestdiv()
347 const struct clk_div_table *table, u8 width, in divider_determine_rate() argument
352 div = clk_divider_bestdiv(hw, req->best_parent_hw, req->rate, in divider_determine_rate()
353 &req->best_parent_rate, table, width, flags); in divider_determine_rate()
355 req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div); in divider_determine_rate()
362 const struct clk_div_table *table, u8 width, in divider_ro_determine_rate() argument
367 div = _get_div(table, val, flags, width); in divider_ro_determine_rate()
369 /* Even a read-only clock can propagate a rate change */ in divider_ro_determine_rate()
371 if (!req->best_parent_hw) in divider_ro_determine_rate()
372 return -EINVAL; in divider_ro_determine_rate()
374 req->best_parent_rate = clk_hw_round_rate(req->best_parent_hw, in divider_ro_determine_rate()
375 req->rate * div); in divider_ro_determine_rate()
378 req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div); in divider_ro_determine_rate()
387 u8 width, unsigned long flags) in divider_round_rate_parent() argument
396 ret = divider_determine_rate(hw, &req, table, width, flags); in divider_round_rate_parent()
408 const struct clk_div_table *table, u8 width, in divider_ro_round_rate_parent() argument
418 ret = divider_ro_determine_rate(hw, &req, table, width, flags, val); in divider_ro_round_rate_parent()
434 if (divider->flags & CLK_DIVIDER_READ_ONLY) { in clk_divider_round_rate()
437 val = clk_div_readl(divider) >> divider->shift; in clk_divider_round_rate()
438 val &= clk_div_mask(divider->width); in clk_divider_round_rate()
440 return divider_ro_round_rate(hw, rate, prate, divider->table, in clk_divider_round_rate()
441 divider->width, divider->flags, in clk_divider_round_rate()
445 return divider_round_rate(hw, rate, prate, divider->table, in clk_divider_round_rate()
446 divider->width, divider->flags); in clk_divider_round_rate()
455 if (divider->flags & CLK_DIVIDER_READ_ONLY) { in clk_divider_determine_rate()
458 val = clk_div_readl(divider) >> divider->shift; in clk_divider_determine_rate()
459 val &= clk_div_mask(divider->width); in clk_divider_determine_rate()
461 return divider_ro_determine_rate(hw, req, divider->table, in clk_divider_determine_rate()
462 divider->width, in clk_divider_determine_rate()
463 divider->flags, val); in clk_divider_determine_rate()
466 return divider_determine_rate(hw, req, divider->table, divider->width, in clk_divider_determine_rate()
467 divider->flags); in clk_divider_determine_rate()
471 const struct clk_div_table *table, u8 width, in divider_get_val() argument
479 return -EINVAL; in divider_get_val()
481 value = _get_val(table, div, flags, width); in divider_get_val()
483 return min_t(unsigned int, value, clk_div_mask(width)); in divider_get_val()
495 value = divider_get_val(rate, parent_rate, divider->table, in clk_divider_set_rate()
496 divider->width, divider->flags); in clk_divider_set_rate()
500 if (divider->lock) in clk_divider_set_rate()
501 spin_lock_irqsave(divider->lock, flags); in clk_divider_set_rate()
503 __acquire(divider->lock); in clk_divider_set_rate()
505 if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { in clk_divider_set_rate()
506 val = clk_div_mask(divider->width) << (divider->shift + 16); in clk_divider_set_rate()
509 val &= ~(clk_div_mask(divider->width) << divider->shift); in clk_divider_set_rate()
511 val |= (u32)value << divider->shift; in clk_divider_set_rate()
514 if (divider->lock) in clk_divider_set_rate()
515 spin_unlock_irqrestore(divider->lock, flags); in clk_divider_set_rate()
517 __release(divider->lock); in clk_divider_set_rate()
537 struct clk_hw *__clk_hw_register_divider(struct device *dev, in __clk_hw_register_divider()
541 void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, in __clk_hw_register_divider() argument
550 if (width + shift > 16) { in __clk_hw_register_divider()
552 return ERR_PTR(-EINVAL); in __clk_hw_register_divider()
559 return ERR_PTR(-ENOMEM); in __clk_hw_register_divider()
576 div->reg = reg; in __clk_hw_register_divider()
577 div->shift = shift; in __clk_hw_register_divider()
578 div->width = width; in __clk_hw_register_divider()
579 div->flags = clk_divider_flags; in __clk_hw_register_divider()
580 div->lock = lock; in __clk_hw_register_divider()
581 div->hw.init = &init; in __clk_hw_register_divider()
582 div->table = table; in __clk_hw_register_divider()
585 hw = &div->hw; in __clk_hw_register_divider()
597 * clk_register_divider_table - register a table based divider clock with
599 * @dev: device registering this clock
602 * @flags: framework-specific flags
605 * @width: width of the bitfield
606 * @clk_divider_flags: divider-specific flags for this clock
610 struct clk *clk_register_divider_table(struct device *dev, const char *name, in clk_register_divider_table()
612 void __iomem *reg, u8 shift, u8 width, in clk_register_divider_table() argument
619 NULL, flags, reg, shift, width, clk_divider_flags, in clk_register_divider_table()
623 return hw->clk; in clk_register_divider_table()
644 * clk_hw_unregister_divider - unregister a clk divider
645 * @hw: hardware-specific clock data to unregister
658 static void devm_clk_hw_release_divider(struct device *dev, void *res) in devm_clk_hw_release_divider()
663 struct clk_hw *__devm_clk_hw_register_divider(struct device *dev, in __devm_clk_hw_register_divider()
667 void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, in __devm_clk_hw_register_divider() argument
674 return ERR_PTR(-ENOMEM); in __devm_clk_hw_register_divider()
677 parent_data, flags, reg, shift, width, in __devm_clk_hw_register_divider()