diff mbox

[2/2] clk: axi-clkgen: Round closest in round_rate() and recalc_rate()

Message ID 20170905093241.18582-2-lars@metafoo.de (mailing list archive)
State Accepted, archived
Headers show

Commit Message

Lars-Peter Clausen Sept. 5, 2017, 9:32 a.m. UTC
To minimize the rounding error round to the closest integer when
calculating the result in the recalc_rate() and set_rate() callbacks.

Also in order to improve precision multiply first and then divide.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/clk/clk-axi-clkgen.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

Comments

Stephen Boyd Dec. 22, 2017, 2:08 a.m. UTC | #1
On 09/05, Lars-Peter Clausen wrote:
> To minimize the rounding error round to the closest integer when
> calculating the result in the recalc_rate() and set_rate() callbacks.
> 
> Also in order to improve precision multiply first and then divide.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
> ---

Applied to clk-next
diff mbox

Patch

diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c
index 95a6e9834392..48d11f2598e8 100644
--- a/drivers/clk/clk-axi-clkgen.c
+++ b/drivers/clk/clk-axi-clkgen.c
@@ -302,13 +302,17 @@  static long axi_clkgen_round_rate(struct clk_hw *hw, unsigned long rate,
 	unsigned long *parent_rate)
 {
 	unsigned int d, m, dout;
+	unsigned long long tmp;
 
 	axi_clkgen_calc_params(*parent_rate, rate, &d, &m, &dout);
 
 	if (d == 0 || dout == 0 || m == 0)
 		return -EINVAL;
 
-	return *parent_rate / d * m / dout;
+	tmp = (unsigned long long)*parent_rate * m;
+	tmp = DIV_ROUND_CLOSEST_ULL(tmp, dout * d);
+
+	return min_t(unsigned long long, tmp, LONG_MAX);
 }
 
 static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw,
@@ -344,8 +348,8 @@  static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw,
 	if (d == 0 || dout == 0)
 		return 0;
 
-	tmp = (unsigned long long)(parent_rate / d) * m;
-	do_div(tmp, dout);
+	tmp = (unsigned long long)parent_rate * m;
+	tmp = DIV_ROUND_CLOSEST_ULL(tmp, dout * d);
 
 	return min_t(unsigned long long, tmp, ULONG_MAX);
 }