3.16.7-ckt11 -stable review patch.  If anyone has any objections, please let me 
know.

------------------

From: Boris Brezillon <[email protected]>

commit 69daf75aafc8410ef046c70be65c71f2dd4e08f9 upstream.

First check for rate == 0 in set_rate and round_rate to avoid div by zero.
Then, in order to get the closest rate, round all divisions to the closest
result instead of rounding them down.

Signed-off-by: Boris Brezillon <[email protected]>
Acked-by: Nicolas Ferre <[email protected]>
Signed-off-by: Michael Turquette <[email protected]>
[ luis: 3.16 prereq for:
  4591243102fa "clk: at91: usb: propagate rate modification to the parent clk" ]
Signed-off-by: Luis Henriques <[email protected]>
---
 drivers/clk/at91/clk-usb.c | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c
index 7d1d26a4bd04..03fda404bb96 100644
--- a/drivers/clk/at91/clk-usb.c
+++ b/drivers/clk/at91/clk-usb.c
@@ -52,29 +52,26 @@ static unsigned long at91sam9x5_clk_usb_recalc_rate(struct 
clk_hw *hw,
 
        tmp = pmc_read(pmc, AT91_PMC_USB);
        usbdiv = (tmp & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT;
-       return parent_rate / (usbdiv + 1);
+
+       return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1));
 }
 
 static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long 
rate,
                                          unsigned long *parent_rate)
 {
        unsigned long div;
-       unsigned long bestrate;
-       unsigned long tmp;
+
+       if (!rate)
+               return -EINVAL;
 
        if (rate >= *parent_rate)
                return *parent_rate;
 
-       div = *parent_rate / rate;
-       if (div >= SAM9X5_USB_MAX_DIV)
-               return *parent_rate / (SAM9X5_USB_MAX_DIV + 1);
+       div = DIV_ROUND_CLOSEST(*parent_rate, rate);
+       if (div > SAM9X5_USB_MAX_DIV + 1)
+               div = SAM9X5_USB_MAX_DIV + 1;
 
-       bestrate = *parent_rate / div;
-       tmp = *parent_rate / (div + 1);
-       if (bestrate - rate > rate - tmp)
-               bestrate = tmp;
-
-       return bestrate;
+       return DIV_ROUND_CLOSEST(*parent_rate, div);
 }
 
 static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index)
@@ -106,9 +103,13 @@ static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, 
unsigned long rate,
        u32 tmp;
        struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
        struct at91_pmc *pmc = usb->pmc;
-       unsigned long div = parent_rate / rate;
+       unsigned long div;
+
+       if (!rate)
+               return -EINVAL;
 
-       if (parent_rate % rate || div < 1 || div >= SAM9X5_USB_MAX_DIV)
+       div = DIV_ROUND_CLOSEST(parent_rate, rate);
+       if (div > SAM9X5_USB_MAX_DIV + 1 || !div)
                return -EINVAL;
 
        tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_OHCIUSBDIV;
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to