aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-mxc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ehci-mxc.c')
-rw-r--r--drivers/usb/host/ehci-mxc.c120
1 files changed, 50 insertions, 70 deletions
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index 6b8c1584065f..c6dc4655e0a5 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -17,75 +17,38 @@
17 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */ 18 */
19 19
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/io.h>
20#include <linux/platform_device.h> 23#include <linux/platform_device.h>
21#include <linux/clk.h> 24#include <linux/clk.h>
22#include <linux/delay.h> 25#include <linux/delay.h>
23#include <linux/usb/otg.h> 26#include <linux/usb/otg.h>
24#include <linux/usb/ulpi.h> 27#include <linux/usb/ulpi.h>
25#include <linux/slab.h> 28#include <linux/slab.h>
29#include <linux/usb.h>
30#include <linux/usb/hcd.h>
26 31
27#include <linux/platform_data/usb-ehci-mxc.h> 32#include <linux/platform_data/usb-ehci-mxc.h>
28 33
29#include <asm/mach-types.h> 34#include <asm/mach-types.h>
30 35
36#include "ehci.h"
37
38#define DRIVER_DESC "Freescale On-Chip EHCI Host driver"
39
40static const char hcd_name[] = "ehci-mxc";
41
31#define ULPI_VIEWPORT_OFFSET 0x170 42#define ULPI_VIEWPORT_OFFSET 0x170
32 43
33struct ehci_mxc_priv { 44struct ehci_mxc_priv {
34 struct clk *usbclk, *ahbclk, *phyclk; 45 struct clk *usbclk, *ahbclk, *phyclk;
35 struct usb_hcd *hcd;
36}; 46};
37 47
38/* called during probe() after chip reset completes */ 48static struct hc_driver __read_mostly ehci_mxc_hc_driver;
39static int ehci_mxc_setup(struct usb_hcd *hcd)
40{
41 hcd->has_tt = 1;
42
43 return ehci_setup(hcd);
44}
45 49
46static const struct hc_driver ehci_mxc_hc_driver = { 50static const struct ehci_driver_overrides ehci_mxc_overrides __initdata = {
47 .description = hcd_name, 51 .extra_priv_size = sizeof(struct ehci_mxc_priv),
48 .product_desc = "Freescale On-Chip EHCI Host Controller",
49 .hcd_priv_size = sizeof(struct ehci_hcd),
50
51 /*
52 * generic hardware linkage
53 */
54 .irq = ehci_irq,
55 .flags = HCD_USB2 | HCD_MEMORY,
56
57 /*
58 * basic lifecycle operations
59 */
60 .reset = ehci_mxc_setup,
61 .start = ehci_run,
62 .stop = ehci_stop,
63 .shutdown = ehci_shutdown,
64
65 /*
66 * managing i/o requests and associated device resources
67 */
68 .urb_enqueue = ehci_urb_enqueue,
69 .urb_dequeue = ehci_urb_dequeue,
70 .endpoint_disable = ehci_endpoint_disable,
71 .endpoint_reset = ehci_endpoint_reset,
72
73 /*
74 * scheduling support
75 */
76 .get_frame_number = ehci_get_frame,
77
78 /*
79 * root hub support
80 */
81 .hub_status_data = ehci_hub_status_data,
82 .hub_control = ehci_hub_control,
83 .bus_suspend = ehci_bus_suspend,
84 .bus_resume = ehci_bus_resume,
85 .relinquish_port = ehci_relinquish_port,
86 .port_handed_over = ehci_port_handed_over,
87
88 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
89}; 52};
90 53
91static int ehci_mxc_drv_probe(struct platform_device *pdev) 54static int ehci_mxc_drv_probe(struct platform_device *pdev)
@@ -111,12 +74,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
111 if (!hcd) 74 if (!hcd)
112 return -ENOMEM; 75 return -ENOMEM;
113 76
114 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
115 if (!priv) {
116 ret = -ENOMEM;
117 goto err_alloc;
118 }
119
120 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 77 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
121 if (!res) { 78 if (!res) {
122 dev_err(dev, "Found HC with no register addr. Check setup!\n"); 79 dev_err(dev, "Found HC with no register addr. Check setup!\n");
@@ -134,6 +91,10 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
134 goto err_alloc; 91 goto err_alloc;
135 } 92 }
136 93
94 hcd->has_tt = 1;
95 ehci = hcd_to_ehci(hcd);
96 priv = (struct ehci_mxc_priv *) ehci->priv;
97
137 /* enable clocks */ 98 /* enable clocks */
138 priv->usbclk = devm_clk_get(&pdev->dev, "ipg"); 99 priv->usbclk = devm_clk_get(&pdev->dev, "ipg");
139 if (IS_ERR(priv->usbclk)) { 100 if (IS_ERR(priv->usbclk)) {
@@ -168,8 +129,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
168 mdelay(10); 129 mdelay(10);
169 } 130 }
170 131
171 ehci = hcd_to_ehci(hcd);
172
173 /* EHCI registers start at offset 0x100 */ 132 /* EHCI registers start at offset 0x100 */
174 ehci->caps = hcd->regs + 0x100; 133 ehci->caps = hcd->regs + 0x100;
175 ehci->regs = hcd->regs + 0x100 + 134 ehci->regs = hcd->regs + 0x100 +
@@ -197,8 +156,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
197 } 156 }
198 } 157 }
199 158
200 priv->hcd = hcd; 159 platform_set_drvdata(pdev, hcd);
201 platform_set_drvdata(pdev, priv);
202 160
203 ret = usb_add_hcd(hcd, irq, IRQF_SHARED); 161 ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
204 if (ret) 162 if (ret)
@@ -224,8 +182,11 @@ err_alloc:
224static int __exit ehci_mxc_drv_remove(struct platform_device *pdev) 182static int __exit ehci_mxc_drv_remove(struct platform_device *pdev)
225{ 183{
226 struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data; 184 struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
227 struct ehci_mxc_priv *priv = platform_get_drvdata(pdev); 185 struct usb_hcd *hcd = platform_get_drvdata(pdev);
228 struct usb_hcd *hcd = priv->hcd; 186 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
187 struct ehci_mxc_priv *priv = (struct ehci_mxc_priv *) ehci->priv;
188
189 usb_remove_hcd(hcd);
229 190
230 if (pdata && pdata->exit) 191 if (pdata && pdata->exit)
231 pdata->exit(pdev); 192 pdata->exit(pdev);
@@ -233,23 +194,20 @@ static int __exit ehci_mxc_drv_remove(struct platform_device *pdev)
233 if (pdata->otg) 194 if (pdata->otg)
234 usb_phy_shutdown(pdata->otg); 195 usb_phy_shutdown(pdata->otg);
235 196
236 usb_remove_hcd(hcd);
237 usb_put_hcd(hcd);
238 platform_set_drvdata(pdev, NULL);
239
240 clk_disable_unprepare(priv->usbclk); 197 clk_disable_unprepare(priv->usbclk);
241 clk_disable_unprepare(priv->ahbclk); 198 clk_disable_unprepare(priv->ahbclk);
242 199
243 if (priv->phyclk) 200 if (priv->phyclk)
244 clk_disable_unprepare(priv->phyclk); 201 clk_disable_unprepare(priv->phyclk);
245 202
203 usb_put_hcd(hcd);
204 platform_set_drvdata(pdev, NULL);
246 return 0; 205 return 0;
247} 206}
248 207
249static void ehci_mxc_drv_shutdown(struct platform_device *pdev) 208static void ehci_mxc_drv_shutdown(struct platform_device *pdev)
250{ 209{
251 struct ehci_mxc_priv *priv = platform_get_drvdata(pdev); 210 struct usb_hcd *hcd = platform_get_drvdata(pdev);
252 struct usb_hcd *hcd = priv->hcd;
253 211
254 if (hcd->driver->shutdown) 212 if (hcd->driver->shutdown)
255 hcd->driver->shutdown(hcd); 213 hcd->driver->shutdown(hcd);
@@ -259,9 +217,31 @@ MODULE_ALIAS("platform:mxc-ehci");
259 217
260static struct platform_driver ehci_mxc_driver = { 218static struct platform_driver ehci_mxc_driver = {
261 .probe = ehci_mxc_drv_probe, 219 .probe = ehci_mxc_drv_probe,
262 .remove = __exit_p(ehci_mxc_drv_remove), 220 .remove = ehci_mxc_drv_remove,
263 .shutdown = ehci_mxc_drv_shutdown, 221 .shutdown = ehci_mxc_drv_shutdown,
264 .driver = { 222 .driver = {
265 .name = "mxc-ehci", 223 .name = "mxc-ehci",
266 }, 224 },
267}; 225};
226
227static int __init ehci_mxc_init(void)
228{
229 if (usb_disabled())
230 return -ENODEV;
231
232 pr_info("%s: " DRIVER_DESC "\n", hcd_name);
233
234 ehci_init_driver(&ehci_mxc_hc_driver, &ehci_mxc_overrides);
235 return platform_driver_register(&ehci_mxc_driver);
236}
237module_init(ehci_mxc_init);
238
239static void __exit ehci_mxc_cleanup(void)
240{
241 platform_driver_unregister(&ehci_mxc_driver);
242}
243module_exit(ehci_mxc_cleanup);
244
245MODULE_DESCRIPTION(DRIVER_DESC);
246MODULE_AUTHOR("Sascha Hauer");
247MODULE_LICENSE("GPL");