Root/target/linux/ar71xx/patches-3.3/001-USB-EHCI-Add-a-generic-platform-device-driver.patch

1From 4fa3face95f1ca2e396dd59324a6c6ef01df24cc Mon Sep 17 00:00:00 2001
2From: Hauke Mehrtens <hauke@hauke-m.de>
3Date: Tue, 13 Mar 2012 01:04:48 +0100
4Subject: [PATCH 02/47] USB: EHCI: Add a generic platform device driver
5
6This adds a generic driver for platform devices. It works like the PCI
7driver and is based on it. This is for devices which do not have an own
8bus but their EHCI controller works like a PCI controller. It will be
9used for the Broadcom bcma and ssb USB EHCI controller.
10
11Acked-by: Alan Stern <stern@rowland.harvard.edu>
12Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
13Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
14---
15 drivers/usb/host/Kconfig | 10 ++
16 drivers/usb/host/ehci-hcd.c | 5 +
17 drivers/usb/host/ehci-platform.c | 198 ++++++++++++++++++++++++++++++++++++++
18 include/linux/usb/ehci_pdriver.h | 46 +++++++++
19 4 files changed, 259 insertions(+), 0 deletions(-)
20 create mode 100644 drivers/usb/host/ehci-platform.c
21 create mode 100644 include/linux/usb/ehci_pdriver.h
22
23--- a/drivers/usb/host/Kconfig
24+++ b/drivers/usb/host/Kconfig
25@@ -403,6 +403,16 @@ config USB_OHCI_HCD_PLATFORM
26 
27       If unsure, say N.
28 
29+config USB_EHCI_HCD_PLATFORM
30+ bool "Generic EHCI driver for a platform device"
31+ depends on USB_EHCI_HCD && EXPERIMENTAL
32+ default n
33+ ---help---
34+ Adds an EHCI host driver for a generic platform device, which
35+ provieds a memory space and an irq.
36+
37+ If unsure, say N.
38+
39 config USB_OHCI_BIG_ENDIAN_DESC
40     bool
41     depends on USB_OHCI_HCD
42--- a/drivers/usb/host/ehci-hcd.c
43+++ b/drivers/usb/host/ehci-hcd.c
44@@ -1381,6 +1381,11 @@ MODULE_LICENSE ("GPL");
45 #define PLATFORM_DRIVER ehci_mv_driver
46 #endif
47 
48+#ifdef CONFIG_USB_EHCI_HCD_PLATFORM
49+#include "ehci-platform.c"
50+#define PLATFORM_DRIVER ehci_platform_driver
51+#endif
52+
53 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
54     !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
55     !defined(XILINX_OF_PLATFORM_DRIVER)
56--- /dev/null
57+++ b/drivers/usb/host/ehci-platform.c
58@@ -0,0 +1,198 @@
59+/*
60+ * Generic platform ehci driver
61+ *
62+ * Copyright 2007 Steven Brown <sbrown@cortland.com>
63+ * Copyright 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
64+ *
65+ * Derived from the ohci-ssb driver
66+ * Copyright 2007 Michael Buesch <m@bues.ch>
67+ *
68+ * Derived from the EHCI-PCI driver
69+ * Copyright (c) 2000-2004 by David Brownell
70+ *
71+ * Derived from the ohci-pci driver
72+ * Copyright 1999 Roman Weissgaerber
73+ * Copyright 2000-2002 David Brownell
74+ * Copyright 1999 Linus Torvalds
75+ * Copyright 1999 Gregory P. Smith
76+ *
77+ * Licensed under the GNU/GPL. See COPYING for details.
78+ */
79+#include <linux/platform_device.h>
80+#include <linux/usb/ehci_pdriver.h>
81+
82+static int ehci_platform_reset(struct usb_hcd *hcd)
83+{
84+ struct platform_device *pdev = to_platform_device(hcd->self.controller);
85+ struct usb_ehci_pdata *pdata = pdev->dev.platform_data;
86+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
87+ int retval;
88+
89+ hcd->has_tt = pdata->has_tt;
90+ ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug;
91+ ehci->big_endian_desc = pdata->big_endian_desc;
92+ ehci->big_endian_mmio = pdata->big_endian_mmio;
93+
94+ ehci->caps = hcd->regs + pdata->caps_offset;
95+ retval = ehci_setup(hcd);
96+ if (retval)
97+ return retval;
98+
99+ if (pdata->port_power_on)
100+ ehci_port_power(ehci, 1);
101+ if (pdata->port_power_off)
102+ ehci_port_power(ehci, 0);
103+
104+ return 0;
105+}
106+
107+static const struct hc_driver ehci_platform_hc_driver = {
108+ .description = hcd_name,
109+ .product_desc = "Generic Platform EHCI Controller",
110+ .hcd_priv_size = sizeof(struct ehci_hcd),
111+
112+ .irq = ehci_irq,
113+ .flags = HCD_MEMORY | HCD_USB2,
114+
115+ .reset = ehci_platform_reset,
116+ .start = ehci_run,
117+ .stop = ehci_stop,
118+ .shutdown = ehci_shutdown,
119+
120+ .urb_enqueue = ehci_urb_enqueue,
121+ .urb_dequeue = ehci_urb_dequeue,
122+ .endpoint_disable = ehci_endpoint_disable,
123+ .endpoint_reset = ehci_endpoint_reset,
124+
125+ .get_frame_number = ehci_get_frame,
126+
127+ .hub_status_data = ehci_hub_status_data,
128+ .hub_control = ehci_hub_control,
129+#if defined(CONFIG_PM)
130+ .bus_suspend = ehci_bus_suspend,
131+ .bus_resume = ehci_bus_resume,
132+#endif
133+ .relinquish_port = ehci_relinquish_port,
134+ .port_handed_over = ehci_port_handed_over,
135+
136+ .update_device = ehci_update_device,
137+
138+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
139+};
140+
141+static int __devinit ehci_platform_probe(struct platform_device *dev)
142+{
143+ struct usb_hcd *hcd;
144+ struct resource *res_mem;
145+ int irq;
146+ int err = -ENOMEM;
147+
148+ BUG_ON(!dev->dev.platform_data);
149+
150+ if (usb_disabled())
151+ return -ENODEV;
152+
153+ irq = platform_get_irq(dev, 0);
154+ if (irq < 0) {
155+ pr_err("no irq provieded");
156+ return irq;
157+ }
158+ res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
159+ if (!res_mem) {
160+ pr_err("no memory recourse provieded");
161+ return -ENXIO;
162+ }
163+
164+ hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
165+ dev_name(&dev->dev));
166+ if (!hcd)
167+ return -ENOMEM;
168+
169+ hcd->rsrc_start = res_mem->start;
170+ hcd->rsrc_len = resource_size(res_mem);
171+
172+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
173+ pr_err("controller already in use");
174+ err = -EBUSY;
175+ goto err_put_hcd;
176+ }
177+
178+ hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
179+ if (!hcd->regs)
180+ goto err_release_region;
181+ err = usb_add_hcd(hcd, irq, IRQF_SHARED);
182+ if (err)
183+ goto err_iounmap;
184+
185+ platform_set_drvdata(dev, hcd);
186+
187+ return err;
188+
189+err_iounmap:
190+ iounmap(hcd->regs);
191+err_release_region:
192+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
193+err_put_hcd:
194+ usb_put_hcd(hcd);
195+ return err;
196+}
197+
198+static int __devexit ehci_platform_remove(struct platform_device *dev)
199+{
200+ struct usb_hcd *hcd = platform_get_drvdata(dev);
201+
202+ usb_remove_hcd(hcd);
203+ iounmap(hcd->regs);
204+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
205+ usb_put_hcd(hcd);
206+ platform_set_drvdata(dev, NULL);
207+
208+ return 0;
209+}
210+
211+#ifdef CONFIG_PM
212+
213+static int ehci_platform_suspend(struct device *dev)
214+{
215+ struct usb_hcd *hcd = dev_get_drvdata(dev);
216+ bool wakeup = device_may_wakeup(dev);
217+
218+ ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), wakeup);
219+ return 0;
220+}
221+
222+static int ehci_platform_resume(struct device *dev)
223+{
224+ struct usb_hcd *hcd = dev_get_drvdata(dev);
225+
226+ ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
227+ return 0;
228+}
229+
230+#else /* !CONFIG_PM */
231+#define ehci_platform_suspend NULL
232+#define ehci_platform_resume NULL
233+#endif /* CONFIG_PM */
234+
235+static const struct platform_device_id ehci_platform_table[] = {
236+ { "ehci-platform", 0 },
237+ { }
238+};
239+MODULE_DEVICE_TABLE(platform, ehci_platform_table);
240+
241+static const struct dev_pm_ops ehci_platform_pm_ops = {
242+ .suspend = ehci_platform_suspend,
243+ .resume = ehci_platform_resume,
244+};
245+
246+static struct platform_driver ehci_platform_driver = {
247+ .id_table = ehci_platform_table,
248+ .probe = ehci_platform_probe,
249+ .remove = __devexit_p(ehci_platform_remove),
250+ .shutdown = usb_hcd_platform_shutdown,
251+ .driver = {
252+ .owner = THIS_MODULE,
253+ .name = "ehci-platform",
254+ .pm = &ehci_platform_pm_ops,
255+ }
256+};
257--- /dev/null
258+++ b/include/linux/usb/ehci_pdriver.h
259@@ -0,0 +1,46 @@
260+/*
261+ * Copyright (C) 2012 Hauke Mehrtens <hauke@hauke-m.de>
262+ *
263+ * This program is free software; you can redistribute it and/or modify it
264+ * under the terms of the GNU General Public License as published by the
265+ * Free Software Foundation; either version 2 of the License, or (at your
266+ * option) any later version.
267+ *
268+ * This program is distributed in the hope that it will be useful, but
269+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
270+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
271+ * for more details.
272+ *
273+ * You should have received a copy of the GNU General Public License
274+ * along with this program; if not, write to the Free Software Foundation,
275+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
276+ */
277+
278+#ifndef __USB_CORE_EHCI_PDRIVER_H
279+#define __USB_CORE_EHCI_PDRIVER_H
280+
281+/**
282+ * struct usb_ehci_pdata - platform_data for generic ehci driver
283+ *
284+ * @caps_offset: offset of the EHCI Capability Registers to the start of
285+ * the io memory region provided to the driver.
286+ * @has_tt: set to 1 if TT is integrated in root hub.
287+ * @port_power_on: set to 1 if the controller needs a power up after
288+ * initialization.
289+ * @port_power_off: set to 1 if the controller needs to be powered down
290+ * after initialization.
291+ *
292+ * These are general configuration options for the EHCI controller. All of
293+ * these options are activating more or less workarounds for some hardware.
294+ */
295+struct usb_ehci_pdata {
296+ int caps_offset;
297+ unsigned has_tt:1;
298+ unsigned has_synopsys_hc_bug:1;
299+ unsigned big_endian_desc:1;
300+ unsigned big_endian_mmio:1;
301+ unsigned port_power_on:1;
302+ unsigned port_power_off:1;
303+};
304+
305+#endif /* __USB_CORE_EHCI_PDRIVER_H */
306

Archive Download this file



interactive