lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1430407809-31147-3-git-send-email-boris.brezillon@free-electrons.com>
Date:	Thu, 30 Apr 2015 17:30:09 +0200
From:	Boris Brezillon <boris.brezillon@...e-electrons.com>
To:	Mike Turquette <mturquette@...aro.org>,
	Stephen Boyd <sboyd@...eaurora.org>, linux-clk@...r.kernel.org
Cc:	linux-kernel@...r.kernel.org,
	Boris Brezillon <boris.brezillon@...e-electrons.com>,
	Jonathan Corbet <corbet@....net>,
	Tony Lindgren <tony@...mide.com>,
	Ralf Baechle <ralf@...ux-mips.org>,
	Emilio López <emilio@...pez.com.ar>,
	Maxime Ripard <maxime.ripard@...e-electrons.com>,
	Tero Kristo <t-kristo@...com>, linux-doc@...r.kernel.org,
	linux-arm-kernel@...ts.infradead.org, linux-omap@...r.kernel.org,
	linux-mips@...ux-mips.org
Subject: [PATCH v2 2/2] 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
the requested rate as a pointer so that it can be adjusted depending on
hardware capabilities.

Signed-off-by: Boris Brezillon <boris.brezillon@...e-electrons.com>
Tested-by: Mikko Perttunen <mikko.perttunen@...si.fi>
---
CC: Jonathan Corbet <corbet@....net>
CC: Tony Lindgren <tony@...mide.com>
CC: Ralf Baechle <ralf@...ux-mips.org>
CC: "Emilio López" <emilio@...pez.com.ar>
CC: Maxime Ripard <maxime.ripard@...e-electrons.com>
CC: Tero Kristo <t-kristo@...com>
CC: linux-doc@...r.kernel.org
CC: linux-kernel@...r.kernel.org
CC: linux-arm-kernel@...ts.infradead.org
CC: linux-omap@...r.kernel.org
CC: linux-mips@...ux-mips.org

 Documentation/clk.txt               |  4 +--
 arch/arm/mach-omap2/dpll3xxx.c      | 20 ++++++------
 arch/arm/mach-omap2/dpll44xx.c      | 20 ++++++------
 arch/mips/alchemy/common/clock.c    | 63 ++++++++++++++++++++++++-------------
 drivers/clk/at91/clk-programmable.c | 28 ++++++++++-------
 drivers/clk/at91/clk-usb.c          | 26 ++++++++-------
 drivers/clk/bcm/clk-kona.c          | 24 +++++++++-----
 drivers/clk/clk-composite.c         | 22 ++++++-------
 drivers/clk/clk.c                   | 58 +++++++++++++++++++---------------
 drivers/clk/hisilicon/clk-hi3620.c  | 22 ++++++-------
 drivers/clk/mmp/clk-mix.c           | 17 +++++-----
 drivers/clk/qcom/clk-pll.c          | 12 ++++---
 drivers/clk/qcom/clk-rcg.c          | 32 ++++++++++---------
 drivers/clk/qcom/clk-rcg2.c         | 54 +++++++++++++++++--------------
 drivers/clk/sunxi/clk-factors.c     | 19 +++++------
 drivers/clk/sunxi/clk-sun6i-ar100.c | 18 ++++++-----
 drivers/clk/sunxi/clk-sunxi.c       | 19 +++++------
 include/linux/clk-provider.h        | 24 +++++++-------
 include/linux/clk/ti.h              | 24 +++++++-------
 19 files changed, 282 insertions(+), 224 deletions(-)

diff --git a/Documentation/clk.txt b/Documentation/clk.txt
index fca8b7a..f5cae13 100644
--- a/Documentation/clk.txt
+++ b/Documentation/clk.txt
@@ -71,8 +71,8 @@ the operations defined in clk.h:
 		int		(*round_rate)(struct clk_hw *hw,
 						unsigned long *rate,
 						unsigned long *parent_rate);
