1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2015 Maxime Ripard <maxime.ripard@free-electrons.com>
6 #include <linux/bitops.h>
7 #include <linux/clk-provider.h>
9 #include <linux/export.h>
10 #include <linux/kernel.h>
12 #include <linux/slab.h>
14 static unsigned long __get_mult(struct clk_multiplier *mult,
16 unsigned long parent_rate)
18 if (mult->flags & CLK_MULTIPLIER_ROUND_CLOSEST)
19 return DIV_ROUND_CLOSEST(rate, parent_rate);
21 return rate / parent_rate;
24 static unsigned long clk_multiplier_recalc_rate(struct clk_hw *hw,
25 unsigned long parent_rate)
27 struct clk_multiplier *mult = to_clk_multiplier(hw);
30 val = clk_readl(mult->reg) >> mult->shift;
31 val &= GENMASK(mult->width - 1, 0);
33 if (!val && mult->flags & CLK_MULTIPLIER_ZERO_BYPASS)
36 return parent_rate * val;
39 static bool __is_best_rate(unsigned long rate, unsigned long new,
40 unsigned long best, unsigned long flags)
42 if (flags & CLK_MULTIPLIER_ROUND_CLOSEST)
43 return abs(rate - new) < abs(rate - best);
45 return new >= rate && new < best;
48 static unsigned long __bestmult(struct clk_hw *hw, unsigned long rate,
49 unsigned long *best_parent_rate,
50 u8 width, unsigned long flags)
52 struct clk_multiplier *mult = to_clk_multiplier(hw);
53 unsigned long orig_parent_rate = *best_parent_rate;
54 unsigned long parent_rate, current_rate, best_rate = ~0;
55 unsigned int i, bestmult = 0;
56 unsigned int maxmult = (1 << width) - 1;
58 if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
59 bestmult = rate / orig_parent_rate;
61 /* Make sure we don't end up with a 0 multiplier */
62 if ((bestmult == 0) &&
63 !(mult->flags & CLK_MULTIPLIER_ZERO_BYPASS))
66 /* Make sure we don't overflow the multiplier */
67 if (bestmult > maxmult)
73 for (i = 1; i < maxmult; i++) {
74 if (rate == orig_parent_rate * i) {
76 * This is the best case for us if we have a
77 * perfect match without changing the parent
80 *best_parent_rate = orig_parent_rate;
84 parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
86 current_rate = parent_rate * i;
88 if (__is_best_rate(rate, current_rate, best_rate, flags)) {
90 best_rate = current_rate;
91 *best_parent_rate = parent_rate;
98 static long clk_multiplier_round_rate(struct clk_hw *hw, unsigned long rate,
99 unsigned long *parent_rate)
101 struct clk_multiplier *mult = to_clk_multiplier(hw);
102 unsigned long factor = __bestmult(hw, rate, parent_rate,
103 mult->width, mult->flags);
105 return *parent_rate * factor;
108 static int clk_multiplier_set_rate(struct clk_hw *hw, unsigned long rate,
109 unsigned long parent_rate)
111 struct clk_multiplier *mult = to_clk_multiplier(hw);
112 unsigned long factor = __get_mult(mult, rate, parent_rate);
113 unsigned long flags = 0;
117 spin_lock_irqsave(mult->lock, flags);
119 __acquire(mult->lock);
121 val = clk_readl(mult->reg);
122 val &= ~GENMASK(mult->width + mult->shift - 1, mult->shift);
123 val |= factor << mult->shift;
124 clk_writel(val, mult->reg);
127 spin_unlock_irqrestore(mult->lock, flags);
129 __release(mult->lock);
134 const struct clk_ops clk_multiplier_ops = {
135 .recalc_rate = clk_multiplier_recalc_rate,
136 .round_rate = clk_multiplier_round_rate,
137 .set_rate = clk_multiplier_set_rate,
139 EXPORT_SYMBOL_GPL(clk_multiplier_ops);