aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/host/Kconfig5
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-hcd.c6
-rw-r--r--drivers/usb/host/ehci-s5p.c164
4 files changed, 85 insertions, 91 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index ae2c747b6e17..5d4f42afb4b5 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -220,10 +220,11 @@ config USB_EHCI_SH
220 If you use the PCI EHCI controller, this option is not necessary. 220 If you use the PCI EHCI controller, this option is not necessary.
221 221
222config USB_EHCI_S5P 222config USB_EHCI_S5P
223 boolean "S5P EHCI support" 223 tristate "EHCI support for Samsung S5P/EXYNOS SoC Series"
224 depends on USB_EHCI_HCD && PLAT_S5P 224 depends on USB_EHCI_HCD && PLAT_S5P
225 help 225 help
226 Enable support for the S5P SOC's on-chip EHCI controller. 226 Enable support for the Samsung S5Pxxxx and Exynos3/4/5 SOC's
227 on-chip EHCI controller.
227 228
228config USB_EHCI_MV 229config USB_EHCI_MV
229 bool "EHCI support for Marvell PXA/MMP USB controller" 230 bool "EHCI support for Marvell PXA/MMP USB controller"
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 3e02471e0f50..3d895b5adc32 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
30obj-$(CONFIG_USB_EHCI_HCD_OMAP) += ehci-omap.o 30obj-$(CONFIG_USB_EHCI_HCD_OMAP) += ehci-omap.o
31obj-$(CONFIG_USB_EHCI_HCD_ORION) += ehci-orion.o 31obj-$(CONFIG_USB_EHCI_HCD_ORION) += ehci-orion.o
32obj-$(CONFIG_USB_EHCI_HCD_SPEAR) += ehci-spear.o 32obj-$(CONFIG_USB_EHCI_HCD_SPEAR) += ehci-spear.o
33obj-$(CONFIG_USB_EHCI_S5P) += ehci-s5p.o
33 34
34obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o 35obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o
35obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o 36obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index c8c70a1fabc4..8f1f4b489a68 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1284,11 +1284,6 @@ MODULE_LICENSE ("GPL");
1284#define PLATFORM_DRIVER tegra_ehci_driver 1284#define PLATFORM_DRIVER tegra_ehci_driver
1285#endif 1285#endif
1286 1286
1287#ifdef CONFIG_USB_EHCI_S5P
1288#include "ehci-s5p.c"
1289#define PLATFORM_DRIVER s5p_ehci_driver
1290#endif
1291
1292#ifdef CONFIG_SPARC_LEON 1287#ifdef CONFIG_SPARC_LEON
1293#include "ehci-grlib.c" 1288#include "ehci-grlib.c"
1294#define PLATFORM_DRIVER ehci_grlib_driver 1289#define PLATFORM_DRIVER ehci_grlib_driver
@@ -1311,6 +1306,7 @@ MODULE_LICENSE ("GPL");
1311 !IS_ENABLED(CONFIG_USB_EHCI_HCD_OMAP) && \ 1306 !IS_ENABLED(CONFIG_USB_EHCI_HCD_OMAP) && \
1312 !IS_ENABLED(CONFIG_USB_EHCI_HCD_ORION) && \ 1307 !IS_ENABLED(CONFIG_USB_EHCI_HCD_ORION) && \
1313 !IS_ENABLED(CONFIG_USB_EHCI_HCD_SPEAR) && \ 1308 !IS_ENABLED(CONFIG_USB_EHCI_HCD_SPEAR) && \
1309 !IS_ENABLED(CONFIG_USB_EHCI_S5P) && \
1314 !defined(PLATFORM_DRIVER) && \ 1310 !defined(PLATFORM_DRIVER) && \
1315 !defined(PS3_SYSTEM_BUS_DRIVER) && \ 1311 !defined(PS3_SYSTEM_BUS_DRIVER) && \
1316 !defined(OF_PLATFORM_DRIVER) && \ 1312 !defined(OF_PLATFORM_DRIVER) && \
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index 43a2a16732f5..d8cb0ca563b5 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -13,13 +13,24 @@
13 */ 13 */
14 14
15#include <linux/clk.h> 15#include <linux/clk.h>
16#include <linux/dma-mapping.h>
17#include <linux/io.h>
18#include <linux/kernel.h>
19#include <linux/module.h>
16#include <linux/of.h> 20#include <linux/of.h>
17#include <linux/platform_device.h>
18#include <linux/of_gpio.h> 21#include <linux/of_gpio.h>
22#include <linux/platform_device.h>
19#include <linux/platform_data/usb-ehci-s5p.h> 23#include <linux/platform_data/usb-ehci-s5p.h>
20#include <linux/usb/phy.h> 24#include <linux/usb/phy.h>
21#include <linux/usb/samsung_usb_phy.h> 25#include <linux/usb/samsung_usb_phy.h>
22#include <plat/usb-phy.h> 26#include <plat/usb-phy.h>
27#include <linux/usb.h>
28#include <linux/usb/hcd.h>
29#include <linux/usb/otg.h>
30
31#include "ehci.h"
32
33#define DRIVER_DESC "EHCI s5p driver"
23 34
24#define EHCI_INSNREG00(base) (base + 0x90) 35#define EHCI_INSNREG00(base) (base + 0x90)
25#define EHCI_INSNREG00_ENA_INCR16 (0x1 << 25) 36#define EHCI_INSNREG00_ENA_INCR16 (0x1 << 25)
@@ -30,65 +41,17 @@
30 (EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 | \ 41 (EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 | \
31 EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN) 42 EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN)
32 43
44static const char hcd_name[] = "ehci-s5p";
45static struct hc_driver __read_mostly s5p_ehci_hc_driver;
46
33struct s5p_ehci_hcd { 47struct s5p_ehci_hcd {
34 struct device *dev;
35 struct usb_hcd *hcd;
36 struct clk *clk; 48 struct clk *clk;
37 struct usb_phy *phy; 49 struct usb_phy *phy;
38 struct usb_otg *otg; 50 struct usb_otg *otg;
39 struct s5p_ehci_platdata *pdata; 51 struct s5p_ehci_platdata *pdata;
40}; 52};
41 53
42static const struct hc_driver s5p_ehci_hc_driver = { 54#define to_s5p_ehci(hcd) (struct s5p_ehci_hcd *)(hcd_to_ehci(hcd)->priv)
43 .description = hcd_name,
44 .product_desc = "S5P EHCI Host Controller",
45 .hcd_priv_size = sizeof(struct ehci_hcd),
46
47 .irq = ehci_irq,
48 .flags = HCD_MEMORY | HCD_USB2,
49
50 .reset = ehci_setup,
51 .start = ehci_run,
52 .stop = ehci_stop,
53 .shutdown = ehci_shutdown,
54
55 .get_frame_number = ehci_get_frame,
56
57 .urb_enqueue = ehci_urb_enqueue,
58 .urb_dequeue = ehci_urb_dequeue,
59 .endpoint_disable = ehci_endpoint_disable,
60 .endpoint_reset = ehci_endpoint_reset,
61
62 .hub_status_data = ehci_hub_status_data,
63 .hub_control = ehci_hub_control,
64 .bus_suspend = ehci_bus_suspend,
65 .bus_resume = ehci_bus_resume,
66
67 .relinquish_port = ehci_relinquish_port,
68 .port_handed_over = ehci_port_handed_over,
69
70 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
71};
72
73static void s5p_ehci_phy_enable(struct s5p_ehci_hcd *s5p_ehci)
74{
75 struct platform_device *pdev = to_platform_device(s5p_ehci->dev);
76
77 if (s5p_ehci->phy)
78 usb_phy_init(s5p_ehci->phy);
79 else if (s5p_ehci->pdata->phy_init)
80 s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST);
81}
82
83static void s5p_ehci_phy_disable(struct s5p_ehci_hcd *s5p_ehci)
84{
85 struct platform_device *pdev = to_platform_device(s5p_ehci->dev);
86
87 if (s5p_ehci->phy)
88 usb_phy_shutdown(s5p_ehci->phy);
89 else if (s5p_ehci->pdata->phy_exit)
90 s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST);
91}
92 55
93static void s5p_setup_vbus_gpio(struct platform_device *pdev) 56static void s5p_setup_vbus_gpio(struct platform_device *pdev)
94{ 57{
@@ -134,11 +97,13 @@ static int s5p_ehci_probe(struct platform_device *pdev)
134 97
135 s5p_setup_vbus_gpio(pdev); 98 s5p_setup_vbus_gpio(pdev);
136 99
137 s5p_ehci = devm_kzalloc(&pdev->dev, sizeof(struct s5p_ehci_hcd), 100 hcd = usb_create_hcd(&s5p_ehci_hc_driver,
138 GFP_KERNEL); 101 &pdev->dev, dev_name(&pdev->dev));
139 if (!s5p_ehci) 102 if (!hcd) {
103 dev_err(&pdev->dev, "Unable to create HCD\n");
140 return -ENOMEM; 104 return -ENOMEM;
141 105 }
106 s5p_ehci = to_s5p_ehci(hcd);
142 phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); 107 phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
143 if (IS_ERR(phy)) { 108 if (IS_ERR(phy)) {
144 /* Fallback to pdata */ 109 /* Fallback to pdata */
@@ -153,16 +118,6 @@ static int s5p_ehci_probe(struct platform_device *pdev)
153 s5p_ehci->otg = phy->otg; 118 s5p_ehci->otg = phy->otg;
154 } 119 }
155 120
156 s5p_ehci->dev = &pdev->dev;
157
158 hcd = usb_create_hcd(&s5p_ehci_hc_driver, &pdev->dev,
159 dev_name(&pdev->dev));
160 if (!hcd) {
161 dev_err(&pdev->dev, "Unable to create HCD\n");
162 return -ENOMEM;
163 }
164
165 s5p_ehci->hcd = hcd;
166 s5p_ehci->clk = devm_clk_get(&pdev->dev, "usbhost"); 121 s5p_ehci->clk = devm_clk_get(&pdev->dev, "usbhost");
167 122
168 if (IS_ERR(s5p_ehci->clk)) { 123 if (IS_ERR(s5p_ehci->clk)) {
@@ -199,9 +154,12 @@ static int s5p_ehci_probe(struct platform_device *pdev)
199 } 154 }
200 155
201 if (s5p_ehci->otg) 156 if (s5p_ehci->otg)
202 s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self); 157 s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self);
203 158
204 s5p_ehci_phy_enable(s5p_ehci); 159 if (s5p_ehci->phy)
160 usb_phy_init(s5p_ehci->phy);
161 else if (s5p_ehci->pdata->phy_init)
162 s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST);
205 163
206 ehci = hcd_to_ehci(hcd); 164 ehci = hcd_to_ehci(hcd);
207 ehci->caps = hcd->regs; 165 ehci->caps = hcd->regs;
@@ -220,7 +178,10 @@ static int s5p_ehci_probe(struct platform_device *pdev)
220 return 0; 178 return 0;
221 179
222fail_add_hcd: 180fail_add_hcd:
223 s5p_ehci_phy_disable(s5p_ehci); 181 if (s5p_ehci->phy)
182 usb_phy_shutdown(s5p_ehci->phy);
183 else if (s5p_ehci->pdata->phy_exit)
184 s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST);
224fail_io: 185fail_io:
225 clk_disable_unprepare(s5p_ehci->clk); 186 clk_disable_unprepare(s5p_ehci->clk);
226fail_clk: 187fail_clk:
@@ -230,15 +191,18 @@ fail_clk:
230 191
231static int s5p_ehci_remove(struct platform_device *pdev) 192static int s5p_ehci_remove(struct platform_device *pdev)
232{ 193{
233 struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev); 194 struct usb_hcd *hcd = platform_get_drvdata(pdev);
234 struct usb_hcd *hcd = s5p_ehci->hcd; 195 struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd);
235 196
236 usb_remove_hcd(hcd); 197 usb_remove_hcd(hcd);
237 198
238 if (s5p_ehci->otg) 199 if (s5p_ehci->otg)
239 s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self); 200 s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self);
240 201
241 s5p_ehci_phy_disable(s5p_ehci); 202 if (s5p_ehci->phy)
203 usb_phy_shutdown(s5p_ehci->phy);
204 else if (s5p_ehci->pdata->phy_exit)
205 s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST);
242 206
243 clk_disable_unprepare(s5p_ehci->clk); 207 clk_disable_unprepare(s5p_ehci->clk);
244 208
@@ -249,8 +213,7 @@ static int s5p_ehci_remove(struct platform_device *pdev)
249 213
250static void s5p_ehci_shutdown(struct platform_device *pdev) 214static void s5p_ehci_shutdown(struct platform_device *pdev)
251{ 215{
252 struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev); 216 struct usb_hcd *hcd = platform_get_drvdata(pdev);
253 struct usb_hcd *hcd = s5p_ehci->hcd;
254 217
255 if (hcd->driver->shutdown) 218 if (hcd->driver->shutdown)
256 hcd->driver->shutdown(hcd); 219 hcd->driver->shutdown(hcd);
@@ -259,17 +222,22 @@ static void s5p_ehci_shutdown(struct platform_device *pdev)
259#ifdef CONFIG_PM 222#ifdef CONFIG_PM
260static int s5p_ehci_suspend(struct device *dev) 223static int s5p_ehci_suspend(struct device *dev)
261{ 224{
262 struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); 225 struct usb_hcd *hcd = dev_get_drvdata(dev);
263 struct usb_hcd *hcd = s5p_ehci->hcd; 226 struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd);
227 struct platform_device *pdev = to_platform_device(dev);
228
264 bool do_wakeup = device_may_wakeup(dev); 229 bool do_wakeup = device_may_wakeup(dev);
265 int rc; 230 int rc;
266 231
267 rc = ehci_suspend(hcd, do_wakeup); 232 rc = ehci_suspend(hcd, do_wakeup);
268 233
269 if (s5p_ehci->otg) 234 if (s5p_ehci->otg)
270 s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self); 235 s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self);
271 236
272 s5p_ehci_phy_disable(s5p_ehci); 237 if (s5p_ehci->phy)
238 usb_phy_shutdown(s5p_ehci->phy);
239 else if (s5p_ehci->pdata->phy_exit)
240 s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST);
273 241
274 clk_disable_unprepare(s5p_ehci->clk); 242 clk_disable_unprepare(s5p_ehci->clk);
275 243
@@ -278,15 +246,19 @@ static int s5p_ehci_suspend(struct device *dev)
278 246
279static int s5p_ehci_resume(struct device *dev) 247static int s5p_ehci_resume(struct device *dev)
280{ 248{
281 struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); 249 struct usb_hcd *hcd = dev_get_drvdata(dev);
282 struct usb_hcd *hcd = s5p_ehci->hcd; 250 struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd);
251 struct platform_device *pdev = to_platform_device(dev);
283 252
284 clk_prepare_enable(s5p_ehci->clk); 253 clk_prepare_enable(s5p_ehci->clk);
285 254
286 if (s5p_ehci->otg) 255 if (s5p_ehci->otg)
287 s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self); 256 s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self);
288 257
289 s5p_ehci_phy_enable(s5p_ehci); 258 if (s5p_ehci->phy)
259 usb_phy_init(s5p_ehci->phy);
260 else if (s5p_ehci->pdata->phy_init)
261 s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST);
290 262
291 /* DMA burst Enable */ 263 /* DMA burst Enable */
292 writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); 264 writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
@@ -323,5 +295,29 @@ static struct platform_driver s5p_ehci_driver = {
323 .of_match_table = of_match_ptr(exynos_ehci_match), 295 .of_match_table = of_match_ptr(exynos_ehci_match),
324 } 296 }
325}; 297};
298static const struct ehci_driver_overrides s5p_overrides __initdata = {
299 .extra_priv_size = sizeof(struct s5p_ehci_hcd),
300};
301
302static int __init ehci_s5p_init(void)
303{
304 if (usb_disabled())
305 return -ENODEV;
306
307 pr_info("%s: " DRIVER_DESC "\n", hcd_name);
308 ehci_init_driver(&s5p_ehci_hc_driver, &s5p_overrides);
309 return platform_driver_register(&s5p_ehci_driver);
310}
311module_init(ehci_s5p_init);
312
313static void __exit ehci_s5p_cleanup(void)
314{
315 platform_driver_unregister(&s5p_ehci_driver);
316}
317module_exit(ehci_s5p_cleanup);
326 318
319MODULE_DESCRIPTION(DRIVER_DESC);
327MODULE_ALIAS("platform:s5p-ehci"); 320MODULE_ALIAS("platform:s5p-ehci");
321MODULE_AUTHOR("Jingoo Han");
322MODULE_AUTHOR("Joonyoung Shim");
323MODULE_LICENSE("GPL v2");