|
@@ -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);
|
|
|
-
|
|
|
- bestrate = *parent_rate / div;
|
|
|
- tmp = *parent_rate / (div + 1);
|
|
|
- if (bestrate - rate > rate - tmp)
|
|
|
- bestrate = tmp;
|
|
|
+ div = DIV_ROUND_CLOSEST(*parent_rate, rate);
|
|
|
+ if (div > SAM9X5_USB_MAX_DIV + 1)
|
|
|
+ div = SAM9X5_USB_MAX_DIV + 1;
|
|
|
|
|
|
- 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;
|
|
@@ -253,7 +254,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 +282,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) {
|