brcm47xx: update usb driver to the version send for mainline kernel integartion
[openwrt/staging/dedeckeh.git] / target / linux / brcm47xx / patches-3.2 / 183-USB-Add-driver-for-the-bcma-bus.patch
1 --- a/drivers/usb/host/Kconfig
2 +++ b/drivers/usb/host/Kconfig
3 @@ -618,3 +618,15 @@ config USB_PXA168_EHCI
4 help
5 Enable support for Marvell PXA168 SoC's on-chip EHCI
6 host controller
7 +
8 +config USB_HCD_BCMA
9 + tristate "BCMA usb host driver"
10 + depends on BCMA && EXPERIMENTAL
11 + select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
12 + select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
13 + help
14 + Enbale support for the EHCI and OCHI host controller on an bcma bus.
15 + It converts the bcma driver into two platform device drivers
16 + for ehci and ohci.
17 +
18 + If unsure, say N.
19 --- a/drivers/usb/host/Makefile
20 +++ b/drivers/usb/host/Makefile
21 @@ -37,3 +37,4 @@ obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd
22 obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
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 --- /dev/null
27 +++ b/drivers/usb/host/bcma-hcd.c
28 @@ -0,0 +1,334 @@
29 +/*
30 + * Broadcom specific Advanced Microcontroller Bus
31 + * Broadcom USB-core driver (BCMA bus glue)
32 + *
33 + * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
34 + *
35 + * Based on ssb-ohci driver
36 + * Copyright 2007 Michael Buesch <m@bues.ch>
37 + *
38 + * Derived from the OHCI-PCI driver
39 + * Copyright 1999 Roman Weissgaerber
40 + * Copyright 2000-2002 David Brownell
41 + * Copyright 1999 Linus Torvalds
42 + * Copyright 1999 Gregory P. Smith
43 + *
44 + * Derived from the USBcore related parts of Broadcom-SB
45 + * Copyright 2005-2011 Broadcom Corporation
46 + *
47 + * Licensed under the GNU/GPL. See COPYING for details.
48 + */
49 +#include <linux/bcma/bcma.h>
50 +#include <linux/delay.h>
51 +#include <linux/platform_device.h>
52 +#include <linux/module.h>
53 +#include <linux/usb/ehci_pdriver.h>
54 +#include <linux/usb/ohci_pdriver.h>
55 +
56 +MODULE_AUTHOR("Hauke Mehrtens");
57 +MODULE_DESCRIPTION("Common USB driver for BCMA Bus");
58 +MODULE_LICENSE("GPL");
59 +
60 +struct bcma_hcd_device {
61 + struct platform_device *ehci_dev;
62 + struct platform_device *ohci_dev;
63 +};
64 +
65 +/* Wait for bitmask in a register to get set or cleared.
66 + * timeout is in units of ten-microseconds.
67 + */
68 +static int bcma_wait_bits(struct bcma_device *dev, u16 reg, u32 bitmask,
69 + int timeout)
70 +{
71 + int i;
72 + u32 val;
73 +
74 + for (i = 0; i < timeout; i++) {
75 + val = bcma_read32(dev, reg);
76 + if ((val & bitmask) == bitmask)
77 + return 0;
78 + udelay(10);
79 + }
80 +
81 + return -ETIMEDOUT;
82 +}
83 +
84 +static void __devinit bcma_hcd_4716wa(struct bcma_device *dev)
85 +{
86 +#ifdef CONFIG_BCMA_DRIVER_MIPS
87 + /* Work around for 4716 failures. */
88 + if (dev->bus->chipinfo.id == 0x4716) {
89 + u32 tmp;
90 +
91 + tmp = bcma_cpu_clock(&dev->bus->drv_mips);
92 + if (tmp >= 480000000)
93 + tmp = 0x1846b; /* set CDR to 0x11(fast) */
94 + else if (tmp == 453000000)
95 + tmp = 0x1046b; /* set CDR to 0x10(slow) */
96 + else
97 + tmp = 0;
98 +
99 + /* Change Shim mdio control reg to fix host not acking at
100 + * high frequencies
101 + */
102 + if (tmp) {
103 + bcma_write32(dev, 0x524, 0x1); /* write sel to enable */
104 + udelay(500);
105 +
106 + bcma_write32(dev, 0x524, tmp);
107 + udelay(500);
108 + bcma_write32(dev, 0x524, 0x4ab);
109 + udelay(500);
110 + bcma_read32(dev, 0x528);
111 + bcma_write32(dev, 0x528, 0x80000000);
112 + }
113 + }
114 +#endif /* CONFIG_BCMA_DRIVER_MIPS */
115 +}
116 +
117 +/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */
118 +static void __devinit bcma_hcd_init_chip(struct bcma_device *dev)
119 +{
120 + u32 tmp;
121 +
122 + /*
123 + * USB 2.0 special considerations:
124 + *
125 + * 1. Since the core supports both OHCI and EHCI functions, it must
126 + * only be reset once.
127 + *
128 + * 2. In addition to the standard SI reset sequence, the Host Control
129 + * Register must be programmed to bring the USB core and various
130 + * phy components out of reset.
131 + */
132 + if (!bcma_core_is_enabled(dev)) {
133 + bcma_core_enable(dev, 0);
134 + mdelay(10);
135 + if (dev->id.rev >= 5) {
136 + /* Enable Misc PLL */
137 + tmp = bcma_read32(dev, 0x1e0);
138 + tmp |= 0x100;
139 + bcma_write32(dev, 0x1e0, tmp);
140 + if (bcma_wait_bits(dev, 0x1e0, 1 << 24, 100))
141 + printk(KERN_EMERG "Failed to enable misc PPL!\n");
142 +
143 + /* Take out of resets */
144 + bcma_write32(dev, 0x200, 0x4ff);
145 + udelay(25);
146 + bcma_write32(dev, 0x200, 0x6ff);
147 + udelay(25);
148 +
149 + /* Make sure digital and AFE are locked in USB PHY */
150 + bcma_write32(dev, 0x524, 0x6b);
151 + udelay(50);
152 + tmp = bcma_read32(dev, 0x524);
153 + udelay(50);
154 + bcma_write32(dev, 0x524, 0xab);
155 + udelay(50);
156 + tmp = bcma_read32(dev, 0x524);
157 + udelay(50);
158 + bcma_write32(dev, 0x524, 0x2b);
159 + udelay(50);
160 + tmp = bcma_read32(dev, 0x524);
161 + udelay(50);
162 + bcma_write32(dev, 0x524, 0x10ab);
163 + udelay(50);
164 + tmp = bcma_read32(dev, 0x524);
165 +
166 + if (bcma_wait_bits(dev, 0x528, 0xc000, 10000)) {
167 + tmp = bcma_read32(dev, 0x528);
168 + printk(KERN_EMERG
169 + "USB20H mdio_rddata 0x%08x\n", tmp);
170 + }
171 + bcma_write32(dev, 0x528, 0x80000000);
172 + tmp = bcma_read32(dev, 0x314);
173 + udelay(265);
174 + bcma_write32(dev, 0x200, 0x7ff);
175 + udelay(10);
176 +
177 + /* Take USB and HSIC out of non-driving modes */
178 + bcma_write32(dev, 0x510, 0);
179 + } else {
180 + bcma_write32(dev, 0x200, 0x7ff);
181 +
182 + udelay(1);
183 + }
184 +
185 + bcma_hcd_4716wa(dev);
186 + }
187 +}
188 +
189 +static const struct usb_ehci_pdata ehci_pdata = {
190 +};
191 +
192 +static const struct usb_ohci_pdata ohci_pdata = {
193 +};
194 +
195 +static struct platform_device * __devinit
196 +bcma_hcd_create_pdev(struct bcma_device *dev, bool ohci, u32 addr)
197 +{
198 + struct platform_device *hci_dev;
199 + struct resource hci_res[2];
200 + int ret = -ENOMEM;
201 +
202 + memset(hci_res, 0, sizeof(hci_res));
203 +
204 + hci_res[0].start = addr;
205 + hci_res[0].end = hci_res[0].start + 0x1000 - 1;
206 + hci_res[0].flags = IORESOURCE_MEM;
207 +
208 + hci_res[1].start = dev->irq;
209 + hci_res[1].flags = IORESOURCE_IRQ;
210 +
211 + hci_dev = platform_device_alloc(ohci ? "ohci-platform" :
212 + "ehci-platform" , 0);
213 + if (!hci_dev)
214 + return NULL;
215 +
216 + hci_dev->dev.parent = &dev->dev;
217 + hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
218 +
219 + ret = platform_device_add_resources(hci_dev, hci_res,
220 + ARRAY_SIZE(hci_res));
221 + if (ret)
222 + goto err_alloc;
223 + if (ohci)
224 + ret = platform_device_add_data(hci_dev, &ohci_pdata,
225 + sizeof(ohci_pdata));
226 + else
227 + ret = platform_device_add_data(hci_dev, &ehci_pdata,
228 + sizeof(ehci_pdata));
229 + if (ret)
230 + goto err_alloc;
231 + ret = platform_device_add(hci_dev);
232 + if (ret)
233 + goto err_alloc;
234 +
235 + return hci_dev;
236 +
237 +err_alloc:
238 + platform_device_put(hci_dev);
239 + return ERR_PTR(ret);
240 +}
241 +
242 +static int __devinit bcma_hcd_probe(struct bcma_device *dev)
243 +{
244 + int err;
245 + u16 chipid_top;
246 + u32 ohci_addr;
247 + struct bcma_hcd_device *usb_dev;
248 + struct bcma_chipinfo *chipinfo;
249 +
250 + chipinfo = &dev->bus->chipinfo;
251 + /* USBcores are only connected on embedded devices. */
252 + chipid_top = (chipinfo->id & 0xFF00);
253 + if (chipid_top != 0x4700 && chipid_top != 0x5300)
254 + return -ENODEV;
255 +
256 + /* TODO: Probably need checks here; is the core connected? */
257 +
258 + if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
259 + dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
260 + return -EOPNOTSUPP;
261 +
262 + usb_dev = kzalloc(sizeof(struct bcma_hcd_device), GFP_KERNEL);
263 + if (!usb_dev)
264 + return -ENOMEM;
265 +
266 + bcma_hcd_init_chip(dev);
267 +
268 + /* In AI chips EHCI is addrspace 0, OHCI is 1 */
269 + ohci_addr = dev->addr1;
270 + if ((chipinfo->id == 0x5357 || chipinfo->id == 0x4749)
271 + && chipinfo->rev == 0)
272 + ohci_addr = 0x18009000;
273 +
274 + usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, true, ohci_addr);
275 + if (IS_ERR(usb_dev->ohci_dev)) {
276 + err = PTR_ERR(usb_dev->ohci_dev);
277 + goto err_free_usb_dev;
278 + }
279 +
280 + usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, false, dev->addr);
281 + if (IS_ERR(usb_dev->ehci_dev)) {
282 + err = PTR_ERR(usb_dev->ehci_dev);
283 + goto err_unregister_ohci_dev;
284 + }
285 +
286 + bcma_set_drvdata(dev, usb_dev);
287 + return 0;
288 +
289 +err_unregister_ohci_dev:
290 + platform_device_unregister(usb_dev->ohci_dev);
291 +err_free_usb_dev:
292 + kfree(usb_dev);
293 + return err;
294 +}
295 +
296 +static void __devexit bcma_hcd_remove(struct bcma_device *dev)
297 +{
298 + struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
299 + struct platform_device *ohci_dev = usb_dev->ohci_dev;
300 + struct platform_device *ehci_dev = usb_dev->ehci_dev;
301 +
302 + if (ohci_dev)
303 + platform_device_unregister(ohci_dev);
304 + if (ehci_dev)
305 + platform_device_unregister(ehci_dev);
306 +
307 + bcma_core_disable(dev, 0);
308 +}
309 +
310 +static void bcma_hcd_shutdown(struct bcma_device *dev)
311 +{
312 + bcma_core_disable(dev, 0);
313 +}
314 +
315 +#ifdef CONFIG_PM
316 +
317 +static int bcma_hcd_suspend(struct bcma_device *dev, pm_message_t state)
318 +{
319 + bcma_core_disable(dev, 0);
320 +
321 + return 0;
322 +}
323 +
324 +static int bcma_hcd_resume(struct bcma_device *dev)
325 +{
326 + bcma_core_enable(dev, 0);
327 +
328 + return 0;
329 +}
330 +
331 +#else /* !CONFIG_PM */
332 +#define bcma_hcd_suspend NULL
333 +#define bcma_hcd_resume NULL
334 +#endif /* CONFIG_PM */
335 +
336 +static const struct bcma_device_id bcma_hcd_table[] __devinitconst = {
337 + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS),
338 + BCMA_CORETABLE_END
339 +};
340 +MODULE_DEVICE_TABLE(bcma, bcma_hcd_table);
341 +
342 +static struct bcma_driver bcma_hcd_driver = {
343 + .name = KBUILD_MODNAME,
344 + .id_table = bcma_hcd_table,
345 + .probe = bcma_hcd_probe,
346 + .remove = __devexit_p(bcma_hcd_remove),
347 + .shutdown = bcma_hcd_shutdown,
348 + .suspend = bcma_hcd_suspend,
349 + .resume = bcma_hcd_resume,
350 +};
351 +
352 +static int __init bcma_hcd_init(void)
353 +{
354 + return bcma_driver_register(&bcma_hcd_driver);
355 +}
356 +module_init(bcma_hcd_init);
357 +
358 +static void __exit bcma_hcd_exit(void)
359 +{
360 + bcma_driver_unregister(&bcma_hcd_driver);
361 +}
362 +module_exit(bcma_hcd_exit);