Commit ff553ea1 authored by Boris Brezillon's avatar Boris Brezillon Committed by Michael Turquette

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: default avatarBoris Brezillon <boris.brezillon@free-electrons.com>
Reported-by: default avatarAndreas Henriksson <andreas.henriksson@endian.se>
Tested-by: default avatarAndreas Henriksson <andreas.henriksson@endian.se>
Acked-by: default avatarNicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: default avatarMichael Turquette <mturquette@linaro.org>
parent 206c5f60
...@@ -253,7 +253,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -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 = rate * usb->divisors[i];
tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate); 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) if (tmprate < rate)
tmpdiff = rate - tmprate; tmpdiff = rate - tmprate;
else else
...@@ -281,10 +281,10 @@ static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -281,10 +281,10 @@ static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
struct at91_pmc *pmc = usb->pmc; struct at91_pmc *pmc = usb->pmc;
unsigned long div; unsigned long div;
if (!rate || parent_rate % rate) if (!rate)
return -EINVAL; return -EINVAL;
div = parent_rate / rate; div = DIV_ROUND_CLOSEST(parent_rate, rate);
for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) { for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) {
if (usb->divisors[i] == div) { if (usb->divisors[i] == div) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment