summaryrefslogtreecommitdiff
path: root/drivers/clk/at91
diff options
context:
space:
mode:
authorBoris Brezillon <boris.brezillon@free-electrons.com>2014-11-14 19:54:49 +0100
committerMichael Turquette <mturquette@linaro.org>2014-11-17 10:38:40 -0800
commitff553ea1a3d5b903becda790eeb6bd3debf239f9 (patch)
treebecb282ec5a16929bc69a105e7ad2ef09cac6875 /drivers/clk/at91
parent206c5f60a3d902bc4b56dab2de3e88de5eb06108 (diff)
clk: at91: usb: fix at91rm9200 round and set rate
at91rm9200_clk_usb_set_rate might fail depending on the requested rate, because the parent_rate / rate remainder is not necessarily zero. Moreover, when rounding down the calculated rate we might alter the divisor calculation and end up with an invalid divisor. To solve those problems, accept a non zero remainder, and always round division to the closest result. Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com> Reported-by: Andreas Henriksson <andreas.henriksson@endian.se> Tested-by: Andreas Henriksson <andreas.henriksson@endian.se> Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> Signed-off-by: Michael Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers/clk/at91')
-rw-r--r--drivers/clk/at91/clk-usb.c6
1 files changed, 3 insertions, 3 deletions
diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c
index 24b5b020753a..5b3b63c07524 100644
--- a/drivers/clk/at91/clk-usb.c
+++ b/drivers/clk/at91/clk-usb.c
@@ -253,7 +253,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
tmp_parent_rate = rate * usb->divisors[i];
tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate);
- tmprate = tmp_parent_rate / usb->divisors[i];
+ tmprate = DIV_ROUND_CLOSEST(tmp_parent_rate, usb->divisors[i]);
if (tmprate < rate)
tmpdiff = rate - tmprate;
else
@@ -281,10 +281,10 @@ static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
struct at91_pmc *pmc = usb->pmc;
unsigned long div;
- if (!rate || parent_rate % rate)
+ if (!rate)
return -EINVAL;
- div = parent_rate / rate;
+ div = DIV_ROUND_CLOSEST(parent_rate, rate);
for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) {
if (usb->divisors[i] == div) {