aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-01-09 17:39:22 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-01-09 17:39:22 -0500
commit2ac9d7aaccbd598b5bd19ac40761b723bb675442 (patch)
tree09132a44e33798aaa5e80f10bf025b510015cab3 /drivers/usb
parent5ede3ceb7b2c2843e153a1803edbdc8c56655950 (diff)
parentdcf7ec5ee62a78123057a1e286c88ca739717409 (diff)
Merge tag 'drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Driver specific changes Again, a lot of platforms have changes in here: pxa, samsung, omap, at91, imx, ... * tag 'drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (54 commits) ARM: sa1100: clean up of the clock support ARM: pxa: add dummy clock for sa1100-rtc RTC: sa1100: support sa1100, pxa and mmp soc families RTC: sa1100: remove redundant code of setting alarm RTC: sa1100: Clean out ost register Input: zylonite-wm97xx - replace IRQ_GPIO() with gpio_to_irq() pcmcia: pxa: replace IRQ_GPIO() with gpio_to_irq() ARM: EXYNOS: Modified files for SPI consolidation work ARM: S5P64X0: Enable SDHCI support ARM: S5P64X0: Add lookup of sdhci-s3c clocks using generic names ARM: S5P64X0: Add HSMMC setup for host Controller ARM: EXYNOS: Add USB OHCI support to ORIGEN board USB: Add Samsung Exynos OHCI diver ARM: EXYNOS: Add USB OHCI support to SMDKV310 board ARM: EXYNOS: Add USB OHCI device net: macb: fix build break with !CONFIG_OF i2c: tegra: Support DVC controller in device tree i2c: tegra: Add __devinit/exit to probe/remove net/at91_ether: use gpio_is_valid for phy IRQ line ARM: at91/net: add macb ethernet controller in 9g45/9g20 DT ...
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/Kconfig1
-rw-r--r--drivers/usb/host/Kconfig6
-rw-r--r--drivers/usb/host/ehci-omap.c17
-rw-r--r--drivers/usb/host/ohci-exynos.c274
-rw-r--r--drivers/usb/host/ohci-hcd.c5
-rw-r--r--drivers/usb/host/ohci-omap3.c18
6 files changed, 300 insertions, 21 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 791f11bed60..75823a1abeb 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -48,6 +48,7 @@ config USB_ARCH_HAS_OHCI
48 default y if ARCH_DAVINCI_DA8XX 48 default y if ARCH_DAVINCI_DA8XX
49 default y if ARCH_CNS3XXX 49 default y if ARCH_CNS3XXX
50 default y if PLAT_SPEAR 50 default y if PLAT_SPEAR
51 default y if ARCH_EXYNOS
51 # PPC: 52 # PPC:
52 default y if STB03xxx 53 default y if STB03xxx
53 default y if PPC_MPC52xx 54 default y if PPC_MPC52xx
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index a52769b5c90..4c0c9734251 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -380,6 +380,12 @@ config USB_OHCI_SH
380 Enables support for the on-chip OHCI controller on the SuperH. 380 Enables support for the on-chip OHCI controller on the SuperH.
381 If you use the PCI OHCI controller, this option is not necessary. 381 If you use the PCI OHCI controller, this option is not necessary.
382 382
383config USB_OHCI_EXYNOS
384 boolean "OHCI support for Samsung EXYNOS SoC Series"
385 depends on USB_OHCI_HCD && ARCH_EXYNOS
386 help
387 Enable support for the Samsung Exynos SOC's on-chip OHCI controller.
388
383config USB_CNS3XXX_OHCI 389config USB_CNS3XXX_OHCI
384 bool "Cavium CNS3XXX OHCI Module" 390 bool "Cavium CNS3XXX OHCI Module"
385 depends on USB_OHCI_HCD && ARCH_CNS3XXX 391 depends on USB_OHCI_HCD && ARCH_CNS3XXX
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index e33baf9052c..bba9850f32f 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -41,6 +41,7 @@
41#include <linux/usb/ulpi.h> 41#include <linux/usb/ulpi.h>
42#include <plat/usb.h> 42#include <plat/usb.h>
43#include <linux/regulator/consumer.h> 43#include <linux/regulator/consumer.h>
44#include <linux/pm_runtime.h>
44 45
45/* EHCI Register Set */ 46/* EHCI Register Set */
46#define EHCI_INSNREG04 (0xA0) 47#define EHCI_INSNREG04 (0xA0)
@@ -190,11 +191,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
190 } 191 }
191 } 192 }
192 193
193 ret = omap_usbhs_enable(dev); 194 pm_runtime_enable(dev);
194 if (ret) { 195 pm_runtime_get_sync(dev);
195 dev_err(dev, "failed to start usbhs with err %d\n", ret);
196 goto err_enable;
197 }
198 196
199 /* 197 /*
200 * An undocumented "feature" in the OMAP3 EHCI controller, 198 * An undocumented "feature" in the OMAP3 EHCI controller,
@@ -242,11 +240,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
242 return 0; 240 return 0;
243 241
244err_add_hcd: 242err_add_hcd:
245 omap_usbhs_disable(dev);
246
247err_enable:
248 disable_put_regulator(pdata); 243 disable_put_regulator(pdata);
249 usb_put_hcd(hcd); 244 pm_runtime_put_sync(dev);
250 245
251err_io: 246err_io:
252 iounmap(regs); 247 iounmap(regs);
@@ -268,10 +263,12 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev)
268 struct usb_hcd *hcd = dev_get_drvdata(dev); 263 struct usb_hcd *hcd = dev_get_drvdata(dev);
269 264
270 usb_remove_hcd(hcd); 265 usb_remove_hcd(hcd);
271 omap_usbhs_disable(dev);
272 disable_put_regulator(dev->platform_data); 266 disable_put_regulator(dev->platform_data);
273 iounmap(hcd->regs); 267 iounmap(hcd->regs);
274 usb_put_hcd(hcd); 268 usb_put_hcd(hcd);
269 pm_runtime_put_sync(dev);
270 pm_runtime_disable(dev);
271
275 return 0; 272 return 0;
276} 273}
277 274
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
new file mode 100644
index 00000000000..55aa35aa3d7
--- /dev/null
+++ b/drivers/usb/host/ohci-exynos.c
@@ -0,0 +1,274 @@
1/*
2 * SAMSUNG EXYNOS USB HOST OHCI Controller
3 *
4 * Copyright (C) 2011 Samsung Electronics Co.Ltd
5 * Author: Jingoo Han <jg1.han@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */
13
14#include <linux/clk.h>
15#include <linux/platform_device.h>
16#include <mach/ohci.h>
17#include <plat/usb-phy.h>
18
19struct exynos_ohci_hcd {
20 struct device *dev;
21 struct usb_hcd *hcd;
22 struct clk *clk;
23};
24
25static int ohci_exynos_start(struct usb_hcd *hcd)
26{
27 struct ohci_hcd *ohci = hcd_to_ohci(hcd);
28 int ret;
29
30 ohci_dbg(ohci, "ohci_exynos_start, ohci:%p", ohci);
31
32 ret = ohci_init(ohci);
33 if (ret < 0)
34 return ret;
35
36 ret = ohci_run(ohci);
37 if (ret < 0) {
38 err("can't start %s", hcd->self.bus_name);
39 ohci_stop(hcd);
40 return ret;
41 }
42
43 return 0;
44}
45
46static const struct hc_driver exynos_ohci_hc_driver = {
47 .description = hcd_name,
48 .product_desc = "EXYNOS OHCI Host Controller",
49 .hcd_priv_size = sizeof(struct ohci_hcd),
50
51 .irq = ohci_irq,
52 .flags = HCD_MEMORY|HCD_USB11,
53
54 .start = ohci_exynos_start,
55 .stop = ohci_stop,
56 .shutdown = ohci_shutdown,
57
58 .get_frame_number = ohci_get_frame,
59
60 .urb_enqueue = ohci_urb_enqueue,
61 .urb_dequeue = ohci_urb_dequeue,
62 .endpoint_disable = ohci_endpoint_disable,
63
64 .hub_status_data = ohci_hub_status_data,
65 .hub_control = ohci_hub_control,
66#ifdef CONFIG_PM
67 .bus_suspend = ohci_bus_suspend,
68 .bus_resume = ohci_bus_resume,
69#endif
70 .start_port_reset = ohci_start_port_reset,
71};
72
73static int __devinit exynos_ohci_probe(struct platform_device *pdev)
74{
75 struct exynos4_ohci_platdata *pdata;
76 struct exynos_ohci_hcd *exynos_ohci;
77 struct usb_hcd *hcd;
78 struct ohci_hcd *ohci;
79 struct resource *res;
80 int irq;
81 int err;
82
83 pdata = pdev->dev.platform_data;
84 if (!pdata) {
85 dev_err(&pdev->dev, "No platform data defined\n");
86 return -EINVAL;
87 }
88
89 exynos_ohci = kzalloc(sizeof(struct exynos_ohci_hcd), GFP_KERNEL);
90 if (!exynos_ohci)
91 return -ENOMEM;
92
93 exynos_ohci->dev = &pdev->dev;
94
95 hcd = usb_create_hcd(&exynos_ohci_hc_driver, &pdev->dev,
96 dev_name(&pdev->dev));
97 if (!hcd) {
98 dev_err(&pdev->dev, "Unable to create HCD\n");
99 err = -ENOMEM;
100 goto fail_hcd;
101 }
102
103 exynos_ohci->hcd = hcd;
104 exynos_ohci->clk = clk_get(&pdev->dev, "usbhost");
105
106 if (IS_ERR(exynos_ohci->clk)) {
107 dev_err(&pdev->dev, "Failed to get usbhost clock\n");
108 err = PTR_ERR(exynos_ohci->clk);
109 goto fail_clk;
110 }
111
112 err = clk_enable(exynos_ohci->clk);
113 if (err)
114 goto fail_clken;
115
116 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
117 if (!res) {
118 dev_err(&pdev->dev, "Failed to get I/O memory\n");
119 err = -ENXIO;
120 goto fail_io;
121 }
122
123 hcd->rsrc_start = res->start;
124 hcd->rsrc_len = resource_size(res);
125 hcd->regs = ioremap(res->start, resource_size(res));
126 if (!hcd->regs) {
127 dev_err(&pdev->dev, "Failed to remap I/O memory\n");
128 err = -ENOMEM;
129 goto fail_io;
130 }
131
132 irq = platform_get_irq(pdev, 0);
133 if (!irq) {
134 dev_err(&pdev->dev, "Failed to get IRQ\n");
135 err = -ENODEV;
136 goto fail;
137 }
138
139 if (pdata->phy_init)
140 pdata->phy_init(pdev, S5P_USB_PHY_HOST);
141
142 ohci = hcd_to_ohci(hcd);
143 ohci_hcd_init(ohci);
144
145 err = usb_add_hcd(hcd, irq, IRQF_SHARED);
146 if (err) {
147 dev_err(&pdev->dev, "Failed to add USB HCD\n");
148 goto fail;
149 }
150
151 platform_set_drvdata(pdev, exynos_ohci);
152
153 return 0;
154
155fail:
156 iounmap(hcd->regs);
157fail_io:
158 clk_disable(exynos_ohci->clk);
159fail_clken:
160 clk_put(exynos_ohci->clk);
161fail_clk:
162 usb_put_hcd(hcd);
163fail_hcd:
164 kfree(exynos_ohci);
165 return err;
166}
167
168static int __devexit exynos_ohci_remove(struct platform_device *pdev)
169{
170 struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
171 struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev);
172 struct usb_hcd *hcd = exynos_ohci->hcd;
173
174 usb_remove_hcd(hcd);
175
176 if (pdata && pdata->phy_exit)
177 pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
178
179 iounmap(hcd->regs);
180
181 clk_disable(exynos_ohci->clk);
182 clk_put(exynos_ohci->clk);
183
184 usb_put_hcd(hcd);
185 kfree(exynos_ohci);
186
187 return 0;
188}
189
190static void exynos_ohci_shutdown(struct platform_device *pdev)
191{
192 struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev);
193 struct usb_hcd *hcd = exynos_ohci->hcd;
194
195 if (hcd->driver->shutdown)
196 hcd->driver->shutdown(hcd);
197}
198
199#ifdef CONFIG_PM
200static int exynos_ohci_suspend(struct device *dev)
201{
202 struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev);
203 struct usb_hcd *hcd = exynos_ohci->hcd;
204 struct ohci_hcd *ohci = hcd_to_ohci(hcd);
205 struct platform_device *pdev = to_platform_device(dev);
206 struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
207 unsigned long flags;
208 int rc = 0;
209
210 /*
211 * Root hub was already suspended. Disable irq emission and
212 * mark HW unaccessible, bail out if RH has been resumed. Use
213 * the spinlock to properly synchronize with possible pending
214 * RH suspend or resume activity.
215 *
216 * This is still racy as hcd->state is manipulated outside of
217 * any locks =P But that will be a different fix.
218 */
219 spin_lock_irqsave(&ohci->lock, flags);
220 if (hcd->state != HC_STATE_SUSPENDED && hcd->state != HC_STATE_HALT) {
221 rc = -EINVAL;
222 goto fail;
223 }
224
225 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
226
227 if (pdata && pdata->phy_exit)
228 pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
229fail:
230 spin_unlock_irqrestore(&ohci->lock, flags);
231
232 return rc;
233}
234
235static int exynos_ohci_resume(struct device *dev)
236{
237 struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev);
238 struct usb_hcd *hcd = exynos_ohci->hcd;
239 struct platform_device *pdev = to_platform_device(dev);
240 struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
241
242 if (pdata && pdata->phy_init)
243 pdata->phy_init(pdev, S5P_USB_PHY_HOST);
244
245 /* Mark hardware accessible again as we are out of D3 state by now */
246 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
247
248 ohci_finish_controller_resume(hcd);
249
250 return 0;
251}
252#else
253#define exynos_ohci_suspend NULL
254#define exynos_ohci_resume NULL
255#endif
256
257static const struct dev_pm_ops exynos_ohci_pm_ops = {
258 .suspend = exynos_ohci_suspend,
259 .resume = exynos_ohci_resume,
260};
261
262static struct platform_driver exynos_ohci_driver = {
263 .probe = exynos_ohci_probe,
264 .remove = __devexit_p(exynos_ohci_remove),
265 .shutdown = exynos_ohci_shutdown,
266 .driver = {
267 .name = "exynos-ohci",
268 .owner = THIS_MODULE,
269 .pm = &exynos_ohci_pm_ops,
270 }
271};
272
273MODULE_ALIAS("platform:exynos-ohci");
274MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 4fa5d8c4d23..5f5a6324143 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1005,6 +1005,11 @@ MODULE_LICENSE ("GPL");
1005#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver 1005#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver
1006#endif 1006#endif
1007 1007
1008#ifdef CONFIG_USB_OHCI_EXYNOS
1009#include "ohci-exynos.c"
1010#define PLATFORM_DRIVER exynos_ohci_driver
1011#endif
1012
1008#ifdef CONFIG_USB_OHCI_HCD_OMAP1 1013#ifdef CONFIG_USB_OHCI_HCD_OMAP1
1009#include "ohci-omap.c" 1014#include "ohci-omap.c"
1010#define OMAP1_PLATFORM_DRIVER ohci_hcd_omap_driver 1015#define OMAP1_PLATFORM_DRIVER ohci_hcd_omap_driver
diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c
index 516ebc4d6cc..1b8133b6e45 100644
--- a/drivers/usb/host/ohci-omap3.c
+++ b/drivers/usb/host/ohci-omap3.c
@@ -31,6 +31,7 @@
31 31
32#include <linux/platform_device.h> 32#include <linux/platform_device.h>
33#include <plat/usb.h> 33#include <plat/usb.h>
34#include <linux/pm_runtime.h>
34 35
35/*-------------------------------------------------------------------------*/ 36/*-------------------------------------------------------------------------*/
36 37
@@ -134,7 +135,7 @@ static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev)
134 int irq; 135 int irq;
135 136
136 if (usb_disabled()) 137 if (usb_disabled())
137 goto err_end; 138 return -ENODEV;
138 139
139 if (!dev->parent) { 140 if (!dev->parent) {
140 dev_err(dev, "Missing parent device\n"); 141 dev_err(dev, "Missing parent device\n");
@@ -172,11 +173,8 @@ static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev)
172 hcd->rsrc_len = resource_size(res); 173 hcd->rsrc_len = resource_size(res);
173 hcd->regs = regs; 174 hcd->regs = regs;
174 175
175 ret = omap_usbhs_enable(dev); 176 pm_runtime_enable(dev);
176 if (ret) { 177 pm_runtime_get_sync(dev);
177 dev_dbg(dev, "failed to start ohci\n");
178 goto err_end;
179 }
180 178
181 ohci_hcd_init(hcd_to_ohci(hcd)); 179 ohci_hcd_init(hcd_to_ohci(hcd));
182 180
@@ -189,9 +187,7 @@ static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev)
189 return 0; 187 return 0;
190 188
191err_add_hcd: 189err_add_hcd:
192 omap_usbhs_disable(dev); 190 pm_runtime_put_sync(dev);
193
194err_end:
195 usb_put_hcd(hcd); 191 usb_put_hcd(hcd);
196 192
197err_io: 193err_io:
@@ -220,9 +216,9 @@ static int __devexit ohci_hcd_omap3_remove(struct platform_device *pdev)
220 216
221 iounmap(hcd->regs); 217 iounmap(hcd->regs);
222 usb_remove_hcd(hcd); 218 usb_remove_hcd(hcd);
223 omap_usbhs_disable(dev); 219 pm_runtime_put_sync(dev);
220 pm_runtime_disable(dev);
224 usb_put_hcd(hcd); 221 usb_put_hcd(hcd);
225
226 return 0; 222 return 0;
227} 223}
228 224