diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2017-09-05 11:32:41 +0200 |
---|---|---|
committer | Stephen Boyd <sboyd@codeaurora.org> | 2017-12-21 18:07:53 -0800 |
commit | 448c3c057a1dbb6ecf6e507a3f1a58f5eab21560 (patch) | |
tree | 358c0a4e6675ce3f4396baebe422d8aad2f2168d | |
parent | 063578dc5f407f67d149133818efabe457daafda (diff) | |
download | linux-448c3c057a1dbb6ecf6e507a3f1a58f5eab21560.tar.bz2 |
clk: axi-clkgen: Round closest in round_rate() and recalc_rate()
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>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-rw-r--r-- | drivers/clk/clk-axi-clkgen.c | 10 |
1 files changed, 7 insertions, 3 deletions
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); } |