1 --- a/drivers/usb/host/Kconfig
2 +++ b/drivers/usb/host/Kconfig
3 @@ -618,3 +618,15 @@ config USB_PXA168_EHCI
5 Enable support for Marvell PXA168 SoC's on-chip EHCI
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
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
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
27 +++ b/drivers/usb/host/bcma-hcd.c
30 + * Broadcom specific Advanced Microcontroller Bus
31 + * Broadcom USB-core driver (BCMA bus glue)
33 + * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
35 + * Based on ssb-ohci driver
36 + * Copyright 2007 Michael Buesch <m@bues.ch>
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
44 + * Derived from the USBcore related parts of Broadcom-SB
45 + * Copyright 2005-2011 Broadcom Corporation
47 + * Licensed under the GNU/GPL. See COPYING for details.
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>
56 +MODULE_AUTHOR("Hauke Mehrtens");
57 +MODULE_DESCRIPTION("Common USB driver for BCMA Bus");
58 +MODULE_LICENSE("GPL");
60 +struct bcma_hcd_device {
61 + struct platform_device *ehci_dev;
62 + struct platform_device *ohci_dev;
65 +/* Wait for bitmask in a register to get set or cleared.
66 + * timeout is in units of ten-microseconds.
68 +static int bcma_wait_bits(struct bcma_device *dev, u16 reg, u32 bitmask,
74 + for (i = 0; i < timeout; i++) {
75 + val = bcma_read32(dev, reg);
76 + if ((val & bitmask) == bitmask)
84 +static void __devinit bcma_hcd_4716wa(struct bcma_device *dev)
86 +#ifdef CONFIG_BCMA_DRIVER_MIPS
87 + /* Work around for 4716 failures. */
88 + if (dev->bus->chipinfo.id == 0x4716) {
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) */
99 + /* Change Shim mdio control reg to fix host not acking at
103 + bcma_write32(dev, 0x524, 0x1); /* write sel to enable */
106 + bcma_write32(dev, 0x524, tmp);
108 + bcma_write32(dev, 0x524, 0x4ab);
110 + bcma_read32(dev, 0x528);
111 + bcma_write32(dev, 0x528, 0x80000000);
114 +#endif /* CONFIG_BCMA_DRIVER_MIPS */
117 +/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */
118 +static void __devinit bcma_hcd_init_chip(struct bcma_device *dev)
123 + * USB 2.0 special considerations:
125 + * 1. Since the core supports both OHCI and EHCI functions, it must
126 + * only be reset once.
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.
132 + if (!bcma_core_is_enabled(dev)) {
133 + bcma_core_enable(dev, 0);
135 + if (dev->id.rev >= 5) {
136 + /* Enable Misc PLL */
137 + tmp = bcma_read32(dev, 0x1e0);
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");
143 + /* Take out of resets */
144 + bcma_write32(dev, 0x200, 0x4ff);
146 + bcma_write32(dev, 0x200, 0x6ff);
149 + /* Make sure digital and AFE are locked in USB PHY */
150 + bcma_write32(dev, 0x524, 0x6b);
152 + tmp = bcma_read32(dev, 0x524);
154 + bcma_write32(dev, 0x524, 0xab);
156 + tmp = bcma_read32(dev, 0x524);
158 + bcma_write32(dev, 0x524, 0x2b);
160 + tmp = bcma_read32(dev, 0x524);
162 + bcma_write32(dev, 0x524, 0x10ab);
164 + tmp = bcma_read32(dev, 0x524);
166 + if (bcma_wait_bits(dev, 0x528, 0xc000, 10000)) {
167 + tmp = bcma_read32(dev, 0x528);
169 + "USB20H mdio_rddata 0x%08x\n", tmp);
171 + bcma_write32(dev, 0x528, 0x80000000);
172 + tmp = bcma_read32(dev, 0x314);
174 + bcma_write32(dev, 0x200, 0x7ff);
177 + /* Take USB and HSIC out of non-driving modes */
178 + bcma_write32(dev, 0x510, 0);
180 + bcma_write32(dev, 0x200, 0x7ff);
185 + bcma_hcd_4716wa(dev);
189 +static const struct usb_ehci_pdata ehci_pdata = {
192 +static const struct usb_ohci_pdata ohci_pdata = {
195 +static struct platform_device * __devinit
196 +bcma_hcd_create_pdev(struct bcma_device *dev, bool ohci, u32 addr)
198 + struct platform_device *hci_dev;
199 + struct resource hci_res[2];
202 + memset(hci_res, 0, sizeof(hci_res));
204 + hci_res[0].start = addr;
205 + hci_res[0].end = hci_res[0].start + 0x1000 - 1;
206 + hci_res[0].flags = IORESOURCE_MEM;
208 + hci_res[1].start = dev->irq;
209 + hci_res[1].flags = IORESOURCE_IRQ;
211 + hci_dev = platform_device_alloc(ohci ? "ohci-platform" :
212 + "ehci-platform" , 0);
216 + hci_dev->dev.parent = &dev->dev;
217 + hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
219 + ret = platform_device_add_resources(hci_dev, hci_res,
220 + ARRAY_SIZE(hci_res));
224 + ret = platform_device_add_data(hci_dev, &ohci_pdata,
225 + sizeof(ohci_pdata));
227 + ret = platform_device_add_data(hci_dev, &ehci_pdata,
228 + sizeof(ehci_pdata));
231 + ret = platform_device_add(hci_dev);
238 + platform_device_put(hci_dev);
239 + return ERR_PTR(ret);
242 +static int __devinit bcma_hcd_probe(struct bcma_device *dev)
247 + struct bcma_hcd_device *usb_dev;
248 + struct bcma_chipinfo *chipinfo;
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)
256 + /* TODO: Probably need checks here; is the core connected? */
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;
262 + usb_dev = kzalloc(sizeof(struct bcma_hcd_device), GFP_KERNEL);
266 + bcma_hcd_init_chip(dev);
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;
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;
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;
286 + bcma_set_drvdata(dev, usb_dev);
289 +err_unregister_ohci_dev:
290 + platform_device_unregister(usb_dev->ohci_dev);
296 +static void __devexit bcma_hcd_remove(struct bcma_device *dev)
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;
303 + platform_device_unregister(ohci_dev);
305 + platform_device_unregister(ehci_dev);
307 + bcma_core_disable(dev, 0);
310 +static void bcma_hcd_shutdown(struct bcma_device *dev)
312 + bcma_core_disable(dev, 0);
317 +static int bcma_hcd_suspend(struct bcma_device *dev, pm_message_t state)
319 + bcma_core_disable(dev, 0);
324 +static int bcma_hcd_resume(struct bcma_device *dev)
326 + bcma_core_enable(dev, 0);
331 +#else /* !CONFIG_PM */
332 +#define bcma_hcd_suspend NULL
333 +#define bcma_hcd_resume NULL
334 +#endif /* CONFIG_PM */
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),
340 +MODULE_DEVICE_TABLE(bcma, bcma_hcd_table);
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,
352 +static int __init bcma_hcd_init(void)
354 + return bcma_driver_register(&bcma_hcd_driver);
356 +module_init(bcma_hcd_init);
358 +static void __exit bcma_hcd_exit(void)
360 + bcma_driver_unregister(&bcma_hcd_driver);
362 +module_exit(bcma_hcd_exit);