aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-platform.c
diff options
context:
space:
mode:
authorHauke Mehrtens <hauke@hauke-m.de>2012-03-12 20:04:48 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-03-15 15:42:07 -0400
commit7a7a4a592f42d9abf3b6cc40620b3f79fef49246 (patch)
treeb51cd6655476657d11127d166b9036b1e73e84de /drivers/usb/host/ehci-platform.c
parentfa3364b5a2d79b0c94a912b371c92bd3d06bc8fb (diff)
USB: EHCI: Add a generic platform device driver
This adds a generic driver for platform devices. It works like the PCI driver and is based on it. This is for devices which do not have an own bus but their EHCI controller works like a PCI controller. It will be used for the Broadcom bcma and ssb USB EHCI controller. Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host/ehci-platform.c')
-rw-r--r--drivers/usb/host/ehci-platform.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
new file mode 100644
index 000000000000..d238b4e24bb6
--- /dev/null
+++ b/drivers/usb/host/ehci-platform.c
@@ -0,0 +1,198 @@
1/*
2 * Generic platform ehci driver
3 *
4 * Copyright 2007 Steven Brown <sbrown@cortland.com>
5 * Copyright 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
6 *
7 * Derived from the ohci-ssb driver
8 * Copyright 2007 Michael Buesch <m@bues.ch>
9 *
10 * Derived from the EHCI-PCI driver
11 * Copyright (c) 2000-2004 by David Brownell
12 *
13 * Derived from the ohci-pci driver
14 * Copyright 1999 Roman Weissgaerber
15 * Copyright 2000-2002 David Brownell
16 * Copyright 1999 Linus Torvalds
17 * Copyright 1999 Gregory P. Smith
18 *
19 * Licensed under the GNU/GPL. See COPYING for details.
20 */
21#include <linux/platform_device.h>
22#include <linux/usb/ehci_pdriver.h>
23
24static int ehci_platform_reset(struct usb_hcd *hcd)
25{
26 struct platform_device *pdev = to_platform_device(hcd->self.controller);
27 struct usb_ehci_pdata *pdata = pdev->dev.platform_data;
28 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
29 int retval;
30
31 hcd->has_tt = pdata->has_tt;
32 ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug;
33 ehci->big_endian_desc = pdata->big_endian_desc;
34 ehci->big_endian_mmio = pdata->big_endian_mmio;
35
36 ehci->caps = hcd->regs + pdata->caps_offset;
37 retval = ehci_setup(hcd);
38 if (retval)
39 return retval;
40
41 if (pdata->port_power_on)
42 ehci_port_power(ehci, 1);
43 if (pdata->port_power_off)
44 ehci_port_power(ehci, 0);
45
46 return 0;
47}
48
49static const struct hc_driver ehci_platform_hc_driver = {
50 .description = hcd_name,
51 .product_desc = "Generic Platform EHCI Controller",
52 .hcd_priv_size = sizeof(struct ehci_hcd),
53
54 .irq = ehci_irq,
55 .flags = HCD_MEMORY | HCD_USB2,
56
57 .reset = ehci_platform_reset,
58 .start = ehci_run,
59 .stop = ehci_stop,
60 .shutdown = ehci_shutdown,
61
62 .urb_enqueue = ehci_urb_enqueue,
63 .urb_dequeue = ehci_urb_dequeue,
64 .endpoint_disable = ehci_endpoint_disable,
65 .endpoint_reset = ehci_endpoint_reset,
66
67 .get_frame_number = ehci_get_frame,
68
69 .hub_status_data = ehci_hub_status_data,
70 .hub_control = ehci_hub_control,
71#if defined(CONFIG_PM)
72 .bus_suspend = ehci_bus_suspend,
73 .bus_resume = ehci_bus_resume,
74#endif
75 .relinquish_port = ehci_relinquish_port,
76 .port_handed_over = ehci_port_handed_over,
77
78 .update_device = ehci_update_device,
79
80 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
81};
82
83static int __devinit ehci_platform_probe(struct platform_device *dev)
84{
85 struct usb_hcd *hcd;
86 struct resource *res_mem;
87 int irq;
88 int err = -ENOMEM;
89
90 BUG_ON(!dev->dev.platform_data);
91
92 if (usb_disabled())
93 return -ENODEV;
94
95 irq = platform_get_irq(dev, 0);
96 if (irq < 0) {
97 pr_err("no irq provieded");
98 return irq;
99 }
100 res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
101 if (!res_mem) {
102 pr_err("no memory recourse provieded");
103 return -ENXIO;
104 }
105
106 hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
107 dev_name(&dev->dev));
108 if (!hcd)
109 return -ENOMEM;
110
111 hcd->rsrc_start = res_mem->start;
112 hcd->rsrc_len = resource_size(res_mem);
113
114 if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
115 pr_err("controller already in use");
116 err = -EBUSY;
117 goto err_put_hcd;
118 }
119
120 hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
121 if (!hcd->regs)
122 goto err_release_region;
123 err = usb_add_hcd(hcd, irq, IRQF_SHARED);
124 if (err)
125 goto err_iounmap;
126
127 platform_set_drvdata(dev, hcd);
128
129 return err;
130
131err_iounmap:
132 iounmap(hcd->regs);
133err_release_region:
134 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
135err_put_hcd:
136 usb_put_hcd(hcd);
137 return err;
138}
139
140static int __devexit ehci_platform_remove(struct platform_device *dev)
141{
142 struct usb_hcd *hcd = platform_get_drvdata(dev);
143
144 usb_remove_hcd(hcd);
145 iounmap(hcd->regs);
146 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
147 usb_put_hcd(hcd);
148 platform_set_drvdata(dev, NULL);
149
150 return 0;
151}
152
153#ifdef CONFIG_PM
154
155static int ehci_platform_suspend(struct device *dev)
156{
157 struct usb_hcd *hcd = dev_get_drvdata(dev);
158 bool wakeup = device_may_wakeup(dev);
159
160 ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), wakeup);
161 return 0;
162}
163
164static int ehci_platform_resume(struct device *dev)
165{
166 struct usb_hcd *hcd = dev_get_drvdata(dev);
167
168 ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
169 return 0;
170}
171
172#else /* !CONFIG_PM */
173#define ehci_platform_suspend NULL
174#define ehci_platform_resume NULL
175#endif /* CONFIG_PM */
176
177static const struct platform_device_id ehci_platform_table[] = {
178 { "ehci-platform", 0 },
179 { }
180};
181MODULE_DEVICE_TABLE(platform, ehci_platform_table);
182
183static const struct dev_pm_ops ehci_platform_pm_ops = {
184 .suspend = ehci_platform_suspend,
185 .resume = ehci_platform_resume,
186};
187
188static struct platform_driver ehci_platform_driver = {
189 .id_table = ehci_platform_table,
190 .probe = ehci_platform_probe,
191 .remove = __devexit_p(ehci_platform_remove),
192 .shutdown = usb_hcd_platform_shutdown,
193 .driver = {
194 .owner = THIS_MODULE,
195 .name = "ehci-platform",
196 .pm = &ehci_platform_pm_ops,
197 }
198};