diff options
author | Gregory CLEMENT <gregory.clement@free-electrons.com> | 2014-05-15 12:17:32 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-05-27 15:33:13 -0700 |
commit | 4718c177405112386a977fd9f1cba5fd6aa82315 (patch) | |
tree | 999a876e99861cc4d84a6d18dc5ae1f3bc6cf8b5 /drivers/usb/host | |
parent | 48157bb97f074d21372bd3ae87e5988ed23c8972 (diff) |
usb: host: xhci-plat: add clock support
Some platforms (such as the Armada 38x ones) can gate the clock of
their USB controller. This patch adds the support for one clock in
xhci-plat, by enabling it during probe and disabling it on remove.
To achieve this, it adds a 'struct clk *' member in xhci_hcd. While
only used for now in xhci-plat, it might be used by other drivers in
the future. Moreover, the xhci_hcd structure already holds other
members such as msix_count and msix_entries, which are MSI-X specific,
and therefore only used by xhci-pci.
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Acked-by: Felipe Balbi <balbi@ti.com>
Acked-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/xhci-plat.c | 24 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 2 |
2 files changed, 25 insertions, 1 deletions
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index f5351af4b2c5..8108e58c9e02 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -11,6 +11,7 @@ * version 2 as published by the Free Software Foundation. */ +#include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/module.h> #include <linux/of.h> @@ -91,6 +92,7 @@ static int xhci_plat_probe(struct platform_device *pdev) struct xhci_hcd *xhci; struct resource *res; struct usb_hcd *hcd; + struct clk *clk; int ret; int irq; @@ -137,14 +139,27 @@ static int xhci_plat_probe(struct platform_device *pdev) goto release_mem_region; } + /* + * Not all platforms have a clk so it is not an error if the + * clock does not exists. + */ + clk = devm_clk_get(&pdev->dev, NULL); + if (!IS_ERR(clk)) { + ret = clk_prepare_enable(clk); + if (ret) + goto unmap_registers; + } + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) - goto unmap_registers; + goto disable_clk; + device_wakeup_enable(hcd->self.controller); /* USB 2.0 roothub is stored in the platform_device now. */ hcd = platform_get_drvdata(pdev); xhci = hcd_to_xhci(hcd); + xhci->clk = clk; xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev, dev_name(&pdev->dev), hcd); if (!xhci->shared_hcd) { @@ -173,6 +188,10 @@ put_usb3_hcd: dealloc_usb2_hcd: usb_remove_hcd(hcd); +disable_clk: + if (!IS_ERR(clk)) + clk_disable_unprepare(clk); + unmap_registers: iounmap(hcd->regs); @@ -189,11 +208,14 @@ static int xhci_plat_remove(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct clk *clk = xhci->clk; usb_remove_hcd(xhci->shared_hcd); usb_put_hcd(xhci->shared_hcd); usb_remove_hcd(hcd); + if (!IS_ERR(clk)) + clk_disable_unprepare(clk); iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 2774526449a6..9ffecd56600d 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1472,6 +1472,8 @@ struct xhci_hcd { /* msi-x vectors */ int msix_count; struct msix_entry *msix_entries; + /* optional clock */ + struct clk *clk; /* data structures */ struct xhci_device_context_array *dcbaa; struct xhci_ring *cmd_ring; |