xref: /openbmc/linux/drivers/usb/host/bcma-hcd.c (revision eb4861c3)
162e11d1bSHauke Mehrtens /*
262e11d1bSHauke Mehrtens  * Broadcom specific Advanced Microcontroller Bus
362e11d1bSHauke Mehrtens  * Broadcom USB-core driver (BCMA bus glue)
462e11d1bSHauke Mehrtens  *
510bc04b7SHauke Mehrtens  * Copyright 2011-2015 Hauke Mehrtens <hauke@hauke-m.de>
610bc04b7SHauke Mehrtens  * Copyright 2015 Felix Fietkau <nbd@openwrt.org>
762e11d1bSHauke Mehrtens  *
862e11d1bSHauke Mehrtens  * Based on ssb-ohci driver
962e11d1bSHauke Mehrtens  * Copyright 2007 Michael Buesch <m@bues.ch>
1062e11d1bSHauke Mehrtens  *
1162e11d1bSHauke Mehrtens  * Derived from the OHCI-PCI driver
1262e11d1bSHauke Mehrtens  * Copyright 1999 Roman Weissgaerber
1362e11d1bSHauke Mehrtens  * Copyright 2000-2002 David Brownell
1462e11d1bSHauke Mehrtens  * Copyright 1999 Linus Torvalds
1562e11d1bSHauke Mehrtens  * Copyright 1999 Gregory P. Smith
1662e11d1bSHauke Mehrtens  *
1762e11d1bSHauke Mehrtens  * Derived from the USBcore related parts of Broadcom-SB
1862e11d1bSHauke Mehrtens  * Copyright 2005-2011 Broadcom Corporation
1962e11d1bSHauke Mehrtens  *
2062e11d1bSHauke Mehrtens  * Licensed under the GNU/GPL. See COPYING for details.
2162e11d1bSHauke Mehrtens  */
2262e11d1bSHauke Mehrtens #include <linux/bcma/bcma.h>
2362e11d1bSHauke Mehrtens #include <linux/delay.h>
2462e11d1bSHauke Mehrtens #include <linux/platform_device.h>
2562e11d1bSHauke Mehrtens #include <linux/module.h>
266ba0d809SGeert Uytterhoeven #include <linux/slab.h>
27eb4861c3SHauke Mehrtens #include <linux/of.h>
28eb4861c3SHauke Mehrtens #include <linux/of_gpio.h>
2962e11d1bSHauke Mehrtens #include <linux/usb/ehci_pdriver.h>
3062e11d1bSHauke Mehrtens #include <linux/usb/ohci_pdriver.h>
3162e11d1bSHauke Mehrtens 
3262e11d1bSHauke Mehrtens MODULE_AUTHOR("Hauke Mehrtens");
3362e11d1bSHauke Mehrtens MODULE_DESCRIPTION("Common USB driver for BCMA Bus");
3462e11d1bSHauke Mehrtens MODULE_LICENSE("GPL");
3562e11d1bSHauke Mehrtens 
3662e11d1bSHauke Mehrtens struct bcma_hcd_device {
3762e11d1bSHauke Mehrtens 	struct platform_device *ehci_dev;
3862e11d1bSHauke Mehrtens 	struct platform_device *ohci_dev;
3962e11d1bSHauke Mehrtens };
4062e11d1bSHauke Mehrtens 
4162e11d1bSHauke Mehrtens /* Wait for bitmask in a register to get set or cleared.
4262e11d1bSHauke Mehrtens  * timeout is in units of ten-microseconds.
4362e11d1bSHauke Mehrtens  */
4462e11d1bSHauke Mehrtens static int bcma_wait_bits(struct bcma_device *dev, u16 reg, u32 bitmask,
4562e11d1bSHauke Mehrtens 			  int timeout)
4662e11d1bSHauke Mehrtens {
4762e11d1bSHauke Mehrtens 	int i;
4862e11d1bSHauke Mehrtens 	u32 val;
4962e11d1bSHauke Mehrtens 
5062e11d1bSHauke Mehrtens 	for (i = 0; i < timeout; i++) {
5162e11d1bSHauke Mehrtens 		val = bcma_read32(dev, reg);
5262e11d1bSHauke Mehrtens 		if ((val & bitmask) == bitmask)
5362e11d1bSHauke Mehrtens 			return 0;
5462e11d1bSHauke Mehrtens 		udelay(10);
5562e11d1bSHauke Mehrtens 	}
5662e11d1bSHauke Mehrtens 
5762e11d1bSHauke Mehrtens 	return -ETIMEDOUT;
5862e11d1bSHauke Mehrtens }
5962e11d1bSHauke Mehrtens 
6041ac7b3aSBill Pemberton static void bcma_hcd_4716wa(struct bcma_device *dev)
6162e11d1bSHauke Mehrtens {
6262e11d1bSHauke Mehrtens #ifdef CONFIG_BCMA_DRIVER_MIPS
6362e11d1bSHauke Mehrtens 	/* Work around for 4716 failures. */
6462e11d1bSHauke Mehrtens 	if (dev->bus->chipinfo.id == 0x4716) {
6562e11d1bSHauke Mehrtens 		u32 tmp;
6662e11d1bSHauke Mehrtens 
6762e11d1bSHauke Mehrtens 		tmp = bcma_cpu_clock(&dev->bus->drv_mips);
6862e11d1bSHauke Mehrtens 		if (tmp >= 480000000)
6962e11d1bSHauke Mehrtens 			tmp = 0x1846b; /* set CDR to 0x11(fast) */
7062e11d1bSHauke Mehrtens 		else if (tmp == 453000000)
7162e11d1bSHauke Mehrtens 			tmp = 0x1046b; /* set CDR to 0x10(slow) */
7262e11d1bSHauke Mehrtens 		else
7362e11d1bSHauke Mehrtens 			tmp = 0;
7462e11d1bSHauke Mehrtens 
7562e11d1bSHauke Mehrtens 		/* Change Shim mdio control reg to fix host not acking at
7662e11d1bSHauke Mehrtens 		 * high frequencies
7762e11d1bSHauke Mehrtens 		 */
7862e11d1bSHauke Mehrtens 		if (tmp) {
7962e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x524, 0x1); /* write sel to enable */
8062e11d1bSHauke Mehrtens 			udelay(500);
8162e11d1bSHauke Mehrtens 
8262e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x524, tmp);
8362e11d1bSHauke Mehrtens 			udelay(500);
8462e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x524, 0x4ab);
8562e11d1bSHauke Mehrtens 			udelay(500);
8662e11d1bSHauke Mehrtens 			bcma_read32(dev, 0x528);
8762e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x528, 0x80000000);
8862e11d1bSHauke Mehrtens 		}
8962e11d1bSHauke Mehrtens 	}
9062e11d1bSHauke Mehrtens #endif /* CONFIG_BCMA_DRIVER_MIPS */
9162e11d1bSHauke Mehrtens }
9262e11d1bSHauke Mehrtens 
9362e11d1bSHauke Mehrtens /* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */
9410bc04b7SHauke Mehrtens static void bcma_hcd_init_chip_mips(struct bcma_device *dev)
9562e11d1bSHauke Mehrtens {
9662e11d1bSHauke Mehrtens 	u32 tmp;
9762e11d1bSHauke Mehrtens 
9862e11d1bSHauke Mehrtens 	/*
9962e11d1bSHauke Mehrtens 	 * USB 2.0 special considerations:
10062e11d1bSHauke Mehrtens 	 *
10162e11d1bSHauke Mehrtens 	 * 1. Since the core supports both OHCI and EHCI functions, it must
10262e11d1bSHauke Mehrtens 	 *    only be reset once.
10362e11d1bSHauke Mehrtens 	 *
10462e11d1bSHauke Mehrtens 	 * 2. In addition to the standard SI reset sequence, the Host Control
10562e11d1bSHauke Mehrtens 	 *    Register must be programmed to bring the USB core and various
10662e11d1bSHauke Mehrtens 	 *    phy components out of reset.
10762e11d1bSHauke Mehrtens 	 */
10862e11d1bSHauke Mehrtens 	if (!bcma_core_is_enabled(dev)) {
10962e11d1bSHauke Mehrtens 		bcma_core_enable(dev, 0);
11062e11d1bSHauke Mehrtens 		mdelay(10);
11162e11d1bSHauke Mehrtens 		if (dev->id.rev >= 5) {
11262e11d1bSHauke Mehrtens 			/* Enable Misc PLL */
11362e11d1bSHauke Mehrtens 			tmp = bcma_read32(dev, 0x1e0);
11462e11d1bSHauke Mehrtens 			tmp |= 0x100;
11562e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x1e0, tmp);
11662e11d1bSHauke Mehrtens 			if (bcma_wait_bits(dev, 0x1e0, 1 << 24, 100))
11762e11d1bSHauke Mehrtens 				printk(KERN_EMERG "Failed to enable misc PPL!\n");
11862e11d1bSHauke Mehrtens 
11962e11d1bSHauke Mehrtens 			/* Take out of resets */
12062e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x200, 0x4ff);
12162e11d1bSHauke Mehrtens 			udelay(25);
12262e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x200, 0x6ff);
12362e11d1bSHauke Mehrtens 			udelay(25);
12462e11d1bSHauke Mehrtens 
12562e11d1bSHauke Mehrtens 			/* Make sure digital and AFE are locked in USB PHY */
12662e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x524, 0x6b);
12762e11d1bSHauke Mehrtens 			udelay(50);
12862e11d1bSHauke Mehrtens 			tmp = bcma_read32(dev, 0x524);
12962e11d1bSHauke Mehrtens 			udelay(50);
13062e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x524, 0xab);
13162e11d1bSHauke Mehrtens 			udelay(50);
13262e11d1bSHauke Mehrtens 			tmp = bcma_read32(dev, 0x524);
13362e11d1bSHauke Mehrtens 			udelay(50);
13462e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x524, 0x2b);
13562e11d1bSHauke Mehrtens 			udelay(50);
13662e11d1bSHauke Mehrtens 			tmp = bcma_read32(dev, 0x524);
13762e11d1bSHauke Mehrtens 			udelay(50);
13862e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x524, 0x10ab);
13962e11d1bSHauke Mehrtens 			udelay(50);
14062e11d1bSHauke Mehrtens 			tmp = bcma_read32(dev, 0x524);
14162e11d1bSHauke Mehrtens 
14262e11d1bSHauke Mehrtens 			if (bcma_wait_bits(dev, 0x528, 0xc000, 10000)) {
14362e11d1bSHauke Mehrtens 				tmp = bcma_read32(dev, 0x528);
14462e11d1bSHauke Mehrtens 				printk(KERN_EMERG
14562e11d1bSHauke Mehrtens 				       "USB20H mdio_rddata 0x%08x\n", tmp);
14662e11d1bSHauke Mehrtens 			}
14762e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x528, 0x80000000);
14862e11d1bSHauke Mehrtens 			tmp = bcma_read32(dev, 0x314);
14962e11d1bSHauke Mehrtens 			udelay(265);
15062e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x200, 0x7ff);
15162e11d1bSHauke Mehrtens 			udelay(10);
15262e11d1bSHauke Mehrtens 
15362e11d1bSHauke Mehrtens 			/* Take USB and HSIC out of non-driving modes */
15462e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x510, 0);
15562e11d1bSHauke Mehrtens 		} else {
15662e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x200, 0x7ff);
15762e11d1bSHauke Mehrtens 
15862e11d1bSHauke Mehrtens 			udelay(1);
15962e11d1bSHauke Mehrtens 		}
16062e11d1bSHauke Mehrtens 
16162e11d1bSHauke Mehrtens 		bcma_hcd_4716wa(dev);
16262e11d1bSHauke Mehrtens 	}
16362e11d1bSHauke Mehrtens }
16462e11d1bSHauke Mehrtens 
16510bc04b7SHauke Mehrtens static void bcma_hcd_init_chip_arm_phy(struct bcma_device *dev)
16610bc04b7SHauke Mehrtens {
16710bc04b7SHauke Mehrtens 	struct bcma_device *arm_core;
16810bc04b7SHauke Mehrtens 	void __iomem *dmu;
16910bc04b7SHauke Mehrtens 
17010bc04b7SHauke Mehrtens 	arm_core = bcma_find_core(dev->bus, BCMA_CORE_ARMCA9);
17110bc04b7SHauke Mehrtens 	if (!arm_core) {
17210bc04b7SHauke Mehrtens 		dev_err(&dev->dev, "can not find ARM Cortex A9 ihost core\n");
17310bc04b7SHauke Mehrtens 		return;
17410bc04b7SHauke Mehrtens 	}
17510bc04b7SHauke Mehrtens 
17610bc04b7SHauke Mehrtens 	dmu = ioremap_nocache(arm_core->addr_s[0], 0x1000);
17710bc04b7SHauke Mehrtens 	if (!dmu) {
17810bc04b7SHauke Mehrtens 		dev_err(&dev->dev, "can not map ARM Cortex A9 ihost core\n");
17910bc04b7SHauke Mehrtens 		return;
18010bc04b7SHauke Mehrtens 	}
18110bc04b7SHauke Mehrtens 
18210bc04b7SHauke Mehrtens 	/* Unlock DMU PLL settings */
18310bc04b7SHauke Mehrtens 	iowrite32(0x0000ea68, dmu + 0x180);
18410bc04b7SHauke Mehrtens 
18510bc04b7SHauke Mehrtens 	/* Write USB 2.0 PLL control setting */
18610bc04b7SHauke Mehrtens 	iowrite32(0x00dd10c3, dmu + 0x164);
18710bc04b7SHauke Mehrtens 
18810bc04b7SHauke Mehrtens 	/* Lock DMU PLL settings */
18910bc04b7SHauke Mehrtens 	iowrite32(0x00000000, dmu + 0x180);
19010bc04b7SHauke Mehrtens 
19110bc04b7SHauke Mehrtens 	iounmap(dmu);
19210bc04b7SHauke Mehrtens }
19310bc04b7SHauke Mehrtens 
19410bc04b7SHauke Mehrtens static void bcma_hcd_init_chip_arm_hc(struct bcma_device *dev)
19510bc04b7SHauke Mehrtens {
19610bc04b7SHauke Mehrtens 	u32 val;
19710bc04b7SHauke Mehrtens 
19810bc04b7SHauke Mehrtens 	/*
19910bc04b7SHauke Mehrtens 	 * Delay after PHY initialized to ensure HC is ready to be configured
20010bc04b7SHauke Mehrtens 	 */
20110bc04b7SHauke Mehrtens 	usleep_range(1000, 2000);
20210bc04b7SHauke Mehrtens 
20310bc04b7SHauke Mehrtens 	/* Set packet buffer OUT threshold */
20410bc04b7SHauke Mehrtens 	val = bcma_read32(dev, 0x94);
20510bc04b7SHauke Mehrtens 	val &= 0xffff;
20610bc04b7SHauke Mehrtens 	val |= 0x80 << 16;
20710bc04b7SHauke Mehrtens 	bcma_write32(dev, 0x94, val);
20810bc04b7SHauke Mehrtens 
20910bc04b7SHauke Mehrtens 	/* Enable break memory transfer */
21010bc04b7SHauke Mehrtens 	val = bcma_read32(dev, 0x9c);
21110bc04b7SHauke Mehrtens 	val |= 1;
21210bc04b7SHauke Mehrtens 	bcma_write32(dev, 0x9c, val);
21310bc04b7SHauke Mehrtens }
21410bc04b7SHauke Mehrtens 
21510bc04b7SHauke Mehrtens static void bcma_hcd_init_chip_arm(struct bcma_device *dev)
21610bc04b7SHauke Mehrtens {
21710bc04b7SHauke Mehrtens 	bcma_core_enable(dev, 0);
21810bc04b7SHauke Mehrtens 
21910bc04b7SHauke Mehrtens 	if (dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM4707 ||
22010bc04b7SHauke Mehrtens 	    dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM53018) {
22110bc04b7SHauke Mehrtens 		if (dev->bus->chipinfo.pkg == BCMA_PKG_ID_BCM4707 ||
22210bc04b7SHauke Mehrtens 		    dev->bus->chipinfo.pkg == BCMA_PKG_ID_BCM4708)
22310bc04b7SHauke Mehrtens 			bcma_hcd_init_chip_arm_phy(dev);
22410bc04b7SHauke Mehrtens 
22510bc04b7SHauke Mehrtens 		bcma_hcd_init_chip_arm_hc(dev);
22610bc04b7SHauke Mehrtens 	}
22710bc04b7SHauke Mehrtens }
22810bc04b7SHauke Mehrtens 
229eb4861c3SHauke Mehrtens static void bcma_hci_platform_power_gpio(struct bcma_device *dev, bool val)
230eb4861c3SHauke Mehrtens {
231eb4861c3SHauke Mehrtens 	int gpio;
232eb4861c3SHauke Mehrtens 
233eb4861c3SHauke Mehrtens 	gpio = of_get_named_gpio(dev->dev.of_node, "vcc-gpio", 0);
234eb4861c3SHauke Mehrtens 	if (!gpio_is_valid(gpio))
235eb4861c3SHauke Mehrtens 		return;
236eb4861c3SHauke Mehrtens 
237eb4861c3SHauke Mehrtens 	if (val) {
238eb4861c3SHauke Mehrtens 		gpio_request(gpio, "bcma-hcd-gpio");
239eb4861c3SHauke Mehrtens 		gpio_set_value(gpio, 1);
240eb4861c3SHauke Mehrtens 	} else {
241eb4861c3SHauke Mehrtens 		gpio_set_value(gpio, 0);
242eb4861c3SHauke Mehrtens 		gpio_free(gpio);
243eb4861c3SHauke Mehrtens 	}
244eb4861c3SHauke Mehrtens }
245eb4861c3SHauke Mehrtens 
24662e11d1bSHauke Mehrtens static const struct usb_ehci_pdata ehci_pdata = {
24762e11d1bSHauke Mehrtens };
24862e11d1bSHauke Mehrtens 
24962e11d1bSHauke Mehrtens static const struct usb_ohci_pdata ohci_pdata = {
25062e11d1bSHauke Mehrtens };
25162e11d1bSHauke Mehrtens 
25241ac7b3aSBill Pemberton static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev, bool ohci, u32 addr)
25362e11d1bSHauke Mehrtens {
25462e11d1bSHauke Mehrtens 	struct platform_device *hci_dev;
25562e11d1bSHauke Mehrtens 	struct resource hci_res[2];
256ab2de579SHauke Mehrtens 	int ret;
25762e11d1bSHauke Mehrtens 
25862e11d1bSHauke Mehrtens 	memset(hci_res, 0, sizeof(hci_res));
25962e11d1bSHauke Mehrtens 
26062e11d1bSHauke Mehrtens 	hci_res[0].start = addr;
26162e11d1bSHauke Mehrtens 	hci_res[0].end = hci_res[0].start + 0x1000 - 1;
26262e11d1bSHauke Mehrtens 	hci_res[0].flags = IORESOURCE_MEM;
26362e11d1bSHauke Mehrtens 
26462e11d1bSHauke Mehrtens 	hci_res[1].start = dev->irq;
26562e11d1bSHauke Mehrtens 	hci_res[1].flags = IORESOURCE_IRQ;
26662e11d1bSHauke Mehrtens 
26762e11d1bSHauke Mehrtens 	hci_dev = platform_device_alloc(ohci ? "ohci-platform" :
26862e11d1bSHauke Mehrtens 					"ehci-platform" , 0);
26962e11d1bSHauke Mehrtens 	if (!hci_dev)
270ab2de579SHauke Mehrtens 		return ERR_PTR(-ENOMEM);
27162e11d1bSHauke Mehrtens 
27262e11d1bSHauke Mehrtens 	hci_dev->dev.parent = &dev->dev;
27362e11d1bSHauke Mehrtens 	hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
27462e11d1bSHauke Mehrtens 
27562e11d1bSHauke Mehrtens 	ret = platform_device_add_resources(hci_dev, hci_res,
27662e11d1bSHauke Mehrtens 					    ARRAY_SIZE(hci_res));
27762e11d1bSHauke Mehrtens 	if (ret)
27862e11d1bSHauke Mehrtens 		goto err_alloc;
27962e11d1bSHauke Mehrtens 	if (ohci)
28062e11d1bSHauke Mehrtens 		ret = platform_device_add_data(hci_dev, &ohci_pdata,
28162e11d1bSHauke Mehrtens 					       sizeof(ohci_pdata));
28262e11d1bSHauke Mehrtens 	else
28362e11d1bSHauke Mehrtens 		ret = platform_device_add_data(hci_dev, &ehci_pdata,
28462e11d1bSHauke Mehrtens 					       sizeof(ehci_pdata));
28562e11d1bSHauke Mehrtens 	if (ret)
28662e11d1bSHauke Mehrtens 		goto err_alloc;
28762e11d1bSHauke Mehrtens 	ret = platform_device_add(hci_dev);
28862e11d1bSHauke Mehrtens 	if (ret)
28962e11d1bSHauke Mehrtens 		goto err_alloc;
29062e11d1bSHauke Mehrtens 
29162e11d1bSHauke Mehrtens 	return hci_dev;
29262e11d1bSHauke Mehrtens 
29362e11d1bSHauke Mehrtens err_alloc:
29462e11d1bSHauke Mehrtens 	platform_device_put(hci_dev);
29562e11d1bSHauke Mehrtens 	return ERR_PTR(ret);
29662e11d1bSHauke Mehrtens }
29762e11d1bSHauke Mehrtens 
29841ac7b3aSBill Pemberton static int bcma_hcd_probe(struct bcma_device *dev)
29962e11d1bSHauke Mehrtens {
30062e11d1bSHauke Mehrtens 	int err;
30162e11d1bSHauke Mehrtens 	u32 ohci_addr;
30262e11d1bSHauke Mehrtens 	struct bcma_hcd_device *usb_dev;
30362e11d1bSHauke Mehrtens 	struct bcma_chipinfo *chipinfo;
30462e11d1bSHauke Mehrtens 
30562e11d1bSHauke Mehrtens 	chipinfo = &dev->bus->chipinfo;
30662e11d1bSHauke Mehrtens 
30762e11d1bSHauke Mehrtens 	/* TODO: Probably need checks here; is the core connected? */
30862e11d1bSHauke Mehrtens 
309d288059eSRussell King 	if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32)))
31062e11d1bSHauke Mehrtens 		return -EOPNOTSUPP;
31162e11d1bSHauke Mehrtens 
312c27da2b2SHauke Mehrtens 	usb_dev = devm_kzalloc(&dev->dev, sizeof(struct bcma_hcd_device),
313c27da2b2SHauke Mehrtens 			       GFP_KERNEL);
31462e11d1bSHauke Mehrtens 	if (!usb_dev)
31562e11d1bSHauke Mehrtens 		return -ENOMEM;
31662e11d1bSHauke Mehrtens 
317eb4861c3SHauke Mehrtens 	bcma_hci_platform_power_gpio(dev, true);
318eb4861c3SHauke Mehrtens 
31910bc04b7SHauke Mehrtens 	switch (dev->id.id) {
32010bc04b7SHauke Mehrtens 	case BCMA_CORE_NS_USB20:
32110bc04b7SHauke Mehrtens 		bcma_hcd_init_chip_arm(dev);
32210bc04b7SHauke Mehrtens 		break;
32310bc04b7SHauke Mehrtens 	case BCMA_CORE_USB20_HOST:
32410bc04b7SHauke Mehrtens 		bcma_hcd_init_chip_mips(dev);
32510bc04b7SHauke Mehrtens 		break;
32610bc04b7SHauke Mehrtens 	default:
32710bc04b7SHauke Mehrtens 		return -ENODEV;
32810bc04b7SHauke Mehrtens 	}
32962e11d1bSHauke Mehrtens 
33062e11d1bSHauke Mehrtens 	/* In AI chips EHCI is addrspace 0, OHCI is 1 */
33123a2f39cSHauke Mehrtens 	ohci_addr = dev->addr_s[0];
33298e13e05SHauke Mehrtens 	if ((chipinfo->id == BCMA_CHIP_ID_BCM5357 ||
33398e13e05SHauke Mehrtens 	     chipinfo->id == BCMA_CHIP_ID_BCM4749)
33462e11d1bSHauke Mehrtens 	    && chipinfo->rev == 0)
33562e11d1bSHauke Mehrtens 		ohci_addr = 0x18009000;
33662e11d1bSHauke Mehrtens 
33762e11d1bSHauke Mehrtens 	usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, true, ohci_addr);
338c27da2b2SHauke Mehrtens 	if (IS_ERR(usb_dev->ohci_dev))
339c27da2b2SHauke Mehrtens 		return PTR_ERR(usb_dev->ohci_dev);
34062e11d1bSHauke Mehrtens 
34162e11d1bSHauke Mehrtens 	usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, false, dev->addr);
34262e11d1bSHauke Mehrtens 	if (IS_ERR(usb_dev->ehci_dev)) {
34362e11d1bSHauke Mehrtens 		err = PTR_ERR(usb_dev->ehci_dev);
34462e11d1bSHauke Mehrtens 		goto err_unregister_ohci_dev;
34562e11d1bSHauke Mehrtens 	}
34662e11d1bSHauke Mehrtens 
34762e11d1bSHauke Mehrtens 	bcma_set_drvdata(dev, usb_dev);
34862e11d1bSHauke Mehrtens 	return 0;
34962e11d1bSHauke Mehrtens 
35062e11d1bSHauke Mehrtens err_unregister_ohci_dev:
35162e11d1bSHauke Mehrtens 	platform_device_unregister(usb_dev->ohci_dev);
35262e11d1bSHauke Mehrtens 	return err;
35362e11d1bSHauke Mehrtens }
35462e11d1bSHauke Mehrtens 
355fb4e98abSBill Pemberton static void bcma_hcd_remove(struct bcma_device *dev)
35662e11d1bSHauke Mehrtens {
35762e11d1bSHauke Mehrtens 	struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
35862e11d1bSHauke Mehrtens 	struct platform_device *ohci_dev = usb_dev->ohci_dev;
35962e11d1bSHauke Mehrtens 	struct platform_device *ehci_dev = usb_dev->ehci_dev;
36062e11d1bSHauke Mehrtens 
36162e11d1bSHauke Mehrtens 	if (ohci_dev)
36262e11d1bSHauke Mehrtens 		platform_device_unregister(ohci_dev);
36362e11d1bSHauke Mehrtens 	if (ehci_dev)
36462e11d1bSHauke Mehrtens 		platform_device_unregister(ehci_dev);
36562e11d1bSHauke Mehrtens 
36662e11d1bSHauke Mehrtens 	bcma_core_disable(dev, 0);
36762e11d1bSHauke Mehrtens }
36862e11d1bSHauke Mehrtens 
36962e11d1bSHauke Mehrtens static void bcma_hcd_shutdown(struct bcma_device *dev)
37062e11d1bSHauke Mehrtens {
371eb4861c3SHauke Mehrtens 	bcma_hci_platform_power_gpio(dev, false);
37262e11d1bSHauke Mehrtens 	bcma_core_disable(dev, 0);
37362e11d1bSHauke Mehrtens }
37462e11d1bSHauke Mehrtens 
37562e11d1bSHauke Mehrtens #ifdef CONFIG_PM
37662e11d1bSHauke Mehrtens 
3771f6155f5SDan Carpenter static int bcma_hcd_suspend(struct bcma_device *dev)
37862e11d1bSHauke Mehrtens {
379eb4861c3SHauke Mehrtens 	bcma_hci_platform_power_gpio(dev, false);
38062e11d1bSHauke Mehrtens 	bcma_core_disable(dev, 0);
38162e11d1bSHauke Mehrtens 
38262e11d1bSHauke Mehrtens 	return 0;
38362e11d1bSHauke Mehrtens }
38462e11d1bSHauke Mehrtens 
38562e11d1bSHauke Mehrtens static int bcma_hcd_resume(struct bcma_device *dev)
38662e11d1bSHauke Mehrtens {
387eb4861c3SHauke Mehrtens 	bcma_hci_platform_power_gpio(dev, true);
38862e11d1bSHauke Mehrtens 	bcma_core_enable(dev, 0);
38962e11d1bSHauke Mehrtens 
39062e11d1bSHauke Mehrtens 	return 0;
39162e11d1bSHauke Mehrtens }
39262e11d1bSHauke Mehrtens 
39362e11d1bSHauke Mehrtens #else /* !CONFIG_PM */
39462e11d1bSHauke Mehrtens #define bcma_hcd_suspend	NULL
39562e11d1bSHauke Mehrtens #define bcma_hcd_resume	NULL
39662e11d1bSHauke Mehrtens #endif /* CONFIG_PM */
39762e11d1bSHauke Mehrtens 
3982f82686eSBill Pemberton static const struct bcma_device_id bcma_hcd_table[] = {
39962e11d1bSHauke Mehrtens 	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS),
40010bc04b7SHauke Mehrtens 	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB20, BCMA_ANY_REV, BCMA_ANY_CLASS),
401f7219b52SJoe Perches 	{},
40262e11d1bSHauke Mehrtens };
40362e11d1bSHauke Mehrtens MODULE_DEVICE_TABLE(bcma, bcma_hcd_table);
40462e11d1bSHauke Mehrtens 
40562e11d1bSHauke Mehrtens static struct bcma_driver bcma_hcd_driver = {
40662e11d1bSHauke Mehrtens 	.name		= KBUILD_MODNAME,
40762e11d1bSHauke Mehrtens 	.id_table	= bcma_hcd_table,
40862e11d1bSHauke Mehrtens 	.probe		= bcma_hcd_probe,
4097690417dSBill Pemberton 	.remove		= bcma_hcd_remove,
41062e11d1bSHauke Mehrtens 	.shutdown	= bcma_hcd_shutdown,
41162e11d1bSHauke Mehrtens 	.suspend	= bcma_hcd_suspend,
41262e11d1bSHauke Mehrtens 	.resume		= bcma_hcd_resume,
41362e11d1bSHauke Mehrtens };
41462e11d1bSHauke Mehrtens 
41562e11d1bSHauke Mehrtens static int __init bcma_hcd_init(void)
41662e11d1bSHauke Mehrtens {
41762e11d1bSHauke Mehrtens 	return bcma_driver_register(&bcma_hcd_driver);
41862e11d1bSHauke Mehrtens }
41962e11d1bSHauke Mehrtens module_init(bcma_hcd_init);
42062e11d1bSHauke Mehrtens 
42162e11d1bSHauke Mehrtens static void __exit bcma_hcd_exit(void)
42262e11d1bSHauke Mehrtens {
42362e11d1bSHauke Mehrtens 	bcma_driver_unregister(&bcma_hcd_driver);
42462e11d1bSHauke Mehrtens }
42562e11d1bSHauke Mehrtens module_exit(bcma_hcd_exit);
426