-		long		(*determine_rate)(struct clk_hw *hw,
-						unsigned long rate,
+		int		(*determine_rate)(struct clk_hw *hw,
+						unsigned long *rate,
 						unsigned long min_rate,
 						unsigned long max_rate,
 						unsigned long *best_parent_rate,
diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
index 7a6fb45..cfa24fd 100644
--- a/arch/arm/mach-omap2/dpll3xxx.c
+++ b/arch/arm/mach-omap2/dpll3xxx.c
@@ -472,37 +472,37 @@ void omap3_noncore_dpll_disable(struct clk_hw *hw)
  * Returns a positive clock rate with success, negative error value
  * in failure.
  */
-long omap3_noncore_dpll_determine_rate(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)
+int omap3_noncore_dpll_determine_rate(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)
 {
 	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
 	struct dpll_data *dd;
 	int ret;
 
-	if (!hw || !rate)
+	if (!hw || !*rate)
 		return -EINVAL;
 
 	dd = clk->dpll_data;
 	if (!dd)
 		return -EINVAL;
 
-	if (__clk_get_rate(dd->clk_bypass) == rate &&
+	if (__clk_get_rate(dd->clk_bypass) == *rate &&
 	    (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
 		*best_parent_clk = __clk_get_hw(dd->clk_bypass);
 	} else {
-		ret = omap2_dpll_round_rate(hw, &rate, best_parent_rate);
+		ret = omap2_dpll_round_rate(hw, rate, best_parent_rate);
 		if (ret)
 			return ret;
 
 		*best_parent_clk = __clk_get_hw(dd->clk_ref);
 	}
 
-	*best_parent_rate = rate;
+	*best_parent_rate = *rate;
 
-	return rate;
+	return 0;
 }
 
 /**
diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c
index afd3284..1571d41 100644
--- a/arch/arm/mach-omap2/dpll44xx.c
+++ b/arch/arm/mach-omap2/dpll44xx.c
@@ -203,28 +203,28 @@ out:
  * Returns a positive clock rate with success, negative error value
  * in failure.
  */
-long omap4_dpll_regm4xen_determine_rate(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)
+int omap4_dpll_regm4xen_determine_rate(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)
 {
 	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
 	struct dpll_data *dd;
 	int ret;
 
-	if (!hw || !rate)
+	if (!hw || !*rate)
 		return -EINVAL;
 
 	dd = clk->dpll_data;
 	if (!dd)
 		return -EINVAL;
 
-	if (__clk_get_rate(dd->clk_bypass) == rate &&
+	if (__clk_get_rate(dd->clk_bypass) == *rate &&
 	    (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
 		*best_parent_clk = __clk_get_hw(dd->clk_bypass);
 	} else {
-		ret = omap4_dpll_regm4xen_round_rate(hw, &rate,
+		ret = omap4_dpll_regm4xen_round_rate(hw, rate,
 						     best_parent_rate);
 		if (ret)
 			return ret;
@@ -232,7 +232,7 @@ long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long rate,
 		*best_parent_clk = __clk_get_hw(dd->clk_ref);
 	}
 
-	*best_parent_rate = rate;
+	*best_parent_rate = *rate;
 
-	return rate;
+	return 0;
 }
diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c
index d697d8f..0abcfc6 100644
--- a/arch/mips/alchemy/common/clock.c
+++ b/arch/mips/alchemy/common/clock.c
@@ -565,14 +565,22 @@ 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, unsigned long *rate,
+				 unsigned long min_rate,
+				 unsigned long max_rate,
+				 unsigned long *best_parent_rate,
+				 struct clk_hw **best_parent_clk)
 {
-	return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate,
-				     best_parent_clk, 2, 512);
+	long ret;
+
+	ret = alchemy_clk_fgcs_detr(hw, *rate, best_parent_rate,
+				    best_parent_clk, 2, 512);
+	if (ret < 0)
+		return ret;
+
+	*rate = ret;
+
+	return 0;
 }
 
 /* Au1000, Au1100, Au15x0, Au12x0 */
@@ -699,14 +707,15 @@ 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, unsigned long *rate,
+				 unsigned long min_rate,
+				 unsigned long max_rate,
+				 unsigned long *best_parent_rate,
+				 struct clk_hw **best_parent_clk)
 {
 	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
 	int scale, maxdiv;
+	long ret;
 
 	if (alchemy_rdsys(c->reg) & (1 << 30)) {
 		scale = 1;
@@ -716,8 +725,13 @@ 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);
+	ret = alchemy_clk_fgcs_detr(hw, *rate, best_parent_rate,
+				    best_parent_clk, scale, maxdiv);
+	if (ret < 0)
+		return ret;
+
+	*rate = ret;
+	return 0;
 }
 
 /* Au1300 larger input mux, no separate disable bit, flexible divider */
@@ -920,17 +934,24 @@ 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, unsigned long *rate,
+				 unsigned long min_rate,
+				 unsigned long max_rate,
+				 unsigned long *best_parent_rate,
+				 struct clk_hw **best_parent_clk)
 {
 	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
 	int scale = c->dt[2] == 3 ? 1 : 2; /* au1300 check */
+	long ret;
 
-	return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate,
-				     best_parent_clk, scale, 4);
+	ret = alchemy_clk_fgcs_detr(hw, *rate, best_parent_rate,
+				    best_parent_clk, scale, 4);
+	if (ret < 0)
+		return ret;
+
+	*rate = ret;
+
+	return 0;
 }
 
 static struct clk_ops alchemy_clkops_csrc = {
diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c
index 86c8a07..5f9570d 100644
--- a/drivers/clk/at91/clk-programmable.c
+++ b/drivers/clk/at91/clk-programmable.c
@@ -54,17 +54,18 @@ static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
 	return parent_rate >> pres;
 }
 
-static long clk_programmable_determine_rate(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_hw)
+static int clk_programmable_determine_rate(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_hw)
 {
 	struct clk *parent = NULL;
-	long best_rate = -EINVAL;
 	unsigned long parent_rate;
+	unsigned long best_rate;
 	unsigned long tmp_rate;
+	int ret = -EINVAL;
 	int shift;
 	int i;
 
@@ -76,24 +77,29 @@ static long clk_programmable_determine_rate(struct clk_hw *hw,
 		parent_rate = __clk_get_rate(parent);
 		for (shift = 0; shift < PROG_PRES_MASK; shift++) {
 			tmp_rate = parent_rate >> shift;
-			if (tmp_rate <= rate)
+			if (tmp_rate <= *rate)
 				break;
 		}
 
-		if (tmp_rate > rate)
+		if (tmp_rate > *rate)
 			continue;
 
-		if (best_rate < 0 || (rate - tmp_rate) < (rate - best_rate)) {
+		if (best_rate < 0 || (*rate - tmp_rate) < (*rate - best_rate)) {
 			best_rate = tmp_rate;
 			*best_parent_rate = parent_rate;
 			*best_parent_hw = __clk_get_hw(parent);
+			ret = 0;
 		}
 
 		if (!best_rate)
 			break;
 	}
 
-	return best_rate;
+	if (ret)
+		return ret;
+
+	*rate = best_rate;
+	return 0;
 }
 
 static int clk_programmable_set_parent(struct clk_hw *hw, u8 index)
diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c
index 08a2ee2..3cb5c3d 100644
--- a/drivers/clk/at91/clk-usb.c
+++ b/drivers/clk/at91/clk-usb.c
@@ -56,12 +56,12 @@ static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw,
 	return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1));
 }
 
