aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoonyoung Shim <jy0922.shim@samsung.com>2011-04-08 01:08:50 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-04-13 19:50:52 -0400
commit1bcc5aa87f043d34522d783154d08173b435fb46 (patch)
treedec628a085e998895e71c1a79e0020709f8fe094
parent8f1d169f999fea892c3fcbf5a79ae8525a477572 (diff)
USB: Add initial S5P EHCI driver
This patch adds host USB high speed driver for samsung S5P series. This is initial driver and we need additional implementation to support some functions like power management. Signed-off-by: Jingoo Han <jg1.han@samsung.com> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/Kconfig1
-rw-r--r--drivers/usb/host/Kconfig6
-rw-r--r--drivers/usb/host/ehci-hcd.c5
-rw-r--r--drivers/usb/host/ehci-s5p.c201
4 files changed, 213 insertions, 0 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index d299906e4f00..cf7614d29f03 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -65,6 +65,7 @@ config USB_ARCH_HAS_EHCI
65 default y if ARCH_CNS3XXX 65 default y if ARCH_CNS3XXX
66 default y if ARCH_VT8500 66 default y if ARCH_VT8500
67 default y if PLAT_SPEAR 67 default y if PLAT_SPEAR
68 default y if PLAT_S5P
68 default y if ARCH_MSM 69 default y if ARCH_MSM
69 default PCI 70 default PCI
70 71
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 5f518ded1955..ade009081feb 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -188,6 +188,12 @@ config USB_EHCI_SH
188 Enables support for the on-chip EHCI controller on the SuperH. 188 Enables support for the on-chip EHCI controller on the SuperH.
189 If you use the PCI EHCI controller, this option is not necessary. 189 If you use the PCI EHCI controller, this option is not necessary.
190 190
191config USB_EHCI_S5P
192 boolean "S5P EHCI support"
193 depends on USB_EHCI_HCD && PLAT_S5P
194 help
195 Enable support for the S5P SOC's on-chip EHCI controller.
196
191config USB_W90X900_EHCI 197config USB_W90X900_EHCI
192 bool "W90X900(W90P910) EHCI support" 198 bool "W90X900(W90P910) EHCI support"
193 depends on USB_EHCI_HCD && ARCH_W90X900 199 depends on USB_EHCI_HCD && ARCH_W90X900
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 78561d112c04..6b20b3b12d65 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1265,6 +1265,11 @@ MODULE_LICENSE ("GPL");
1265#define PLATFORM_DRIVER tegra_ehci_driver 1265#define PLATFORM_DRIVER tegra_ehci_driver
1266#endif 1266#endif
1267 1267
1268#ifdef CONFIG_USB_EHCI_S5P
1269#include "ehci-s5p.c"
1270#define PLATFORM_DRIVER s5p_ehci_driver
1271#endif
1272
1268#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ 1273#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
1269 !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ 1274 !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
1270 !defined(XILINX_OF_PLATFORM_DRIVER) 1275 !defined(XILINX_OF_PLATFORM_DRIVER)
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
new file mode 100644
index 000000000000..0c18f280bf4c
--- /dev/null
+++ b/drivers/usb/host/ehci-s5p.c
@@ -0,0 +1,201 @@
1/*
2 * SAMSUNG S5P USB HOST EHCI Controller
3 *
4 * Copyright (C) 2011 Samsung Electronics Co.Ltd
5 * Author: Jingoo Han <jg1.han@samsung.com>
6 * Author: Joonyoung Shim <jy0922.shim@samsung.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 */
14
15#include <linux/clk.h>
16#include <linux/platform_device.h>
17#include <mach/regs-pmu.h>
18#include <plat/cpu.h>
19#include <plat/ehci.h>
20#include <plat/usb-phy.h>
21
22struct s5p_ehci_hcd {
23 struct device *dev;
24 struct usb_hcd *hcd;
25 struct clk *clk;
26};
27
28static const struct hc_driver s5p_ehci_hc_driver = {
29 .description = hcd_name,
30 .product_desc = "S5P EHCI Host Controller",
31 .hcd_priv_size = sizeof(struct ehci_hcd),
32
33 .irq = ehci_irq,
34 .flags = HCD_MEMORY | HCD_USB2,
35
36 .reset = ehci_init,
37 .start = ehci_run,
38 .stop = ehci_stop,
39 .shutdown = ehci_shutdown,
40
41 .get_frame_number = ehci_get_frame,
42
43 .urb_enqueue = ehci_urb_enqueue,
44 .urb_dequeue = ehci_urb_dequeue,
45 .endpoint_disable = ehci_endpoint_disable,
46 .endpoint_reset = ehci_endpoint_reset,
47
48 .hub_status_data = ehci_hub_status_data,
49 .hub_control = ehci_hub_control,
50 .bus_suspend = ehci_bus_suspend,
51 .bus_resume = ehci_bus_resume,
52
53 .relinquish_port = ehci_relinquish_port,
54 .port_handed_over = ehci_port_handed_over,
55
56 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
57};
58
59static int s5p_ehci_probe(struct platform_device *pdev)
60{
61 struct s5p_ehci_platdata *pdata;
62 struct s5p_ehci_hcd *s5p_ehci;
63 struct usb_hcd *hcd;
64 struct ehci_hcd *ehci;
65 struct resource *res;
66 int irq;
67 int err;
68
69 pdata = pdev->dev.platform_data;
70 if (!pdata) {
71 dev_err(&pdev->dev, "No platform data defined\n");
72 return -EINVAL;
73 }
74
75 s5p_ehci = kzalloc(sizeof(struct s5p_ehci_hcd), GFP_KERNEL);
76 if (!s5p_ehci)
77 return -ENOMEM;
78
79 s5p_ehci->dev = &pdev->dev;
80
81 hcd = usb_create_hcd(&s5p_ehci_hc_driver, &pdev->dev,
82 dev_name(&pdev->dev));
83 if (!hcd) {
84 dev_err(&pdev->dev, "Unable to create HCD\n");
85 err = -ENOMEM;
86 goto fail_hcd;
87 }
88
89 s5p_ehci->clk = clk_get(&pdev->dev, "usbhost");
90
91 if (IS_ERR(s5p_ehci->clk)) {
92 dev_err(&pdev->dev, "Failed to get usbhost clock\n");
93 err = PTR_ERR(s5p_ehci->clk);
94 goto fail_clk;
95 }
96
97 err = clk_enable(s5p_ehci->clk);
98 if (err)
99 goto fail_clken;
100
101 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
102 if (!res) {
103 dev_err(&pdev->dev, "Failed to get I/O memory\n");
104 err = -ENXIO;
105 goto fail_io;
106 }
107
108 hcd->rsrc_start = res->start;
109 hcd->rsrc_len = resource_size(res);
110 hcd->regs = ioremap(res->start, resource_size(res));
111 if (!hcd->regs) {
112 dev_err(&pdev->dev, "Failed to remap I/O memory\n");
113 err = -ENOMEM;
114 goto fail_io;
115 }
116
117 irq = platform_get_irq(pdev, 0);
118 if (!irq) {
119 dev_err(&pdev->dev, "Failed to get IRQ\n");
120 err = -ENODEV;
121 goto fail;
122 }
123
124 if (pdata->phy_init)
125 pdata->phy_init(pdev, S5P_USB_PHY_HOST);
126
127 ehci = hcd_to_ehci(hcd);
128 ehci->caps = hcd->regs;
129 ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
130
131 dbg_hcs_params(ehci, "reset");
132 dbg_hcc_params(ehci, "reset");
133
134 /* cache this readonly data; minimize chip reads */
135 ehci->hcs_params = readl(&ehci->caps->hcs_params);
136
137 err = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
138 if (err) {
139 dev_err(&pdev->dev, "Failed to add USB HCD\n");
140 goto fail;
141 }
142
143 platform_set_drvdata(pdev, s5p_ehci);
144
145 return 0;
146
147fail:
148 iounmap(hcd->regs);
149fail_io:
150 clk_disable(s5p_ehci->clk);
151fail_clken:
152 clk_put(s5p_ehci->clk);
153fail_clk:
154 usb_put_hcd(hcd);
155fail_hcd:
156 kfree(s5p_ehci);
157 return err;
158}
159
160static int s5p_ehci_remove(struct platform_device *pdev)
161{
162 struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
163 struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev);
164 struct usb_hcd *hcd = s5p_ehci->hcd;
165
166 usb_remove_hcd(hcd);
167
168 if (pdata && pdata->phy_exit)
169 pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
170
171 iounmap(hcd->regs);
172
173 clk_disable(s5p_ehci->clk);
174 clk_put(s5p_ehci->clk);
175
176 usb_put_hcd(hcd);
177 kfree(s5p_ehci);
178
179 return 0;
180}
181
182static void s5p_ehci_shutdown(struct platform_device *pdev)
183{
184 struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev);
185 struct usb_hcd *hcd = s5p_ehci->hcd;
186
187 if (hcd->driver->shutdown)
188 hcd->driver->shutdown(hcd);
189}
190
191static struct platform_driver s5p_ehci_driver = {
192 .probe = s5p_ehci_probe,
193 .remove = s5p_ehci_remove,
194 .shutdown = s5p_ehci_shutdown,
195 .driver = {
196 .name = "s5p-ehci",
197 .owner = THIS_MODULE,
198 }
199};
200
201MODULE_ALIAS("platform:s5p-ehci");