Root/target/linux/brcm47xx/patches-3.3/184-USB-Add-driver-for-the-ssb-bus.patch

1
2--- a/drivers/usb/host/Kconfig
3+++ b/drivers/usb/host/Kconfig
4@@ -645,3 +645,15 @@ config USB_HCD_BCMA
5       for ehci and ohci.
6 
7       If unsure, say N.
8+
9+config USB_HCD_SSB
10+ tristate "SSB usb host driver"
11+ depends on SSB && EXPERIMENTAL
12+ select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
13+ select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
14+ help
15+ Enbale support for the EHCI and OCHI host controller on an bcma bus.
16+ It converts the bcma driver into two platform device drivers
17+ for ehci and ohci.
18+
19+ If unsure, say N.
20--- a/drivers/usb/host/Makefile
21+++ b/drivers/usb/host/Makefile
22@@ -38,3 +38,4 @@ obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-m
23 obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
24 obj-$(CONFIG_MIPS_ALCHEMY) += alchemy-common.o
25 obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o
26+obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o
27--- /dev/null
28+++ b/drivers/usb/host/ssb-hcd.c
29@@ -0,0 +1,279 @@
30+/*
31+ * Sonics Silicon Backplane
32+ * Broadcom USB-core driver (SSB bus glue)
33+ *
34+ * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
35+ *
36+ * Based on ssb-ohci driver
37+ * Copyright 2007 Michael Buesch <m@bues.ch>
38+ *
39+ * Derived from the OHCI-PCI driver
40+ * Copyright 1999 Roman Weissgaerber
41+ * Copyright 2000-2002 David Brownell
42+ * Copyright 1999 Linus Torvalds
43+ * Copyright 1999 Gregory P. Smith
44+ *
45+ * Derived from the USBcore related parts of Broadcom-SB
46+ * Copyright 2005-2011 Broadcom Corporation
47+ *
48+ * Licensed under the GNU/GPL. See COPYING for details.
49+ */
50+#include <linux/ssb/ssb.h>
51+#include <linux/delay.h>
52+#include <linux/platform_device.h>
53+#include <linux/module.h>
54+#include <linux/usb/ehci_pdriver.h>
55+#include <linux/usb/ohci_pdriver.h>
56+
57+MODULE_AUTHOR("Hauke Mehrtens");
58+MODULE_DESCRIPTION("Common USB driver for SSB Bus");
59+MODULE_LICENSE("GPL");
60+
61+#define SSB_HCD_TMSLOW_HOSTMODE (1 << 29)
62+
63+struct ssb_hcd_device {
64+ struct platform_device *ehci_dev;
65+ struct platform_device *ohci_dev;
66+
67+ u32 enable_flags;
68+};
69+
70+static void __devinit ssb_hcd_5354wa(struct ssb_device *dev)
71+{
72+#ifdef CONFIG_SSB_DRIVER_MIPS
73+ /* Work around for 5354 failures */
74+ if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) {
75+ /* Change syn01 reg */
76+ ssb_write32(dev, 0x894, 0x00fe00fe);
77+
78+ /* Change syn03 reg */
79+ ssb_write32(dev, 0x89c, ssb_read32(dev, 0x89c) | 0x1);
80+ }
81+#endif
82+}
83+
84+static void __devinit ssb_hcd_usb20wa(struct ssb_device *dev)
85+{
86+ if (dev->id.coreid == SSB_DEV_USB20_HOST) {
87+ /*
88+ * USB 2.0 special considerations:
89+ *
90+ * In addition to the standard SSB reset sequence, the Host
91+ * Control Register must be programmed to bring the USB core
92+ * and various phy components out of reset.
93+ */
94+ ssb_write32(dev, 0x200, 0x7ff);
95+
96+ /* Change Flush control reg */
97+ ssb_write32(dev, 0x400, ssb_read32(dev, 0x400) & ~8);
98+ ssb_read32(dev, 0x400);
99+
100+ /* Change Shim control reg */
101+ ssb_write32(dev, 0x304, ssb_read32(dev, 0x304) & ~0x100);
102+ ssb_read32(dev, 0x304);
103+
104+ udelay(1);
105+
106+ ssb_hcd_5354wa(dev);
107+ }
108+}
109+
110+/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */
111+static u32 __devinit ssb_hcd_init_chip(struct ssb_device *dev)
112+{
113+ u32 flags = 0;
114+
115+ if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
116+ /* Put the device into host-mode. */
117+ flags |= SSB_HCD_TMSLOW_HOSTMODE;
118+
119+ ssb_device_enable(dev, flags);
120+
121+ ssb_hcd_usb20wa(dev);
122+
123+ return flags;
124+}
125+
126+static const struct usb_ehci_pdata ehci_pdata = {
127+};
128+
129+static const struct usb_ohci_pdata ohci_pdata = {
130+};
131+
132+static struct platform_device * __devinit
133+ssb_hcd_create_pdev(struct ssb_device *dev, bool ohci, u32 addr, u32 len)
134+{
135+ struct platform_device *hci_dev;
136+ struct resource hci_res[2];
137+ int ret = -ENOMEM;
138+
139+ memset(hci_res, 0, sizeof(hci_res));
140+
141+ hci_res[0].start = addr;
142+ hci_res[0].end = hci_res[0].start + len - 1;
143+ hci_res[0].flags = IORESOURCE_MEM;
144+
145+ hci_res[1].start = dev->irq;
146+ hci_res[1].flags = IORESOURCE_IRQ;
147+
148+ hci_dev = platform_device_alloc(ohci ? "ohci-platform" :
149+ "ehci-platform" , 0);
150+ if (!hci_dev)
151+ return NULL;
152+
153+ hci_dev->dev.parent = dev->dev;
154+ hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
155+
156+ ret = platform_device_add_resources(hci_dev, hci_res,
157+ ARRAY_SIZE(hci_res));
158+ if (ret)
159+ goto err_alloc;
160+ if (ohci)
161+ ret = platform_device_add_data(hci_dev, &ohci_pdata,
162+ sizeof(ohci_pdata));
163+ else
164+ ret = platform_device_add_data(hci_dev, &ehci_pdata,
165+ sizeof(ehci_pdata));
166+ if (ret)
167+ goto err_alloc;
168+ ret = platform_device_add(hci_dev);
169+ if (ret)
170+ goto err_alloc;
171+
172+ return hci_dev;
173+
174+err_alloc:
175+ platform_device_put(hci_dev);
176+ return ERR_PTR(ret);
177+}
178+
179+static int __devinit ssb_hcd_probe(struct ssb_device *dev,
180+ const struct ssb_device_id *id)
181+{
182+ int err, tmp;
183+ int start, len;
184+ u16 chipid_top;
185+ u16 coreid = dev->id.coreid;
186+ struct ssb_hcd_device *usb_dev;
187+
188+ /* USBcores are only connected on embedded devices. */
189+ chipid_top = (dev->bus->chip_id & 0xFF00);
190+ if (chipid_top != 0x4700 && chipid_top != 0x5300)
191+ return -ENODEV;
192+
193+ /* TODO: Probably need checks here; is the core connected? */
194+
195+ if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
196+ dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
197+ return -EOPNOTSUPP;
198+
199+ usb_dev = kzalloc(sizeof(struct ssb_hcd_device), GFP_KERNEL);
200+ if (!usb_dev)
201+ return -ENOMEM;
202+
203+ /* We currently always attach SSB_DEV_USB11_HOSTDEV
204+ * as HOST OHCI. If we want to attach it as Client device,
205+ * we must branch here and call into the (yet to
206+ * be written) Client mode driver. Same for remove(). */
207+ usb_dev->enable_flags = ssb_hcd_init_chip(dev);
208+
209+ tmp = ssb_read32(dev, SSB_ADMATCH0);
210+
211+ start = ssb_admatch_base(tmp);
212+ len = (coreid == SSB_DEV_USB20_HOST) ? 0x800 : ssb_admatch_size(tmp);
213+ usb_dev->ohci_dev = ssb_hcd_create_pdev(dev, true, start, len);
214+ if (IS_ERR(usb_dev->ohci_dev)) {
215+ err = PTR_ERR(usb_dev->ohci_dev);
216+ goto err_free_usb_dev;
217+ }
218+
219+ if (coreid == SSB_DEV_USB20_HOST) {
220+ start = ssb_admatch_base(tmp) + 0x800; /* ehci core offset */
221+ usb_dev->ehci_dev = ssb_hcd_create_pdev(dev, false, start, len);
222+ if (IS_ERR(usb_dev->ehci_dev)) {
223+ err = PTR_ERR(usb_dev->ehci_dev);
224+ goto err_unregister_ohci_dev;
225+ }
226+ }
227+
228+ ssb_set_drvdata(dev, usb_dev);
229+ return 0;
230+
231+err_unregister_ohci_dev:
232+ platform_device_unregister(usb_dev->ohci_dev);
233+err_free_usb_dev:
234+ kfree(usb_dev);
235+ return err;
236+}
237+
238+static void __devexit ssb_hcd_remove(struct ssb_device *dev)
239+{
240+ struct ssb_hcd_device *usb_dev = ssb_get_drvdata(dev);
241+ struct platform_device *ohci_dev = usb_dev->ohci_dev;
242+ struct platform_device *ehci_dev = usb_dev->ehci_dev;
243+
244+ if (ohci_dev)
245+ platform_device_unregister(ohci_dev);
246+ if (ehci_dev)
247+ platform_device_unregister(ehci_dev);
248+
249+ ssb_device_disable(dev, 0);
250+}
251+
252+static void __devexit ssb_hcd_shutdown(struct ssb_device *dev)
253+{
254+ ssb_device_disable(dev, 0);
255+}
256+
257+#ifdef CONFIG_PM
258+
259+static int ssb_hcd_suspend(struct ssb_device *dev, pm_message_t state)
260+{
261+ ssb_device_disable(dev, 0);
262+
263+ return 0;
264+}
265+
266+static int ssb_hcd_resume(struct ssb_device *dev)
267+{
268+ struct ssb_hcd_device *usb_dev = ssb_get_drvdata(dev);
269+
270+ ssb_device_enable(dev, usb_dev->enable_flags);
271+
272+ return 0;
273+}
274+
275+#else /* !CONFIG_PM */
276+#define ssb_hcd_suspend NULL
277+#define ssb_hcd_resume NULL
278+#endif /* CONFIG_PM */
279+
280+static const struct ssb_device_id ssb_hcd_table[] __devinitconst = {
281+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
282+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
283+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
284+ SSB_DEVTABLE_END
285+};
286+MODULE_DEVICE_TABLE(ssb, ssb_hcd_table);
287+
288+static struct ssb_driver ssb_hcd_driver = {
289+ .name = KBUILD_MODNAME,
290+ .id_table = ssb_hcd_table,
291+ .probe = ssb_hcd_probe,
292+ .remove = __devexit_p(ssb_hcd_remove),
293+ .shutdown = ssb_hcd_shutdown,
294+ .suspend = ssb_hcd_suspend,
295+ .resume = ssb_hcd_resume,
296+};
297+
298+static int __init ssb_hcd_init(void)
299+{
300+ return ssb_driver_register(&ssb_hcd_driver);
301+}
302+module_init(ssb_hcd_init);
303+
304+static void __exit ssb_hcd_exit(void)
305+{
306+ ssb_driver_unregister(&ssb_hcd_driver);
307+}
308+module_exit(ssb_hcd_exit);
309

Archive Download this file



interactive