[PATCH 1/2] clk: at91: usb: fix at91rm9200 round and set rate
Andreas Henriksson
andreas at fatal.se
Wed Nov 5 05:12:07 PST 2014
Hello!
Just confirming this exact patch fixes the problem I was running into.
On Wed, Nov 05, 2014 at 10:33:14AM +0100, Boris Brezillon wrote:
> 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 at free-electrons.com>
> Reported-by: Andreas Henriksson <andreas.henriksson at endian.se>
Tested-by: Andreas Henriksson <andreas.henriksson at endian.se>
> ---
> drivers/clk/at91/clk-usb.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c
> index 24b5b02..5b3b63c 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) {
> --
> 1.9.1
>
More information about the linux-arm-kernel
mailing list