-static long at91sam9x5_clk_usb_determine_rate(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_hw)
+static int at91sam9x5_clk_usb_determine_rate(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_hw)
 {
 	struct clk *parent = NULL;
 	long best_rate = -EINVAL;
@@ -80,14 +80,14 @@ static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw,
 		for (div = 1; div < SAM9X5_USB_MAX_DIV + 2; div++) {
 			unsigned long tmp_parent_rate;
 
-			tmp_parent_rate = rate * div;
+			tmp_parent_rate = *rate * div;
 			tmp_parent_rate = __clk_round_rate(parent,
 							   tmp_parent_rate);
 			tmp_rate = DIV_ROUND_CLOSEST(tmp_parent_rate, div);
-			if (tmp_rate < rate)
-				tmp_diff = rate - tmp_rate;
+			if (tmp_rate < *rate)
+				tmp_diff = *rate - tmp_rate;
 			else
-				tmp_diff = tmp_rate - rate;
+				tmp_diff = tmp_rate - *rate;
 
 			if (best_diff < 0 || best_diff > tmp_diff) {
 				best_rate = tmp_rate;
@@ -96,7 +96,7 @@ static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw,
 				*best_parent_hw = __clk_get_hw(parent);
 			}
 
-			if (!best_diff || tmp_rate < rate)
+			if (!best_diff || tmp_rate < *rate)
 				break;
 		}
 
@@ -104,7 +104,9 @@ static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw,
 			break;
 	}
 
-	return best_rate;
+	*rate = best_rate;
+
+	return 0;
 }
 
 static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index)
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c
index 05abae8..4a2a66b 100644
--- a/drivers/clk/bcm/clk-kona.c
+++ b/drivers/clk/bcm/clk-kona.c
@@ -1031,7 +1031,7 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate,
 				rate ? rate : 1, *parent_rate, NULL);
 }
 
-static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
+static int kona_peri_clk_determine_rate(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)
@@ -1044,6 +1044,7 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
 	unsigned long best_rate;
 	u32 parent_count;
 	u32 which;
+	long ret;
 
 	/*
 	 * If there is no other parent to choose, use the current one.
@@ -1051,14 +1052,20 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
 	 */
 	WARN_ON_ONCE(bcm_clk->init_data.flags & CLK_SET_RATE_NO_REPARENT);
 	parent_count = (u32)bcm_clk->init_data.num_parents;
-	if (parent_count < 2)
-		return kona_peri_clk_round_rate(hw, rate, best_parent_rate);
+	if (parent_count < 2) {
+		ret = kona_peri_clk_round_rate(hw, *rate, best_parent_rate);
+		if (ret < 0)
+			return ret;
+
+		*rate = ret;
+		return 0;
+	}
 
 	/* Unless we can do better, stick with current parent */
 	current_parent = clk_get_parent(clk);
 	parent_rate = __clk_get_rate(current_parent);
-	best_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate);
-	best_delta = abs(best_rate - rate);
+	best_rate = kona_peri_clk_round_rate(hw, *rate, &parent_rate);
+	best_delta = abs(best_rate - *rate);
 
 	/* Check whether any other parent clock can produce a better result */
 	for (which = 0; which < parent_count; which++) {
@@ -1072,8 +1079,8 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
 
 		/* We don't support CLK_SET_RATE_PARENT */
 		parent_rate = __clk_get_rate(parent);
-		other_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate);
-		delta = abs(other_rate - rate);
+		other_rate = kona_peri_clk_round_rate(hw, *rate, &parent_rate);
+		delta = abs(other_rate - *rate);
 		if (delta < best_delta) {
 			best_delta = delta;
 			best_rate = other_rate;
@@ -1082,7 +1089,8 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
 		}
 	}
 
-	return best_rate;
+	*rate = best_rate;
+	return 0;
 }
 
 static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index)
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
index f56a71d..45c2b51 100644
--- a/drivers/clk/clk-composite.c
+++ b/drivers/clk/clk-composite.c
@@ -55,7 +55,7 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw,
 	return rate_ops->recalc_rate(rate_hw, parent_rate);
 }
 
