diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/atm/cxacru.c | 7 | ||||
-rw-r--r-- | drivers/usb/class/usblp.c | 66 | ||||
-rw-r--r-- | drivers/usb/core/driver.c | 1 | ||||
-rw-r--r-- | drivers/usb/core/hcd.c | 19 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 4 | ||||
-rw-r--r-- | drivers/usb/core/sysfs.c | 31 | ||||
-rw-r--r-- | drivers/usb/host/bcma-hcd.c | 128 | ||||
-rw-r--r-- | drivers/usb/host/ehci-fsl.c | 49 | ||||
-rw-r--r-- | drivers/usb/host/ehci-fsl.h | 1 | ||||
-rw-r--r-- | drivers/usb/host/fsl-mph-dr-of.c | 25 | ||||
-rw-r--r-- | drivers/usb/host/xhci.c | 2 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/mod_gadget.c | 62 | ||||
-rw-r--r-- | drivers/usb/storage/transport.c | 2 |
13 files changed, 326 insertions, 71 deletions
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 813d4d3a51c6..1173f9cbc137 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -270,6 +270,7 @@ static ssize_t cxacru_sysfs_showattr_dB(s16 value, char *buf) static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf) { static char *str[] = { "no", "yes" }; + if (unlikely(value >= ARRAY_SIZE(str))) return snprintf(buf, PAGE_SIZE, "%u\n", value); return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); @@ -278,6 +279,7 @@ static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf) static ssize_t cxacru_sysfs_showattr_LINK(u32 value, char *buf) { static char *str[] = { NULL, "not connected", "connected", "lost" }; + if (unlikely(value >= ARRAY_SIZE(str) || str[value] == NULL)) return snprintf(buf, PAGE_SIZE, "%u\n", value); return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); @@ -702,6 +704,7 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ len = ret / 4; for (offb = 0; offb < len; ) { int l = le32_to_cpu(buf[offb++]); + if (l < 0 || l > stride || l > (len - offb) / 2) { if (printk_ratelimit()) usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n", @@ -732,6 +735,7 @@ cleanup: static int cxacru_card_status(struct cxacru_data *instance) { int ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0); + if (ret < 0) { /* firmware not loaded */ usb_dbg(instance->usbatm, "cxacru_adsl_start: CARD_GET_STATUS returned %d\n", ret); return ret; @@ -945,6 +949,7 @@ static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw, offb = offd = 0; do { int l = min_t(int, stride, size - offd); + buf[offb++] = fw; buf[offb++] = l; buf[offb++] = code1; @@ -1091,8 +1096,8 @@ static int cxacru_heavy_init(struct usbatm_data *usbatm_instance, { const struct firmware *fw, *bp; struct cxacru_data *instance = usbatm_instance->driver_data; - int ret = cxacru_find_firmware(instance, "fw", &fw); + if (ret) { usb_warn(usbatm_instance, "firmware (cxacru-fw.bin) unavailable (system misconfigured?)\n"); return ret; diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index f38e875a3fb1..433bbc34a8a4 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -57,6 +57,7 @@ #include <linux/mutex.h> #undef DEBUG #include <linux/usb.h> +#include <linux/usb/ch9.h> #include <linux/ratelimit.h> /* @@ -79,12 +80,20 @@ #define IOCNR_SOFT_RESET 7 /* Get device_id string: */ #define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) -/* The following ioctls were added for http://hpoj.sourceforge.net: */ -/* Get two-int array: - * [0]=current protocol (1=7/1/1, 2=7/1/2, 3=7/1/3), - * [1]=supported protocol mask (mask&(1<<n)!=0 means 7/1/n supported): */ +/* The following ioctls were added for http://hpoj.sourceforge.net: + * Get two-int array: + * [0]=current protocol + * (1=USB_CLASS_PRINTER/1/1, 2=USB_CLASS_PRINTER/1/2, + * 3=USB_CLASS_PRINTER/1/3), + * [1]=supported protocol mask (mask&(1<<n)!=0 means + * USB_CLASS_PRINTER/1/n supported): + */ #define LPIOC_GET_PROTOCOLS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_PROTOCOLS, len) -/* Set protocol (arg: 1=7/1/1, 2=7/1/2, 3=7/1/3): */ +/* + * Set protocol + * (arg: 1=USB_CLASS_PRINTER/1/1, 2=USB_CLASS_PRINTER/1/2, + * 3=USB_CLASS_PRINTER/1/3): + */ #define LPIOC_SET_PROTOCOL _IOC(_IOC_WRITE, 'P', IOCNR_SET_PROTOCOL, 0) /* Set channel number (HP Vendor-specific command): */ #define LPIOC_HP_SET_CHANNEL _IOC(_IOC_WRITE, 'P', IOCNR_HP_SET_CHANNEL, 0) @@ -146,8 +155,10 @@ struct usblp { int readcount; /* Counter for reads */ int ifnum; /* Interface number */ struct usb_interface *intf; /* The interface */ - /* Alternate-setting numbers and endpoints for each protocol - * (7/1/{index=1,2,3}) that the device supports: */ + /* + * Alternate-setting numbers and endpoints for each protocol + * (USB_CLASS_PRINTER/1/{index=1,2,3}) that the device supports: + */ struct { int alt_setting; struct usb_endpoint_descriptor *epwrite; @@ -1206,19 +1217,23 @@ abort_ret: * but our requirements are too intricate for simple match to handle. * * The "proto_bias" option may be used to specify the preferred protocol - * for all USB printers (1=7/1/1, 2=7/1/2, 3=7/1/3). If the device - * supports the preferred protocol, then we bind to it. + * for all USB printers (1=USB_CLASS_PRINTER/1/1, 2=USB_CLASS_PRINTER/1/2, + * 3=USB_CLASS_PRINTER/1/3). If the device supports the preferred protocol, + * then we bind to it. * - * The best interface for us is 7/1/2, because it is compatible - * with a stream of characters. If we find it, we bind to it. + * The best interface for us is USB_CLASS_PRINTER/1/2, because it + * is compatible with a stream of characters. If we find it, we bind to it. * * Note that the people from hpoj.sourceforge.net need to be able to - * bind to 7/1/3 (MLC/1284.4), so we provide them ioctls for this purpose. + * bind to USB_CLASS_PRINTER/1/3 (MLC/1284.4), so we provide them ioctls + * for this purpose. * - * Failing 7/1/2, we look for 7/1/3, even though it's probably not - * stream-compatible, because this matches the behaviour of the old code. + * Failing USB_CLASS_PRINTER/1/2, we look for USB_CLASS_PRINTER/1/3, + * even though it's probably not stream-compatible, because this matches + * the behaviour of the old code. * - * If nothing else, we bind to 7/1/1 - the unidirectional interface. + * If nothing else, we bind to USB_CLASS_PRINTER/1/1 + * - the unidirectional interface. */ static int usblp_select_alts(struct usblp *usblp) { @@ -1236,7 +1251,8 @@ static int usblp_select_alts(struct usblp *usblp) for (i = 0; i < if_alt->num_altsetting; i++) { ifd = &if_alt->altsetting[i]; - if (ifd->desc.bInterfaceClass != 7 || ifd->desc.bInterfaceSubClass != 1) + if (ifd->desc.bInterfaceClass != USB_CLASS_PRINTER || + ifd->desc.bInterfaceSubClass != 1) if (!(usblp->quirks & USBLP_QUIRK_BAD_CLASS)) continue; @@ -1262,8 +1278,10 @@ static int usblp_select_alts(struct usblp *usblp) if (!epwrite || (ifd->desc.bInterfaceProtocol > 1 && !epread)) continue; - /* Turn off reads for 7/1/1 (unidirectional) interfaces - * and buggy bidirectional printers. */ + /* + * Turn off reads for USB_CLASS_PRINTER/1/1 (unidirectional) + * interfaces and buggy bidirectional printers. + */ if (ifd->desc.bInterfaceProtocol == 1) { epread = NULL; } else if (usblp->quirks & USBLP_QUIRK_BIDIR) { @@ -1406,12 +1424,12 @@ static int usblp_resume(struct usb_interface *intf) } static const struct usb_device_id usblp_ids[] = { - { USB_DEVICE_INFO(7, 1, 1) }, - { USB_DEVICE_INFO(7, 1, 2) }, - { USB_DEVICE_INFO(7, 1, 3) }, - { USB_INTERFACE_INFO(7, 1, 1) }, - { USB_INTERFACE_INFO(7, 1, 2) }, - { USB_INTERFACE_INFO(7, 1, 3) }, + { USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 1) }, + { USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 2) }, + { USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 3) }, + { USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 1) }, + { USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 2) }, + { USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 3) }, { USB_DEVICE(0x04b8, 0x0202) }, /* Seiko Epson Receipt Printer M129C */ { } /* Terminating entry */ }; diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 818369afff63..6b5063e7943f 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -160,6 +160,7 @@ static ssize_t remove_id_store(struct device_driver *driver, const char *buf, spin_lock(&usb_driver->dynids.lock); list_for_each_entry_safe(dynid, n, &usb_driver->dynids.list, node) { struct usb_device_id *id = &dynid->id; + if ((id->idVendor == idVendor) && (id->idProduct == idProduct)) { list_del(&dynid->node); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index cbcd0920fb51..4d64e5c499e1 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2686,12 +2686,14 @@ int usb_add_hcd(struct usb_hcd *hcd, * bottom up so that hcds can customize the root hubs before hub_wq * starts talking to them. (Note, bus id is assigned early too.) */ - if ((retval = hcd_buffer_create(hcd)) != 0) { + retval = hcd_buffer_create(hcd); + if (retval != 0) { dev_dbg(hcd->self.controller, "pool alloc failed\n"); goto err_create_buf; } - if ((retval = usb_register_bus(&hcd->self)) < 0) + retval = usb_register_bus(&hcd->self); + if (retval < 0) goto err_register_bus; rhdev = usb_alloc_dev(NULL, &hcd->self, 0); @@ -2737,9 +2739,13 @@ int usb_add_hcd(struct usb_hcd *hcd, /* "reset" is misnamed; its role is now one-time init. the controller * should already have been reset (and boot firmware kicked off etc). */ - if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) { - dev_err(hcd->self.controller, "can't setup: %d\n", retval); - goto err_hcd_driver_setup; + if (hcd->driver->reset) { + retval = hcd->driver->reset(hcd); + if (retval < 0) { + dev_err(hcd->self.controller, "can't setup: %d\n", + retval); + goto err_hcd_driver_setup; + } } hcd->rh_pollable = 1; @@ -2769,7 +2775,8 @@ int usb_add_hcd(struct usb_hcd *hcd, } /* starting here, usbcore will pay attention to this root hub */ - if ((retval = register_root_hub(hcd)) != 0) + retval = register_root_hub(hcd); + if (retval != 0) goto err_register_root_hub; retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 73dfa194160b..917c27c4675a 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3950,6 +3950,8 @@ int usb_disable_lpm(struct usb_device *udev) if (usb_disable_link_state(hcd, udev, USB3_LPM_U2)) goto enable_lpm; + udev->usb3_lpm_enabled = 0; + return 0; enable_lpm: @@ -4007,6 +4009,8 @@ void usb_enable_lpm(struct usb_device *udev) usb_enable_link_state(hcd, udev, USB3_LPM_U1); usb_enable_link_state(hcd, udev, USB3_LPM_U2); + + udev->usb3_lpm_enabled = 1; } EXPORT_SYMBOL_GPL(usb_enable_lpm); diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index d26973844a4d..cfc68c11c3f5 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -531,6 +531,25 @@ static ssize_t usb2_lpm_besl_store(struct device *dev, } static DEVICE_ATTR_RW(usb2_lpm_besl); +static ssize_t usb3_hardware_lpm_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_device *udev = to_usb_device(dev); + const char *p; + + usb_lock_device(udev); + + if (udev->usb3_lpm_enabled) + p = "enabled"; + else + p = "disabled"; + + usb_unlock_device(udev); + + return sprintf(buf, "%s\n", p); +} +static DEVICE_ATTR_RO(usb3_hardware_lpm); + static struct attribute *usb2_hardware_lpm_attr[] = { &dev_attr_usb2_hardware_lpm.attr, &dev_attr_usb2_lpm_l1_timeout.attr, @@ -542,6 +561,15 @@ static struct attribute_group usb2_hardware_lpm_attr_group = { .attrs = usb2_hardware_lpm_attr, }; +static struct attribute *usb3_hardware_lpm_attr[] = { + &dev_attr_usb3_hardware_lpm.attr, + NULL, +}; +static struct attribute_group usb3_hardware_lpm_attr_group = { + .name = power_group_name, + .attrs = usb3_hardware_lpm_attr, +}; + static struct attribute *power_attrs[] = { &dev_attr_autosuspend.attr, &dev_attr_level.attr, @@ -564,6 +592,9 @@ static int add_power_attributes(struct device *dev) if (udev->usb2_hw_lpm_capable == 1) rc = sysfs_merge_group(&dev->kobj, &usb2_hardware_lpm_attr_group); + if (udev->lpm_capable == 1) + rc = sysfs_merge_group(&dev->kobj, + &usb3_hardware_lpm_attr_group); } return rc; diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 526cfab41d5f..5398e3d42822 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -2,7 +2,8 @@ * Broadcom specific Advanced Microcontroller Bus * Broadcom USB-core driver (BCMA bus glue) * - * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de> + * Copyright 2011-2015 Hauke Mehrtens <hauke@hauke-m.de> + * Copyright 2015 Felix Fietkau <nbd@openwrt.org> * * Based on ssb-ohci driver * Copyright 2007 Michael Buesch <m@bues.ch> @@ -23,6 +24,8 @@ #include <linux/platform_device.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_gpio.h> #include <linux/usb/ehci_pdriver.h> #include <linux/usb/ohci_pdriver.h> @@ -88,7 +91,7 @@ static void bcma_hcd_4716wa(struct bcma_device *dev) } /* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */ -static void bcma_hcd_init_chip(struct bcma_device *dev) +static void bcma_hcd_init_chip_mips(struct bcma_device *dev) { u32 tmp; @@ -159,6 +162,87 @@ static void bcma_hcd_init_chip(struct bcma_device *dev) } } +static void bcma_hcd_init_chip_arm_phy(struct bcma_device *dev) +{ + struct bcma_device *arm_core; + void __iomem *dmu; + + arm_core = bcma_find_core(dev->bus, BCMA_CORE_ARMCA9); + if (!arm_core) { + dev_err(&dev->dev, "can not find ARM Cortex A9 ihost core\n"); + return; + } + + dmu = ioremap_nocache(arm_core->addr_s[0], 0x1000); + if (!dmu) { + dev_err(&dev->dev, "can not map ARM Cortex A9 ihost core\n"); + return; + } + + /* Unlock DMU PLL settings */ + iowrite32(0x0000ea68, dmu + 0x180); + + /* Write USB 2.0 PLL control setting */ + iowrite32(0x00dd10c3, dmu + 0x164); + + /* Lock DMU PLL settings */ + iowrite32(0x00000000, dmu + 0x180); + + iounmap(dmu); +} + +static void bcma_hcd_init_chip_arm_hc(struct bcma_device *dev) +{ + u32 val; + + /* + * Delay after PHY initialized to ensure HC is ready to be configured + */ + usleep_range(1000, 2000); + + /* Set packet buffer OUT threshold */ + val = bcma_read32(dev, 0x94); + val &= 0xffff; + val |= 0x80 << 16; + bcma_write32(dev, 0x94, val); + + /* Enable break memory transfer */ + val = bcma_read32(dev, 0x9c); + val |= 1; + bcma_write32(dev, 0x9c, val); +} + +static void bcma_hcd_init_chip_arm(struct bcma_device *dev) +{ + bcma_core_enable(dev, 0); + + if (dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM4707 || + dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM53018) { + if (dev->bus->chipinfo.pkg == BCMA_PKG_ID_BCM4707 || + dev->bus->chipinfo.pkg == BCMA_PKG_ID_BCM4708) + bcma_hcd_init_chip_arm_phy(dev); + + bcma_hcd_init_chip_arm_hc(dev); + } +} + +static void bcma_hci_platform_power_gpio(struct bcma_device *dev, bool val) +{ + int gpio; + + gpio = of_get_named_gpio(dev->dev.of_node, "vcc-gpio", 0); + if (!gpio_is_valid(gpio)) + return; + + if (val) { + gpio_request(gpio, "bcma-hcd-gpio"); + gpio_set_value(gpio, 1); + } else { + gpio_set_value(gpio, 0); + gpio_free(gpio); + } +} + static const struct usb_ehci_pdata ehci_pdata = { }; @@ -169,7 +253,7 @@ static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev, boo { struct platform_device *hci_dev; struct resource hci_res[2]; - int ret = -ENOMEM; + int ret; memset(hci_res, 0, sizeof(hci_res)); @@ -183,7 +267,7 @@ static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev, boo hci_dev = platform_device_alloc(ohci ? "ohci-platform" : "ehci-platform" , 0); if (!hci_dev) - return NULL; + return ERR_PTR(-ENOMEM); hci_dev->dev.parent = &dev->dev; hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask; @@ -214,39 +298,45 @@ err_alloc: static int bcma_hcd_probe(struct bcma_device *dev) { int err; - u16 chipid_top; u32 ohci_addr; struct bcma_hcd_device *usb_dev; struct bcma_chipinfo *chipinfo; chipinfo = &dev->bus->chipinfo; - /* USBcores are only connected on embedded devices. */ - chipid_top = (chipinfo->id & 0xFF00); - if (chipid_top != 0x4700 && chipid_top != 0x5300) - return -ENODEV; /* TODO: Probably need checks here; is the core connected? */ if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32))) return -EOPNOTSUPP; - usb_dev = kzalloc(sizeof(struct bcma_hcd_device), GFP_KERNEL); + usb_dev = devm_kzalloc(&dev->dev, sizeof(struct bcma_hcd_device), + GFP_KERNEL); if (!usb_dev) return -ENOMEM; - bcma_hcd_init_chip(dev); + bcma_hci_platform_power_gpio(dev, true); + + switch (dev->id.id) { + case BCMA_CORE_NS_USB20: + bcma_hcd_init_chip_arm(dev); + break; + case BCMA_CORE_USB20_HOST: + bcma_hcd_init_chip_mips(dev); + break; + default: + return -ENODEV; + } /* In AI chips EHCI is addrspace 0, OHCI is 1 */ ohci_addr = dev->addr_s[0]; - if ((chipinfo->id == 0x5357 || chipinfo->id == 0x4749) + if ((chipinfo->id == BCMA_CHIP_ID_BCM5357 || + chipinfo->id == BCMA_CHIP_ID_BCM4749) && chipinfo->rev == 0) ohci_addr = 0x18009000; usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, true, ohci_addr); - if (IS_ERR(usb_dev->ohci_dev)) { - err = PTR_ERR(usb_dev->ohci_dev); - goto err_free_usb_dev; - } + if (IS_ERR(usb_dev->ohci_dev)) + return PTR_ERR(usb_dev->ohci_dev); usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, false, dev->addr); if (IS_ERR(usb_dev->ehci_dev)) { @@ -259,8 +349,6 @@ static int bcma_hcd_probe(struct bcma_device *dev) err_unregister_ohci_dev: platform_device_unregister(usb_dev->ohci_dev); -err_free_usb_dev: - kfree(usb_dev); return err; } @@ -280,6 +368,7 @@ static void bcma_hcd_remove(struct bcma_device *dev) static void bcma_hcd_shutdown(struct bcma_device *dev) { + bcma_hci_platform_power_gpio(dev, false); bcma_core_disable(dev, 0); } @@ -287,6 +376,7 @@ static void bcma_hcd_shutdown(struct bcma_device *dev) static int bcma_hcd_suspend(struct bcma_device *dev) { + bcma_hci_platform_power_gpio(dev, false); bcma_core_disable(dev, 0); return 0; @@ -294,6 +384,7 @@ static int bcma_hcd_suspend(struct bcma_device *dev) static int bcma_hcd_resume(struct bcma_device *dev) { + bcma_hci_platform_power_gpio(dev, true); bcma_core_enable(dev, 0); return 0; @@ -306,6 +397,7 @@ static int bcma_hcd_resume(struct bcma_device *dev) static const struct bcma_device_id bcma_hcd_table[] = { BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS), + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB20, BCMA_ANY_REV, BCMA_ANY_CLASS), {}, }; MODULE_DEVICE_TABLE(bcma, bcma_hcd_table); diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 5352e74b92e2..202dafb7d0cb 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -127,7 +127,18 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) /* Enable USB controller, 83xx or 8536 */ if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6) - setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4); + clrsetbits_be32(hcd->regs + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, 0x4); + + /* + * Enable UTMI phy and program PTS field in UTMI mode before asserting + * controller reset for USB Controller version 2.5 + */ + if (pdata->has_fsl_erratum_a007792) { + clrsetbits_be32(hcd->regs + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, CTRL_UTMI_PHY_EN); + writel(PORT_PTS_UTMI, hcd->regs + FSL_SOC_USB_PORTSC1); + } /* Don't need to set host mode here. It will be done by tdi_reset() */ @@ -191,9 +202,11 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, case FSL_USB2_PHY_ULPI: if (pdata->have_sysif_regs && pdata->controller_ver) { /* controller version 1.6 or above */ - clrbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN); - setbits32(non_ehci + FSL_SOC_USB_CTRL, - ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN); + clrbits32(non_ehci + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK | UTMI_PHY_EN); + clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, + ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN); } portsc |= PORT_PTS_ULPI; break; @@ -204,30 +217,33 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, portsc |= PORT_PTS_PTW; /* fall through */ case FSL_USB2_PHY_UTMI: + case FSL_USB2_PHY_UTMI_DUAL: if (pdata->have_sysif_regs && pdata->controller_ver) { /* controller version 1.6 or above */ - setbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN); + clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, UTMI_PHY_EN); mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to become stable - 10ms*/ } /* enable UTMI PHY */ if (pdata->have_sysif_regs) - setbits32(non_ehci + FSL_SOC_USB_CTRL, - CTRL_UTMI_PHY_EN); + clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, + CTRL_UTMI_PHY_EN); portsc |= PORT_PTS_UTMI; break; case FSL_USB2_PHY_NONE: break; } - if (pdata->have_sysif_regs && - pdata->controller_ver > FSL_USB_VER_1_6 && - (phy_mode == FSL_USB2_PHY_ULPI)) { - /* check PHY_CLK_VALID to get phy clk valid */ - if (!(spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) & - PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0) || - in_be32(non_ehci + FSL_SOC_USB_PRICTRL))) { - dev_warn(hcd->self.controller, "USB PHY clock invalid\n"); + /* + * check PHY_CLK_VALID to determine phy clock presence before writing + * to portsc + */ + if (pdata->check_phy_clk_valid) { + if (!(in_be32(non_ehci + FSL_SOC_USB_CTRL) & PHY_CLK_VALID)) { + dev_warn(hcd->self.controller, + "USB PHY clock invalid\n"); return -EINVAL; } } @@ -235,7 +251,8 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); if (phy_mode != FSL_USB2_PHY_ULPI && pdata->have_sysif_regs) - setbits32(non_ehci + FSL_SOC_USB_CTRL, USB_CTRL_USB_EN); + clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, USB_CTRL_USB_EN); return 0; } diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h index dbd292e9f0a7..1a8a60a57cf2 100644 --- a/drivers/usb/host/ehci-fsl.h +++ b/drivers/usb/host/ehci-fsl.h @@ -52,6 +52,7 @@ #define SNOOP_SIZE_2GB 0x1e /* control Register Bit Masks */ +#define CONTROL_REGISTER_W1C_MASK 0x00020000 /* W1C: PHY_CLK_VALID */ #define ULPI_INT_EN (1<<0) #define WU_INT_EN (1<<1) #define USB_CTRL_USB_EN (1<<2) diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 5e0d60035216..9f731413ab3e 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -69,6 +69,8 @@ static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type) return FSL_USB2_PHY_UTMI; if (!strcasecmp(phy_type, "utmi_wide")) return FSL_USB2_PHY_UTMI_WIDE; + if (!strcasecmp(phy_type, "utmi_dual")) + return FSL_USB2_PHY_UTMI_DUAL; if (!strcasecmp(phy_type, "serial")) return FSL_USB2_PHY_SERIAL; @@ -119,9 +121,9 @@ error: static const struct of_device_id fsl_usb2_mph_dr_of_match[]; -static int usb_get_ver_info(struct device_node *np) +static enum fsl_usb2_controller_ver usb_get_ver_info(struct device_node *np) { - int ver = -1; + enum fsl_usb2_controller_ver ver = FSL_USB_VER_NONE; /* * returns 1 for usb controller version 1.6 @@ -142,7 +144,7 @@ static int usb_get_ver_info(struct device_node *np) else /* for previous controller versions */ ver = FSL_USB_VER_OLD; - if (ver > -1) + if (ver > FSL_USB_VER_NONE) return ver; } @@ -214,8 +216,23 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) pdata->phy_mode = determine_usb_phy(prop); pdata->controller_ver = usb_get_ver_info(np); + /* Activate Erratum by reading property in device tree */ + if (of_get_property(np, "fsl,usb-erratum-a007792", NULL)) + pdata->has_fsl_erratum_a007792 = 1; + else + pdata->has_fsl_erratum_a007792 = 0; + + /* + * Determine whether phy_clk_valid needs to be checked + * by reading property in device tree + */ + if (of_get_property(np, "phy-clk-valid", NULL)) + pdata->check_phy_clk_valid = 1; + else + pdata->check_phy_clk_valid = 0; + if (pdata->have_sysif_regs) { - if (pdata->controller_ver < 0) { + if (pdata->controller_ver == FSL_USB_VER_NONE) { dev_warn(&ofdev->dev, "Could not get controller version\n"); return -ENODEV; } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 526ebc0c7e72..c3ac0a2aac37 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3117,7 +3117,7 @@ static u32 xhci_calculate_no_streams_bitmask(struct xhci_hcd *xhci, } /* - * The USB device drivers use this function (though the HCD interface in USB + * The USB device drivers use this function (through the HCD interface in USB * core) to prepare a set of bulk endpoints to use streams. Streams are used to * coordinate mass storage command queueing across multiple endpoints (basically * a stream ID == a task ID). diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index dc2aa3261202..54f916fa238d 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -21,6 +21,7 @@ #include <linux/platform_device.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> +#include <linux/usb/otg.h> #include "common.h" /* @@ -50,6 +51,8 @@ struct usbhsg_gpriv { int uep_size; struct usb_gadget_driver *driver; + struct usb_phy *transceiver; + bool vbus_active; u32 status; #define USBHSG_STATUS_STARTED (1 << 0) @@ -873,6 +876,27 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) } /* + * VBUS provided by the PHY + */ +static int usbhsm_phy_get_vbus(struct platform_device *pdev) +{ + struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); + struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); + + return gpriv->vbus_active; +} + +static void usbhs_mod_phy_mode(struct usbhs_priv *priv) +{ + struct usbhs_mod_info *info = &priv->mod_info; + + info->irq_vbus = NULL; + priv->pfunc.get_vbus = usbhsm_phy_get_vbus; + + usbhs_irq_callback_update(priv, NULL); +} + +/* * * linux usb function * @@ -882,12 +906,28 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget, { struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); + struct device *dev = usbhs_priv_to_dev(priv); + int ret; if (!driver || !driver->setup || driver->max_speed < USB_SPEED_FULL) return -EINVAL; + /* connect to bus through transceiver */ + if (!IS_ERR_OR_NULL(gpriv->transceiver)) { + ret = otg_set_peripheral(gpriv->transceiver->otg, + &gpriv->gadget); + if (ret) { + dev_err(dev, "%s: can't bind to transceiver\n", + gpriv->gadget.name); + return ret; + } + + /* get vbus using phy versions */ + usbhs_mod_phy_mode(priv); + } + /* first hook up the driver ... */ gpriv->driver = driver; @@ -900,6 +940,10 @@ static int usbhsg_gadget_stop(struct usb_gadget *gadget) struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); usbhsg_try_stop(priv, USBHSG_STATUS_REGISTERD); + + if (!IS_ERR_OR_NULL(gpriv->transceiver)) + otg_set_peripheral(gpriv->transceiver->otg, NULL); + gpriv->driver = NULL; return 0; @@ -947,12 +991,26 @@ static int usbhsg_set_selfpowered(struct usb_gadget *gadget, int is_self) return 0; } +static int usbhsg_vbus_session(struct usb_gadget *gadget, int is_active) +{ + struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); + struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); + struct platform_device *pdev = usbhs_priv_to_pdev(priv); + + gpriv->vbus_active = !!is_active; + + renesas_usbhs_call_notify_hotplug(pdev); + + return 0; +} + static const struct usb_gadget_ops usbhsg_gadget_ops = { .get_frame = usbhsg_get_frame, .set_selfpowered = usbhsg_set_selfpowered, .udc_start = usbhsg_gadget_start, .udc_stop = usbhsg_gadget_stop, .pullup = usbhsg_pullup, + .vbus_session = usbhsg_vbus_session, }; static int usbhsg_start(struct usbhs_priv *priv) @@ -994,6 +1052,10 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) goto usbhs_mod_gadget_probe_err_gpriv; } + gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED); + dev_info(dev, "%stransceiver found\n", + gpriv->transceiver ? "" : "no "); + /* * CAUTION * diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 540add24a12f..5e67f63b2e46 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -1111,7 +1111,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) * command phase and the data phase. Some devices need a little * more than that, probably because of clock rate inaccuracies. */ if (unlikely(us->fflags & US_FL_GO_SLOW)) - udelay(125); + usleep_range(125, 150); if (transfer_length) { unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? |