162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Broadcom specific Advanced Microcontroller Bus 462306a36Sopenharmony_ci * Broadcom USB-core driver (BCMA bus glue) 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright 2011-2015 Hauke Mehrtens <hauke@hauke-m.de> 762306a36Sopenharmony_ci * Copyright 2015 Felix Fietkau <nbd@openwrt.org> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Based on ssb-ohci driver 1062306a36Sopenharmony_ci * Copyright 2007 Michael Buesch <m@bues.ch> 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Derived from the OHCI-PCI driver 1362306a36Sopenharmony_ci * Copyright 1999 Roman Weissgaerber 1462306a36Sopenharmony_ci * Copyright 2000-2002 David Brownell 1562306a36Sopenharmony_ci * Copyright 1999 Linus Torvalds 1662306a36Sopenharmony_ci * Copyright 1999 Gregory P. Smith 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Derived from the USBcore related parts of Broadcom-SB 1962306a36Sopenharmony_ci * Copyright 2005-2011 Broadcom Corporation 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_ci#include <linux/bcma/bcma.h> 2262306a36Sopenharmony_ci#include <linux/delay.h> 2362306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 2462306a36Sopenharmony_ci#include <linux/platform_device.h> 2562306a36Sopenharmony_ci#include <linux/module.h> 2662306a36Sopenharmony_ci#include <linux/slab.h> 2762306a36Sopenharmony_ci#include <linux/of.h> 2862306a36Sopenharmony_ci#include <linux/of_gpio.h> 2962306a36Sopenharmony_ci#include <linux/of_platform.h> 3062306a36Sopenharmony_ci#include <linux/usb/ehci_pdriver.h> 3162306a36Sopenharmony_ci#include <linux/usb/ohci_pdriver.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ciMODULE_AUTHOR("Hauke Mehrtens"); 3462306a36Sopenharmony_ciMODULE_DESCRIPTION("Common USB driver for BCMA Bus"); 3562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* See BCMA_CLKCTLST_EXTRESREQ and BCMA_CLKCTLST_EXTRESST */ 3862306a36Sopenharmony_ci#define USB_BCMA_CLKCTLST_USB_CLK_REQ 0x00000100 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistruct bcma_hcd_device { 4162306a36Sopenharmony_ci struct bcma_device *core; 4262306a36Sopenharmony_ci struct platform_device *ehci_dev; 4362306a36Sopenharmony_ci struct platform_device *ohci_dev; 4462306a36Sopenharmony_ci struct gpio_desc *gpio_desc; 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* Wait for bitmask in a register to get set or cleared. 4862306a36Sopenharmony_ci * timeout is in units of ten-microseconds. 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_cistatic int bcma_wait_bits(struct bcma_device *dev, u16 reg, u32 bitmask, 5162306a36Sopenharmony_ci int timeout) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci int i; 5462306a36Sopenharmony_ci u32 val; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci for (i = 0; i < timeout; i++) { 5762306a36Sopenharmony_ci val = bcma_read32(dev, reg); 5862306a36Sopenharmony_ci if ((val & bitmask) == bitmask) 5962306a36Sopenharmony_ci return 0; 6062306a36Sopenharmony_ci udelay(10); 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci return -ETIMEDOUT; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic void bcma_hcd_4716wa(struct bcma_device *dev) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci#ifdef CONFIG_BCMA_DRIVER_MIPS 6962306a36Sopenharmony_ci /* Work around for 4716 failures. */ 7062306a36Sopenharmony_ci if (dev->bus->chipinfo.id == 0x4716) { 7162306a36Sopenharmony_ci u32 tmp; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci tmp = bcma_cpu_clock(&dev->bus->drv_mips); 7462306a36Sopenharmony_ci if (tmp >= 480000000) 7562306a36Sopenharmony_ci tmp = 0x1846b; /* set CDR to 0x11(fast) */ 7662306a36Sopenharmony_ci else if (tmp == 453000000) 7762306a36Sopenharmony_ci tmp = 0x1046b; /* set CDR to 0x10(slow) */ 7862306a36Sopenharmony_ci else 7962306a36Sopenharmony_ci tmp = 0; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* Change Shim mdio control reg to fix host not acking at 8262306a36Sopenharmony_ci * high frequencies 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_ci if (tmp) { 8562306a36Sopenharmony_ci bcma_write32(dev, 0x524, 0x1); /* write sel to enable */ 8662306a36Sopenharmony_ci udelay(500); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci bcma_write32(dev, 0x524, tmp); 8962306a36Sopenharmony_ci udelay(500); 9062306a36Sopenharmony_ci bcma_write32(dev, 0x524, 0x4ab); 9162306a36Sopenharmony_ci udelay(500); 9262306a36Sopenharmony_ci bcma_read32(dev, 0x528); 9362306a36Sopenharmony_ci bcma_write32(dev, 0x528, 0x80000000); 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci#endif /* CONFIG_BCMA_DRIVER_MIPS */ 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */ 10062306a36Sopenharmony_cistatic void bcma_hcd_init_chip_mips(struct bcma_device *dev) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci u32 tmp; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci /* 10562306a36Sopenharmony_ci * USB 2.0 special considerations: 10662306a36Sopenharmony_ci * 10762306a36Sopenharmony_ci * 1. Since the core supports both OHCI and EHCI functions, it must 10862306a36Sopenharmony_ci * only be reset once. 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci * 2. In addition to the standard SI reset sequence, the Host Control 11162306a36Sopenharmony_ci * Register must be programmed to bring the USB core and various 11262306a36Sopenharmony_ci * phy components out of reset. 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_ci if (!bcma_core_is_enabled(dev)) { 11562306a36Sopenharmony_ci bcma_core_enable(dev, 0); 11662306a36Sopenharmony_ci mdelay(10); 11762306a36Sopenharmony_ci if (dev->id.rev >= 5) { 11862306a36Sopenharmony_ci /* Enable Misc PLL */ 11962306a36Sopenharmony_ci tmp = bcma_read32(dev, 0x1e0); 12062306a36Sopenharmony_ci tmp |= 0x100; 12162306a36Sopenharmony_ci bcma_write32(dev, 0x1e0, tmp); 12262306a36Sopenharmony_ci if (bcma_wait_bits(dev, 0x1e0, 1 << 24, 100)) 12362306a36Sopenharmony_ci printk(KERN_EMERG "Failed to enable misc PPL!\n"); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* Take out of resets */ 12662306a36Sopenharmony_ci bcma_write32(dev, 0x200, 0x4ff); 12762306a36Sopenharmony_ci udelay(25); 12862306a36Sopenharmony_ci bcma_write32(dev, 0x200, 0x6ff); 12962306a36Sopenharmony_ci udelay(25); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* Make sure digital and AFE are locked in USB PHY */ 13262306a36Sopenharmony_ci bcma_write32(dev, 0x524, 0x6b); 13362306a36Sopenharmony_ci udelay(50); 13462306a36Sopenharmony_ci tmp = bcma_read32(dev, 0x524); 13562306a36Sopenharmony_ci udelay(50); 13662306a36Sopenharmony_ci bcma_write32(dev, 0x524, 0xab); 13762306a36Sopenharmony_ci udelay(50); 13862306a36Sopenharmony_ci tmp = bcma_read32(dev, 0x524); 13962306a36Sopenharmony_ci udelay(50); 14062306a36Sopenharmony_ci bcma_write32(dev, 0x524, 0x2b); 14162306a36Sopenharmony_ci udelay(50); 14262306a36Sopenharmony_ci tmp = bcma_read32(dev, 0x524); 14362306a36Sopenharmony_ci udelay(50); 14462306a36Sopenharmony_ci bcma_write32(dev, 0x524, 0x10ab); 14562306a36Sopenharmony_ci udelay(50); 14662306a36Sopenharmony_ci tmp = bcma_read32(dev, 0x524); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (bcma_wait_bits(dev, 0x528, 0xc000, 10000)) { 14962306a36Sopenharmony_ci tmp = bcma_read32(dev, 0x528); 15062306a36Sopenharmony_ci printk(KERN_EMERG 15162306a36Sopenharmony_ci "USB20H mdio_rddata 0x%08x\n", tmp); 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci bcma_write32(dev, 0x528, 0x80000000); 15462306a36Sopenharmony_ci tmp = bcma_read32(dev, 0x314); 15562306a36Sopenharmony_ci udelay(265); 15662306a36Sopenharmony_ci bcma_write32(dev, 0x200, 0x7ff); 15762306a36Sopenharmony_ci udelay(10); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* Take USB and HSIC out of non-driving modes */ 16062306a36Sopenharmony_ci bcma_write32(dev, 0x510, 0); 16162306a36Sopenharmony_ci } else { 16262306a36Sopenharmony_ci bcma_write32(dev, 0x200, 0x7ff); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci udelay(1); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci bcma_hcd_4716wa(dev); 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/* 17262306a36Sopenharmony_ci * bcma_hcd_usb20_old_arm_init - Initialize old USB 2.0 controller on ARM 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci * Old USB 2.0 core is identified as BCMA_CORE_USB20_HOST and was introduced 17562306a36Sopenharmony_ci * long before Northstar devices. It seems some cheaper chipsets like BCM53573 17662306a36Sopenharmony_ci * still use it. 17762306a36Sopenharmony_ci * Initialization of this old core differs between MIPS and ARM. 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_cistatic int bcma_hcd_usb20_old_arm_init(struct bcma_hcd_device *usb_dev) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct bcma_device *core = usb_dev->core; 18262306a36Sopenharmony_ci struct device *dev = &core->dev; 18362306a36Sopenharmony_ci struct bcma_device *pmu_core; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci usleep_range(10000, 20000); 18662306a36Sopenharmony_ci if (core->id.rev < 5) 18762306a36Sopenharmony_ci return 0; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci pmu_core = bcma_find_core(core->bus, BCMA_CORE_PMU); 19062306a36Sopenharmony_ci if (!pmu_core) { 19162306a36Sopenharmony_ci dev_err(dev, "Could not find PMU core\n"); 19262306a36Sopenharmony_ci return -ENOENT; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* Take USB core out of reset */ 19662306a36Sopenharmony_ci bcma_awrite32(core, BCMA_IOCTL, BCMA_IOCTL_CLK | BCMA_IOCTL_FGC); 19762306a36Sopenharmony_ci usleep_range(100, 200); 19862306a36Sopenharmony_ci bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET); 19962306a36Sopenharmony_ci usleep_range(100, 200); 20062306a36Sopenharmony_ci bcma_awrite32(core, BCMA_RESET_CTL, 0); 20162306a36Sopenharmony_ci usleep_range(100, 200); 20262306a36Sopenharmony_ci bcma_awrite32(core, BCMA_IOCTL, BCMA_IOCTL_CLK); 20362306a36Sopenharmony_ci usleep_range(100, 200); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* Enable Misc PLL */ 20662306a36Sopenharmony_ci bcma_write32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT | 20762306a36Sopenharmony_ci BCMA_CLKCTLST_HQCLKREQ | 20862306a36Sopenharmony_ci USB_BCMA_CLKCTLST_USB_CLK_REQ); 20962306a36Sopenharmony_ci usleep_range(100, 200); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci bcma_write32(core, 0x510, 0xc7f85000); 21262306a36Sopenharmony_ci bcma_write32(core, 0x510, 0xc7f85003); 21362306a36Sopenharmony_ci usleep_range(300, 600); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* Program USB PHY PLL parameters */ 21662306a36Sopenharmony_ci bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_ADDR, 0x6); 21762306a36Sopenharmony_ci bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_DATA, 0x005360c1); 21862306a36Sopenharmony_ci usleep_range(100, 200); 21962306a36Sopenharmony_ci bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_ADDR, 0x7); 22062306a36Sopenharmony_ci bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_DATA, 0x0); 22162306a36Sopenharmony_ci usleep_range(100, 200); 22262306a36Sopenharmony_ci bcma_set32(pmu_core, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD); 22362306a36Sopenharmony_ci usleep_range(100, 200); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci bcma_write32(core, 0x510, 0x7f8d007); 22662306a36Sopenharmony_ci udelay(1000); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* Take controller out of reset */ 22962306a36Sopenharmony_ci bcma_write32(core, 0x200, 0x4ff); 23062306a36Sopenharmony_ci usleep_range(25, 50); 23162306a36Sopenharmony_ci bcma_write32(core, 0x200, 0x6ff); 23262306a36Sopenharmony_ci usleep_range(25, 50); 23362306a36Sopenharmony_ci bcma_write32(core, 0x200, 0x7ff); 23462306a36Sopenharmony_ci usleep_range(25, 50); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci of_platform_default_populate(dev->of_node, NULL, dev); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return 0; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic void bcma_hcd_usb20_ns_init_hc(struct bcma_device *dev) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci u32 val; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci /* Set packet buffer OUT threshold */ 24662306a36Sopenharmony_ci val = bcma_read32(dev, 0x94); 24762306a36Sopenharmony_ci val &= 0xffff; 24862306a36Sopenharmony_ci val |= 0x80 << 16; 24962306a36Sopenharmony_ci bcma_write32(dev, 0x94, val); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* Enable break memory transfer */ 25262306a36Sopenharmony_ci val = bcma_read32(dev, 0x9c); 25362306a36Sopenharmony_ci val |= 1; 25462306a36Sopenharmony_ci bcma_write32(dev, 0x9c, val); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* 25762306a36Sopenharmony_ci * Broadcom initializes PHY and then waits to ensure HC is ready to be 25862306a36Sopenharmony_ci * configured. In our case the order is reversed. We just initialized 25962306a36Sopenharmony_ci * controller and we let HCD initialize PHY, so let's wait (sleep) now. 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_ci usleep_range(1000, 2000); 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/* 26562306a36Sopenharmony_ci * bcma_hcd_usb20_ns_init - Initialize Northstar USB 2.0 controller 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_cistatic int bcma_hcd_usb20_ns_init(struct bcma_hcd_device *bcma_hcd) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci struct bcma_device *core = bcma_hcd->core; 27062306a36Sopenharmony_ci struct bcma_chipinfo *ci = &core->bus->chipinfo; 27162306a36Sopenharmony_ci struct device *dev = &core->dev; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci bcma_core_enable(core, 0); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (ci->id == BCMA_CHIP_ID_BCM4707 || 27662306a36Sopenharmony_ci ci->id == BCMA_CHIP_ID_BCM53018) 27762306a36Sopenharmony_ci bcma_hcd_usb20_ns_init_hc(core); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci of_platform_default_populate(dev->of_node, NULL, dev); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic void bcma_hci_platform_power_gpio(struct bcma_device *dev, bool val) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (!usb_dev->gpio_desc) 28962306a36Sopenharmony_ci return; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci gpiod_set_value(usb_dev->gpio_desc, val); 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic const struct usb_ehci_pdata ehci_pdata = { 29562306a36Sopenharmony_ci}; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic const struct usb_ohci_pdata ohci_pdata = { 29862306a36Sopenharmony_ci}; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev, 30162306a36Sopenharmony_ci const char *name, u32 addr, 30262306a36Sopenharmony_ci const void *data, 30362306a36Sopenharmony_ci size_t size) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct platform_device *hci_dev; 30662306a36Sopenharmony_ci struct resource hci_res[2]; 30762306a36Sopenharmony_ci int ret; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci memset(hci_res, 0, sizeof(hci_res)); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci hci_res[0].start = addr; 31262306a36Sopenharmony_ci hci_res[0].end = hci_res[0].start + 0x1000 - 1; 31362306a36Sopenharmony_ci hci_res[0].flags = IORESOURCE_MEM; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci hci_res[1].start = dev->irq; 31662306a36Sopenharmony_ci hci_res[1].flags = IORESOURCE_IRQ; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci hci_dev = platform_device_alloc(name, 0); 31962306a36Sopenharmony_ci if (!hci_dev) 32062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci hci_dev->dev.parent = &dev->dev; 32362306a36Sopenharmony_ci hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci ret = platform_device_add_resources(hci_dev, hci_res, 32662306a36Sopenharmony_ci ARRAY_SIZE(hci_res)); 32762306a36Sopenharmony_ci if (ret) 32862306a36Sopenharmony_ci goto err_alloc; 32962306a36Sopenharmony_ci if (data) 33062306a36Sopenharmony_ci ret = platform_device_add_data(hci_dev, data, size); 33162306a36Sopenharmony_ci if (ret) 33262306a36Sopenharmony_ci goto err_alloc; 33362306a36Sopenharmony_ci ret = platform_device_add(hci_dev); 33462306a36Sopenharmony_ci if (ret) 33562306a36Sopenharmony_ci goto err_alloc; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci return hci_dev; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cierr_alloc: 34062306a36Sopenharmony_ci platform_device_put(hci_dev); 34162306a36Sopenharmony_ci return ERR_PTR(ret); 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic int bcma_hcd_usb20_init(struct bcma_hcd_device *usb_dev) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci struct bcma_device *dev = usb_dev->core; 34762306a36Sopenharmony_ci struct bcma_chipinfo *chipinfo = &dev->bus->chipinfo; 34862306a36Sopenharmony_ci u32 ohci_addr; 34962306a36Sopenharmony_ci int err; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32))) 35262306a36Sopenharmony_ci return -EOPNOTSUPP; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci bcma_hcd_init_chip_mips(dev); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* In AI chips EHCI is addrspace 0, OHCI is 1 */ 35762306a36Sopenharmony_ci ohci_addr = dev->addr_s[0]; 35862306a36Sopenharmony_ci if ((chipinfo->id == BCMA_CHIP_ID_BCM5357 || 35962306a36Sopenharmony_ci chipinfo->id == BCMA_CHIP_ID_BCM4749) 36062306a36Sopenharmony_ci && chipinfo->rev == 0) 36162306a36Sopenharmony_ci ohci_addr = 0x18009000; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, "ohci-platform", 36462306a36Sopenharmony_ci ohci_addr, &ohci_pdata, 36562306a36Sopenharmony_ci sizeof(ohci_pdata)); 36662306a36Sopenharmony_ci if (IS_ERR(usb_dev->ohci_dev)) 36762306a36Sopenharmony_ci return PTR_ERR(usb_dev->ohci_dev); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, "ehci-platform", 37062306a36Sopenharmony_ci dev->addr, &ehci_pdata, 37162306a36Sopenharmony_ci sizeof(ehci_pdata)); 37262306a36Sopenharmony_ci if (IS_ERR(usb_dev->ehci_dev)) { 37362306a36Sopenharmony_ci err = PTR_ERR(usb_dev->ehci_dev); 37462306a36Sopenharmony_ci goto err_unregister_ohci_dev; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci return 0; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cierr_unregister_ohci_dev: 38062306a36Sopenharmony_ci platform_device_unregister(usb_dev->ohci_dev); 38162306a36Sopenharmony_ci return err; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic int bcma_hcd_usb30_init(struct bcma_hcd_device *bcma_hcd) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct bcma_device *core = bcma_hcd->core; 38762306a36Sopenharmony_ci struct device *dev = &core->dev; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci bcma_core_enable(core, 0); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci of_platform_default_populate(dev->of_node, NULL, dev); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return 0; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic int bcma_hcd_probe(struct bcma_device *core) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci int err; 39962306a36Sopenharmony_ci struct bcma_hcd_device *usb_dev; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* TODO: Probably need checks here; is the core connected? */ 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci usb_dev = devm_kzalloc(&core->dev, sizeof(struct bcma_hcd_device), 40462306a36Sopenharmony_ci GFP_KERNEL); 40562306a36Sopenharmony_ci if (!usb_dev) 40662306a36Sopenharmony_ci return -ENOMEM; 40762306a36Sopenharmony_ci usb_dev->core = core; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci usb_dev->gpio_desc = devm_gpiod_get_optional(&core->dev, "vcc", 41062306a36Sopenharmony_ci GPIOD_OUT_HIGH); 41162306a36Sopenharmony_ci if (IS_ERR(usb_dev->gpio_desc)) 41262306a36Sopenharmony_ci return dev_err_probe(&core->dev, PTR_ERR(usb_dev->gpio_desc), 41362306a36Sopenharmony_ci "error obtaining VCC GPIO"); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci switch (core->id.id) { 41662306a36Sopenharmony_ci case BCMA_CORE_USB20_HOST: 41762306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ARM)) 41862306a36Sopenharmony_ci err = bcma_hcd_usb20_old_arm_init(usb_dev); 41962306a36Sopenharmony_ci else if (IS_ENABLED(CONFIG_MIPS)) 42062306a36Sopenharmony_ci err = bcma_hcd_usb20_init(usb_dev); 42162306a36Sopenharmony_ci else 42262306a36Sopenharmony_ci err = -ENOTSUPP; 42362306a36Sopenharmony_ci break; 42462306a36Sopenharmony_ci case BCMA_CORE_NS_USB20: 42562306a36Sopenharmony_ci err = bcma_hcd_usb20_ns_init(usb_dev); 42662306a36Sopenharmony_ci break; 42762306a36Sopenharmony_ci case BCMA_CORE_NS_USB30: 42862306a36Sopenharmony_ci err = bcma_hcd_usb30_init(usb_dev); 42962306a36Sopenharmony_ci break; 43062306a36Sopenharmony_ci default: 43162306a36Sopenharmony_ci return -ENODEV; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci if (err) 43462306a36Sopenharmony_ci return err; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci bcma_set_drvdata(core, usb_dev); 43762306a36Sopenharmony_ci return 0; 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic void bcma_hcd_remove(struct bcma_device *dev) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev); 44362306a36Sopenharmony_ci struct platform_device *ohci_dev = usb_dev->ohci_dev; 44462306a36Sopenharmony_ci struct platform_device *ehci_dev = usb_dev->ehci_dev; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (ohci_dev) 44762306a36Sopenharmony_ci platform_device_unregister(ohci_dev); 44862306a36Sopenharmony_ci if (ehci_dev) 44962306a36Sopenharmony_ci platform_device_unregister(ehci_dev); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci bcma_core_disable(dev, 0); 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic void bcma_hcd_shutdown(struct bcma_device *dev) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci bcma_hci_platform_power_gpio(dev, false); 45762306a36Sopenharmony_ci bcma_core_disable(dev, 0); 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci#ifdef CONFIG_PM 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic int bcma_hcd_suspend(struct bcma_device *dev) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci bcma_hci_platform_power_gpio(dev, false); 46562306a36Sopenharmony_ci bcma_core_disable(dev, 0); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci return 0; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic int bcma_hcd_resume(struct bcma_device *dev) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci bcma_hci_platform_power_gpio(dev, true); 47362306a36Sopenharmony_ci bcma_core_enable(dev, 0); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci return 0; 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci#else /* !CONFIG_PM */ 47962306a36Sopenharmony_ci#define bcma_hcd_suspend NULL 48062306a36Sopenharmony_ci#define bcma_hcd_resume NULL 48162306a36Sopenharmony_ci#endif /* CONFIG_PM */ 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic const struct bcma_device_id bcma_hcd_table[] = { 48462306a36Sopenharmony_ci BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS), 48562306a36Sopenharmony_ci BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB20, BCMA_ANY_REV, BCMA_ANY_CLASS), 48662306a36Sopenharmony_ci BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB30, BCMA_ANY_REV, BCMA_ANY_CLASS), 48762306a36Sopenharmony_ci {}, 48862306a36Sopenharmony_ci}; 48962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(bcma, bcma_hcd_table); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_cistatic struct bcma_driver bcma_hcd_driver = { 49262306a36Sopenharmony_ci .name = KBUILD_MODNAME, 49362306a36Sopenharmony_ci .id_table = bcma_hcd_table, 49462306a36Sopenharmony_ci .probe = bcma_hcd_probe, 49562306a36Sopenharmony_ci .remove = bcma_hcd_remove, 49662306a36Sopenharmony_ci .shutdown = bcma_hcd_shutdown, 49762306a36Sopenharmony_ci .suspend = bcma_hcd_suspend, 49862306a36Sopenharmony_ci .resume = bcma_hcd_resume, 49962306a36Sopenharmony_ci}; 50062306a36Sopenharmony_cimodule_bcma_driver(bcma_hcd_driver); 501