Commit 13a6073d authored by Boris BREZILLON's avatar Boris BREZILLON Committed by Mike Turquette

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: default avatarBoris BREZILLON <boris.brezillon@free-electrons.com>
Reported-by: default avatarGaël PORTAY <gael.portay@gmail.com>
Tested-by: default avatarGaël PORTAY <gael.portay@gmail.com>
Signed-off-by: default avatarMike Turquette <mturquette@linaro.org>
parent 87e2ed33
...@@ -238,16 +238,22 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -238,16 +238,22 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate) unsigned long *parent_rate)
{ {
struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
struct clk *parent = __clk_get_parent(hw->clk);
unsigned long bestrate = 0; unsigned long bestrate = 0;
int bestdiff = -1; int bestdiff = -1;
unsigned long tmprate; unsigned long tmprate;
int tmpdiff; int tmpdiff;
int i = 0; int i = 0;
for (i = 0; i < 4; i++) { for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) {
unsigned long tmp_parent_rate;
if (!usb->divisors[i]) if (!usb->divisors[i])
continue; continue;
tmprate = *parent_rate / usb->divisors[i];
tmp_parent_rate = rate * usb->divisors[i];
tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate);
tmprate = tmp_parent_rate / usb->divisors[i];
if (tmprate < rate) if (tmprate < rate)
tmpdiff = rate - tmprate; tmpdiff = rate - tmprate;
else else
...@@ -256,6 +262,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -256,6 +262,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
if (bestdiff < 0 || bestdiff > tmpdiff) { if (bestdiff < 0 || bestdiff > tmpdiff) {
bestrate = tmprate; bestrate = tmprate;
bestdiff = tmpdiff; bestdiff = tmpdiff;
*parent_rate = tmp_parent_rate;
} }
if (!bestdiff) if (!bestdiff)
...@@ -311,7 +318,7 @@ at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name, ...@@ -311,7 +318,7 @@ at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name,
init.ops = &at91rm9200_usb_ops; init.ops = &at91rm9200_usb_ops;
init.parent_names = &parent_name; init.parent_names = &parent_name;
init.num_parents = 1; init.num_parents = 1;
init.flags = 0; init.flags = CLK_SET_RATE_PARENT;
usb->hw.init = &init; usb->hw.init = &init;
usb->pmc = pmc; usb->pmc = pmc;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment