diff options
author | Gregory CLEMENT <gregory.clement@free-electrons.com> | 2014-05-15 06:17:32 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-05-27 18:33:13 -0400 |
commit | 4718c177405112386a977fd9f1cba5fd6aa82315 (patch) | |
tree | 999a876e99861cc4d84a6d18dc5ae1f3bc6cf8b5 /drivers/usb/host/xhci-plat.c | |
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/xhci-plat.c')
-rw-r--r-- | drivers/usb/host/xhci-plat.c | 24 |
1 files changed, 23 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 @@ | |||
11 | * version 2 as published by the Free Software Foundation. | 11 | * version 2 as published by the Free Software Foundation. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/clk.h> | ||
14 | #include <linux/dma-mapping.h> | 15 | #include <linux/dma-mapping.h> |
15 | #include <linux/module.h> | 16 | #include <linux/module.h> |
16 | #include <linux/of.h> | 17 | #include <linux/of.h> |
@@ -91,6 +92,7 @@ static int xhci_plat_probe(struct platform_device *pdev) | |||
91 | struct xhci_hcd *xhci; | 92 | struct xhci_hcd *xhci; |
92 | struct resource *res; | 93 | struct resource *res; |
93 | struct usb_hcd *hcd; | 94 | struct usb_hcd *hcd; |
95 | struct clk *clk; | ||
94 | int ret; | 96 | int ret; |
95 | int irq; | 97 | int irq; |
96 | 98 | ||
@@ -137,14 +139,27 @@ static int xhci_plat_probe(struct platform_device *pdev) | |||
137 | goto release_mem_region; | 139 | goto release_mem_region; |
138 | } | 140 | } |
139 | 141 | ||
142 | /* | ||
143 | * Not all platforms have a clk so it is not an error if the | ||
144 | * clock does not exists. | ||
145 | */ | ||
146 | clk = devm_clk_get(&pdev->dev, NULL); | ||
147 | if (!IS_ERR(clk)) { | ||
148 | ret = clk_prepare_enable(clk); | ||
149 | if (ret) | ||
150 | goto unmap_registers; | ||
151 | } | ||
152 | |||
140 | ret = usb_add_hcd(hcd, irq, IRQF_SHARED); | 153 | ret = usb_add_hcd(hcd, irq, IRQF_SHARED); |
141 | if (ret) | 154 | if (ret) |
142 | goto unmap_registers; | 155 | goto disable_clk; |
156 | |||
143 | device_wakeup_enable(hcd->self.controller); | 157 | device_wakeup_enable(hcd->self.controller); |
144 | 158 | ||
145 | /* USB 2.0 roothub is stored in the platform_device now. */ | 159 | /* USB 2.0 roothub is stored in the platform_device now. */ |
146 | hcd = platform_get_drvdata(pdev); | 160 | hcd = platform_get_drvdata(pdev); |
147 | xhci = hcd_to_xhci(hcd); | 161 | xhci = hcd_to_xhci(hcd); |
162 | xhci->clk = clk; | ||
148 | xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev, | 163 | xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev, |
149 | dev_name(&pdev->dev), hcd); | 164 | dev_name(&pdev->dev), hcd); |
150 | if (!xhci->shared_hcd) { | 165 | if (!xhci->shared_hcd) { |
@@ -173,6 +188,10 @@ put_usb3_hcd: | |||
173 | dealloc_usb2_hcd: | 188 | dealloc_usb2_hcd: |
174 | usb_remove_hcd(hcd); | 189 | usb_remove_hcd(hcd); |
175 | 190 | ||
191 | disable_clk: | ||
192 | if (!IS_ERR(clk)) | ||
193 | clk_disable_unprepare(clk); | ||
194 | |||
176 | unmap_registers: | 195 | unmap_registers: |
177 | iounmap(hcd->regs); | 196 | iounmap(hcd->regs); |
178 | 197 | ||
@@ -189,11 +208,14 @@ static int xhci_plat_remove(struct platform_device *dev) | |||
189 | { | 208 | { |
190 | struct usb_hcd *hcd = platform_get_drvdata(dev); | 209 | struct usb_hcd *hcd = platform_get_drvdata(dev); |
191 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | 210 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
211 | struct clk *clk = xhci->clk; | ||
192 | 212 | ||
193 | usb_remove_hcd(xhci->shared_hcd); | 213 | usb_remove_hcd(xhci->shared_hcd); |
194 | usb_put_hcd(xhci->shared_hcd); | 214 | usb_put_hcd(xhci->shared_hcd); |
195 | 215 | ||
196 | usb_remove_hcd(hcd); | 216 | usb_remove_hcd(hcd); |
217 | if (!IS_ERR(clk)) | ||
218 | clk_disable_unprepare(clk); | ||
197 | iounmap(hcd->regs); | 219 | iounmap(hcd->regs); |
198 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | 220 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
199 | usb_put_hcd(hcd); | 221 | usb_put_hcd(hcd); |