-static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
+static int clk_composite_determine_rate(struct clk_hw *hw, unsigned long *rate,
 					unsigned long min_rate,
 					unsigned long max_rate,
 					unsigned long *best_parent_rate,
@@ -88,12 +88,8 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
 			*best_parent_p = __clk_get_hw(parent);
 			*best_parent_rate = __clk_get_rate(parent);
 
-			ret = rate_ops->round_rate(rate_hw, &rate,
-						   best_parent_rate);
-			if (ret)
-				return ret;
-
-			return rate;
+			return rate_ops->round_rate(rate_hw, rate,
+						    best_parent_rate);
 		}
 
 		for (i = 0; i < __clk_get_num_parents(mux_hw->clk); i++) {
@@ -103,13 +99,13 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
 
 			parent_rate = __clk_get_rate(parent);
 
-			tmp_rate = rate;
+			tmp_rate = *rate;
 			ret = rate_ops->round_rate(rate_hw, &tmp_rate,
 						   &parent_rate);
 			if (ret < 0)
 				continue;
 
-			rate_diff = abs(rate - tmp_rate);
+			rate_diff = abs(*rate - tmp_rate);
 
 			if (!rate_diff || !*best_parent_p
 				       || best_rate_diff > rate_diff) {
@@ -120,10 +116,10 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
 			}
 
 			if (!rate_diff)
-				return rate;
+				break;
 		}
 
-		return best_rate;
+		*rate = best_rate;
 	} else if (mux_hw && mux_ops && mux_ops->determine_rate) {
 		__clk_hw_set_clk(mux_hw, hw);
 		return mux_ops->determine_rate(mux_hw, rate, min_rate,
@@ -131,8 +127,10 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
 					       best_parent_p);
 	} else {
 		pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n");
-		return 0;
+		*rate = 0;
 	}
