1e1bd55e5SStephen Boyd // SPDX-License-Identifier: GPL-2.0
2f2e0a532SMaxime Ripard /*
3f2e0a532SMaxime Ripard * Copyright (C) 2015 Maxime Ripard <maxime.ripard@free-electrons.com>
4f2e0a532SMaxime Ripard */
5f2e0a532SMaxime Ripard
6f2e0a532SMaxime Ripard #include <linux/bitops.h>
7f2e0a532SMaxime Ripard #include <linux/clk-provider.h>
8f2e0a532SMaxime Ripard #include <linux/err.h>
9f2e0a532SMaxime Ripard #include <linux/export.h>
10*62e59c4eSStephen Boyd #include <linux/io.h>
11f2e0a532SMaxime Ripard #include <linux/kernel.h>
12f2e0a532SMaxime Ripard #include <linux/of.h>
13f2e0a532SMaxime Ripard #include <linux/slab.h>
14f2e0a532SMaxime Ripard
clk_mult_readl(struct clk_multiplier * mult)159427b71aSJonas Gorski static inline u32 clk_mult_readl(struct clk_multiplier *mult)
169427b71aSJonas Gorski {
179427b71aSJonas Gorski if (mult->flags & CLK_MULTIPLIER_BIG_ENDIAN)
189427b71aSJonas Gorski return ioread32be(mult->reg);
199427b71aSJonas Gorski
205834fd75SJonas Gorski return readl(mult->reg);
219427b71aSJonas Gorski }
229427b71aSJonas Gorski
clk_mult_writel(struct clk_multiplier * mult,u32 val)239427b71aSJonas Gorski static inline void clk_mult_writel(struct clk_multiplier *mult, u32 val)
249427b71aSJonas Gorski {
259427b71aSJonas Gorski if (mult->flags & CLK_MULTIPLIER_BIG_ENDIAN)
269427b71aSJonas Gorski iowrite32be(val, mult->reg);
279427b71aSJonas Gorski else
285834fd75SJonas Gorski writel(val, mult->reg);
299427b71aSJonas Gorski }
309427b71aSJonas Gorski
__get_mult(struct clk_multiplier * mult,unsigned long rate,unsigned long parent_rate)31f2e0a532SMaxime Ripard static unsigned long __get_mult(struct clk_multiplier *mult,
32f2e0a532SMaxime Ripard unsigned long rate,
33f2e0a532SMaxime Ripard unsigned long parent_rate)
34f2e0a532SMaxime Ripard {
35f2e0a532SMaxime Ripard if (mult->flags & CLK_MULTIPLIER_ROUND_CLOSEST)
36f2e0a532SMaxime Ripard return DIV_ROUND_CLOSEST(rate, parent_rate);
37f2e0a532SMaxime Ripard
38f2e0a532SMaxime Ripard return rate / parent_rate;
39f2e0a532SMaxime Ripard }
40f2e0a532SMaxime Ripard
clk_multiplier_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)41f2e0a532SMaxime Ripard static unsigned long clk_multiplier_recalc_rate(struct clk_hw *hw,
42f2e0a532SMaxime Ripard unsigned long parent_rate)
43f2e0a532SMaxime Ripard {
44f2e0a532SMaxime Ripard struct clk_multiplier *mult = to_clk_multiplier(hw);
45f2e0a532SMaxime Ripard unsigned long val;
46f2e0a532SMaxime Ripard
479427b71aSJonas Gorski val = clk_mult_readl(mult) >> mult->shift;
48f2e0a532SMaxime Ripard val &= GENMASK(mult->width - 1, 0);
49f2e0a532SMaxime Ripard
50f2e0a532SMaxime Ripard if (!val && mult->flags & CLK_MULTIPLIER_ZERO_BYPASS)
51f2e0a532SMaxime Ripard val = 1;
52f2e0a532SMaxime Ripard
53f2e0a532SMaxime Ripard return parent_rate * val;
54f2e0a532SMaxime Ripard }
55f2e0a532SMaxime Ripard
__is_best_rate(unsigned long rate,unsigned long new,unsigned long best,unsigned long flags)56f2e0a532SMaxime Ripard static bool __is_best_rate(unsigned long rate, unsigned long new,
57f2e0a532SMaxime Ripard unsigned long best, unsigned long flags)
58f2e0a532SMaxime Ripard {
59f2e0a532SMaxime Ripard if (flags & CLK_MULTIPLIER_ROUND_CLOSEST)
60f2e0a532SMaxime Ripard return abs(rate - new) < abs(rate - best);
61f2e0a532SMaxime Ripard
62f2e0a532SMaxime Ripard return new >= rate && new < best;
63f2e0a532SMaxime Ripard }
64f2e0a532SMaxime Ripard
__bestmult(struct clk_hw * hw,unsigned long rate,unsigned long * best_parent_rate,u8 width,unsigned long flags)65f2e0a532SMaxime Ripard static unsigned long __bestmult(struct clk_hw *hw, unsigned long rate,
66f2e0a532SMaxime Ripard unsigned long *best_parent_rate,
67f2e0a532SMaxime Ripard u8 width, unsigned long flags)
68f2e0a532SMaxime Ripard {
6925f77a3aSMaxime Ripard struct clk_multiplier *mult = to_clk_multiplier(hw);
70f2e0a532SMaxime Ripard unsigned long orig_parent_rate = *best_parent_rate;
71f2e0a532SMaxime Ripard unsigned long parent_rate, current_rate, best_rate = ~0;
72f2e0a532SMaxime Ripard unsigned int i, bestmult = 0;
7325f77a3aSMaxime Ripard unsigned int maxmult = (1 << width) - 1;
74f2e0a532SMaxime Ripard
7525f77a3aSMaxime Ripard if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
7625f77a3aSMaxime Ripard bestmult = rate / orig_parent_rate;
77f2e0a532SMaxime Ripard
7825f77a3aSMaxime Ripard /* Make sure we don't end up with a 0 multiplier */
7925f77a3aSMaxime Ripard if ((bestmult == 0) &&
8025f77a3aSMaxime Ripard !(mult->flags & CLK_MULTIPLIER_ZERO_BYPASS))
8125f77a3aSMaxime Ripard bestmult = 1;
8225f77a3aSMaxime Ripard
8325f77a3aSMaxime Ripard /* Make sure we don't overflow the multiplier */
8425f77a3aSMaxime Ripard if (bestmult > maxmult)
8525f77a3aSMaxime Ripard bestmult = maxmult;
8625f77a3aSMaxime Ripard
8725f77a3aSMaxime Ripard return bestmult;
8825f77a3aSMaxime Ripard }
8925f77a3aSMaxime Ripard
9025f77a3aSMaxime Ripard for (i = 1; i < maxmult; i++) {
91f2e0a532SMaxime Ripard if (rate == orig_parent_rate * i) {
92f2e0a532SMaxime Ripard /*
93f2e0a532SMaxime Ripard * This is the best case for us if we have a
94f2e0a532SMaxime Ripard * perfect match without changing the parent
95f2e0a532SMaxime Ripard * rate.
96f2e0a532SMaxime Ripard */
97f2e0a532SMaxime Ripard *best_parent_rate = orig_parent_rate;
98f2e0a532SMaxime Ripard return i;
99f2e0a532SMaxime Ripard }
100f2e0a532SMaxime Ripard
101f2e0a532SMaxime Ripard parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
102f2e0a532SMaxime Ripard rate / i);
103f2e0a532SMaxime Ripard current_rate = parent_rate * i;
104f2e0a532SMaxime Ripard
105f2e0a532SMaxime Ripard if (__is_best_rate(rate, current_rate, best_rate, flags)) {
106f2e0a532SMaxime Ripard bestmult = i;
107f2e0a532SMaxime Ripard best_rate = current_rate;
108f2e0a532SMaxime Ripard *best_parent_rate = parent_rate;
109f2e0a532SMaxime Ripard }
110f2e0a532SMaxime Ripard }
111f2e0a532SMaxime Ripard
112f2e0a532SMaxime Ripard return bestmult;
113f2e0a532SMaxime Ripard }
114f2e0a532SMaxime Ripard
clk_multiplier_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)115f2e0a532SMaxime Ripard static long clk_multiplier_round_rate(struct clk_hw *hw, unsigned long rate,
116f2e0a532SMaxime Ripard unsigned long *parent_rate)
117f2e0a532SMaxime Ripard {
118f2e0a532SMaxime Ripard struct clk_multiplier *mult = to_clk_multiplier(hw);
119f2e0a532SMaxime Ripard unsigned long factor = __bestmult(hw, rate, parent_rate,
120f2e0a532SMaxime Ripard mult->width, mult->flags);
121f2e0a532SMaxime Ripard
122f2e0a532SMaxime Ripard return *parent_rate * factor;
123f2e0a532SMaxime Ripard }
124f2e0a532SMaxime Ripard
clk_multiplier_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)125f2e0a532SMaxime Ripard static int clk_multiplier_set_rate(struct clk_hw *hw, unsigned long rate,
126f2e0a532SMaxime Ripard unsigned long parent_rate)
127f2e0a532SMaxime Ripard {
128f2e0a532SMaxime Ripard struct clk_multiplier *mult = to_clk_multiplier(hw);
129f2e0a532SMaxime Ripard unsigned long factor = __get_mult(mult, rate, parent_rate);
130f2e0a532SMaxime Ripard unsigned long flags = 0;
131f2e0a532SMaxime Ripard unsigned long val;
132f2e0a532SMaxime Ripard
133f2e0a532SMaxime Ripard if (mult->lock)
134f2e0a532SMaxime Ripard spin_lock_irqsave(mult->lock, flags);
135f2e0a532SMaxime Ripard else
136f2e0a532SMaxime Ripard __acquire(mult->lock);
137f2e0a532SMaxime Ripard
1389427b71aSJonas Gorski val = clk_mult_readl(mult);
139f2e0a532SMaxime Ripard val &= ~GENMASK(mult->width + mult->shift - 1, mult->shift);
140f2e0a532SMaxime Ripard val |= factor << mult->shift;
1419427b71aSJonas Gorski clk_mult_writel(mult, val);
142f2e0a532SMaxime Ripard
143f2e0a532SMaxime Ripard if (mult->lock)
144f2e0a532SMaxime Ripard spin_unlock_irqrestore(mult->lock, flags);
145f2e0a532SMaxime Ripard else
146f2e0a532SMaxime Ripard __release(mult->lock);
147f2e0a532SMaxime Ripard
148f2e0a532SMaxime Ripard return 0;
149f2e0a532SMaxime Ripard }
150f2e0a532SMaxime Ripard
151f2e0a532SMaxime Ripard const struct clk_ops clk_multiplier_ops = {
152f2e0a532SMaxime Ripard .recalc_rate = clk_multiplier_recalc_rate,
153f2e0a532SMaxime Ripard .round_rate = clk_multiplier_round_rate,
154f2e0a532SMaxime Ripard .set_rate = clk_multiplier_set_rate,
155f2e0a532SMaxime Ripard };
156f2e0a532SMaxime Ripard EXPORT_SYMBOL_GPL(clk_multiplier_ops);
157