summaryrefslogtreecommitdiff
path: root/arch/mips/alchemy
diff options
context:
space:
mode:
authorBoris Brezillon <boris.brezillon@free-electrons.com>2015-07-07 21:48:08 +0300
committerStephen Boyd <sboyd@codeaurora.org>2015-07-28 04:12:01 +0300
commit0817b62cc037a56c5e4238c7eb7522299ea27aef (patch)
treee49a8eaceb710fd2873c93c86ef71bf4ff502902 /arch/mips/alchemy
parentd770e558e21961ad6cfdf0ff7df0eb5d7d4f0754 (diff)
downloadlinux-0817b62cc037a56c5e4238c7eb7522299ea27aef.tar.xz
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 'arch/mips/alchemy')
-rw-r--r--arch/mips/alchemy/common/clock.c61
1 files changed, 25 insertions, 36 deletions
diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c
index 6e46abe0dac6..0b4cf3e9f005 100644
--- a/arch/mips/alchemy/common/clock.c
+++ b/arch/mips/alchemy/common/clock.c
@@ -389,10 +389,9 @@ static long alchemy_calc_div(unsigned long rate, unsigned long prate,
return div1;
}
-static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_clk,
- int scale, int maxdiv)
+static int alchemy_clk_fgcs_detr(struct clk_hw *hw,
+ struct clk_rate_request *req,
+ int scale, int maxdiv)
{
struct clk *pc, *bpc, *free;
long tdv, tpr, pr, nr, br, bpr, diff, lastdiff;
@@ -422,14 +421,14 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate,
}
pr = clk_get_rate(pc);
- if (pr < rate)
+ if (pr < req->rate)
continue;
/* what can hardware actually provide */
- tdv = alchemy_calc_div(rate, pr, scale, maxdiv, NULL);
+ tdv = alchemy_calc_div(req->rate, pr, scale, maxdiv, NULL);
nr = pr / tdv;
- diff = rate - nr;
- if (nr > rate)
+ diff = req->rate - nr;
+ if (nr > req->rate)
continue;
if (diff < lastdiff) {
@@ -448,15 +447,16 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate,
*/
if (lastdiff && free) {
for (j = (maxdiv == 4) ? 1 : scale; j <= maxdiv; j += scale) {
- tpr = rate * j;
+ tpr = req->rate * j;
if (tpr < 0)
break;
pr = clk_round_rate(free, tpr);
- tdv = alchemy_calc_div(rate, pr, scale, maxdiv, NULL);
+ tdv = alchemy_calc_div(req->rate, pr, scale, maxdiv,
+ NULL);
nr = pr / tdv;
- diff = rate - nr;
- if (nr > rate)
+ diff = req->rate - nr;
+ if (nr > req->rate)
continue;
if (diff < lastdiff) {
lastdiff = diff;
@@ -469,9 +469,10 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate,
}
}
- *best_parent_rate = bpr;
- *best_parent_clk = __clk_get_hw(bpc);
- return br;
+ req->best_parent_rate = bpr;
+ req->best_parent_hw = __clk_get_hw(bpc);
+ req->rate = br;
+ return 0;
}
static int alchemy_clk_fgv1_en(struct clk_hw *hw)
@@ -562,14 +563,10 @@ static unsigned long alchemy_clk_fgv1_recalc(struct clk_hw *hw,
return parent_rate / v;
}
-static long alchemy_clk_fgv1_detr(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_clk)
+static int alchemy_clk_fgv1_detr(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
- return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate,
- best_parent_clk, 2, 512);
+ return alchemy_clk_fgcs_detr(hw, req, 2, 512);
}
/* Au1000, Au1100, Au15x0, Au12x0 */
@@ -696,11 +693,8 @@ static unsigned long alchemy_clk_fgv2_recalc(struct clk_hw *hw,
return t;
}
-static long alchemy_clk_fgv2_detr(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_clk)
+static int alchemy_clk_fgv2_detr(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
int scale, maxdiv;
@@ -713,8 +707,7 @@ static long alchemy_clk_fgv2_detr(struct clk_hw *hw, unsigned long rate,
maxdiv = 512;
}
- return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate,
- best_parent_clk, scale, maxdiv);
+ return alchemy_clk_fgcs_detr(hw, req, scale, maxdiv);
}
/* Au1300 larger input mux, no separate disable bit, flexible divider */
@@ -917,17 +910,13 @@ static int alchemy_clk_csrc_setr(struct clk_hw *hw, unsigned long rate,
return 0;
}
-static long alchemy_clk_csrc_detr(struct clk_hw *hw, unsigned long rate,
- unsigned long min_rate,
- unsigned long max_rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_clk)
+static int alchemy_clk_csrc_detr(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
int scale = c->dt[2] == 3 ? 1 : 2; /* au1300 check */
- return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate,
- best_parent_clk, scale, 4);
+ return alchemy_clk_fgcs_detr(hw, req, scale, 4);
}
static struct clk_ops alchemy_clkops_csrc = {