Skip to content

Commit

Permalink
clk: at91: usb: fix at91rm9200 round and set rate
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Boris Brezillon authored and Michael Turquette committed Nov 17, 2014
1 parent 206c5f6 commit ff553ea
Showing 1 changed file with 3 additions and 3 deletions.
6 changes: 3 additions & 3 deletions drivers/clk/at91/clk-usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit ff553ea

Please sign in to comment.