1 // SPDX-License-Identifier: GPL-2.0+
3 // OWL factor clock driver
5 // Copyright (c) 2014 Actions Semi Inc.
6 // Author: David Liu <liuwei@actions-semi.com>
8 // Copyright (c) 2018 Linaro Ltd.
9 // Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
11 #include <linux/clk-provider.h>
12 #include <linux/regmap.h>
13 #include <linux/slab.h>
15 #include "owl-factor.h"
17 static unsigned int _get_table_maxval(const struct clk_factor_table
*table
)
19 unsigned int maxval
= 0;
20 const struct clk_factor_table
*clkt
;
22 for (clkt
= table
; clkt
->div
; clkt
++)
23 if (clkt
->val
> maxval
)
28 static int _get_table_div_mul(const struct clk_factor_table
*table
,
29 unsigned int val
, unsigned int *mul
, unsigned int *div
)
31 const struct clk_factor_table
*clkt
;
33 for (clkt
= table
; clkt
->div
; clkt
++) {
34 if (clkt
->val
== val
) {
44 static unsigned int _get_table_val(const struct clk_factor_table
*table
,
45 unsigned long rate
, unsigned long parent_rate
)
47 const struct clk_factor_table
*clkt
;
51 for (clkt
= table
; clkt
->div
; clkt
++) {
52 calc_rate
= parent_rate
* clkt
->mul
;
53 do_div(calc_rate
, clkt
->div
);
55 if ((unsigned long)calc_rate
<= rate
) {
62 val
= _get_table_maxval(table
);
67 static int clk_val_best(struct clk_hw
*hw
, unsigned long rate
,
68 unsigned long *best_parent_rate
)
70 struct owl_factor
*factor
= hw_to_owl_factor(hw
);
71 struct owl_factor_hw
*factor_hw
= &factor
->factor_hw
;
72 const struct clk_factor_table
*clkt
= factor_hw
->table
;
73 unsigned long parent_rate
, try_parent_rate
, best
= 0, cur_rate
;
74 unsigned long parent_rate_saved
= *best_parent_rate
;
80 if (!(clk_hw_get_flags(hw
) & CLK_SET_RATE_PARENT
)) {
81 parent_rate
= *best_parent_rate
;
82 bestval
= _get_table_val(clkt
, rate
, parent_rate
);
86 for (clkt
= factor_hw
->table
; clkt
->div
; clkt
++) {
87 try_parent_rate
= rate
* clkt
->div
/ clkt
->mul
;
89 if (try_parent_rate
== parent_rate_saved
) {
90 pr_debug("%s: [%d %d %d] found try_parent_rate %ld\n",
91 __func__
, clkt
->val
, clkt
->mul
, clkt
->div
,
94 * It's the most ideal case if the requested rate can be
95 * divided from parent clock without any need to change
96 * parent rate, so return the divider immediately.
98 *best_parent_rate
= parent_rate_saved
;
102 parent_rate
= clk_hw_round_rate(clk_hw_get_parent(hw
),
104 cur_rate
= DIV_ROUND_UP(parent_rate
, clkt
->div
) * clkt
->mul
;
105 if (cur_rate
<= rate
&& cur_rate
> best
) {
108 *best_parent_rate
= parent_rate
;
113 bestval
= _get_table_maxval(clkt
);
114 *best_parent_rate
= clk_hw_round_rate(
115 clk_hw_get_parent(hw
), 1);
121 long owl_factor_helper_round_rate(struct owl_clk_common
*common
,
122 const struct owl_factor_hw
*factor_hw
,
124 unsigned long *parent_rate
)
126 const struct clk_factor_table
*clkt
= factor_hw
->table
;
127 unsigned int val
, mul
= 0, div
= 1;
129 val
= clk_val_best(&common
->hw
, rate
, parent_rate
);
130 _get_table_div_mul(clkt
, val
, &mul
, &div
);
132 return *parent_rate
* mul
/ div
;
135 static long owl_factor_round_rate(struct clk_hw
*hw
, unsigned long rate
,
136 unsigned long *parent_rate
)
138 struct owl_factor
*factor
= hw_to_owl_factor(hw
);
139 struct owl_factor_hw
*factor_hw
= &factor
->factor_hw
;
141 return owl_factor_helper_round_rate(&factor
->common
, factor_hw
,
145 unsigned long owl_factor_helper_recalc_rate(struct owl_clk_common
*common
,
146 const struct owl_factor_hw
*factor_hw
,
147 unsigned long parent_rate
)
149 const struct clk_factor_table
*clkt
= factor_hw
->table
;
150 unsigned long long int rate
;
151 u32 reg
, val
, mul
, div
;
156 regmap_read(common
->regmap
, factor_hw
->reg
, ®
);
158 val
= reg
>> factor_hw
->shift
;
159 val
&= div_mask(factor_hw
);
161 _get_table_div_mul(clkt
, val
, &mul
, &div
);
163 WARN(!(factor_hw
->fct_flags
& CLK_DIVIDER_ALLOW_ZERO
),
164 "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
165 __clk_get_name(common
->hw
.clk
));
169 rate
= (unsigned long long int)parent_rate
* mul
;
175 static unsigned long owl_factor_recalc_rate(struct clk_hw
*hw
,
176 unsigned long parent_rate
)
178 struct owl_factor
*factor
= hw_to_owl_factor(hw
);
179 struct owl_factor_hw
*factor_hw
= &factor
->factor_hw
;
180 struct owl_clk_common
*common
= &factor
->common
;
182 return owl_factor_helper_recalc_rate(common
, factor_hw
, parent_rate
);
185 int owl_factor_helper_set_rate(const struct owl_clk_common
*common
,
186 const struct owl_factor_hw
*factor_hw
,
188 unsigned long parent_rate
)
192 val
= _get_table_val(factor_hw
->table
, rate
, parent_rate
);
194 if (val
> div_mask(factor_hw
))
195 val
= div_mask(factor_hw
);
197 regmap_read(common
->regmap
, factor_hw
->reg
, ®
);
199 reg
&= ~(div_mask(factor_hw
) << factor_hw
->shift
);
200 reg
|= val
<< factor_hw
->shift
;
202 regmap_write(common
->regmap
, factor_hw
->reg
, reg
);
207 static int owl_factor_set_rate(struct clk_hw
*hw
, unsigned long rate
,
208 unsigned long parent_rate
)
210 struct owl_factor
*factor
= hw_to_owl_factor(hw
);
211 struct owl_factor_hw
*factor_hw
= &factor
->factor_hw
;
212 struct owl_clk_common
*common
= &factor
->common
;
214 return owl_factor_helper_set_rate(common
, factor_hw
,
218 const struct clk_ops owl_factor_ops
= {
219 .round_rate
= owl_factor_round_rate
,
220 .recalc_rate
= owl_factor_recalc_rate
,
221 .set_rate
= owl_factor_set_rate
,