diff options
-rw-r--r-- | drivers/usb/host/Kconfig | 5 | ||||
-rw-r--r-- | drivers/usb/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 6 | ||||
-rw-r--r-- | drivers/usb/host/ehci-s5p.c | 164 |
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 | ||
222 | config USB_EHCI_S5P | 222 | config 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 | ||
228 | config USB_EHCI_MV | 229 | config 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 | |||
30 | obj-$(CONFIG_USB_EHCI_HCD_OMAP) += ehci-omap.o | 30 | obj-$(CONFIG_USB_EHCI_HCD_OMAP) += ehci-omap.o |
31 | obj-$(CONFIG_USB_EHCI_HCD_ORION) += ehci-orion.o | 31 | obj-$(CONFIG_USB_EHCI_HCD_ORION) += ehci-orion.o |
32 | obj-$(CONFIG_USB_EHCI_HCD_SPEAR) += ehci-spear.o | 32 | obj-$(CONFIG_USB_EHCI_HCD_SPEAR) += ehci-spear.o |
33 | obj-$(CONFIG_USB_EHCI_S5P) += ehci-s5p.o | ||
33 | 34 | ||
34 | obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o | 35 | obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o |
35 | obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o | 36 | obj-$(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 | ||
44 | static const char hcd_name[] = "ehci-s5p"; | ||
45 | static struct hc_driver __read_mostly s5p_ehci_hc_driver; | ||
46 | |||
33 | struct s5p_ehci_hcd { | 47 | struct 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 | ||
42 | static 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 | |||
73 | static 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 | |||
83 | static 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 | ||
93 | static void s5p_setup_vbus_gpio(struct platform_device *pdev) | 56 | static 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 | ||
222 | fail_add_hcd: | 180 | fail_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); | ||
224 | fail_io: | 185 | fail_io: |
225 | clk_disable_unprepare(s5p_ehci->clk); | 186 | clk_disable_unprepare(s5p_ehci->clk); |
226 | fail_clk: | 187 | fail_clk: |
@@ -230,15 +191,18 @@ fail_clk: | |||
230 | 191 | ||
231 | static int s5p_ehci_remove(struct platform_device *pdev) | 192 | static 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 | ||
250 | static void s5p_ehci_shutdown(struct platform_device *pdev) | 214 | static 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 |
260 | static int s5p_ehci_suspend(struct device *dev) | 223 | static 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 | ||
279 | static int s5p_ehci_resume(struct device *dev) | 247 | static 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 | }; |
298 | static const struct ehci_driver_overrides s5p_overrides __initdata = { | ||
299 | .extra_priv_size = sizeof(struct s5p_ehci_hcd), | ||
300 | }; | ||
301 | |||
302 | static 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 | } | ||
311 | module_init(ehci_s5p_init); | ||
312 | |||
313 | static void __exit ehci_s5p_cleanup(void) | ||
314 | { | ||
315 | platform_driver_unregister(&s5p_ehci_driver); | ||
316 | } | ||
317 | module_exit(ehci_s5p_cleanup); | ||
326 | 318 | ||
319 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
327 | MODULE_ALIAS("platform:s5p-ehci"); | 320 | MODULE_ALIAS("platform:s5p-ehci"); |
321 | MODULE_AUTHOR("Jingoo Han"); | ||
322 | MODULE_AUTHOR("Joonyoung Shim"); | ||
323 | MODULE_LICENSE("GPL v2"); | ||