xref: /OK3568_Linux_fs/kernel/drivers/clk/clk-multiplier.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2015 Maxime Ripard <maxime.ripard@free-electrons.com>
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <linux/bitops.h>
7*4882a593Smuzhiyun #include <linux/clk-provider.h>
8*4882a593Smuzhiyun #include <linux/err.h>
9*4882a593Smuzhiyun #include <linux/export.h>
10*4882a593Smuzhiyun #include <linux/io.h>
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #include <linux/of.h>
13*4882a593Smuzhiyun #include <linux/slab.h>
14*4882a593Smuzhiyun 
clk_mult_readl(struct clk_multiplier * mult)15*4882a593Smuzhiyun static inline u32 clk_mult_readl(struct clk_multiplier *mult)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun 	if (mult->flags & CLK_MULTIPLIER_BIG_ENDIAN)
18*4882a593Smuzhiyun 		return ioread32be(mult->reg);
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun 	return readl(mult->reg);
21*4882a593Smuzhiyun }
22*4882a593Smuzhiyun 
clk_mult_writel(struct clk_multiplier * mult,u32 val)23*4882a593Smuzhiyun static inline void clk_mult_writel(struct clk_multiplier *mult, u32 val)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun 	if (mult->flags & CLK_MULTIPLIER_BIG_ENDIAN)
26*4882a593Smuzhiyun 		iowrite32be(val, mult->reg);
27*4882a593Smuzhiyun 	else
28*4882a593Smuzhiyun 		writel(val, mult->reg);
29*4882a593Smuzhiyun }
30*4882a593Smuzhiyun 
__get_mult(struct clk_multiplier * mult,unsigned long rate,unsigned long parent_rate)31*4882a593Smuzhiyun static unsigned long __get_mult(struct clk_multiplier *mult,
32*4882a593Smuzhiyun 				unsigned long rate,
33*4882a593Smuzhiyun 				unsigned long parent_rate)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	if (mult->flags & CLK_MULTIPLIER_ROUND_CLOSEST)
36*4882a593Smuzhiyun 		return DIV_ROUND_CLOSEST(rate, parent_rate);
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	return rate / parent_rate;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun 
clk_multiplier_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)41*4882a593Smuzhiyun static unsigned long clk_multiplier_recalc_rate(struct clk_hw *hw,
42*4882a593Smuzhiyun 						unsigned long parent_rate)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun 	struct clk_multiplier *mult = to_clk_multiplier(hw);
45*4882a593Smuzhiyun 	unsigned long val;
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	val = clk_mult_readl(mult) >> mult->shift;
48*4882a593Smuzhiyun 	val &= GENMASK(mult->width - 1, 0);
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	if (!val && mult->flags & CLK_MULTIPLIER_ZERO_BYPASS)
51*4882a593Smuzhiyun 		val = 1;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	return parent_rate * val;
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
__is_best_rate(unsigned long rate,unsigned long new,unsigned long best,unsigned long flags)56*4882a593Smuzhiyun static bool __is_best_rate(unsigned long rate, unsigned long new,
57*4882a593Smuzhiyun 			   unsigned long best, unsigned long flags)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun 	if (flags & CLK_MULTIPLIER_ROUND_CLOSEST)
60*4882a593Smuzhiyun 		return abs(rate - new) < abs(rate - best);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	return new >= rate && new < best;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
__bestmult(struct clk_hw * hw,unsigned long rate,unsigned long * best_parent_rate,u8 width,unsigned long flags)65*4882a593Smuzhiyun static unsigned long __bestmult(struct clk_hw *hw, unsigned long rate,
66*4882a593Smuzhiyun 				unsigned long *best_parent_rate,
67*4882a593Smuzhiyun 				u8 width, unsigned long flags)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun 	struct clk_multiplier *mult = to_clk_multiplier(hw);
70*4882a593Smuzhiyun 	unsigned long orig_parent_rate = *best_parent_rate;
71*4882a593Smuzhiyun 	unsigned long parent_rate, current_rate, best_rate = ~0;
72*4882a593Smuzhiyun 	unsigned int i, bestmult = 0;
73*4882a593Smuzhiyun 	unsigned int maxmult = (1 << width) - 1;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
76*4882a593Smuzhiyun 		bestmult = rate / orig_parent_rate;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 		/* Make sure we don't end up with a 0 multiplier */
79*4882a593Smuzhiyun 		if ((bestmult == 0) &&
80*4882a593Smuzhiyun 		    !(mult->flags & CLK_MULTIPLIER_ZERO_BYPASS))
81*4882a593Smuzhiyun 			bestmult = 1;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 		/* Make sure we don't overflow the multiplier */
84*4882a593Smuzhiyun 		if (bestmult > maxmult)
85*4882a593Smuzhiyun 			bestmult = maxmult;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 		return bestmult;
88*4882a593Smuzhiyun 	}
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	for (i = 1; i < maxmult; i++) {
91*4882a593Smuzhiyun 		if (rate == orig_parent_rate * i) {
92*4882a593Smuzhiyun 			/*
93*4882a593Smuzhiyun 			 * This is the best case for us if we have a
94*4882a593Smuzhiyun 			 * perfect match without changing the parent
95*4882a593Smuzhiyun 			 * rate.
96*4882a593Smuzhiyun 			 */
97*4882a593Smuzhiyun 			*best_parent_rate = orig_parent_rate;
98*4882a593Smuzhiyun 			return i;
99*4882a593Smuzhiyun 		}
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 		parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
102*4882a593Smuzhiyun 						rate / i);
103*4882a593Smuzhiyun 		current_rate = parent_rate * i;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 		if (__is_best_rate(rate, current_rate, best_rate, flags)) {
106*4882a593Smuzhiyun 			bestmult = i;
107*4882a593Smuzhiyun 			best_rate = current_rate;
108*4882a593Smuzhiyun 			*best_parent_rate = parent_rate;
109*4882a593Smuzhiyun 		}
110*4882a593Smuzhiyun 	}
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	return bestmult;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
clk_multiplier_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)115*4882a593Smuzhiyun static long clk_multiplier_round_rate(struct clk_hw *hw, unsigned long rate,
116*4882a593Smuzhiyun 				  unsigned long *parent_rate)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun 	struct clk_multiplier *mult = to_clk_multiplier(hw);
119*4882a593Smuzhiyun 	unsigned long factor = __bestmult(hw, rate, parent_rate,
120*4882a593Smuzhiyun 					  mult->width, mult->flags);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	return *parent_rate * factor;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
clk_multiplier_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)125*4882a593Smuzhiyun static int clk_multiplier_set_rate(struct clk_hw *hw, unsigned long rate,
126*4882a593Smuzhiyun 			       unsigned long parent_rate)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun 	struct clk_multiplier *mult = to_clk_multiplier(hw);
129*4882a593Smuzhiyun 	unsigned long factor = __get_mult(mult, rate, parent_rate);
130*4882a593Smuzhiyun 	unsigned long flags = 0;
131*4882a593Smuzhiyun 	unsigned long val;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	if (mult->lock)
134*4882a593Smuzhiyun 		spin_lock_irqsave(mult->lock, flags);
135*4882a593Smuzhiyun 	else
136*4882a593Smuzhiyun 		__acquire(mult->lock);
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	val = clk_mult_readl(mult);
139*4882a593Smuzhiyun 	val &= ~GENMASK(mult->width + mult->shift - 1, mult->shift);
140*4882a593Smuzhiyun 	val |= factor << mult->shift;
141*4882a593Smuzhiyun 	clk_mult_writel(mult, val);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	if (mult->lock)
144*4882a593Smuzhiyun 		spin_unlock_irqrestore(mult->lock, flags);
145*4882a593Smuzhiyun 	else
146*4882a593Smuzhiyun 		__release(mult->lock);
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	return 0;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun const struct clk_ops clk_multiplier_ops = {
152*4882a593Smuzhiyun 	.recalc_rate	= clk_multiplier_recalc_rate,
153*4882a593Smuzhiyun 	.round_rate	= clk_multiplier_round_rate,
154*4882a593Smuzhiyun 	.set_rate	= clk_multiplier_set_rate,
155*4882a593Smuzhiyun };
156*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(clk_multiplier_ops);
157