summaryrefslogtreecommitdiffstats
path: root/drivers/clk/mmp
diff options
context:
space:
mode:
authorBoris Brezillon <boris.brezillon@free-electrons.com>2015-07-07 14:48:08 -0400
committerStephen Boyd <sboyd@codeaurora.org>2015-07-27 21:12:01 -0400
commit0817b62cc037a56c5e4238c7eb7522299ea27aef (patch)
treee49a8eaceb710fd2873c93c86ef71bf4ff502902 /drivers/clk/mmp
parentd770e558e21961ad6cfdf0ff7df0eb5d7d4f0754 (diff)
clk: change clk_ops' ->determine_rate() prototype
Clock rates are stored in an unsigned long field, but ->determine_rate() (which returns a rounded rate from a requested one) returns a long value (errors are reported using negative error codes), which can lead to long overflow if the clock rate exceed 2Ghz. Change ->determine_rate() prototype to return 0 or an error code, and pass a pointer to a clk_rate_request structure containing the expected target rate and the rate constraints imposed by clk users. The clk_rate_request structure might be extended in the future to contain other kind of constraints like the rounding policy, the maximum clock inaccuracy or other things that are not yet supported by the CCF (power consumption constraints ?). Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com> CC: Jonathan Corbet <corbet@lwn.net> CC: Tony Lindgren <tony@atomide.com> CC: Ralf Baechle <ralf@linux-mips.org> CC: "Emilio López" <emilio@elopez.com.ar> CC: Maxime Ripard <maxime.ripard@free-electrons.com> Acked-by: Tero Kristo <t-kristo@ti.com> CC: Peter De Schrijver <pdeschrijver@nvidia.com> CC: Prashant Gaikwad <pgaikwad@nvidia.com> CC: Stephen Warren <swarren@wwwdotorg.org> CC: Thierry Reding <thierry.reding@gmail.com> CC: Alexandre Courbot <gnurou@gmail.com> CC: linux-doc@vger.kernel.org CC: linux-kernel@vger.kernel.org CC: linux-arm-kernel@lists.infradead.org CC: linux-omap@vger.kernel.org CC: linux-mips@linux-mips.org CC: linux-tegra@vger.kernel.org [sboyd@codeaurora.org: Fix parent dereference problem in __clk_determine_rate()] Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> Tested-by: Romain Perier <romain.perier@gmail.com> Signed-off-by: Heiko Stuebner <heiko@sntech.de> [sboyd@codeaurora.org: Folded in fix from Heiko for fixed-rate clocks without parents or a rate determining op] Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Diffstat (limited to 'drivers/clk/mmp')
-rw-r--r--drivers/clk/mmp/clk-mix.c20
1 files changed, 9 insertions, 11 deletions
diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c
index de6a873175d2..7a37432761f9 100644
--- a/drivers/clk/mmp/clk-mix.c
+++ b/drivers/clk/mmp/clk-mix.c
@@ -201,11 +201,8 @@ error:
201 return ret; 201 return ret;
202} 202}
203 203
204static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, 204static int mmp_clk_mix_determine_rate(struct clk_hw *hw,
205 unsigned long min_rate, 205 struct clk_rate_request *req)
206 unsigned long max_rate,
207 unsigned long *best_parent_rate,
208 struct clk_hw **best_parent_clk)
209{ 206{
210 struct mmp_clk_mix *mix = to_clk_mix(hw); 207 struct mmp_clk_mix *mix = to_clk_mix(hw);
211 struct mmp_clk_mix_clk_table *item; 208 struct mmp_clk_mix_clk_table *item;
@@ -221,7 +218,7 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
221 parent = NULL; 218 parent = NULL;
222 mix_rate_best = 0; 219 mix_rate_best = 0;
223 parent_rate_best = 0; 220 parent_rate_best = 0;
224 gap_best = rate; 221 gap_best = req->rate;
225 parent_best = NULL; 222 parent_best = NULL;
226 223
227 if (mix->table) { 224 if (mix->table) {
@@ -233,7 +230,7 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
233 item->parent_index); 230 item->parent_index);
234 parent_rate = __clk_get_rate(parent); 231 parent_rate = __clk_get_rate(parent);
235 mix_rate = parent_rate / item->divisor; 232 mix_rate = parent_rate / item->divisor;
236 gap = abs(mix_rate - rate); 233 gap = abs(mix_rate - req->rate);
237 if (parent_best == NULL || gap < gap_best) { 234 if (parent_best == NULL || gap < gap_best) {
238 parent_best = parent; 235 parent_best = parent;
239 parent_rate_best = parent_rate; 236 parent_rate_best = parent_rate;
@@ -251,7 +248,7 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
251 for (j = 0; j < div_val_max; j++) { 248 for (j = 0; j < div_val_max; j++) {
252 div = _get_div(mix, j); 249 div = _get_div(mix, j);
253 mix_rate = parent_rate / div; 250 mix_rate = parent_rate / div;
254 gap = abs(mix_rate - rate); 251 gap = abs(mix_rate - req->rate);
255 if (parent_best == NULL || gap < gap_best) { 252 if (parent_best == NULL || gap < gap_best) {
256 parent_best = parent; 253 parent_best = parent;
257 parent_rate_best = parent_rate; 254 parent_rate_best = parent_rate;
@@ -265,10 +262,11 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
265 } 262 }
266 263
267found: 264found:
268 *best_parent_rate = parent_rate_best; 265 req->best_parent_rate = parent_rate_best;
269 *best_parent_clk = __clk_get_hw(parent_best); 266 req->best_parent_hw = __clk_get_hw(parent_best);
267 req->rate = mix_rate_best;
270 268
271 return mix_rate_best; 269 return 0;
272} 270}
273 271
274static int mmp_clk_mix_set_rate_and_parent(struct clk_hw *hw, 272static int mmp_clk_mix_set_rate_and_parent(struct clk_hw *hw,