Skip to content

Commit

Permalink
USB: ehci-atmel: rework clk handling
Browse files Browse the repository at this point in the history
The EHCI IP only needs the UTMI/UPLL (uclk) and the peripheral (iclk)
clocks to work properly. Remove the useless system clock (fclk).

Avoid calling set_rate on the fixed rate UTMI/IPLL clock and remove
useless IS_ENABLED(CONFIG_COMMON_CLK) tests (all at91 platforms have been
moved to the CCF).

This patch also fixes a bug introduced by 3440ef1 (ARM: at91/dt: fix USB
high-speed clock to select UTMI), which was leaving the usb clock
uninitialized and preventing the OHCI driver from setting the usb clock
rate to 48MHz.
This bug was caused by several things:
1/ usb clock drivers set the CLK_SET_RATE_GATE flag, which means the rate
   cannot be changed once the clock is prepared
2/ The EHCI driver was retrieving and preparing/enabling the uhpck
   clock which was in turn preparing its parent clock (the usb clock),
   thus preventing any rate change because of 1/

Fixes: 3440ef1 ("ARM: at91/dt: fix USB high-speed clock to select UTMI")
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Boris Brezillon authored and Greg Kroah-Hartman committed Mar 18, 2015
1 parent 963ffa3 commit e32643a
Showing 1 changed file with 9 additions and 21 deletions.
30 changes: 9 additions & 21 deletions drivers/usb/host/ehci-atmel.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ static const char hcd_name[] = "ehci-atmel";

struct atmel_ehci_priv {
struct clk *iclk;
struct clk *fclk;
struct clk *uclk;
bool clocked;
};
Expand All @@ -51,23 +50,19 @@ static void atmel_start_clock(struct atmel_ehci_priv *atmel_ehci)
{
if (atmel_ehci->clocked)
return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
clk_set_rate(atmel_ehci->uclk, 48000000);
clk_prepare_enable(atmel_ehci->uclk);
}

clk_prepare_enable(atmel_ehci->uclk);
clk_prepare_enable(atmel_ehci->iclk);
clk_prepare_enable(atmel_ehci->fclk);
atmel_ehci->clocked = true;
}

static void atmel_stop_clock(struct atmel_ehci_priv *atmel_ehci)
{
if (!atmel_ehci->clocked)
return;
clk_disable_unprepare(atmel_ehci->fclk);

clk_disable_unprepare(atmel_ehci->iclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
clk_disable_unprepare(atmel_ehci->uclk);
clk_disable_unprepare(atmel_ehci->uclk);
atmel_ehci->clocked = false;
}

Expand Down Expand Up @@ -146,20 +141,13 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
retval = -ENOENT;
goto fail_request_resource;
}
atmel_ehci->fclk = devm_clk_get(&pdev->dev, "uhpck");
if (IS_ERR(atmel_ehci->fclk)) {
dev_err(&pdev->dev, "Error getting function clock\n");
retval = -ENOENT;

atmel_ehci->uclk = devm_clk_get(&pdev->dev, "usb_clk");
if (IS_ERR(atmel_ehci->uclk)) {
dev_err(&pdev->dev, "failed to get uclk\n");
retval = PTR_ERR(atmel_ehci->uclk);
goto fail_request_resource;
}
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
atmel_ehci->uclk = devm_clk_get(&pdev->dev, "usb_clk");
if (IS_ERR(atmel_ehci->uclk)) {
dev_err(&pdev->dev, "failed to get uclk\n");
retval = PTR_ERR(atmel_ehci->uclk);
goto fail_request_resource;
}
}

ehci = hcd_to_ehci(hcd);
/* registers start at offset 0x0 */
Expand Down

0 comments on commit e32643a

Please sign in to comment.