aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoris BREZILLON <boris.brezillon@free-electrons.com>2014-09-02 03:50:17 -0400
committerMike Turquette <mturquette@linaro.org>2014-09-02 18:37:22 -0400
commit13a6073d4c5db3103011eebe8c68b049323ced20 (patch)
treea9e2dee2d3c352d77e7275b28d853eca06fb13ab
parent87e2ed338f1b56798807ccf12eb6112d25062202 (diff)
clk: at91: rework rm9200 USB clock to propagate set_rate to the parent clk
The RM9200 USB clock is actually connected to a single parent (the PLLB) on which we can apply a specific divider. The USB clock divider does not allow for fine grained control on the USB clock frequency, hence propagating the set_rate request to the parent is the only choice we have to properly configure the USB clock rate. Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com> Reported-by: Gaël PORTAY <gael.portay@gmail.com> Tested-by: Gaël PORTAY <gael.portay@gmail.com> Signed-off-by: Mike Turquette <mturquette@linaro.org>
-rw-r--r--drivers/clk/at91/clk-usb.c13
1 files changed, 10 insertions, 3 deletions
diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c
index 7d1d26a4bd04..183877712c6c 100644
--- a/drivers/clk/at91/clk-usb.c
+++ b/drivers/clk/at91/clk-usb.c
@@ -238,16 +238,22 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
238 unsigned long *parent_rate) 238 unsigned long *parent_rate)
239{ 239{
240 struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); 240 struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
241 struct clk *parent = __clk_get_parent(hw->clk);
241 unsigned long bestrate = 0; 242 unsigned long bestrate = 0;
242 int bestdiff = -1; 243 int bestdiff = -1;
243 unsigned long tmprate; 244 unsigned long tmprate;
244 int tmpdiff; 245 int tmpdiff;
245 int i = 0; 246 int i = 0;
246 247
247 for (i = 0; i < 4; i++) { 248 for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) {
249 unsigned long tmp_parent_rate;
250
248 if (!usb->divisors[i]) 251 if (!usb->divisors[i])
249 continue; 252 continue;
250 tmprate = *parent_rate / usb->divisors[i]; 253
254 tmp_parent_rate = rate * usb->divisors[i];
255 tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate);
256 tmprate = tmp_parent_rate / usb->divisors[i];
251 if (tmprate < rate) 257 if (tmprate < rate)
252 tmpdiff = rate - tmprate; 258 tmpdiff = rate - tmprate;
253 else 259 else
@@ -256,6 +262,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
256 if (bestdiff < 0 || bestdiff > tmpdiff) { 262 if (bestdiff < 0 || bestdiff > tmpdiff) {
257 bestrate = tmprate; 263 bestrate = tmprate;
258 bestdiff = tmpdiff; 264 bestdiff = tmpdiff;
265 *parent_rate = tmp_parent_rate;
259 } 266 }
260 267
261 if (!bestdiff) 268 if (!bestdiff)
@@ -311,7 +318,7 @@ at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name,
311 init.ops = &at91rm9200_usb_ops; 318 init.ops = &at91rm9200_usb_ops;
312 init.parent_names = &parent_name; 319 init.parent_names = &parent_name;
313 init.num_parents = 1; 320 init.num_parents = 1;
314 init.flags = 0; 321 init.flags = CLK_SET_RATE_PARENT;
315 322
316 usb->hw.init = &init; 323 usb->hw.init = &init;
317 usb->pmc = pmc; 324 usb->pmc = pmc;