+
+	return 0;
 }
 
 static int clk_composite_round_rate(struct clk_hw *hw, unsigned long *rate,
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 6039bd2..ce2dfbb 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -795,8 +795,8 @@ static bool mux_is_better_rate(unsigned long rate, unsigned long now,
 	return now <= rate && now > best;
 }
 
-static long
-clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
+static int
+clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long *rate,
 			     unsigned long min_rate,
 			     unsigned long max_rate,
 			     unsigned long *best_parent_rate,
@@ -804,15 +804,15 @@ clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
 			     unsigned long flags)
 {
 	struct clk_core *core = hw->core, *parent, *best_parent = NULL;
-	int i, num_parents;
-	unsigned long parent_rate, best = 0;
+	int i, num_parents, ret = 0;
+	unsigned long parent_rate = *rate, best = *rate;
 
 	/* if NO_REPARENT flag set, pass through to current parent */
 	if (core->flags & CLK_SET_RATE_NO_REPARENT) {
 		parent = core->parent;
 		if (core->flags & CLK_SET_RATE_PARENT)
-			best = __clk_determine_rate(parent ? parent->hw : NULL,
-						    rate, min_rate, max_rate);
+			ret = __clk_determine_rate(parent ? parent->hw : NULL,
+						   &best, min_rate, max_rate);
 		else if (parent)
 			best = clk_core_get_rate_nolock(parent);
 		else
@@ -827,23 +827,28 @@ clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
 		if (!parent)
 			continue;
 		if (core->flags & CLK_SET_RATE_PARENT)
-			parent_rate = __clk_determine_rate(parent->hw, rate,
-							   min_rate,
-							   max_rate);
+			ret = __clk_determine_rate(parent->hw, &parent_rate,
+						   min_rate,
+						   max_rate);
 		else
 			parent_rate = clk_core_get_rate_nolock(parent);
-		if (mux_is_better_rate(rate, parent_rate, best, flags)) {
+		if (!ret &&
+		    mux_is_better_rate(*rate, parent_rate, best, flags)) {
 			best_parent = parent;
 			best = parent_rate;
 		}
 	}
 
 out:
+	if (ret)
+		return ret;
+
 	if (best_parent)
 		*best_parent_p = best_parent->hw;
 	*best_parent_rate = best;
+	*rate = best;
 
-	return best;
+	return 0;
 }
 
 struct clk *__clk_lookup(const char *name)
@@ -874,11 +879,11 @@ static void clk_core_get_boundaries(struct clk_core *clk,
  * directly as a determine_rate callback (e.g. for a mux), or from a more
  * complex clock that may combine a mux with other operations.
  */
-long __clk_mux_determine_rate(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_p)
+int __clk_mux_determine_rate(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_p)
 {
 	return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate,
 					    best_parent_rate,
@@ -886,7 +891,7 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
 }
 EXPORT_SYMBOL_GPL(__clk_mux_determine_rate);
 
-long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate,
+int __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long *rate,
 			      unsigned long min_rate,
 			      unsigned long max_rate,
 			      unsigned long *best_parent_rate,
@@ -1143,9 +1148,12 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *clk,
 
 	if (clk->ops->determine_rate) {
 		parent_hw = parent ? parent->hw : NULL;
-		return clk->ops->determine_rate(clk->hw, rate,
-						min_rate, max_rate,
-						&parent_rate, &parent_hw);
+		if (clk->ops->determine_rate(clk->hw, &rate,
+					     min_rate, max_rate,
+					     &parent_rate, &parent_hw))
+			return 0;
+
+		return rate;
 	} else if (clk->ops->round_rate) {
 		if (clk->ops->round_rate(clk->hw, &rate, &parent_rate))
 			return 0;
@@ -1168,15 +1176,13 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *clk,
  * Caller must hold prepare_lock.  Useful for clk_ops such as .set_rate and
  * .determine_rate.
  */
-unsigned long __clk_determine_rate(struct clk_hw *hw,
-				   unsigned long rate,
-				   unsigned long min_rate,
-				   unsigned long max_rate)
+int __clk_determine_rate(struct clk_hw *hw, unsigned long *rate,
+			 unsigned long min_rate, unsigned long max_rate)
 {
 	if (!hw)
 		return 0;
 
-	return clk_core_round_rate_nolock(hw->core, rate, min_rate, max_rate);
+	return clk_core_round_rate_nolock(hw->core, *rate, min_rate, max_rate);
 }
 EXPORT_SYMBOL_GPL(__clk_determine_rate);
 
@@ -1637,7 +1643,7 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *clk,
 	/* find the closest rate and parent clk/rate */
 	if (clk->ops->determine_rate) {
 		parent_hw = parent ? parent->hw : NULL;
-		ret = clk->ops->determine_rate(clk->hw, rate,
+		ret = clk->ops->determine_rate(clk->hw, &new_rate,
 					       min_rate,
 					       max_rate,
 					       &best_parent_rate,
diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c
index 472dd2c..c87ae93 100644
--- a/drivers/clk/hisilicon/clk-hi3620.c
+++ b/drivers/clk/hisilicon/clk-hi3620.c
@@ -294,7 +294,7 @@ static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw,
 	}
 }
 
-static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
+static int mmc_clk_determine_rate(struct clk_hw *hw, unsigned long *rate,
 			      unsigned long min_rate,
 			      unsigned long max_rate,
 			      unsigned long *best_parent_rate,
@@ -303,25 +303,25 @@ static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
 	struct clk_mmc *mclk = to_mmc(hw);
 	unsigned long best = 0;
 
-	if ((rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) {
-		rate = 13000000;
+	if ((*rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) {
+		*rate = 13000000;
 		best = 26000000;
-	} else if (rate <= 26000000) {
-		rate = 25000000;
+	} else if (*rate <= 26000000) {
+		*rate = 25000000;
 		best = 180000000;
-	} else if (rate <= 52000000) {
-		rate = 50000000;
+	} else if (*rate <= 52000000) {
+		*rate = 50000000;
 		best = 360000000;
-	} else if (rate <= 100000000) {
-		rate = 100000000;
+	} else if (*rate <= 100000000) {
+		*rate = 100000000;
 		best = 720000000;
 	} else {
 		/* max is 180M */
-		rate = 180000000;
+		*rate = 180000000;
 		best = 1440000000;
 	}
 	*best_parent_rate = best;
-	return rate;
+	return 0;
 }
 
 static u32 mmc_clk_delay(u32 val, u32 para, u32 off, u32 len)
diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c
index de6a873..e15bb57 100644
--- a/drivers/clk/mmp/clk-mix.c
+++ b/drivers/clk/mmp/clk-mix.c
@@ -201,11 +201,11 @@ error:
 	return ret;
 }
 
-static long mmp_clk_mix_determine_rate(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 mmp_clk_mix_determine_rate(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)
 {
 	struct mmp_clk_mix *mix = to_clk_mix(hw);
 	struct mmp_clk_mix_clk_table *item;
@@ -233,7 +233,7 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
 							item->parent_index);
 			parent_rate = __clk_get_rate(parent);
 			mix_rate = parent_rate / item->divisor;
-			gap = abs(mix_rate - rate);
+			gap = abs(mix_rate - *rate);
 			if (parent_best == NULL || gap < gap_best) {
 				parent_best = parent;
 				parent_rate_best = parent_rate;
@@ -251,7 +251,7 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
 			for (j = 0; j < div_val_max; j++) {
 				div = _get_div(mix, j);
 				mix_rate = parent_rate / div;
-				gap = abs(mix_rate - rate);
+				gap = abs(mix_rate - *rate);
 				if (parent_best == NULL || gap < gap_best) {
 					parent_best = parent;
 					parent_rate_best = parent_rate;
@@ -267,8 +267,9 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
 found:
 	*best_parent_rate = parent_rate_best;
 	*best_parent_clk = __clk_get_hw(parent_best);
+	*rate = mix_rate_best;
 
-	return mix_rate_best;
+	return 0;
 }
 
 static int mmp_clk_mix_set_rate_and_parent(struct clk_hw *hw,
diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c
index 245d506..627293a 100644
--- a/drivers/clk/qcom/clk-pll.c
+++ b/drivers/clk/qcom/clk-pll.c
@@ -135,19 +135,21 @@ struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate)
 	return NULL;
 }
 
-static long
-clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate,
+static int
+clk_pll_determine_rate(struct clk_hw *hw, unsigned long *rate,
 		       unsigned long min_rate, unsigned long max_rate,
 		       unsigned long *p_rate, struct clk_hw **p)
 {
 	struct clk_pll *pll = to_clk_pll(hw);
 	const struct pll_freq_tbl *f;
 
-	f = find_freq(pll->freq_tbl, rate);
+	f = find_freq(pll->freq_tbl, *rate);
 	if (!f)
-		return clk_pll_recalc_rate(hw, *p_rate);
+		*rate = clk_pll_recalc_rate(hw, *p_rate);
+	else
+		*rate = f->freq;
 
-	return f->freq;
+	return 0;
 }
 
 static int
diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c
index 7b3d626..8d15a86 100644
--- a/drivers/clk/qcom/clk-rcg.c
+++ b/drivers/clk/qcom/clk-rcg.c
@@ -404,17 +404,17 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
 	return calc_rate(parent_rate, m, n, mode, pre_div);
 }
 
-static long _freq_tbl_determine_rate(struct clk_hw *hw,
-		const struct freq_tbl *f, unsigned long rate,
+static int _freq_tbl_determine_rate(struct clk_hw *hw,
+		const struct freq_tbl *f, unsigned long *rate,
 		unsigned long min_rate, unsigned long max_rate,
 		unsigned long *p_rate, struct clk_hw **p_hw,
 		const struct parent_map *parent_map)
 {
-	unsigned long clk_flags;
+	unsigned long clk_flags, parent_rate;
 	struct clk *p;
 	int index;
 
-	f = qcom_find_freq(f, rate);
+	f = qcom_find_freq(f, *rate);
 	if (!f)
 		return -EINVAL;
 
@@ -425,23 +425,24 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
 	clk_flags = __clk_get_flags(hw->clk);
 	p = clk_get_parent_by_index(hw->clk, index);
 	if (clk_flags & CLK_SET_RATE_PARENT) {
-		rate = rate * f->pre_div;
+		parent_rate = *rate * f->pre_div;
 		if (f->n) {
-			u64 tmp = rate;
+			u64 tmp = parent_rate;
 			tmp = tmp * f->n;
 			do_div(tmp, f->m);
-			rate = tmp;
+			parent_rate = tmp;
 		}
 	} else {
-		rate =  __clk_get_rate(p);
+		parent_rate =  __clk_get_rate(p);
 	}
 	*p_hw = __clk_get_hw(p);
-	*p_rate = rate;
+	*p_rate = parent_rate;
+	*rate = f->freq;
 
-	return f->freq;
+	return 0;
 }
 
-static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
+static int clk_rcg_determine_rate(struct clk_hw *hw, unsigned long *rate,
 		unsigned long min_rate, unsigned long max_rate,
 		unsigned long *p_rate, struct clk_hw **p)
 {
@@ -451,7 +452,7 @@ static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
 			max_rate, p_rate, p, rcg->s.parent_map);
 }
 
-static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
+static int clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long *rate,
 		unsigned long min_rate, unsigned long max_rate,
 		unsigned long *p_rate, struct clk_hw **p)
 {
@@ -468,7 +469,7 @@ static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
 			max_rate, p_rate, p, s->parent_map);
 }
 
-static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate,
+static int clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long *rate,
 		unsigned long min_rate, unsigned long max_rate,
 		unsigned long *p_rate, struct clk_hw **p_hw)
 {
@@ -479,9 +480,10 @@ static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate,
 
 	p = clk_get_parent_by_index(hw->clk, index);
 	*p_hw = __clk_get_hw(p);
-	*p_rate = __clk_round_rate(p, rate);
+	*p_rate = __clk_round_rate(p, *rate);
+	*rate = *p_rate;
 
-	return *p_rate;
+	return 0;
 }
 
 static int __clk_rcg_set_rate(struct clk_rcg *rcg, const struct freq_tbl *f)
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index b95d17f..db1f1c9 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -176,16 +176,16 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
 	return calc_rate(parent_rate, m, n, mode, hid_div);
 }
 
-static long _freq_tbl_determine_rate(struct clk_hw *hw,
-		const struct freq_tbl *f, unsigned long rate,
+static int _freq_tbl_determine_rate(struct clk_hw *hw,
+		const struct freq_tbl *f, unsigned long *rate,
 		unsigned long *p_rate, struct clk_hw **p_hw)
 {
-	unsigned long clk_flags;
+	unsigned long clk_flags, parent_rate = *rate;
 	struct clk *p;
 	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
 	int index;
 
-	f = qcom_find_freq(f, rate);
+	f = qcom_find_freq(f, *rate);
 	if (!f)
 		return -EINVAL;
 
@@ -197,26 +197,27 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
 	p = clk_get_parent_by_index(hw->clk, index);
 	if (clk_flags & CLK_SET_RATE_PARENT) {
 		if (f->pre_div) {
-			rate /= 2;
-			rate *= f->pre_div + 1;
+			parent_rate /= 2;
+			parent_rate *= f->pre_div + 1;
 		}
 
 		if (f->n) {
-			u64 tmp = rate;
+			u64 tmp = parent_rate;
 			tmp = tmp * f->n;
 			do_div(tmp, f->m);
-			rate = tmp;
+			parent_rate = tmp;
 		}
 	} else {
-		rate =  __clk_get_rate(p);
+		parent_rate =  __clk_get_rate(p);
 	}
 	*p_hw = __clk_get_hw(p);
-	*p_rate = rate;
+	*p_rate = parent_rate;
+	*rate = f->freq;
 
-	return f->freq;
+	return 0;
 }
 
-static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate,
+static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long *rate,
 		unsigned long min_rate, unsigned long max_rate,
 		unsigned long *p_rate, struct clk_hw **p)
 {
@@ -374,7 +375,7 @@ static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw,
 	return clk_edp_pixel_set_rate(hw, rate, parent_rate);
 }
 
-static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
+static int clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long *rate,
 				 unsigned long min_rate,
 				 unsigned long max_rate,
 				 unsigned long *p_rate, struct clk_hw **p)
@@ -398,7 +399,7 @@ static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
 		frac = frac_table_675m;
 
 	for (; frac->num; frac++) {
-		request = rate;
+		request = *rate;
 		request *= frac->den;
 		request = div_s64(request, frac->num);
 		if ((src_rate < (request - delta)) ||
@@ -410,8 +411,10 @@ static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
 		hid_div >>= CFG_SRC_DIV_SHIFT;
 		hid_div &= mask;
 
-		return calc_rate(src_rate, frac->num, frac->den, !!frac->den,
-				 hid_div);
+		*rate = calc_rate(src_rate, frac->num, frac->den, !!frac->den,
+				  hid_div);
+
+		return 0;
 	}
 
 	return -EINVAL;
@@ -428,7 +431,7 @@ const struct clk_ops clk_edp_pixel_ops = {
 };
 EXPORT_SYMBOL_GPL(clk_edp_pixel_ops);
 
-static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate,
+static int clk_byte_determine_rate(struct clk_hw *hw, unsigned long *rate,
 			 unsigned long min_rate, unsigned long max_rate,
 			 unsigned long *p_rate, struct clk_hw **p_hw)
 {
@@ -439,17 +442,18 @@ static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate,
 	u32 mask = BIT(rcg->hid_width) - 1;
 	struct clk *p;
 
-	if (rate == 0)
+	if (*rate == 0)
 		return -EINVAL;
 
 	p = clk_get_parent_by_index(hw->clk, index);
 	*p_hw = __clk_get_hw(p);
-	*p_rate = parent_rate = __clk_round_rate(p, rate);
+	*p_rate = parent_rate = __clk_round_rate(p, *rate);
 
-	div = DIV_ROUND_UP((2 * parent_rate), rate) - 1;
+	div = DIV_ROUND_UP((2 * parent_rate), *rate) - 1;
 	div = min_t(u32, div, mask);
+	*rate = calc_rate(parent_rate, 0, 0, 0, div);
 
-	return calc_rate(parent_rate, 0, 0, 0, div);
+	return 0;
 }
 
 static int clk_byte_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -494,7 +498,7 @@ static const struct frac_entry frac_table_pixel[] = {
 	{ }
 };
 
-static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
+static int clk_pixel_determine_rate(struct clk_hw *hw, unsigned long *rate,
 				 unsigned long min_rate,
 				 unsigned long max_rate,
 				 unsigned long *p_rate, struct clk_hw **p)
@@ -510,7 +514,7 @@ static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
 	*p = __clk_get_hw(parent);
 
 	for (; frac->num; frac++) {
-		request = (rate * frac->den) / frac->num;
+		request = (*rate * frac->den) / frac->num;
 
 		src_rate = __clk_round_rate(parent, request);
 		if ((src_rate < (request - delta)) ||
@@ -518,7 +522,9 @@ static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
 			continue;
 
 		*p_rate = src_rate;
-		return (src_rate * frac->num) / frac->den;
+		*rate = (src_rate * frac->num) / frac->den;
+
+		return 0;
 	}
 
 	return -EINVAL;
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
index 5865300..1cef6a5 100644
--- a/drivers/clk/sunxi/clk-factors.c
+++ b/drivers/clk/sunxi/clk-factors.c
@@ -82,11 +82,11 @@ static int clk_factors_round_rate(struct clk_hw *hw, unsigned long *rate,
 	return 0;
 }
 
-static long clk_factors_determine_rate(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_p)
+static int clk_factors_determine_rate(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_p)
 {
 	struct clk *clk = hw->clk, *parent, *best_parent = NULL;
 	int i, num_parents;
@@ -99,14 +99,14 @@ static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate,
 		if (!parent)
 			continue;
 		if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT)
-			parent_rate = __clk_round_rate(parent, rate);
+			parent_rate = __clk_round_rate(parent, *rate);
 		else
 			parent_rate = __clk_get_rate(parent);
 
-		child_rate = rate;
+		child_rate = *rate;
 		clk_factors_round_rate(hw, &child_rate, &parent_rate);
 
-		if (child_rate <= rate && child_rate > best_child_rate) {
+		if (child_rate <= *rate && child_rate > best_child_rate) {
 			best_parent = parent;
 			best = parent_rate;
 			best_child_rate = child_rate;
@@ -116,8 +116,9 @@ static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate,
 	if (best_parent)
 		*best_parent_p = __clk_get_hw(best_parent);
 	*best_parent_rate = best;
+	*rate = best_child_rate;
 
-	return best_child_rate;
+	return 0;
 }
 
 static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c
index 63cf149..f398190 100644
--- a/drivers/clk/sunxi/clk-sun6i-ar100.c
+++ b/drivers/clk/sunxi/clk-sun6i-ar100.c
@@ -44,11 +44,11 @@ static unsigned long ar100_recalc_rate(struct clk_hw *hw,
 	return (parent_rate >> shift) / (div + 1);
 }
 
-static long ar100_determine_rate(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 ar100_determine_rate(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)
 {
 	int nparents = __clk_get_num_parents(hw->clk);
 	long best_rate = -EINVAL;
@@ -65,7 +65,7 @@ static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate,
 
 		parent = clk_get_parent_by_index(hw->clk, i);
 		parent_rate = __clk_get_rate(parent);
-		div = DIV_ROUND_UP(parent_rate, rate);
+		div = DIV_ROUND_UP(parent_rate, *rate);
 
 		/*
 		 * The AR100 clk contains 2 divisors:
@@ -108,7 +108,11 @@ static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate,
 		}
 	}
 
-	return best_rate;
+	if (best_rate < 0)
+		return best_rate;
+
+	*rate = best_rate;
+	return 0;
 }
 
 static int ar100_set_parent(struct clk_hw *hw, u8 index)
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 7e1e2bd..3f2420f 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -118,11 +118,11 @@ static long sun6i_ahb1_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp,
 	return (parent_rate / calcm) >> calcp;
 }
 
-static long sun6i_ahb1_clk_determine_rate(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 sun6i_ahb1_clk_determine_rate(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)
 {
 	struct clk *clk = hw->clk, *parent, *best_parent = NULL;
 	int i, num_parents;
@@ -135,14 +135,14 @@ static long sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
 		if (!parent)
 			continue;
 		if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT)
-			parent_rate = __clk_round_rate(parent, rate);
+			parent_rate = __clk_round_rate(parent, *rate);
 		else
 			parent_rate = __clk_get_rate(parent);
 
-		child_rate = sun6i_ahb1_clk_round(rate, NULL, NULL, i,
+		child_rate = sun6i_ahb1_clk_round(*rate, NULL, NULL, i,
 						  parent_rate);
 
-		if (child_rate <= rate && child_rate > best_child_rate) {
+		if (child_rate <= *rate && child_rate > best_child_rate) {
 			best_parent = parent;
 			best = parent_rate;
 			best_child_rate = child_rate;
@@ -152,8 +152,9 @@ static long sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
 	if (best_parent)
 		*best_parent_clk = __clk_get_hw(best_parent);
 	*best_parent_rate = best;
+	*rate = best_child_rate;
 
-	return best_child_rate;
+	return 0;
 }
 
 static int sun6i_ahb1_clk_set_rate(struct clk_hw *hw, unsigned long rate,
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 84047b1..5f6859b 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -175,8 +175,8 @@ struct clk_ops {
 					unsigned long parent_rate);
 	int		(*round_rate)(struct clk_hw *hw, unsigned long *rate,
 				      unsigned long *parent_rate);
-	long		(*determine_rate)(struct clk_hw *hw,
-					  unsigned long rate,
+	int		(*determine_rate)(struct clk_hw *hw,
+					  unsigned long *rate,
 					  unsigned long min_rate,
 					  unsigned long max_rate,
 					  unsigned long *best_parent_rate,
@@ -575,16 +575,16 @@ unsigned long __clk_get_flags(struct clk *clk);
 bool __clk_is_prepared(struct clk *clk);
 bool __clk_is_enabled(struct clk *clk);
 struct clk *__clk_lookup(const char *name);
-long __clk_mux_determine_rate(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_p);
-unsigned long __clk_determine_rate(struct clk_hw *core,
-				   unsigned long rate,
-				   unsigned long min_rate,
-				   unsigned long max_rate);
-long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate,
+int __clk_mux_determine_rate(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_p);
+int __clk_determine_rate(struct clk_hw *core,
+			 unsigned long *rate,
+			 unsigned long min_rate,
+			 unsigned long max_rate);
+int __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long *rate,
 			      unsigned long min_rate,
 			      unsigned long max_rate,
 			      unsigned long *best_parent_rate,
diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h
index 3b2406c..1df140f 100644
--- a/include/linux/clk/ti.h
+++ b/include/linux/clk/ti.h
@@ -269,23 +269,23 @@ int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw,
 					   unsigned long rate,
 					   unsigned long parent_rate,
 					   u8 index);
-long omap3_noncore_dpll_determine_rate(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);
+int omap3_noncore_dpll_determine_rate(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);
 unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
 					 unsigned long parent_rate);
 int omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
 				   unsigned long *target_rate,
 				   unsigned long *parent_rate);
-long omap4_dpll_regm4xen_determine_rate(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);
+int omap4_dpll_regm4xen_determine_rate(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);
 u8 omap2_init_dpll_parent(struct clk_hw *hw);
 unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate);
 int omap2_dpll_round_rate(struct clk_hw *hw, unsigned long *target_rate,
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