xref: /openbmc/linux/drivers/usb/host/bcma-hcd.c (revision e7764e88)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
262e11d1bSHauke Mehrtens /*
362e11d1bSHauke Mehrtens  * Broadcom specific Advanced Microcontroller Bus
462e11d1bSHauke Mehrtens  * Broadcom USB-core driver (BCMA bus glue)
562e11d1bSHauke Mehrtens  *
610bc04b7SHauke Mehrtens  * Copyright 2011-2015 Hauke Mehrtens <hauke@hauke-m.de>
710bc04b7SHauke Mehrtens  * Copyright 2015 Felix Fietkau <nbd@openwrt.org>
862e11d1bSHauke Mehrtens  *
962e11d1bSHauke Mehrtens  * Based on ssb-ohci driver
1062e11d1bSHauke Mehrtens  * Copyright 2007 Michael Buesch <m@bues.ch>
1162e11d1bSHauke Mehrtens  *
1262e11d1bSHauke Mehrtens  * Derived from the OHCI-PCI driver
1362e11d1bSHauke Mehrtens  * Copyright 1999 Roman Weissgaerber
1462e11d1bSHauke Mehrtens  * Copyright 2000-2002 David Brownell
1562e11d1bSHauke Mehrtens  * Copyright 1999 Linus Torvalds
1662e11d1bSHauke Mehrtens  * Copyright 1999 Gregory P. Smith
1762e11d1bSHauke Mehrtens  *
1862e11d1bSHauke Mehrtens  * Derived from the USBcore related parts of Broadcom-SB
1962e11d1bSHauke Mehrtens  * Copyright 2005-2011 Broadcom Corporation
2062e11d1bSHauke Mehrtens  */
2162e11d1bSHauke Mehrtens #include <linux/bcma/bcma.h>
2262e11d1bSHauke Mehrtens #include <linux/delay.h>
239faae5a3SRafał Miłecki #include <linux/gpio/consumer.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>
293cc7e7b7SRafał Miłecki #include <linux/of_platform.h>
3062e11d1bSHauke Mehrtens #include <linux/usb/ehci_pdriver.h>
3162e11d1bSHauke Mehrtens #include <linux/usb/ohci_pdriver.h>
3262e11d1bSHauke Mehrtens 
3362e11d1bSHauke Mehrtens MODULE_AUTHOR("Hauke Mehrtens");
3462e11d1bSHauke Mehrtens MODULE_DESCRIPTION("Common USB driver for BCMA Bus");
3562e11d1bSHauke Mehrtens MODULE_LICENSE("GPL");
3662e11d1bSHauke Mehrtens 
37d6b76c4dSRafał Miłecki /* See BCMA_CLKCTLST_EXTRESREQ and BCMA_CLKCTLST_EXTRESST */
38d6b76c4dSRafał Miłecki #define USB_BCMA_CLKCTLST_USB_CLK_REQ			0x00000100
39d6b76c4dSRafał Miłecki 
4062e11d1bSHauke Mehrtens struct bcma_hcd_device {
41adbff3a4SRafał Miłecki 	struct bcma_device *core;
4262e11d1bSHauke Mehrtens 	struct platform_device *ehci_dev;
4362e11d1bSHauke Mehrtens 	struct platform_device *ohci_dev;
449faae5a3SRafał Miłecki 	struct gpio_desc *gpio_desc;
4562e11d1bSHauke Mehrtens };
4662e11d1bSHauke Mehrtens 
4762e11d1bSHauke Mehrtens /* Wait for bitmask in a register to get set or cleared.
4862e11d1bSHauke Mehrtens  * timeout is in units of ten-microseconds.
4962e11d1bSHauke Mehrtens  */
bcma_wait_bits(struct bcma_device * dev,u16 reg,u32 bitmask,int timeout)5062e11d1bSHauke Mehrtens static int bcma_wait_bits(struct bcma_device *dev, u16 reg, u32 bitmask,
5162e11d1bSHauke Mehrtens 			  int timeout)
5262e11d1bSHauke Mehrtens {
5362e11d1bSHauke Mehrtens 	int i;
5462e11d1bSHauke Mehrtens 	u32 val;
5562e11d1bSHauke Mehrtens 
5662e11d1bSHauke Mehrtens 	for (i = 0; i < timeout; i++) {
5762e11d1bSHauke Mehrtens 		val = bcma_read32(dev, reg);
5862e11d1bSHauke Mehrtens 		if ((val & bitmask) == bitmask)
5962e11d1bSHauke Mehrtens 			return 0;
6062e11d1bSHauke Mehrtens 		udelay(10);
6162e11d1bSHauke Mehrtens 	}
6262e11d1bSHauke Mehrtens 
6362e11d1bSHauke Mehrtens 	return -ETIMEDOUT;
6462e11d1bSHauke Mehrtens }
6562e11d1bSHauke Mehrtens 
bcma_hcd_4716wa(struct bcma_device * dev)6641ac7b3aSBill Pemberton static void bcma_hcd_4716wa(struct bcma_device *dev)
6762e11d1bSHauke Mehrtens {
6862e11d1bSHauke Mehrtens #ifdef CONFIG_BCMA_DRIVER_MIPS
6962e11d1bSHauke Mehrtens 	/* Work around for 4716 failures. */
7062e11d1bSHauke Mehrtens 	if (dev->bus->chipinfo.id == 0x4716) {
7162e11d1bSHauke Mehrtens 		u32 tmp;
7262e11d1bSHauke Mehrtens 
7362e11d1bSHauke Mehrtens 		tmp = bcma_cpu_clock(&dev->bus->drv_mips);
7462e11d1bSHauke Mehrtens 		if (tmp >= 480000000)
7562e11d1bSHauke Mehrtens 			tmp = 0x1846b; /* set CDR to 0x11(fast) */
7662e11d1bSHauke Mehrtens 		else if (tmp == 453000000)
7762e11d1bSHauke Mehrtens 			tmp = 0x1046b; /* set CDR to 0x10(slow) */
7862e11d1bSHauke Mehrtens 		else
7962e11d1bSHauke Mehrtens 			tmp = 0;
8062e11d1bSHauke Mehrtens 
8162e11d1bSHauke Mehrtens 		/* Change Shim mdio control reg to fix host not acking at
8262e11d1bSHauke Mehrtens 		 * high frequencies
8362e11d1bSHauke Mehrtens 		 */
8462e11d1bSHauke Mehrtens 		if (tmp) {
8562e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x524, 0x1); /* write sel to enable */
8662e11d1bSHauke Mehrtens 			udelay(500);
8762e11d1bSHauke Mehrtens 
8862e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x524, tmp);
8962e11d1bSHauke Mehrtens 			udelay(500);
9062e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x524, 0x4ab);
9162e11d1bSHauke Mehrtens 			udelay(500);
9262e11d1bSHauke Mehrtens 			bcma_read32(dev, 0x528);
9362e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x528, 0x80000000);
9462e11d1bSHauke Mehrtens 		}
9562e11d1bSHauke Mehrtens 	}
9662e11d1bSHauke Mehrtens #endif /* CONFIG_BCMA_DRIVER_MIPS */
9762e11d1bSHauke Mehrtens }
9862e11d1bSHauke Mehrtens 
9962e11d1bSHauke Mehrtens /* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */
bcma_hcd_init_chip_mips(struct bcma_device * dev)10010bc04b7SHauke Mehrtens static void bcma_hcd_init_chip_mips(struct bcma_device *dev)
10162e11d1bSHauke Mehrtens {
10262e11d1bSHauke Mehrtens 	u32 tmp;
10362e11d1bSHauke Mehrtens 
10462e11d1bSHauke Mehrtens 	/*
10562e11d1bSHauke Mehrtens 	 * USB 2.0 special considerations:
10662e11d1bSHauke Mehrtens 	 *
10762e11d1bSHauke Mehrtens 	 * 1. Since the core supports both OHCI and EHCI functions, it must
10862e11d1bSHauke Mehrtens 	 *    only be reset once.
10962e11d1bSHauke Mehrtens 	 *
11062e11d1bSHauke Mehrtens 	 * 2. In addition to the standard SI reset sequence, the Host Control
11162e11d1bSHauke Mehrtens 	 *    Register must be programmed to bring the USB core and various
11262e11d1bSHauke Mehrtens 	 *    phy components out of reset.
11362e11d1bSHauke Mehrtens 	 */
11462e11d1bSHauke Mehrtens 	if (!bcma_core_is_enabled(dev)) {
11562e11d1bSHauke Mehrtens 		bcma_core_enable(dev, 0);
11662e11d1bSHauke Mehrtens 		mdelay(10);
11762e11d1bSHauke Mehrtens 		if (dev->id.rev >= 5) {
11862e11d1bSHauke Mehrtens 			/* Enable Misc PLL */
11962e11d1bSHauke Mehrtens 			tmp = bcma_read32(dev, 0x1e0);
12062e11d1bSHauke Mehrtens 			tmp |= 0x100;
12162e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x1e0, tmp);
12262e11d1bSHauke Mehrtens 			if (bcma_wait_bits(dev, 0x1e0, 1 << 24, 100))
12362e11d1bSHauke Mehrtens 				printk(KERN_EMERG "Failed to enable misc PPL!\n");
12462e11d1bSHauke Mehrtens 
12562e11d1bSHauke Mehrtens 			/* Take out of resets */
12662e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x200, 0x4ff);
12762e11d1bSHauke Mehrtens 			udelay(25);
12862e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x200, 0x6ff);
12962e11d1bSHauke Mehrtens 			udelay(25);
13062e11d1bSHauke Mehrtens 
13162e11d1bSHauke Mehrtens 			/* Make sure digital and AFE are locked in USB PHY */
13262e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x524, 0x6b);
13362e11d1bSHauke Mehrtens 			udelay(50);
13462e11d1bSHauke Mehrtens 			tmp = bcma_read32(dev, 0x524);
13562e11d1bSHauke Mehrtens 			udelay(50);
13662e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x524, 0xab);
13762e11d1bSHauke Mehrtens 			udelay(50);
13862e11d1bSHauke Mehrtens 			tmp = bcma_read32(dev, 0x524);
13962e11d1bSHauke Mehrtens 			udelay(50);
14062e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x524, 0x2b);
14162e11d1bSHauke Mehrtens 			udelay(50);
14262e11d1bSHauke Mehrtens 			tmp = bcma_read32(dev, 0x524);
14362e11d1bSHauke Mehrtens 			udelay(50);
14462e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x524, 0x10ab);
14562e11d1bSHauke Mehrtens 			udelay(50);
14662e11d1bSHauke Mehrtens 			tmp = bcma_read32(dev, 0x524);
14762e11d1bSHauke Mehrtens 
14862e11d1bSHauke Mehrtens 			if (bcma_wait_bits(dev, 0x528, 0xc000, 10000)) {
14962e11d1bSHauke Mehrtens 				tmp = bcma_read32(dev, 0x528);
15062e11d1bSHauke Mehrtens 				printk(KERN_EMERG
15162e11d1bSHauke Mehrtens 				       "USB20H mdio_rddata 0x%08x\n", tmp);
15262e11d1bSHauke Mehrtens 			}
15362e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x528, 0x80000000);
15462e11d1bSHauke Mehrtens 			tmp = bcma_read32(dev, 0x314);
15562e11d1bSHauke Mehrtens 			udelay(265);
15662e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x200, 0x7ff);
15762e11d1bSHauke Mehrtens 			udelay(10);
15862e11d1bSHauke Mehrtens 
15962e11d1bSHauke Mehrtens 			/* Take USB and HSIC out of non-driving modes */
16062e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x510, 0);
16162e11d1bSHauke Mehrtens 		} else {
16262e11d1bSHauke Mehrtens 			bcma_write32(dev, 0x200, 0x7ff);
16362e11d1bSHauke Mehrtens 
16462e11d1bSHauke Mehrtens 			udelay(1);
16562e11d1bSHauke Mehrtens 		}
16662e11d1bSHauke Mehrtens 
16762e11d1bSHauke Mehrtens 		bcma_hcd_4716wa(dev);
16862e11d1bSHauke Mehrtens 	}
16962e11d1bSHauke Mehrtens }
17062e11d1bSHauke Mehrtens 
171edd93579SLee Jones /*
172d6b76c4dSRafał Miłecki  * bcma_hcd_usb20_old_arm_init - Initialize old USB 2.0 controller on ARM
173d6b76c4dSRafał Miłecki  *
174d6b76c4dSRafał Miłecki  * Old USB 2.0 core is identified as BCMA_CORE_USB20_HOST and was introduced
175d6b76c4dSRafał Miłecki  * long before Northstar devices. It seems some cheaper chipsets like BCM53573
176d6b76c4dSRafał Miłecki  * still use it.
177d6b76c4dSRafał Miłecki  * Initialization of this old core differs between MIPS and ARM.
178d6b76c4dSRafał Miłecki  */
bcma_hcd_usb20_old_arm_init(struct bcma_hcd_device * usb_dev)179d6b76c4dSRafał Miłecki static int bcma_hcd_usb20_old_arm_init(struct bcma_hcd_device *usb_dev)
180d6b76c4dSRafał Miłecki {
181d6b76c4dSRafał Miłecki 	struct bcma_device *core = usb_dev->core;
182d6b76c4dSRafał Miłecki 	struct device *dev = &core->dev;
183d6b76c4dSRafał Miłecki 	struct bcma_device *pmu_core;
184d6b76c4dSRafał Miłecki 
185d6b76c4dSRafał Miłecki 	usleep_range(10000, 20000);
186d6b76c4dSRafał Miłecki 	if (core->id.rev < 5)
187d6b76c4dSRafał Miłecki 		return 0;
188d6b76c4dSRafał Miłecki 
189d6b76c4dSRafał Miłecki 	pmu_core = bcma_find_core(core->bus, BCMA_CORE_PMU);
190d6b76c4dSRafał Miłecki 	if (!pmu_core) {
191d6b76c4dSRafał Miłecki 		dev_err(dev, "Could not find PMU core\n");
192d6b76c4dSRafał Miłecki 		return -ENOENT;
193d6b76c4dSRafał Miłecki 	}
194d6b76c4dSRafał Miłecki 
195d6b76c4dSRafał Miłecki 	/* Take USB core out of reset */
196d6b76c4dSRafał Miłecki 	bcma_awrite32(core, BCMA_IOCTL, BCMA_IOCTL_CLK | BCMA_IOCTL_FGC);
197d6b76c4dSRafał Miłecki 	usleep_range(100, 200);
198d6b76c4dSRafał Miłecki 	bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
199d6b76c4dSRafał Miłecki 	usleep_range(100, 200);
200d6b76c4dSRafał Miłecki 	bcma_awrite32(core, BCMA_RESET_CTL, 0);
201d6b76c4dSRafał Miłecki 	usleep_range(100, 200);
202d6b76c4dSRafał Miłecki 	bcma_awrite32(core, BCMA_IOCTL, BCMA_IOCTL_CLK);
203d6b76c4dSRafał Miłecki 	usleep_range(100, 200);
204d6b76c4dSRafał Miłecki 
205d6b76c4dSRafał Miłecki 	/* Enable Misc PLL */
206d6b76c4dSRafał Miłecki 	bcma_write32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT |
207d6b76c4dSRafał Miłecki 					  BCMA_CLKCTLST_HQCLKREQ |
208d6b76c4dSRafał Miłecki 					  USB_BCMA_CLKCTLST_USB_CLK_REQ);
209d6b76c4dSRafał Miłecki 	usleep_range(100, 200);
210d6b76c4dSRafał Miłecki 
211d6b76c4dSRafał Miłecki 	bcma_write32(core, 0x510, 0xc7f85000);
212d6b76c4dSRafał Miłecki 	bcma_write32(core, 0x510, 0xc7f85003);
213d6b76c4dSRafał Miłecki 	usleep_range(300, 600);
214d6b76c4dSRafał Miłecki 
215d6b76c4dSRafał Miłecki 	/* Program USB PHY PLL parameters */
216d6b76c4dSRafał Miłecki 	bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_ADDR, 0x6);
217d6b76c4dSRafał Miłecki 	bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_DATA, 0x005360c1);
218d6b76c4dSRafał Miłecki 	usleep_range(100, 200);
219d6b76c4dSRafał Miłecki 	bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_ADDR, 0x7);
220d6b76c4dSRafał Miłecki 	bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_DATA, 0x0);
221d6b76c4dSRafał Miłecki 	usleep_range(100, 200);
222d6b76c4dSRafał Miłecki 	bcma_set32(pmu_core, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
223d6b76c4dSRafał Miłecki 	usleep_range(100, 200);
224d6b76c4dSRafał Miłecki 
225d6b76c4dSRafał Miłecki 	bcma_write32(core, 0x510, 0x7f8d007);
226d6b76c4dSRafał Miłecki 	udelay(1000);
227d6b76c4dSRafał Miłecki 
228d6b76c4dSRafał Miłecki 	/* Take controller out of reset */
229d6b76c4dSRafał Miłecki 	bcma_write32(core, 0x200, 0x4ff);
230d6b76c4dSRafał Miłecki 	usleep_range(25, 50);
231d6b76c4dSRafał Miłecki 	bcma_write32(core, 0x200, 0x6ff);
232d6b76c4dSRafał Miłecki 	usleep_range(25, 50);
233d6b76c4dSRafał Miłecki 	bcma_write32(core, 0x200, 0x7ff);
234d6b76c4dSRafał Miłecki 	usleep_range(25, 50);
235d6b76c4dSRafał Miłecki 
236d6b76c4dSRafał Miłecki 	of_platform_default_populate(dev->of_node, NULL, dev);
237d6b76c4dSRafał Miłecki 
238d6b76c4dSRafał Miłecki 	return 0;
239d6b76c4dSRafał Miłecki }
240d6b76c4dSRafał Miłecki 
bcma_hcd_usb20_ns_init_hc(struct bcma_device * dev)241e8624859SRafał Miłecki static void bcma_hcd_usb20_ns_init_hc(struct bcma_device *dev)
24210bc04b7SHauke Mehrtens {
24310bc04b7SHauke Mehrtens 	u32 val;
24410bc04b7SHauke Mehrtens 
24510bc04b7SHauke Mehrtens 	/* Set packet buffer OUT threshold */
24610bc04b7SHauke Mehrtens 	val = bcma_read32(dev, 0x94);
24710bc04b7SHauke Mehrtens 	val &= 0xffff;
24810bc04b7SHauke Mehrtens 	val |= 0x80 << 16;
24910bc04b7SHauke Mehrtens 	bcma_write32(dev, 0x94, val);
25010bc04b7SHauke Mehrtens 
25110bc04b7SHauke Mehrtens 	/* Enable break memory transfer */
25210bc04b7SHauke Mehrtens 	val = bcma_read32(dev, 0x9c);
25310bc04b7SHauke Mehrtens 	val |= 1;
25410bc04b7SHauke Mehrtens 	bcma_write32(dev, 0x9c, val);
255e8624859SRafał Miłecki 
256e8624859SRafał Miłecki 	/*
257e8624859SRafał Miłecki 	 * Broadcom initializes PHY and then waits to ensure HC is ready to be
258e8624859SRafał Miłecki 	 * configured. In our case the order is reversed. We just initialized
259e8624859SRafał Miłecki 	 * controller and we let HCD initialize PHY, so let's wait (sleep) now.
260e8624859SRafał Miłecki 	 */
261e8624859SRafał Miłecki 	usleep_range(1000, 2000);
26210bc04b7SHauke Mehrtens }
26310bc04b7SHauke Mehrtens 
264edd93579SLee Jones /*
265e8624859SRafał Miłecki  * bcma_hcd_usb20_ns_init - Initialize Northstar USB 2.0 controller
266e8624859SRafał Miłecki  */
bcma_hcd_usb20_ns_init(struct bcma_hcd_device * bcma_hcd)267e8624859SRafał Miłecki static int bcma_hcd_usb20_ns_init(struct bcma_hcd_device *bcma_hcd)
26810bc04b7SHauke Mehrtens {
269e8624859SRafał Miłecki 	struct bcma_device *core = bcma_hcd->core;
270e8624859SRafał Miłecki 	struct bcma_chipinfo *ci = &core->bus->chipinfo;
271e8624859SRafał Miłecki 	struct device *dev = &core->dev;
27210bc04b7SHauke Mehrtens 
273e8624859SRafał Miłecki 	bcma_core_enable(core, 0);
27410bc04b7SHauke Mehrtens 
275e8624859SRafał Miłecki 	if (ci->id == BCMA_CHIP_ID_BCM4707 ||
276e8624859SRafał Miłecki 	    ci->id == BCMA_CHIP_ID_BCM53018)
277e8624859SRafał Miłecki 		bcma_hcd_usb20_ns_init_hc(core);
278e8624859SRafał Miłecki 
279e8624859SRafał Miłecki 	of_platform_default_populate(dev->of_node, NULL, dev);
280e8624859SRafał Miłecki 
281e8624859SRafał Miłecki 	return 0;
28210bc04b7SHauke Mehrtens }
28310bc04b7SHauke Mehrtens 
bcma_hci_platform_power_gpio(struct bcma_device * dev,bool val)284eb4861c3SHauke Mehrtens static void bcma_hci_platform_power_gpio(struct bcma_device *dev, bool val)
285eb4861c3SHauke Mehrtens {
2869faae5a3SRafał Miłecki 	struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
287eb4861c3SHauke Mehrtens 
288e7764e88SLinus Walleij 	if (!usb_dev->gpio_desc)
289eb4861c3SHauke Mehrtens 		return;
290eb4861c3SHauke Mehrtens 
2919faae5a3SRafał Miłecki 	gpiod_set_value(usb_dev->gpio_desc, val);
292eb4861c3SHauke Mehrtens }
293eb4861c3SHauke Mehrtens 
29462e11d1bSHauke Mehrtens static const struct usb_ehci_pdata ehci_pdata = {
29562e11d1bSHauke Mehrtens };
29662e11d1bSHauke Mehrtens 
29762e11d1bSHauke Mehrtens static const struct usb_ohci_pdata ohci_pdata = {
29862e11d1bSHauke Mehrtens };
29962e11d1bSHauke Mehrtens 
bcma_hcd_create_pdev(struct bcma_device * dev,const char * name,u32 addr,const void * data,size_t size)300352d9e2eSRafał Miłecki static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev,
301352d9e2eSRafał Miłecki 						    const char *name, u32 addr,
302352d9e2eSRafał Miłecki 						    const void *data,
303352d9e2eSRafał Miłecki 						    size_t size)
30462e11d1bSHauke Mehrtens {
30562e11d1bSHauke Mehrtens 	struct platform_device *hci_dev;
30662e11d1bSHauke Mehrtens 	struct resource hci_res[2];
307ab2de579SHauke Mehrtens 	int ret;
30862e11d1bSHauke Mehrtens 
30962e11d1bSHauke Mehrtens 	memset(hci_res, 0, sizeof(hci_res));
31062e11d1bSHauke Mehrtens 
31162e11d1bSHauke Mehrtens 	hci_res[0].start = addr;
31262e11d1bSHauke Mehrtens 	hci_res[0].end = hci_res[0].start + 0x1000 - 1;
31362e11d1bSHauke Mehrtens 	hci_res[0].flags = IORESOURCE_MEM;
31462e11d1bSHauke Mehrtens 
31562e11d1bSHauke Mehrtens 	hci_res[1].start = dev->irq;
31662e11d1bSHauke Mehrtens 	hci_res[1].flags = IORESOURCE_IRQ;
31762e11d1bSHauke Mehrtens 
318352d9e2eSRafał Miłecki 	hci_dev = platform_device_alloc(name, 0);
31962e11d1bSHauke Mehrtens 	if (!hci_dev)
320ab2de579SHauke Mehrtens 		return ERR_PTR(-ENOMEM);
32162e11d1bSHauke Mehrtens 
32262e11d1bSHauke Mehrtens 	hci_dev->dev.parent = &dev->dev;
32362e11d1bSHauke Mehrtens 	hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
32462e11d1bSHauke Mehrtens 
32562e11d1bSHauke Mehrtens 	ret = platform_device_add_resources(hci_dev, hci_res,
32662e11d1bSHauke Mehrtens 					    ARRAY_SIZE(hci_res));
32762e11d1bSHauke Mehrtens 	if (ret)
32862e11d1bSHauke Mehrtens 		goto err_alloc;
329352d9e2eSRafał Miłecki 	if (data)
330352d9e2eSRafał Miłecki 		ret = platform_device_add_data(hci_dev, data, size);
33162e11d1bSHauke Mehrtens 	if (ret)
33262e11d1bSHauke Mehrtens 		goto err_alloc;
33362e11d1bSHauke Mehrtens 	ret = platform_device_add(hci_dev);
33462e11d1bSHauke Mehrtens 	if (ret)
33562e11d1bSHauke Mehrtens 		goto err_alloc;
33662e11d1bSHauke Mehrtens 
33762e11d1bSHauke Mehrtens 	return hci_dev;
33862e11d1bSHauke Mehrtens 
33962e11d1bSHauke Mehrtens err_alloc:
34062e11d1bSHauke Mehrtens 	platform_device_put(hci_dev);
34162e11d1bSHauke Mehrtens 	return ERR_PTR(ret);
34262e11d1bSHauke Mehrtens }
34362e11d1bSHauke Mehrtens 
bcma_hcd_usb20_init(struct bcma_hcd_device * usb_dev)344adbff3a4SRafał Miłecki static int bcma_hcd_usb20_init(struct bcma_hcd_device *usb_dev)
34562e11d1bSHauke Mehrtens {
346adbff3a4SRafał Miłecki 	struct bcma_device *dev = usb_dev->core;
347adbff3a4SRafał Miłecki 	struct bcma_chipinfo *chipinfo = &dev->bus->chipinfo;
34862e11d1bSHauke Mehrtens 	u32 ohci_addr;
349adbff3a4SRafał Miłecki 	int err;
35062e11d1bSHauke Mehrtens 
351d288059eSRussell King 	if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32)))
35262e11d1bSHauke Mehrtens 		return -EOPNOTSUPP;
35362e11d1bSHauke Mehrtens 
35410bc04b7SHauke Mehrtens 	bcma_hcd_init_chip_mips(dev);
35562e11d1bSHauke Mehrtens 
35662e11d1bSHauke Mehrtens 	/* In AI chips EHCI is addrspace 0, OHCI is 1 */
35723a2f39cSHauke Mehrtens 	ohci_addr = dev->addr_s[0];
35898e13e05SHauke Mehrtens 	if ((chipinfo->id == BCMA_CHIP_ID_BCM5357 ||
35998e13e05SHauke Mehrtens 	     chipinfo->id == BCMA_CHIP_ID_BCM4749)
36062e11d1bSHauke Mehrtens 	    && chipinfo->rev == 0)
36162e11d1bSHauke Mehrtens 		ohci_addr = 0x18009000;
36262e11d1bSHauke Mehrtens 
363352d9e2eSRafał Miłecki 	usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, "ohci-platform",
364352d9e2eSRafał Miłecki 						 ohci_addr, &ohci_pdata,
365352d9e2eSRafał Miłecki 						 sizeof(ohci_pdata));
366c27da2b2SHauke Mehrtens 	if (IS_ERR(usb_dev->ohci_dev))
367c27da2b2SHauke Mehrtens 		return PTR_ERR(usb_dev->ohci_dev);
36862e11d1bSHauke Mehrtens 
369352d9e2eSRafał Miłecki 	usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, "ehci-platform",
370352d9e2eSRafał Miłecki 						 dev->addr, &ehci_pdata,
371352d9e2eSRafał Miłecki 						 sizeof(ehci_pdata));
37262e11d1bSHauke Mehrtens 	if (IS_ERR(usb_dev->ehci_dev)) {
37362e11d1bSHauke Mehrtens 		err = PTR_ERR(usb_dev->ehci_dev);
37462e11d1bSHauke Mehrtens 		goto err_unregister_ohci_dev;
37562e11d1bSHauke Mehrtens 	}
37662e11d1bSHauke Mehrtens 
37762e11d1bSHauke Mehrtens 	return 0;
37862e11d1bSHauke Mehrtens 
37962e11d1bSHauke Mehrtens err_unregister_ohci_dev:
38062e11d1bSHauke Mehrtens 	platform_device_unregister(usb_dev->ohci_dev);
38162e11d1bSHauke Mehrtens 	return err;
38262e11d1bSHauke Mehrtens }
38362e11d1bSHauke Mehrtens 
bcma_hcd_usb30_init(struct bcma_hcd_device * bcma_hcd)3843cc7e7b7SRafał Miłecki static int bcma_hcd_usb30_init(struct bcma_hcd_device *bcma_hcd)
3853cc7e7b7SRafał Miłecki {
3863cc7e7b7SRafał Miłecki 	struct bcma_device *core = bcma_hcd->core;
3873cc7e7b7SRafał Miłecki 	struct device *dev = &core->dev;
3883cc7e7b7SRafał Miłecki 
3893cc7e7b7SRafał Miłecki 	bcma_core_enable(core, 0);
3903cc7e7b7SRafał Miłecki 
3913cc7e7b7SRafał Miłecki 	of_platform_default_populate(dev->of_node, NULL, dev);
3923cc7e7b7SRafał Miłecki 
3933cc7e7b7SRafał Miłecki 	return 0;
3943cc7e7b7SRafał Miłecki }
3953cc7e7b7SRafał Miłecki 
bcma_hcd_probe(struct bcma_device * core)396adbff3a4SRafał Miłecki static int bcma_hcd_probe(struct bcma_device *core)
397adbff3a4SRafał Miłecki {
398adbff3a4SRafał Miłecki 	int err;
399adbff3a4SRafał Miłecki 	struct bcma_hcd_device *usb_dev;
400adbff3a4SRafał Miłecki 
401adbff3a4SRafał Miłecki 	/* TODO: Probably need checks here; is the core connected? */
402adbff3a4SRafał Miłecki 
403adbff3a4SRafał Miłecki 	usb_dev = devm_kzalloc(&core->dev, sizeof(struct bcma_hcd_device),
404adbff3a4SRafał Miłecki 			       GFP_KERNEL);
405adbff3a4SRafał Miłecki 	if (!usb_dev)
406adbff3a4SRafał Miłecki 		return -ENOMEM;
407adbff3a4SRafał Miłecki 	usb_dev->core = core;
408adbff3a4SRafał Miłecki 
409e7764e88SLinus Walleij 	usb_dev->gpio_desc = devm_gpiod_get_optional(&core->dev, "vcc",
4101507372bSRafał Miłecki 						     GPIOD_OUT_HIGH);
411e7764e88SLinus Walleij 	if (IS_ERR(usb_dev->gpio_desc))
412e7764e88SLinus Walleij 		return dev_err_probe(&core->dev, PTR_ERR(usb_dev->gpio_desc),
413e7764e88SLinus Walleij 				     "error obtaining VCC GPIO");
414adbff3a4SRafał Miłecki 
415adbff3a4SRafał Miłecki 	switch (core->id.id) {
416adbff3a4SRafał Miłecki 	case BCMA_CORE_USB20_HOST:
417d6b76c4dSRafał Miłecki 		if (IS_ENABLED(CONFIG_ARM))
418d6b76c4dSRafał Miłecki 			err = bcma_hcd_usb20_old_arm_init(usb_dev);
419d6b76c4dSRafał Miłecki 		else if (IS_ENABLED(CONFIG_MIPS))
420d6b76c4dSRafał Miłecki 			err = bcma_hcd_usb20_init(usb_dev);
421d6b76c4dSRafał Miłecki 		else
422d6b76c4dSRafał Miłecki 			err = -ENOTSUPP;
423d6b76c4dSRafał Miłecki 		break;
424adbff3a4SRafał Miłecki 	case BCMA_CORE_NS_USB20:
425e8624859SRafał Miłecki 		err = bcma_hcd_usb20_ns_init(usb_dev);
426adbff3a4SRafał Miłecki 		break;
4273cc7e7b7SRafał Miłecki 	case BCMA_CORE_NS_USB30:
4283cc7e7b7SRafał Miłecki 		err = bcma_hcd_usb30_init(usb_dev);
4293cc7e7b7SRafał Miłecki 		break;
430adbff3a4SRafał Miłecki 	default:
431adbff3a4SRafał Miłecki 		return -ENODEV;
432adbff3a4SRafał Miłecki 	}
433d6b76c4dSRafał Miłecki 	if (err)
434d6b76c4dSRafał Miłecki 		return err;
435adbff3a4SRafał Miłecki 
436adbff3a4SRafał Miłecki 	bcma_set_drvdata(core, usb_dev);
437adbff3a4SRafał Miłecki 	return 0;
438adbff3a4SRafał Miłecki }
439adbff3a4SRafał Miłecki 
bcma_hcd_remove(struct bcma_device * dev)440fb4e98abSBill Pemberton static void bcma_hcd_remove(struct bcma_device *dev)
44162e11d1bSHauke Mehrtens {
44262e11d1bSHauke Mehrtens 	struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
44362e11d1bSHauke Mehrtens 	struct platform_device *ohci_dev = usb_dev->ohci_dev;
44462e11d1bSHauke Mehrtens 	struct platform_device *ehci_dev = usb_dev->ehci_dev;
44562e11d1bSHauke Mehrtens 
44662e11d1bSHauke Mehrtens 	if (ohci_dev)
44762e11d1bSHauke Mehrtens 		platform_device_unregister(ohci_dev);
44862e11d1bSHauke Mehrtens 	if (ehci_dev)
44962e11d1bSHauke Mehrtens 		platform_device_unregister(ehci_dev);
45062e11d1bSHauke Mehrtens 
45162e11d1bSHauke Mehrtens 	bcma_core_disable(dev, 0);
45262e11d1bSHauke Mehrtens }
45362e11d1bSHauke Mehrtens 
bcma_hcd_shutdown(struct bcma_device * dev)45462e11d1bSHauke Mehrtens static void bcma_hcd_shutdown(struct bcma_device *dev)
45562e11d1bSHauke Mehrtens {
456eb4861c3SHauke Mehrtens 	bcma_hci_platform_power_gpio(dev, false);
45762e11d1bSHauke Mehrtens 	bcma_core_disable(dev, 0);
45862e11d1bSHauke Mehrtens }
45962e11d1bSHauke Mehrtens 
46062e11d1bSHauke Mehrtens #ifdef CONFIG_PM
46162e11d1bSHauke Mehrtens 
bcma_hcd_suspend(struct bcma_device * dev)4621f6155f5SDan Carpenter static int bcma_hcd_suspend(struct bcma_device *dev)
46362e11d1bSHauke Mehrtens {
464eb4861c3SHauke Mehrtens 	bcma_hci_platform_power_gpio(dev, false);
46562e11d1bSHauke Mehrtens 	bcma_core_disable(dev, 0);
46662e11d1bSHauke Mehrtens 
46762e11d1bSHauke Mehrtens 	return 0;
46862e11d1bSHauke Mehrtens }
46962e11d1bSHauke Mehrtens 
bcma_hcd_resume(struct bcma_device * dev)47062e11d1bSHauke Mehrtens static int bcma_hcd_resume(struct bcma_device *dev)
47162e11d1bSHauke Mehrtens {
472eb4861c3SHauke Mehrtens 	bcma_hci_platform_power_gpio(dev, true);
47362e11d1bSHauke Mehrtens 	bcma_core_enable(dev, 0);
47462e11d1bSHauke Mehrtens 
47562e11d1bSHauke Mehrtens 	return 0;
47662e11d1bSHauke Mehrtens }
47762e11d1bSHauke Mehrtens 
47862e11d1bSHauke Mehrtens #else /* !CONFIG_PM */
47962e11d1bSHauke Mehrtens #define bcma_hcd_suspend	NULL
48062e11d1bSHauke Mehrtens #define bcma_hcd_resume	NULL
48162e11d1bSHauke Mehrtens #endif /* CONFIG_PM */
48262e11d1bSHauke Mehrtens 
4832f82686eSBill Pemberton static const struct bcma_device_id bcma_hcd_table[] = {
48462e11d1bSHauke Mehrtens 	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS),
48510bc04b7SHauke Mehrtens 	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB20, BCMA_ANY_REV, BCMA_ANY_CLASS),
4863cc7e7b7SRafał Miłecki 	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB30, BCMA_ANY_REV, BCMA_ANY_CLASS),
487f7219b52SJoe Perches 	{},
48862e11d1bSHauke Mehrtens };
48962e11d1bSHauke Mehrtens MODULE_DEVICE_TABLE(bcma, bcma_hcd_table);
49062e11d1bSHauke Mehrtens 
49162e11d1bSHauke Mehrtens static struct bcma_driver bcma_hcd_driver = {
49262e11d1bSHauke Mehrtens 	.name		= KBUILD_MODNAME,
49362e11d1bSHauke Mehrtens 	.id_table	= bcma_hcd_table,
49462e11d1bSHauke Mehrtens 	.probe		= bcma_hcd_probe,
4957690417dSBill Pemberton 	.remove		= bcma_hcd_remove,
49662e11d1bSHauke Mehrtens 	.shutdown	= bcma_hcd_shutdown,
49762e11d1bSHauke Mehrtens 	.suspend	= bcma_hcd_suspend,
49862e11d1bSHauke Mehrtens 	.resume		= bcma_hcd_resume,
49962e11d1bSHauke Mehrtens };
50008956609SLiu Shixin module_bcma_driver(bcma_hcd_driver);
501