diff options
author | Arnd Bergmann <arnd@arndb.de> | 2013-03-27 17:44:22 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-03-28 14:22:15 -0400 |
commit | f3bc64d6d1f21c1b92d75f233a37b75d77af6963 (patch) | |
tree | dd21f8705b9fa4661edef271a59651882a624a87 | |
parent | 4d053fdac3c44ec8c7a78c810292a156abf84971 (diff) |
USB: EHCI: DT support for generic bus glue
This lets us use the ehci-platform driver on platforms without special
requirements for their ehci controllers. In particular, this is true
for the vt8500/wm8x50 platforms, which currently have a separate
driver that causes problems with multiplatform configurations.
Tested-by: Tony Prisk <linux@prisktech.co.nz>
Tested-by: Peter Vasil <petervasil@gmail.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 5 | ||||
-rw-r--r-- | drivers/usb/host/ehci-platform.c | 34 | ||||
-rw-r--r-- | drivers/usb/host/ehci-vt8500.c | 150 |
3 files changed, 28 insertions, 161 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 037a4729d549..b12b97d2ccaf 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -1269,11 +1269,6 @@ MODULE_LICENSE ("GPL"); | |||
1269 | #define PLATFORM_DRIVER ehci_octeon_driver | 1269 | #define PLATFORM_DRIVER ehci_octeon_driver |
1270 | #endif | 1270 | #endif |
1271 | 1271 | ||
1272 | #ifdef CONFIG_ARCH_VT8500 | ||
1273 | #include "ehci-vt8500.c" | ||
1274 | #define PLATFORM_DRIVER vt8500_ehci_driver | ||
1275 | #endif | ||
1276 | |||
1277 | #ifdef CONFIG_PLAT_SPEAR | 1272 | #ifdef CONFIG_PLAT_SPEAR |
1278 | #include "ehci-spear.c" | 1273 | #include "ehci-spear.c" |
1279 | #define PLATFORM_DRIVER spear_ehci_hcd_driver | 1274 | #define PLATFORM_DRIVER spear_ehci_hcd_driver |
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index ca7506390542..cda0fa9613e7 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c | |||
@@ -18,11 +18,13 @@ | |||
18 | * | 18 | * |
19 | * Licensed under the GNU/GPL. See COPYING for details. | 19 | * Licensed under the GNU/GPL. See COPYING for details. |
20 | */ | 20 | */ |
21 | #include <linux/dma-mapping.h> | ||
21 | #include <linux/err.h> | 22 | #include <linux/err.h> |
22 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
23 | #include <linux/hrtimer.h> | 24 | #include <linux/hrtimer.h> |
24 | #include <linux/io.h> | 25 | #include <linux/io.h> |
25 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/of.h> | ||
26 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
27 | #include <linux/usb.h> | 29 | #include <linux/usb.h> |
28 | #include <linux/usb/hcd.h> | 30 | #include <linux/usb/hcd.h> |
@@ -62,22 +64,32 @@ static const struct ehci_driver_overrides platform_overrides __initdata = { | |||
62 | .reset = ehci_platform_reset, | 64 | .reset = ehci_platform_reset, |
63 | }; | 65 | }; |
64 | 66 | ||
67 | static struct usb_ehci_pdata ehci_platform_defaults; | ||
68 | |||
65 | static int ehci_platform_probe(struct platform_device *dev) | 69 | static int ehci_platform_probe(struct platform_device *dev) |
66 | { | 70 | { |
67 | struct usb_hcd *hcd; | 71 | struct usb_hcd *hcd; |
68 | struct resource *res_mem; | 72 | struct resource *res_mem; |
69 | struct usb_ehci_pdata *pdata = dev->dev.platform_data; | 73 | struct usb_ehci_pdata *pdata; |
70 | int irq; | 74 | int irq; |
71 | int err = -ENOMEM; | 75 | int err = -ENOMEM; |
72 | 76 | ||
73 | if (!pdata) { | ||
74 | WARN_ON(1); | ||
75 | return -ENODEV; | ||
76 | } | ||
77 | |||
78 | if (usb_disabled()) | 77 | if (usb_disabled()) |
79 | return -ENODEV; | 78 | return -ENODEV; |
80 | 79 | ||
80 | /* | ||
81 | * use reasonable defaults so platforms don't have to provide these. | ||
82 | * with DT probing on ARM, none of these are set. | ||
83 | */ | ||
84 | if (!dev->dev.platform_data) | ||
85 | dev->dev.platform_data = &ehci_platform_defaults; | ||
86 | if (!dev->dev.dma_mask) | ||
87 | dev->dev.dma_mask = &dev->dev.coherent_dma_mask; | ||
88 | if (!dev->dev.coherent_dma_mask) | ||
89 | dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); | ||
90 | |||
91 | pdata = dev->dev.platform_data; | ||
92 | |||
81 | irq = platform_get_irq(dev, 0); | 93 | irq = platform_get_irq(dev, 0); |
82 | if (irq < 0) { | 94 | if (irq < 0) { |
83 | dev_err(&dev->dev, "no irq provided"); | 95 | dev_err(&dev->dev, "no irq provided"); |
@@ -139,6 +151,9 @@ static int ehci_platform_remove(struct platform_device *dev) | |||
139 | if (pdata->power_off) | 151 | if (pdata->power_off) |
140 | pdata->power_off(dev); | 152 | pdata->power_off(dev); |
141 | 153 | ||
154 | if (pdata == &ehci_platform_defaults) | ||
155 | dev->dev.platform_data = NULL; | ||
156 | |||
142 | return 0; | 157 | return 0; |
143 | } | 158 | } |
144 | 159 | ||
@@ -183,6 +198,12 @@ static int ehci_platform_resume(struct device *dev) | |||
183 | #define ehci_platform_resume NULL | 198 | #define ehci_platform_resume NULL |
184 | #endif /* CONFIG_PM */ | 199 | #endif /* CONFIG_PM */ |
185 | 200 | ||
201 | static const struct of_device_id vt8500_ehci_ids[] = { | ||
202 | { .compatible = "via,vt8500-ehci", }, | ||
203 | { .compatible = "wm,prizm-ehci", }, | ||
204 | {} | ||
205 | }; | ||
206 | |||
186 | static const struct platform_device_id ehci_platform_table[] = { | 207 | static const struct platform_device_id ehci_platform_table[] = { |
187 | { "ehci-platform", 0 }, | 208 | { "ehci-platform", 0 }, |
188 | { } | 209 | { } |
@@ -203,6 +224,7 @@ static struct platform_driver ehci_platform_driver = { | |||
203 | .owner = THIS_MODULE, | 224 | .owner = THIS_MODULE, |
204 | .name = "ehci-platform", | 225 | .name = "ehci-platform", |
205 | .pm = &ehci_platform_pm_ops, | 226 | .pm = &ehci_platform_pm_ops, |
227 | .of_match_table = of_match_ptr(vt8500_ehci_ids), | ||
206 | } | 228 | } |
207 | }; | 229 | }; |
208 | 230 | ||
diff --git a/drivers/usb/host/ehci-vt8500.c b/drivers/usb/host/ehci-vt8500.c deleted file mode 100644 index 7ecf709610ba..000000000000 --- a/drivers/usb/host/ehci-vt8500.c +++ /dev/null | |||
@@ -1,150 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/usb/host/ehci-vt8500.c | ||
3 | * | ||
4 | * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> | ||
5 | * | ||
6 | * Based on ehci-au1xxx.c | ||
7 | * | ||
8 | * This software is licensed under the terms of the GNU General Public | ||
9 | * License version 2, as published by the Free Software Foundation, and | ||
10 | * may be copied, distributed, and modified under those terms. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include <linux/err.h> | ||
20 | #include <linux/of.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | |||
23 | static const struct hc_driver vt8500_ehci_hc_driver = { | ||
24 | .description = hcd_name, | ||
25 | .product_desc = "VT8500 EHCI", | ||
26 | .hcd_priv_size = sizeof(struct ehci_hcd), | ||
27 | |||
28 | /* | ||
29 | * generic hardware linkage | ||
30 | */ | ||
31 | .irq = ehci_irq, | ||
32 | .flags = HCD_MEMORY | HCD_USB2, | ||
33 | |||
34 | /* | ||
35 | * basic lifecycle operations | ||
36 | */ | ||
37 | .reset = ehci_setup, | ||
38 | .start = ehci_run, | ||
39 | .stop = ehci_stop, | ||
40 | .shutdown = ehci_shutdown, | ||
41 | |||
42 | /* | ||
43 | * managing i/o requests and associated device resources | ||
44 | */ | ||
45 | .urb_enqueue = ehci_urb_enqueue, | ||
46 | .urb_dequeue = ehci_urb_dequeue, | ||
47 | .endpoint_disable = ehci_endpoint_disable, | ||
48 | .endpoint_reset = ehci_endpoint_reset, | ||
49 | |||
50 | /* | ||
51 | * scheduling support | ||
52 | */ | ||
53 | .get_frame_number = ehci_get_frame, | ||
54 | |||
55 | /* | ||
56 | * root hub support | ||
57 | */ | ||
58 | .hub_status_data = ehci_hub_status_data, | ||
59 | .hub_control = ehci_hub_control, | ||
60 | .bus_suspend = ehci_bus_suspend, | ||
61 | .bus_resume = ehci_bus_resume, | ||
62 | .relinquish_port = ehci_relinquish_port, | ||
63 | .port_handed_over = ehci_port_handed_over, | ||
64 | |||
65 | .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, | ||
66 | }; | ||
67 | |||
68 | static u64 vt8500_ehci_dma_mask = DMA_BIT_MASK(32); | ||
69 | |||
70 | static int vt8500_ehci_drv_probe(struct platform_device *pdev) | ||
71 | { | ||
72 | struct usb_hcd *hcd; | ||
73 | struct ehci_hcd *ehci; | ||
74 | struct resource *res; | ||
75 | int ret; | ||
76 | |||
77 | if (usb_disabled()) | ||
78 | return -ENODEV; | ||
79 | |||
80 | /* | ||
81 | * Right now device-tree probed devices don't get dma_mask set. | ||
82 | * Since shared usb code relies on it, set it here for now. | ||
83 | * Once we have dma capability bindings this can go away. | ||
84 | */ | ||
85 | if (!pdev->dev.dma_mask) | ||
86 | pdev->dev.dma_mask = &vt8500_ehci_dma_mask; | ||
87 | |||
88 | if (pdev->resource[1].flags != IORESOURCE_IRQ) { | ||
89 | pr_debug("resource[1] is not IORESOURCE_IRQ"); | ||
90 | return -ENOMEM; | ||
91 | } | ||
92 | hcd = usb_create_hcd(&vt8500_ehci_hc_driver, &pdev->dev, "VT8500"); | ||
93 | if (!hcd) | ||
94 | return -ENOMEM; | ||
95 | |||
96 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
97 | hcd->rsrc_start = res->start; | ||
98 | hcd->rsrc_len = resource_size(res); | ||
99 | |||
100 | hcd->regs = devm_ioremap_resource(&pdev->dev, res); | ||
101 | if (IS_ERR(hcd->regs)) { | ||
102 | ret = PTR_ERR(hcd->regs); | ||
103 | goto err1; | ||
104 | } | ||
105 | |||
106 | ehci = hcd_to_ehci(hcd); | ||
107 | ehci->caps = hcd->regs; | ||
108 | |||
109 | ret = usb_add_hcd(hcd, pdev->resource[1].start, | ||
110 | IRQF_SHARED); | ||
111 | if (ret == 0) { | ||
112 | platform_set_drvdata(pdev, hcd); | ||
113 | return ret; | ||
114 | } | ||
115 | |||
116 | err1: | ||
117 | usb_put_hcd(hcd); | ||
118 | return ret; | ||
119 | } | ||
120 | |||
121 | static int vt8500_ehci_drv_remove(struct platform_device *pdev) | ||
122 | { | ||
123 | struct usb_hcd *hcd = platform_get_drvdata(pdev); | ||
124 | |||
125 | usb_remove_hcd(hcd); | ||
126 | usb_put_hcd(hcd); | ||
127 | platform_set_drvdata(pdev, NULL); | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static const struct of_device_id vt8500_ehci_ids[] = { | ||
133 | { .compatible = "via,vt8500-ehci", }, | ||
134 | { .compatible = "wm,prizm-ehci", }, | ||
135 | {} | ||
136 | }; | ||
137 | |||
138 | static struct platform_driver vt8500_ehci_driver = { | ||
139 | .probe = vt8500_ehci_drv_probe, | ||
140 | .remove = vt8500_ehci_drv_remove, | ||
141 | .shutdown = usb_hcd_platform_shutdown, | ||
142 | .driver = { | ||
143 | .name = "vt8500-ehci", | ||
144 | .owner = THIS_MODULE, | ||
145 | .of_match_table = of_match_ptr(vt8500_ehci_ids), | ||
146 | } | ||
147 | }; | ||
148 | |||
149 | MODULE_ALIAS("platform:vt8500-ehci"); | ||
150 | MODULE_DEVICE_TABLE(of, vt8500_ehci_ids); | ||