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 owl_clk_val_best(const struct owl_factor_hw
*factor_hw
,
68 struct clk_hw
*hw
, unsigned long rate
,
69 unsigned long *best_parent_rate
)
71 const struct clk_factor_table
*clkt
= factor_hw
->table
;
72 unsigned long parent_rate
, try_parent_rate
, best
= 0, cur_rate
;
73 unsigned long parent_rate_saved
= *best_parent_rate
;
79 if (!(clk_hw_get_flags(hw
) & CLK_SET_RATE_PARENT
)) {
80 parent_rate
= *best_parent_rate
;
81 bestval
= _get_table_val(clkt
, rate
, parent_rate
);
85 for (clkt
= factor_hw
->table
; clkt
->div
; clkt
++) {
86 try_parent_rate
= rate
* clkt
->div
/ clkt
->mul
;
88 if (try_parent_rate
== parent_rate_saved
) {
89 pr_debug("%s: [%d %d %d] found try_parent_rate %ld\n",
90 __func__
, clkt
->val
, clkt
->mul
, clkt
->div
,
93 * It's the most ideal case if the requested rate can be
94 * divided from parent clock without any need to change
95 * parent rate, so return the divider immediately.
97 *best_parent_rate
= parent_rate_saved
;
101 parent_rate
= clk_hw_round_rate(clk_hw_get_parent(hw
),
103 cur_rate
= DIV_ROUND_UP(parent_rate
, clkt
->div
) * clkt
->mul
;
104 if (cur_rate
<= rate
&& cur_rate
> best
) {
107 *best_parent_rate
= parent_rate
;
112 bestval
= _get_table_maxval(clkt
);
113 *best_parent_rate
= clk_hw_round_rate(
114 clk_hw_get_parent(hw
), 1);
120 long owl_factor_helper_round_rate(struct owl_clk_common
*common
,
121 const struct owl_factor_hw
*factor_hw
,
123 unsigned long *parent_rate
)
125 const struct clk_factor_table
*clkt
= factor_hw
->table
;
126 unsigned int val
, mul
= 0, div
= 1;
128 val
= owl_clk_val_best(factor_hw
, &common
->hw
, rate
, parent_rate
);
129 _get_table_div_mul(clkt
, val
, &mul
, &div
);
131 return *parent_rate
* mul
/ div
;
134 static long owl_factor_round_rate(struct clk_hw
*hw
, unsigned long rate
,
135 unsigned long *parent_rate
)
137 struct owl_factor
*factor
= hw_to_owl_factor(hw
);
138 struct owl_factor_hw
*factor_hw
= &factor
->factor_hw
;
140 return owl_factor_helper_round_rate(&factor
->common
, factor_hw
,
144 unsigned long owl_factor_helper_recalc_rate(struct owl_clk_common
*common
,
145 const struct owl_factor_hw
*factor_hw
,
146 unsigned long parent_rate
)
148 const struct clk_factor_table
*clkt
= factor_hw
->table
;
149 unsigned long long int rate
;
150 u32 reg
, val
, mul
, div
;
155 regmap_read(common
->regmap
, factor_hw
->reg
, ®
);
157 val
= reg
>> factor_hw
->shift
;
158 val
&= div_mask(factor_hw
);
160 _get_table_div_mul(clkt
, val
, &mul
, &div
);
162 WARN(!(factor_hw
->fct_flags
& CLK_DIVIDER_ALLOW_ZERO
),
163 "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
164 __clk_get_name(common
->hw
.clk
));
168 rate
= (unsigned long long int)parent_rate
* mul
;
174 static unsigned long owl_factor_recalc_rate(struct clk_hw
*hw
,
175 unsigned long parent_rate
)
177 struct owl_factor
*factor
= hw_to_owl_factor(hw
);
178 struct owl_factor_hw
*factor_hw
= &factor
->factor_hw
;
179 struct owl_clk_common
*common
= &factor
->common
;
181 return owl_factor_helper_recalc_rate(common
, factor_hw
, parent_rate
);
184 int owl_factor_helper_set_rate(const struct owl_clk_common
*common
,
185 const struct owl_factor_hw
*factor_hw
,
187 unsigned long parent_rate
)
191 val
= _get_table_val(factor_hw
->table
, rate
, parent_rate
);
193 if (val
> div_mask(factor_hw
))
194 val
= div_mask(factor_hw
);
196 regmap_read(common
->regmap
, factor_hw
->reg
, ®
);
198 reg
&= ~(div_mask(factor_hw
) << factor_hw
->shift
);
199 reg
|= val
<< factor_hw
->shift
;
201 regmap_write(common
->regmap
, factor_hw
->reg
, reg
);
206 static int owl_factor_set_rate(struct clk_hw
*hw
, unsigned long rate
,
207 unsigned long parent_rate
)
209 struct owl_factor
*factor
= hw_to_owl_factor(hw
);
210 struct owl_factor_hw
*factor_hw
= &factor
->factor_hw
;
211 struct owl_clk_common
*common
= &factor
->common
;
213 return owl_factor_helper_set_rate(common
, factor_hw
,
217 const struct clk_ops owl_factor_ops
= {
218 .round_rate
= owl_factor_round_rate
,
219 .recalc_rate
= owl_factor_recalc_rate
,
220 .set_rate
= owl_factor_set_rate
,