aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/at91/clk-usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/at91/clk-usb.c')
-rw-r--r--drivers/clk/at91/clk-usb.c35
1 files changed, 18 insertions, 17 deletions
diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c
index 24b5b020753a..a23ac0c724f0 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,
52 52
53 tmp = pmc_read(pmc, AT91_PMC_USB); 53 tmp = pmc_read(pmc, AT91_PMC_USB);
54 usbdiv = (tmp & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT; 54 usbdiv = (tmp & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT;
55 return parent_rate / (usbdiv + 1); 55
56 return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1));
56} 57}
57 58
58static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, 59static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
59 unsigned long *parent_rate) 60 unsigned long *parent_rate)
60{ 61{
61 unsigned long div; 62 unsigned long div;
62 unsigned long bestrate; 63
63 unsigned long tmp; 64 if (!rate)
65 return -EINVAL;
64 66
65 if (rate >= *parent_rate) 67 if (rate >= *parent_rate)
66 return *parent_rate; 68 return *parent_rate;
67 69
68 div = *parent_rate / rate; 70 div = DIV_ROUND_CLOSEST(*parent_rate, rate);
69 if (div >= SAM9X5_USB_MAX_DIV) 71 if (div > SAM9X5_USB_MAX_DIV + 1)
70 return *parent_rate / (SAM9X5_USB_MAX_DIV + 1); 72 div = SAM9X5_USB_MAX_DIV + 1;
71
72 bestrate = *parent_rate / div;
73 tmp = *parent_rate / (div + 1);
74 if (bestrate - rate > rate - tmp)
75 bestrate = tmp;
76 73
77 return bestrate; 74 return DIV_ROUND_CLOSEST(*parent_rate, div);
78} 75}
79 76
80static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index) 77static 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,
106 u32 tmp; 103 u32 tmp;
107 struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); 104 struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
108 struct at91_pmc *pmc = usb->pmc; 105 struct at91_pmc *pmc = usb->pmc;
109 unsigned long div = parent_rate / rate; 106 unsigned long div;
107
108 if (!rate)
109 return -EINVAL;
110 110
111 if (parent_rate % rate || div < 1 || div >= SAM9X5_USB_MAX_DIV) 111 div = DIV_ROUND_CLOSEST(parent_rate, rate);
112 if (div > SAM9X5_USB_MAX_DIV + 1 || !div)
112 return -EINVAL; 113 return -EINVAL;
113 114
114 tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_OHCIUSBDIV; 115 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,
253 254
254 tmp_parent_rate = rate * usb->divisors[i]; 255 tmp_parent_rate = rate * usb->divisors[i];
255 tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate); 256 tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate);
256 tmprate = tmp_parent_rate / usb->divisors[i]; 257 tmprate = DIV_ROUND_CLOSEST(tmp_parent_rate, usb->divisors[i]);
257 if (tmprate < rate) 258 if (tmprate < rate)
258 tmpdiff = rate - tmprate; 259 tmpdiff = rate - tmprate;
259 else 260 else
@@ -281,10 +282,10 @@ static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
281 struct at91_pmc *pmc = usb->pmc; 282 struct at91_pmc *pmc = usb->pmc;
282 unsigned long div; 283 unsigned long div;
283 284
284 if (!rate || parent_rate % rate) 285 if (!rate)
285 return -EINVAL; 286 return -EINVAL;
286 287
287 div = parent_rate / rate; 288 div = DIV_ROUND_CLOSEST(parent_rate, rate);
288 289
289 for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) { 290 for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) {
290 if (usb->divisors[i] == div) { 291 if (usb->divisors[i] == div) {