| From 87e26737255c516b108e281e921e784b2731fd5f Mon Sep 17 00:00:00 2001 |
| From: Gregory CLEMENT <gregory.clement@free-electrons.com> |
| Date: Thu, 15 May 2014 12:17:32 +0200 |
| Subject: 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> |
| (cherry picked from commit 4718c177405112386a977fd9f1cba5fd6aa82315) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/usb/host/xhci-plat.c | 24 +++++++++++++++++++++++- |
| drivers/usb/host/xhci.h | 2 ++ |
| 2 files changed, 25 insertions(+), 1 deletion(-) |
| |
| diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c |
| index 706fe185fe4d..17465cce6d0d 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) { |
| @@ -170,6 +185,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); |
| |
| @@ -186,11 +205,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 8faef64371c6..1e60ab8f8f5b 100644 |
| --- a/drivers/usb/host/xhci.h |
| +++ b/drivers/usb/host/xhci.h |
| @@ -1473,6 +1473,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; |
| -- |
| 2.1.2 |
| |