From f4c126ecaef1c08a906a2af51fb538022906f101 Mon Sep 17 00:00:00 2001 From: Nik Nyby Date: Mon, 6 Jul 2015 10:40:32 -0400 Subject: USB: serial: ftdi_sio: Fix broken URL in comment This fixes a typo in the URL: http://zeitcontrol.de/ Signed-off-by: Nik Nyby Signed-off-by: Johan Hovold diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 792e054..cb12b31 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -1365,7 +1365,7 @@ #define FTDI_CTI_NANO_PID 0xF60B /* - * ZeitControl cardsystems GmbH rfid-readers http://zeitconrol.de + * ZeitControl cardsystems GmbH rfid-readers http://zeitcontrol.de */ /* TagTracer MIFARE*/ #define FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID 0xF7C0 -- cgit v0.10.2 From 79a02744bc5a2993d6c5b8dd1a790f7ea12f4e0b Mon Sep 17 00:00:00 2001 From: Kris Borer Date: Tue, 16 Jun 2015 13:24:53 -0400 Subject: usb: fix coding style issue Fixed coding style issue: newline after declaration Signed-off-by: Kris Borer Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 818369a..6b5063e 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); -- cgit v0.10.2 From 298b992fdb7536f0f347935d253ce31479b1fb43 Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Mon, 22 Jun 2015 15:50:22 +0200 Subject: usb: class: Use USB_CLASS_PRINTER instead of number 7 Kernel provides very nice defines for USB device class so it's a good idea to use them in suitable places. It is much easier to grep for such define instead of 7. Signed-off-by: Krzysztof Opasiak Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index f38e875..433bbc3 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -57,6 +57,7 @@ #include #undef DEBUG #include +#include #include /* @@ -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<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 */ }; -- cgit v0.10.2 From cd32fbad6e3dfb26ae12babe07771f92b417af6b Mon Sep 17 00:00:00 2001 From: Aaron Raimist Date: Mon, 22 Jun 2015 21:05:27 -0500 Subject: USB: atm: cxacru: fix blank line after declaration Fixed a coding style issue. Adds blank lines after declarations. Signed-off-by: Aaron Raimist Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 813d4d3..1173f9c 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; -- cgit v0.10.2 From c2a298d96628803586f1ca2027b6387f4e4b5a31 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Tue, 30 Jun 2015 16:48:54 +0200 Subject: usb: host: xhci: remove typo in function documentation Fix "though" to "through" in documentation of xhci_alloc_streams(). Signed-off-by: Luis de Bethencourt Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 7da0d60..e66857f 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). -- cgit v0.10.2 From 0faaad461547e2412e9b519cd757a99b3ebc1302 Mon Sep 17 00:00:00 2001 From: Kris Borer Date: Tue, 14 Jul 2015 09:28:30 -0400 Subject: usb: move assignment out of if condition Fix four occurrences of checkpatch.pl error: ERROR: do not use assignment in if condition The semantic patch that makes this change is: // @@ identifier i; expression E; statement S; constant c; binary operator b; @@ + i = E; if ( - (i = E) + i b c ) S @@ identifier i, i2; expression E1, E2; constant c; @@ + if( E1->i ) { + i2 = E2; + if (i2 < c) { - if( E1->i && (i2 = E2) < c ) { ... - } + } + } // Signed-off-by: Kris Borer Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index be5b207..3204a4d 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2683,12 +2683,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); @@ -2734,9 +2736,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; @@ -2766,7 +2772,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); -- cgit v0.10.2 From 7e4a4da67255d92620ba59b461b5bc295db28dae Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 11 Jun 2015 22:57:35 +0200 Subject: USB: bcma: remove chip id check I have never seen any bcma device with an USB host core which was not a SoC, the bcma devices have an USB device core with a different core id. Some SoC have IDs with 47XX and 53XX in decimal form which would be rejected by this check. Instead of fixing this check just remove it. Signed-off-by: Hauke Mehrtens Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 526cfab..976b4e1 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -214,16 +214,11 @@ 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? */ -- cgit v0.10.2 From 98e13e05a1bab82c3bec1d867159bc8384acbe5b Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 11 Jun 2015 22:57:36 +0200 Subject: USB: bcma: replace numbers with constants The constants for these numbers were added long time ago, use them. Signed-off-by: Hauke Mehrtens Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 976b4e1..b4ec4ec 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -233,7 +233,8 @@ static int bcma_hcd_probe(struct bcma_device *dev) /* 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; -- cgit v0.10.2 From c27da2b22b558390acc515e71e47b1b307f85d5a Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 11 Jun 2015 22:57:37 +0200 Subject: USB: bcma: use devm_kzalloc Instead of manually handling the frees use devm. There was also a free missing in the unregister call which is not needed with devm. Signed-off-by: Hauke Mehrtens Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index b4ec4ec..34ab0a4 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -225,7 +225,8 @@ static int bcma_hcd_probe(struct bcma_device *dev) 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; @@ -239,10 +240,8 @@ static int bcma_hcd_probe(struct bcma_device *dev) 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)) { @@ -255,8 +254,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; } -- cgit v0.10.2 From ab2de5793080dfb9f191ca71068b9f476a55a0f4 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 11 Jun 2015 22:57:38 +0200 Subject: USB: bcma: fix error handling in bcma_hcd_create_pdev() This patch makes bcma_hcd_create_pdev() not return NULL, but a prober error code in case of an error. Signed-off-by: Hauke Mehrtens Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 34ab0a4..35d45a9 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -169,7 +169,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 +183,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; -- cgit v0.10.2 From 10bc04b744c69f253dfe47bc143325349ce8becc Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 11 Jun 2015 22:57:39 +0200 Subject: USB: bcma: add bcm53xx support The Broadcom ARM SoCs with this usb core need a different initialization and they have a different core id. This patch adds support for these USB 2.0 core. Signed-off-by: Felix Fietkau Signed-off-by: Hauke Mehrtens Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 35d45a9..96f1725 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 + * Copyright 2011-2015 Hauke Mehrtens + * Copyright 2015 Felix Fietkau * * Based on ssb-ohci driver * Copyright 2007 Michael Buesch @@ -88,7 +89,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 +160,70 @@ 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 const struct usb_ehci_pdata ehci_pdata = { }; @@ -230,7 +295,16 @@ static int bcma_hcd_probe(struct bcma_device *dev) if (!usb_dev) return -ENOMEM; - bcma_hcd_init_chip(dev); + 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]; @@ -299,6 +373,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); -- cgit v0.10.2 From eb4861c3cef7f745df0d2a26b0f4287da0190424 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 11 Jun 2015 22:57:40 +0200 Subject: USB: bcma: add support for controlling bus power through GPIO On some boards a GPIO is needed to activate USB controller. Make it possible to specify such a GPIO in device tree. Signed-off-by: Felix Fietkau Signed-off-by: Hauke Mehrtens Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 96f1725..5398e3d 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include @@ -224,6 +226,23 @@ static void bcma_hcd_init_chip_arm(struct bcma_device *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 = { }; @@ -295,6 +314,8 @@ static int bcma_hcd_probe(struct bcma_device *dev) if (!usb_dev) return -ENOMEM; + bcma_hci_platform_power_gpio(dev, true); + switch (dev->id.id) { case BCMA_CORE_NS_USB20: bcma_hcd_init_chip_arm(dev); @@ -347,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); } @@ -354,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; @@ -361,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; -- cgit v0.10.2 From 655fe4effe0f1f40e4f6ca6b3cc64a7fe0032183 Mon Sep 17 00:00:00 2001 From: Kevin Strasser Date: Tue, 16 Jun 2015 10:35:30 -0700 Subject: usbcore: add sysfs support to xHCI usb3 hardware LPM Add a sysfs node to make it easier to verify if LPM is supported and being enabled for USB 3.0 devices. Signed-off-by: Kevin Strasser Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index e5cc763..e935625 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -114,6 +114,20 @@ Description: enabled for the device. Developer can write y/Y/1 or n/N/0 to the file to enable/disable the feature. +What: /sys/bus/usb/devices/.../power/usb3_hardware_lpm +Date: June 2015 +Contact: Kevin Strasser +Description: + If CONFIG_PM_RUNTIME is set and a USB 3.0 lpm-capable device is + plugged in to a xHCI host which supports link PM, it will check + if U1 and U2 exit latencies have been set in the BOS + descriptor; if the check is is passed and the host supports + USB3 hardware LPM, USB3 hardware LPM will be enabled for the + device and the USB device directory will contain a file named + power/usb3_hardware_lpm. The file holds a string value (enable + or disable) indicating whether or not USB3 hardware LPM is + enabled for the device. + What: /sys/bus/usb/devices/.../removable Date: February 2012 Contact: Matthew Garrett diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt index b5f8391..4a15c90 100644 --- a/Documentation/usb/power-management.txt +++ b/Documentation/usb/power-management.txt @@ -521,10 +521,10 @@ enabling hardware LPM, the host can automatically put the device into lower power state(L1 for usb2.0 devices, or U1/U2 for usb3.0 devices), which state device can enter and resume very quickly. -The user interface for controlling USB2 hardware LPM is located in the +The user interface for controlling hardware LPM is located in the power/ subdirectory of each USB device's sysfs directory, that is, in /sys/bus/usb/devices/.../power/ where "..." is the device's ID. The -relevant attribute files is usb2_hardware_lpm. +relevant attribute files are usb2_hardware_lpm and usb3_hardware_lpm. power/usb2_hardware_lpm @@ -537,6 +537,17 @@ relevant attribute files is usb2_hardware_lpm. can write y/Y/1 or n/N/0 to the file to enable/disable USB2 hardware LPM manually. This is for test purpose mainly. + power/usb3_hardware_lpm + + When a USB 3.0 lpm-capable device is plugged in to a + xHCI host which supports link PM, it will check if U1 + and U2 exit latencies have been set in the BOS + descriptor; if the check is is passed and the host + supports USB3 hardware LPM, USB3 hardware LPM will be + enabled for the device and this file will be created. + The file holds a string value (enable or disable) + indicating whether or not USB3 hardware LPM is + enabled for the device. USB Port Power Control ---------------------- diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 43cb2f2..d9ce8f9 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 d269738..cfc68c1 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; -- cgit v0.10.2 From e616b39a16d4458224d91697b0a2599336f0c38c Mon Sep 17 00:00:00 2001 From: Sunny Kumar Date: Tue, 7 Jul 2015 12:27:03 +0530 Subject: usb: usleep_range is preferred over udelay where wakeup is flexible According to Documentation/timers/timers-howto.txt" udelay() is only called once from a place where sleeping is allowed. We can replace it with a call to usleep_range() with a reasonable upper limit. Signed-off-by: Sunny Kumar Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 540add2..5e67f63 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 ? -- cgit v0.10.2 From 5fd3fc1c5384fe420ead51f41662ba563336fbea Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Mon, 13 Jul 2015 16:30:18 +0100 Subject: usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS These changes allow a PHY driver to trigger a VBUS interrupt and to provide the value of VBUS. Signed-off-by: Phil Edworthy Reviewed-by: Laurent Pinchart Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index dc2aa32..54f916f 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -21,6 +21,7 @@ #include #include #include +#include #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 * -- cgit v0.10.2 From 38aa420096e565fe9c98f9d9475fd168114501a9 Mon Sep 17 00:00:00 2001 From: Nikhil Badola Date: Mon, 15 Jun 2015 15:46:37 +0530 Subject: drivers:usb:fsl: Replace macros with enumerated type Replace macros with enumerated type to represent usb ip controller version Signed-off-by: Nikhil Badola Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 5e0d600..2195956 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -119,9 +119,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 +142,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; } @@ -215,7 +215,7 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) pdata->controller_ver = usb_get_ver_info(np); 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/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 2a2f56b..0d4855cd 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -20,11 +20,6 @@ #define FSL_UTMI_PHY_DLY 10 /*As per P1010RM, delay for UTMI PHY CLK to become stable - 10ms*/ #define FSL_USB_PHY_CLK_TIMEOUT 10000 /* uSec */ -#define FSL_USB_VER_OLD 0 -#define FSL_USB_VER_1_6 1 -#define FSL_USB_VER_2_2 2 -#define FSL_USB_VER_2_4 3 -#define FSL_USB_VER_2_5 4 #include @@ -52,6 +47,15 @@ * */ +enum fsl_usb2_controller_ver { + FSL_USB_VER_NONE = -1, + FSL_USB_VER_OLD = 0, + FSL_USB_VER_1_6 = 1, + FSL_USB_VER_2_2 = 2, + FSL_USB_VER_2_4 = 3, + FSL_USB_VER_2_5 = 4, +}; + enum fsl_usb2_operating_modes { FSL_USB2_MPH_HOST, FSL_USB2_DR_HOST, @@ -72,7 +76,7 @@ struct platform_device; struct fsl_usb2_platform_data { /* board specific information */ - int controller_ver; + enum fsl_usb2_controller_ver controller_ver; enum fsl_usb2_operating_modes operating_mode; enum fsl_usb2_phy_modes phy_mode; unsigned int port_enables; -- cgit v0.10.2 From 523f1dec58408b36e7683a3d61a0286eed1fc1c8 Mon Sep 17 00:00:00 2001 From: Nikhil Badola Date: Mon, 15 Jun 2015 15:47:29 +0530 Subject: drivers: usb :fsl: Implement Workaround for USB Erratum A007792 USB controller version-2.5 requires to enable internal UTMI phy and program PTS field in PORTSC register before asserting controller reset. This is must for successful resetting of the controller and subsequent enumeration of usb devices Signed-off-by: Nikhil Badola Signed-off-by: Suresh Gupta Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 5352e74..716aa8b 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -129,6 +129,15 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6) setbits32(hcd->regs + FSL_SOC_USB_CTRL, 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) { + writel_be(CTRL_UTMI_PHY_EN, hcd->regs + FSL_SOC_USB_CTRL); + 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() */ retval = usb_add_hcd(hcd, irq, IRQF_SHARED); diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 2195956..17e1e6b 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -214,6 +214,12 @@ 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; + if (pdata->have_sysif_regs) { if (pdata->controller_ver == FSL_USB_VER_NONE) { dev_warn(&ofdev->dev, "Could not get controller version\n"); diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 0d4855cd..bdb40f6 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -97,6 +97,7 @@ struct fsl_usb2_platform_data { unsigned suspended:1; unsigned already_suspended:1; + unsigned has_fsl_erratum_a007792:1; /* register save area for suspend/resume */ u32 pm_command; -- cgit v0.10.2 From 6009d95e04cf74c6f80db56fddca21fea476ad24 Mon Sep 17 00:00:00 2001 From: Nikhil Badola Date: Mon, 15 Jun 2015 15:48:22 +0530 Subject: drivers:usb:fsl: Introduce FSL_USB2_PHY_UTMI_DUAL macro Introduce FSL_USB2_PHY_UTMI_DUAL macro for setting phy mode in SOCs such has T4240, T1040, T2080 which have utmi dual-phy Signed-off-by: Ramneek Mehresh Signed-off-by: Nikhil Badola Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 716aa8b..b04c9db 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -213,6 +213,7 @@ 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); diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 17e1e6b..631fc50 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; diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index bdb40f6..070d9ae 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -69,6 +69,7 @@ enum fsl_usb2_phy_modes { FSL_USB2_PHY_UTMI, FSL_USB2_PHY_UTMI_WIDE, FSL_USB2_PHY_SERIAL, + FSL_USB2_PHY_UTMI_DUAL, }; struct clk; -- cgit v0.10.2 From f4fdfaa280a284be8a056d6840cdbbf42c05bf95 Mon Sep 17 00:00:00 2001 From: Nikhil Badola Date: Tue, 14 Jul 2015 17:28:10 +0530 Subject: drivers: usb: fsl: Modify phy clk valid bit checking Phy_clk_valid bit is checked only when the boolean property phy-clk-valid in present in usb node device tree. This property is added to the usb node via device tree fixup. Signed-off-by: Nikhil Badola Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index b04c9db..05ebe3d 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -230,14 +230,14 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, 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; } } diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 631fc50..9f73141 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -222,6 +222,15 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) 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 == FSL_USB_VER_NONE) { dev_warn(&ofdev->dev, "Could not get controller version\n"); diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 070d9ae..cebdbbb 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -99,6 +99,7 @@ struct fsl_usb2_platform_data { unsigned suspended:1; unsigned already_suspended:1; unsigned has_fsl_erratum_a007792:1; + unsigned check_phy_clk_valid:1; /* register save area for suspend/resume */ u32 pm_command; -- cgit v0.10.2 From 4e02bea82b4e6c1eebeac6e6f4ecb93e9c2aa8c0 Mon Sep 17 00:00:00 2001 From: Nikhil Badola Date: Tue, 14 Jul 2015 17:28:47 +0530 Subject: drivers: usb: fsl: Define usb control register mask for w1c bits Define and use CONTROL_REGISTER_W1C_MASK to make sure that w1c bits of usb control register do not get reset while writing any other bit Signed-off-by: Nikhil Badola Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 05ebe3d..202dafb 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -127,14 +127,16 @@ 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) { - writel_be(CTRL_UTMI_PHY_EN, hcd->regs + FSL_SOC_USB_CTRL); + 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); } @@ -200,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; @@ -216,14 +220,16 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, 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: @@ -245,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 dbd292e..1a8a60a 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) -- cgit v0.10.2 From cbf919bd32d9424be8b77dac06fd90cd0a297562 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Thu, 9 Jul 2015 22:48:25 +0200 Subject: phy: add lpc18xx usb otg phy driver Add PHY driver for the internal USB OTG PHY found on NXP LPC18xx and LPC43xx devices. This driver takes care of enabling the PHY in CREG (syscon) and setting the required clock frequency. Signed-off-by: Joachim Eastwood Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index c0e6ede..e2f2a4d 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -54,6 +54,17 @@ config PHY_EXYNOS_MIPI_VIDEO Support for MIPI CSI-2 and MIPI DSI DPHY found on Samsung S5P and EXYNOS SoCs. +config PHY_LPC18XX_USB_OTG + tristate "NXP LPC18xx/43xx SoC USB OTG PHY driver" + depends on OF && (ARCH_LPC18XX || COMPILE_TEST) + depends on MFD_SYSCON + select GENERIC_PHY + help + Enable this to support NXP LPC18xx/43xx internal USB OTG PHY. + + This driver is need for USB0 support on LPC18xx/43xx and takes + care of enabling and clock setup. + config PHY_PXA_28NM_HSIC tristate "Marvell USB HSIC 28nm PHY Driver" select GENERIC_PHY diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index f344e1b..a5b18c1 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o +obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o diff --git a/drivers/phy/phy-lpc18xx-usb-otg.c b/drivers/phy/phy-lpc18xx-usb-otg.c new file mode 100644 index 0000000..3aa8e4d --- /dev/null +++ b/drivers/phy/phy-lpc18xx-usb-otg.c @@ -0,0 +1,143 @@ +/* + * PHY driver for NXP LPC18xx/43xx internal USB OTG PHY + * + * Copyright (C) 2015 Joachim Eastwood + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* USB OTG PHY register offset and bit in CREG */ +#define LPC18XX_CREG_CREG0 0x004 +#define LPC18XX_CREG_CREG0_USB0PHY BIT(5) + +struct lpc18xx_usb_otg_phy { + struct phy *phy; + struct clk *clk; + struct regmap *reg; +}; + +static int lpc18xx_usb_otg_phy_init(struct phy *phy) +{ + struct lpc18xx_usb_otg_phy *lpc = phy_get_drvdata(phy); + int ret; + + ret = clk_prepare(lpc->clk); + if (ret) + return ret; + + /* The PHY must be clocked at 480 MHz */ + return clk_set_rate(lpc->clk, 480000000); +} + +static int lpc18xx_usb_otg_phy_exit(struct phy *phy) +{ + struct lpc18xx_usb_otg_phy *lpc = phy_get_drvdata(phy); + + clk_unprepare(lpc->clk); + + return 0; +} + +static int lpc18xx_usb_otg_phy_power_on(struct phy *phy) +{ + struct lpc18xx_usb_otg_phy *lpc = phy_get_drvdata(phy); + int ret; + + ret = clk_enable(lpc->clk); + if (ret) + return ret; + + /* The bit in CREG is cleared to enable the PHY */ + return regmap_update_bits(lpc->reg, LPC18XX_CREG_CREG0, + LPC18XX_CREG_CREG0_USB0PHY, 0); +} + +static int lpc18xx_usb_otg_phy_power_off(struct phy *phy) +{ + struct lpc18xx_usb_otg_phy *lpc = phy_get_drvdata(phy); + int ret; + + ret = regmap_update_bits(lpc->reg, LPC18XX_CREG_CREG0, + LPC18XX_CREG_CREG0_USB0PHY, + LPC18XX_CREG_CREG0_USB0PHY); + if (ret) + return ret; + + clk_disable(lpc->clk); + + return 0; +} + +static const struct phy_ops lpc18xx_usb_otg_phy_ops = { + .init = lpc18xx_usb_otg_phy_init, + .exit = lpc18xx_usb_otg_phy_exit, + .power_on = lpc18xx_usb_otg_phy_power_on, + .power_off = lpc18xx_usb_otg_phy_power_off, + .owner = THIS_MODULE, +}; + +static int lpc18xx_usb_otg_phy_probe(struct platform_device *pdev) +{ + struct phy_provider *phy_provider; + struct lpc18xx_usb_otg_phy *lpc; + + lpc = devm_kzalloc(&pdev->dev, sizeof(*lpc), GFP_KERNEL); + if (!lpc) + return -ENOMEM; + + lpc->reg = syscon_node_to_regmap(pdev->dev.of_node->parent); + if (IS_ERR(lpc->reg)) { + dev_err(&pdev->dev, "failed to get syscon\n"); + return PTR_ERR(lpc->reg); + } + + lpc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(lpc->clk)) { + dev_err(&pdev->dev, "failed to get clock\n"); + return PTR_ERR(lpc->clk); + } + + lpc->phy = devm_phy_create(&pdev->dev, NULL, &lpc18xx_usb_otg_phy_ops); + if (IS_ERR(lpc->phy)) { + dev_err(&pdev->dev, "failed to create PHY\n"); + return PTR_ERR(lpc->phy); + } + + phy_set_drvdata(lpc->phy, lpc); + + phy_provider = devm_of_phy_provider_register(&pdev->dev, + of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id lpc18xx_usb_otg_phy_match[] = { + { .compatible = "nxp,lpc1850-usb-otg-phy" }, + { } +}; +MODULE_DEVICE_TABLE(of, lpc18xx_usb_otg_phy_match); + +static struct platform_driver lpc18xx_usb_otg_phy_driver = { + .probe = lpc18xx_usb_otg_phy_probe, + .driver = { + .name = "lpc18xx-usb-otg-phy", + .of_match_table = lpc18xx_usb_otg_phy_match, + }, +}; +module_platform_driver(lpc18xx_usb_otg_phy_driver); + +MODULE_AUTHOR("Joachim Eastwood "); +MODULE_DESCRIPTION("NXP LPC18xx/43xx USB OTG PHY driver"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 2d69a115a991fb7400c501dc643c47ca54cc4045 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Thu, 9 Jul 2015 22:48:26 +0200 Subject: phy: dt bindings: add NXP LPC18xx/43xx USB OTG PHY bindings Add binding documentation for NXP LPC18xx/43xx USB OTG PHY. This PHY can found on NXP LPC18xx and LPC43xx devices with USB support. Signed-off-by: Joachim Eastwood Signed-off-by: Kishon Vijay Abraham I diff --git a/Documentation/devicetree/bindings/phy/phy-lpc18xx-usb-otg.txt b/Documentation/devicetree/bindings/phy/phy-lpc18xx-usb-otg.txt new file mode 100644 index 0000000..bd61b46 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-lpc18xx-usb-otg.txt @@ -0,0 +1,26 @@ +NXP LPC18xx/43xx internal USB OTG PHY binding +--------------------------------------------- + +This file contains documentation for the internal USB OTG PHY found +in NXP LPC18xx and LPC43xx SoCs. + +Required properties: +- compatible : must be "nxp,lpc1850-usb-otg-phy" +- clocks : must be exactly one entry +See: Documentation/devicetree/bindings/clock/clock-bindings.txt +- #phy-cells : must be 0 for this phy +See: Documentation/devicetree/bindings/phy/phy-bindings.txt + +The phy node must be a child of the creg syscon node. + +Example: +creg: syscon@40043000 { + compatible = "nxp,lpc1850-creg", "syscon", "simple-mfd"; + reg = <0x40043000 0x1000>; + + usb0_otg_phy: phy@004 { + compatible = "nxp,lpc1850-usb-otg-phy"; + clocks = <&ccu1 CLK_USB0>; + #phy-cells = <0>; + }; +}; -- cgit v0.10.2 From d2332303efc00d35af7f3d8b025663965862b0e3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 Jun 2015 14:37:45 +0200 Subject: phy-sun4i-usb: Add id and vbus detection support for the otg phy (phy0) The usb0 phy is connected to an OTG controller, and as such needs some special handling: 1) It allows explicit control over the pullups, enable these on phy_init and disable them on phy_exit. 2) It has bits to signal id and vbus detect to the musb-core, add support for for monitoring id and vbus detect gpio-s for use in dual role mode, and set these bits to the correct values for operating in host only mode when no gpios are specified in the devicetree. While updating the devicetree binding documentation also add documentation for the sofar undocumented usage of regulators for vbus for all 3 phys. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt index 16528b9..557fa99 100644 --- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt @@ -23,6 +23,13 @@ Required properties: * "usb1_reset" * "usb2_reset" for sun4i, sun6i or sun7i +Optional properties: +- usb0_id_det-gpios : gpio phandle for reading the otg id pin value +- usb0_vbus_det-gpios : gpio phandle for detecting the presence of usb0 vbus +- usb0_vbus-supply : regulator phandle for controller usb0 vbus +- usb1_vbus-supply : regulator phandle for controller usb1 vbus +- usb2_vbus-supply : regulator phandle for controller usb2 vbus + Example: usbphy: phy@0x01c13400 { #phy-cells = <1>; @@ -32,6 +39,13 @@ Example: reg-names = "phy_ctrl", "pmu1", "pmu2"; clocks = <&usb_clk 8>; clock-names = "usb_phy"; - resets = <&usb_clk 1>, <&usb_clk 2>; - reset-names = "usb1_reset", "usb2_reset"; + resets = <&usb_clk 0>, <&usb_clk 1>, <&usb_clk 2>; + reset-names = "usb0_reset", "usb1_reset", "usb2_reset"; + pinctrl-names = "default"; + pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>; + usb0_id_det-gpios = <&pio 7 19 GPIO_ACTIVE_HIGH>; /* PH19 */ + usb0_vbus_det-gpios = <&pio 7 22 GPIO_ACTIVE_HIGH>; /* PH22 */ + usb0_vbus-supply = <®_usb0_vbus>; + usb1_vbus-supply = <®_usb1_vbus>; + usb2_vbus-supply = <®_usb2_vbus>; }; diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index e17c539..37f52f7 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -1,7 +1,7 @@ /* * Allwinner sun4i USB phy driver * - * Copyright (C) 2014 Hans de Goede + * Copyright (C) 2014-2015 Hans de Goede * * Based on code from * Allwinner Technology Co., Ltd. @@ -24,16 +24,19 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include #include #include +#include #define REG_ISCR 0x00 #define REG_PHYCTL 0x04 @@ -47,6 +50,17 @@ #define SUNXI_AHB_INCRX_ALIGN_EN BIT(8) #define SUNXI_ULPI_BYPASS_EN BIT(0) +/* ISCR, Interface Status and Control bits */ +#define ISCR_ID_PULLUP_EN (1 << 17) +#define ISCR_DPDM_PULLUP_EN (1 << 16) +/* sunxi has the phy id/vbus pins not connected, so we use the force bits */ +#define ISCR_FORCE_ID_MASK (3 << 14) +#define ISCR_FORCE_ID_LOW (2 << 14) +#define ISCR_FORCE_ID_HIGH (3 << 14) +#define ISCR_FORCE_VBUS_MASK (3 << 12) +#define ISCR_FORCE_VBUS_LOW (2 << 12) +#define ISCR_FORCE_VBUS_HIGH (3 << 12) + /* Common Control Bits for Both PHYs */ #define PHY_PLL_BW 0x03 #define PHY_RES45_CAL_EN 0x0c @@ -63,6 +77,13 @@ #define MAX_PHYS 3 +/* + * Note do not raise the debounce time, we must report Vusb high within 100ms + * otherwise we get Vbus errors + */ +#define DEBOUNCE_TIME msecs_to_jiffies(50) +#define POLL_TIME msecs_to_jiffies(250) + struct sun4i_usb_phy_data { void __iomem *base; struct mutex mutex; @@ -74,13 +95,56 @@ struct sun4i_usb_phy_data { struct regulator *vbus; struct reset_control *reset; struct clk *clk; + bool regulator_on; int index; } phys[MAX_PHYS]; + /* phy0 / otg related variables */ + bool phy0_init; + bool phy0_poll; + struct gpio_desc *id_det_gpio; + struct gpio_desc *vbus_det_gpio; + int id_det_irq; + int vbus_det_irq; + int id_det; + int vbus_det; + struct delayed_work detect; }; #define to_sun4i_usb_phy_data(phy) \ container_of((phy), struct sun4i_usb_phy_data, phys[(phy)->index]) +static void sun4i_usb_phy0_update_iscr(struct phy *_phy, u32 clr, u32 set) +{ + struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); + struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); + u32 iscr; + + iscr = readl(data->base + REG_ISCR); + iscr &= ~clr; + iscr |= set; + writel(iscr, data->base + REG_ISCR); +} + +static void sun4i_usb_phy0_set_id_detect(struct phy *phy, u32 val) +{ + if (val) + val = ISCR_FORCE_ID_HIGH; + else + val = ISCR_FORCE_ID_LOW; + + sun4i_usb_phy0_update_iscr(phy, ISCR_FORCE_ID_MASK, val); +} + +static void sun4i_usb_phy0_set_vbus_detect(struct phy *phy, u32 val) +{ + if (val) + val = ISCR_FORCE_VBUS_HIGH; + else + val = ISCR_FORCE_VBUS_LOW; + + sun4i_usb_phy0_update_iscr(phy, ISCR_FORCE_VBUS_MASK, val); +} + static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data, int len) { @@ -171,12 +235,39 @@ static int sun4i_usb_phy_init(struct phy *_phy) sun4i_usb_phy_passby(phy, 1); + if (phy->index == 0) { + data->phy0_init = true; + + /* Enable pull-ups */ + sun4i_usb_phy0_update_iscr(_phy, 0, ISCR_DPDM_PULLUP_EN); + sun4i_usb_phy0_update_iscr(_phy, 0, ISCR_ID_PULLUP_EN); + + if (data->id_det_gpio) { + /* OTG mode, force ISCR and cable state updates */ + data->id_det = -1; + data->vbus_det = -1; + queue_delayed_work(system_wq, &data->detect, 0); + } else { + /* Host only mode */ + sun4i_usb_phy0_set_id_detect(_phy, 0); + sun4i_usb_phy0_set_vbus_detect(_phy, 1); + } + } + return 0; } static int sun4i_usb_phy_exit(struct phy *_phy) { struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); + struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); + + if (phy->index == 0) { + /* Disable pull-ups */ + sun4i_usb_phy0_update_iscr(_phy, ISCR_DPDM_PULLUP_EN, 0); + sun4i_usb_phy0_update_iscr(_phy, ISCR_ID_PULLUP_EN, 0); + data->phy0_init = false; + } sun4i_usb_phy_passby(phy, 0); reset_control_assert(phy->reset); @@ -188,20 +279,46 @@ static int sun4i_usb_phy_exit(struct phy *_phy) static int sun4i_usb_phy_power_on(struct phy *_phy) { struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); - int ret = 0; + struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); + int ret; + + if (!phy->vbus || phy->regulator_on) + return 0; + + /* For phy0 only turn on Vbus if we don't have an ext. Vbus */ + if (phy->index == 0 && data->vbus_det) + return 0; - if (phy->vbus) - ret = regulator_enable(phy->vbus); + ret = regulator_enable(phy->vbus); + if (ret) + return ret; - return ret; + phy->regulator_on = true; + + /* We must report Vbus high within OTG_TIME_A_WAIT_VRISE msec. */ + if (phy->index == 0 && data->phy0_poll) + mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); + + return 0; } static int sun4i_usb_phy_power_off(struct phy *_phy) { struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); + struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); + + if (!phy->vbus || !phy->regulator_on) + return 0; - if (phy->vbus) - regulator_disable(phy->vbus); + regulator_disable(phy->vbus); + phy->regulator_on = false; + + /* + * phy0 vbus typically slowly discharges, sometimes this causes the + * Vbus gpio to not trigger an edge irq on Vbus off, so force a rescan. + */ + if (phy->index == 0 && !data->phy0_poll) + mod_delayed_work(system_wq, &data->detect, POLL_TIME); return 0; } @@ -221,6 +338,49 @@ static struct phy_ops sun4i_usb_phy_ops = { .owner = THIS_MODULE, }; +static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) +{ + struct sun4i_usb_phy_data *data = + container_of(work, struct sun4i_usb_phy_data, detect.work); + struct phy *phy0 = data->phys[0].phy; + int id_det, vbus_det; + + id_det = gpiod_get_value_cansleep(data->id_det_gpio); + vbus_det = gpiod_get_value_cansleep(data->vbus_det_gpio); + + mutex_lock(&phy0->mutex); + + if (!data->phy0_init) { + mutex_unlock(&phy0->mutex); + return; + } + + if (id_det != data->id_det) { + sun4i_usb_phy0_set_id_detect(phy0, id_det); + data->id_det = id_det; + } + + if (vbus_det != data->vbus_det) { + sun4i_usb_phy0_set_vbus_detect(phy0, vbus_det); + data->vbus_det = vbus_det; + } + + mutex_unlock(&phy0->mutex); + + if (data->phy0_poll) + queue_delayed_work(system_wq, &data->detect, POLL_TIME); +} + +static irqreturn_t sun4i_usb_phy0_id_vbus_det_irq(int irq, void *dev_id) +{ + struct sun4i_usb_phy_data *data = dev_id; + + /* vbus or id changed, let the pins settle and then scan them */ + mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); + + return IRQ_HANDLED; +} + static struct phy *sun4i_usb_phy_xlate(struct device *dev, struct of_phandle_args *args) { @@ -232,6 +392,21 @@ static struct phy *sun4i_usb_phy_xlate(struct device *dev, return data->phys[args->args[0]].phy; } +static int sun4i_usb_phy_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sun4i_usb_phy_data *data = dev_get_drvdata(dev); + + if (data->id_det_irq >= 0) + devm_free_irq(dev, data->id_det_irq, data); + if (data->vbus_det_irq >= 0) + devm_free_irq(dev, data->vbus_det_irq, data); + + cancel_delayed_work_sync(&data->detect); + + return 0; +} + static int sun4i_usb_phy_probe(struct platform_device *pdev) { struct sun4i_usb_phy_data *data; @@ -240,13 +415,15 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) struct phy_provider *phy_provider; bool dedicated_clocks; struct resource *res; - int i; + int i, ret; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; mutex_init(&data->mutex); + INIT_DELAYED_WORK(&data->detect, sun4i_usb_phy0_id_vbus_det_scan); + dev_set_drvdata(dev, data); if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy")) data->num_phys = 2; @@ -269,6 +446,26 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) if (IS_ERR(data->base)) return PTR_ERR(data->base); + data->id_det_gpio = devm_gpiod_get(dev, "usb0_id_det", GPIOD_IN); + if (IS_ERR(data->id_det_gpio)) { + if (PTR_ERR(data->id_det_gpio) == -EPROBE_DEFER) + return -EPROBE_DEFER; + data->id_det_gpio = NULL; + } + + data->vbus_det_gpio = devm_gpiod_get(dev, "usb0_vbus_det", GPIOD_IN); + if (IS_ERR(data->vbus_det_gpio)) { + if (PTR_ERR(data->vbus_det_gpio) == -EPROBE_DEFER) + return -EPROBE_DEFER; + data->vbus_det_gpio = NULL; + } + + /* We either want both gpio pins or neither (when in host mode) */ + if (!data->id_det_gpio != !data->vbus_det_gpio) { + dev_err(dev, "failed to get id or vbus detect pin\n"); + return -ENODEV; + } + for (i = 0; i < data->num_phys; i++) { struct sun4i_usb_phy *phy = data->phys + i; char name[16]; @@ -318,10 +515,42 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) phy_set_drvdata(phy->phy, &data->phys[i]); } - dev_set_drvdata(dev, data); + data->id_det_irq = gpiod_to_irq(data->id_det_gpio); + data->vbus_det_irq = gpiod_to_irq(data->vbus_det_gpio); + if (data->id_det_irq < 0 || data->vbus_det_irq < 0) + data->phy0_poll = true; + + if (data->id_det_irq >= 0) { + ret = devm_request_irq(dev, data->id_det_irq, + sun4i_usb_phy0_id_vbus_det_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "usb0-id-det", data); + if (ret) { + dev_err(dev, "Err requesting id-det-irq: %d\n", ret); + return ret; + } + } + + if (data->vbus_det_irq >= 0) { + ret = devm_request_irq(dev, data->vbus_det_irq, + sun4i_usb_phy0_id_vbus_det_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "usb0-vbus-det", data); + if (ret) { + dev_err(dev, "Err requesting vbus-det-irq: %d\n", ret); + data->vbus_det_irq = -1; + sun4i_usb_phy_remove(pdev); /* Stop detect work */ + return ret; + } + } + phy_provider = devm_of_phy_provider_register(dev, sun4i_usb_phy_xlate); + if (IS_ERR(phy_provider)) { + sun4i_usb_phy_remove(pdev); /* Stop detect work */ + return PTR_ERR(phy_provider); + } - return PTR_ERR_OR_ZERO(phy_provider); + return 0; } static const struct of_device_id sun4i_usb_phy_of_match[] = { @@ -335,6 +564,7 @@ MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match); static struct platform_driver sun4i_usb_phy_driver = { .probe = sun4i_usb_phy_probe, + .remove = sun4i_usb_phy_remove, .driver = { .of_match_table = sun4i_usb_phy_of_match, .name = "sun4i-usb-phy", -- cgit v0.10.2 From 1a52abe6821da728b41187c6676b6ab7294e6e2c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 Jun 2015 14:37:46 +0200 Subject: phy-sun4i-usb: Add extcon support for the otg phy (phy0) The sunxi musb glue needs to know if a host or normal usb cable is plugged in, add extcon support so that the musb glue can monitor the host status. Signed-off-by: Hans de Goede Acked-by: Chanwoo Choi Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index e2f2a4d..c0c1ad2 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -208,6 +208,7 @@ config PHY_SUN4I_USB tristate "Allwinner sunxi SoC USB PHY driver" depends on ARCH_SUNXI && HAS_IOMEM && OF depends on RESET_CONTROLLER + depends on EXTCON select GENERIC_PHY help Enable this to support the transceiver that is part of Allwinner diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 37f52f7..a6ea2e6 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -99,6 +100,7 @@ struct sun4i_usb_phy_data { int index; } phys[MAX_PHYS]; /* phy0 / otg related variables */ + struct extcon_dev *extcon; bool phy0_init; bool phy0_poll; struct gpio_desc *id_det_gpio; @@ -343,7 +345,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) struct sun4i_usb_phy_data *data = container_of(work, struct sun4i_usb_phy_data, detect.work); struct phy *phy0 = data->phys[0].phy; - int id_det, vbus_det; + int id_det, vbus_det, id_notify = 0, vbus_notify = 0; id_det = gpiod_get_value_cansleep(data->id_det_gpio); vbus_det = gpiod_get_value_cansleep(data->vbus_det_gpio); @@ -358,15 +360,24 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) if (id_det != data->id_det) { sun4i_usb_phy0_set_id_detect(phy0, id_det); data->id_det = id_det; + id_notify = 1; } if (vbus_det != data->vbus_det) { sun4i_usb_phy0_set_vbus_detect(phy0, vbus_det); data->vbus_det = vbus_det; + vbus_notify = 1; } mutex_unlock(&phy0->mutex); + if (id_notify) + extcon_set_cable_state_(data->extcon, EXTCON_USB_HOST, + !id_det); + + if (vbus_notify) + extcon_set_cable_state_(data->extcon, EXTCON_USB, vbus_det); + if (data->phy0_poll) queue_delayed_work(system_wq, &data->detect, POLL_TIME); } @@ -407,6 +418,12 @@ static int sun4i_usb_phy_remove(struct platform_device *pdev) return 0; } +static const unsigned int sun4i_usb_phy0_cable[] = { + EXTCON_USB, + EXTCON_USB_HOST, + EXTCON_NONE, +}; + static int sun4i_usb_phy_probe(struct platform_device *pdev) { struct sun4i_usb_phy_data *data; @@ -466,6 +483,19 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) return -ENODEV; } + if (data->id_det_gpio) { + data->extcon = devm_extcon_dev_allocate(dev, + sun4i_usb_phy0_cable); + if (IS_ERR(data->extcon)) + return PTR_ERR(data->extcon); + + ret = devm_extcon_dev_register(dev, data->extcon); + if (ret) { + dev_err(dev, "failed to register extcon: %d\n", ret); + return ret; + } + } + for (i = 0; i < data->num_phys; i++) { struct sun4i_usb_phy *phy = data->phys + i; char name[16]; -- cgit v0.10.2 From 2846469631393a1cf150f17a99b8ca2b5772b255 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 Jun 2015 14:37:47 +0200 Subject: phy-sun4i-usb: Swap check for disconnect threshold Before this commit the code for determining the disconnect threshold was checking for "allwinner,sun4i-a10-usb-phy" or "allwinner,sun6i-a31-usb-phy" assuming that those where the exception and then newer SoCs would use a disconnect threshold of 2 like sun7i does. But it turns out that newer SoCs use a disconnect threshold of 3 and sun5i and sun7i are the exceptions, so check for those instead. Here are the settings from the various Allwinner SDK sources: sun4i-a10: USBC_Phy_Write(usbc_no, 0x2a, 3, 2); sun5i-a13: USBC_Phy_Write(usbc_no, 0x2a, 2, 2); sun6i-a31: USBC_Phy_Write(usbc_no, 0x2a, 3, 2); sun7i-a20: USBC_Phy_Write(usbc_no, 0x2a, 2, 2); sun8i-a23: USBC_Phy_Write(usbc_no, 0x2a, 3, 2); sun8i-h3: USBC_Phy_Write(usbc_no, 0x2a, 3, 2); sun9i-a80: USBC_Phy_Write(usbc_no, 0x2a, 3, 2); Note this commit makes no functional changes as currently we only support sun4i - sun7i. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index a6ea2e6..50ecab9 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -447,11 +447,11 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) else data->num_phys = 3; - if (of_device_is_compatible(np, "allwinner,sun4i-a10-usb-phy") || - of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy")) - data->disc_thresh = 3; - else + if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy") || + of_device_is_compatible(np, "allwinner,sun7i-a20-usb-phy")) data->disc_thresh = 2; + else + data->disc_thresh = 3; if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy")) dedicated_clocks = true; -- cgit v0.10.2 From 123dfdbcfaf5eb8753cd6293ab50c41e9b8e9ebf Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 Jun 2015 14:37:48 +0200 Subject: phy-sun4i-usb: Add support for the usb-phys on the sun8i-a23 SoC The usb-phys on the sun8i-a23 SoC have the same setup wrt clocks as on the sun6i-a31 SoC, but there are only 2 instead of 3 like on the sun5i-a13 SoC. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt index 557fa99..f0c640a 100644 --- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt @@ -7,6 +7,7 @@ Required properties: * allwinner,sun5i-a13-usb-phy * allwinner,sun6i-a31-usb-phy * allwinner,sun7i-a20-usb-phy + * allwinner,sun8i-a23-usb-phy - reg : a list of offset + length pairs - reg-names : * "phy_ctrl" @@ -17,6 +18,7 @@ Required properties: - clock-names : * "usb_phy" for sun4i, sun5i or sun7i * "usb0_phy", "usb1_phy" and "usb2_phy" for sun6i + * "usb0_phy", "usb1_phy" for sun8i - resets : a list of phandle + reset specifier pairs - reset-names : * "usb0_reset" diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 50ecab9..00424dd 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -442,7 +442,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&data->detect, sun4i_usb_phy0_id_vbus_det_scan); dev_set_drvdata(dev, data); - if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy")) + if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy") || + of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy")) data->num_phys = 2; else data->num_phys = 3; @@ -453,7 +454,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) else data->disc_thresh = 3; - if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy")) + if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy") || + of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy")) dedicated_clocks = true; else dedicated_clocks = false; @@ -588,6 +590,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = { { .compatible = "allwinner,sun5i-a13-usb-phy" }, { .compatible = "allwinner,sun6i-a31-usb-phy" }, { .compatible = "allwinner,sun7i-a20-usb-phy" }, + { .compatible = "allwinner,sun8i-a23-usb-phy" }, { }, }; MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match); -- cgit v0.10.2 From fc1f45ed3043da3aa901e88a9ef0995bbd320698 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 Jun 2015 14:37:49 +0200 Subject: phy-sun4i-usb: Add support for the usb-phys on the sun8i-a33 SoC The usb-phys on the sun8i-a33 SoC are mostly the same as sun8i-a23 but for some reason (hw bug?) the phyctl register was moved to a different address and is not initialized to 0 on reset. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt index f0c640a..5f48979 100644 --- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt @@ -8,6 +8,7 @@ Required properties: * allwinner,sun6i-a31-usb-phy * allwinner,sun7i-a20-usb-phy * allwinner,sun8i-a23-usb-phy + * allwinner,sun8i-a33-usb-phy - reg : a list of offset + length pairs - reg-names : * "phy_ctrl" diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 00424dd..ddc3995 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -40,9 +40,10 @@ #include #define REG_ISCR 0x00 -#define REG_PHYCTL 0x04 +#define REG_PHYCTL_A10 0x04 #define REG_PHYBIST 0x08 #define REG_PHYTUNE 0x0c +#define REG_PHYCTL_A33 0x10 #define PHYCTL_DATA BIT(7) @@ -90,6 +91,7 @@ struct sun4i_usb_phy_data { struct mutex mutex; int num_phys; u32 disc_thresh; + bool has_a33_phyctl; struct sun4i_usb_phy { struct phy *phy; void __iomem *pmu; @@ -152,37 +154,46 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data, { struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy); u32 temp, usbc_bit = BIT(phy->index * 2); + void *phyctl; int i; mutex_lock(&phy_data->mutex); + if (phy_data->has_a33_phyctl) { + phyctl = phy_data->base + REG_PHYCTL_A33; + /* A33 needs us to set phyctl to 0 explicitly */ + writel(0, phyctl); + } else { + phyctl = phy_data->base + REG_PHYCTL_A10; + } + for (i = 0; i < len; i++) { - temp = readl(phy_data->base + REG_PHYCTL); + temp = readl(phyctl); /* clear the address portion */ temp &= ~(0xff << 8); /* set the address */ temp |= ((addr + i) << 8); - writel(temp, phy_data->base + REG_PHYCTL); + writel(temp, phyctl); /* set the data bit and clear usbc bit*/ - temp = readb(phy_data->base + REG_PHYCTL); + temp = readb(phyctl); if (data & 0x1) temp |= PHYCTL_DATA; else temp &= ~PHYCTL_DATA; temp &= ~usbc_bit; - writeb(temp, phy_data->base + REG_PHYCTL); + writeb(temp, phyctl); /* pulse usbc_bit */ - temp = readb(phy_data->base + REG_PHYCTL); + temp = readb(phyctl); temp |= usbc_bit; - writeb(temp, phy_data->base + REG_PHYCTL); + writeb(temp, phyctl); - temp = readb(phy_data->base + REG_PHYCTL); + temp = readb(phyctl); temp &= ~usbc_bit; - writeb(temp, phy_data->base + REG_PHYCTL); + writeb(temp, phyctl); data >>= 1; } @@ -443,7 +454,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) dev_set_drvdata(dev, data); if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy") || - of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy")) + of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy") || + of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy")) data->num_phys = 2; else data->num_phys = 3; @@ -455,11 +467,15 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) data->disc_thresh = 3; if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy") || - of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy")) + of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy") || + of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy")) dedicated_clocks = true; else dedicated_clocks = false; + if (of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy")) + data->has_a33_phyctl = true; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl"); data->base = devm_ioremap_resource(dev, res); if (IS_ERR(data->base)) @@ -591,6 +607,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = { { .compatible = "allwinner,sun6i-a31-usb-phy" }, { .compatible = "allwinner,sun7i-a20-usb-phy" }, { .compatible = "allwinner,sun8i-a23-usb-phy" }, + { .compatible = "allwinner,sun8i-a33-usb-phy" }, { }, }; MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match); -- cgit v0.10.2 From 1aedf3a7a47b8bbd38c147eeb0c83816c5590215 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 Jun 2015 14:37:50 +0200 Subject: phy-sun4i-usb: Add support for boards with broken Vusb-detection On some boards we cannot detect the presence of an external Vusb, because e.g. the 5V of the otg connector is directly connected to the 5V of the board, and thus is always high. This commit adds support for using such boards by only looking at the id-detection pin. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index ddc3995..4ba9856 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -22,6 +22,7 @@ */ #include +#include #include #include #include @@ -309,7 +310,7 @@ static int sun4i_usb_phy_power_on(struct phy *_phy) phy->regulator_on = true; /* We must report Vbus high within OTG_TIME_A_WAIT_VRISE msec. */ - if (phy->index == 0 && data->phy0_poll) + if (phy->index == 0 && data->vbus_det_gpio && data->phy0_poll) mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); return 0; @@ -330,7 +331,7 @@ static int sun4i_usb_phy_power_off(struct phy *_phy) * phy0 vbus typically slowly discharges, sometimes this causes the * Vbus gpio to not trigger an edge irq on Vbus off, so force a rescan. */ - if (phy->index == 0 && !data->phy0_poll) + if (phy->index == 0 && data->vbus_det_gpio && !data->phy0_poll) mod_delayed_work(system_wq, &data->detect, POLL_TIME); return 0; @@ -359,7 +360,10 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) int id_det, vbus_det, id_notify = 0, vbus_notify = 0; id_det = gpiod_get_value_cansleep(data->id_det_gpio); - vbus_det = gpiod_get_value_cansleep(data->vbus_det_gpio); + if (data->vbus_det_gpio) + vbus_det = gpiod_get_value_cansleep(data->vbus_det_gpio); + else + vbus_det = 1; /* Report vbus as high */ mutex_lock(&phy0->mutex); @@ -369,6 +373,16 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) } if (id_det != data->id_det) { + /* + * When a host cable (id == 0) gets plugged in on systems + * without vbus detection report vbus low for long enough for + * the musb-ip to end the current device session. + */ + if (!data->vbus_det_gpio && id_det == 0) { + sun4i_usb_phy0_set_vbus_detect(phy0, 0); + msleep(200); + sun4i_usb_phy0_set_vbus_detect(phy0, 1); + } sun4i_usb_phy0_set_id_detect(phy0, id_det); data->id_det = id_det; id_notify = 1; @@ -382,9 +396,22 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) mutex_unlock(&phy0->mutex); - if (id_notify) + if (id_notify) { extcon_set_cable_state_(data->extcon, EXTCON_USB_HOST, !id_det); + /* + * When a host cable gets unplugged (id == 1) on systems + * without vbus detection report vbus low for long enough to + * the musb-ip to end the current host session. + */ + if (!data->vbus_det_gpio && id_det == 1) { + mutex_lock(&phy0->mutex); + sun4i_usb_phy0_set_vbus_detect(phy0, 0); + msleep(1000); + sun4i_usb_phy0_set_vbus_detect(phy0, 1); + mutex_unlock(&phy0->mutex); + } + } if (vbus_notify) extcon_set_cable_state_(data->extcon, EXTCON_USB, vbus_det); @@ -495,9 +522,9 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) data->vbus_det_gpio = NULL; } - /* We either want both gpio pins or neither (when in host mode) */ - if (!data->id_det_gpio != !data->vbus_det_gpio) { - dev_err(dev, "failed to get id or vbus detect pin\n"); + /* vbus_det without id_det makes no sense, and is not supported */ + if (data->vbus_det_gpio && !data->id_det_gpio) { + dev_err(dev, "usb0_id_det missing or invalid\n"); return -ENODEV; } @@ -565,7 +592,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) data->id_det_irq = gpiod_to_irq(data->id_det_gpio); data->vbus_det_irq = gpiod_to_irq(data->vbus_det_gpio); - if (data->id_det_irq < 0 || data->vbus_det_irq < 0) + if ((data->id_det_gpio && data->id_det_irq < 0) || + (data->vbus_det_gpio && data->vbus_det_irq < 0)) data->phy0_poll = true; if (data->id_det_irq >= 0) { -- cgit v0.10.2 From 8665c18bece7965c3690ac3824bef2f97bae3d71 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 Jun 2015 14:37:51 +0200 Subject: phy-sun4i-usb: Add support for monitoring vbus via a power-supply On some boards there is no vbus_det gpio pin, instead vbus-detection for otg can be done via the pmic. This commit adds support for monitoring vbus_det via the power_supply exported by the pmic, enabling support for otg on these boards. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt index 5f48979..0cebf74 100644 --- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt @@ -29,6 +29,7 @@ Required properties: Optional properties: - usb0_id_det-gpios : gpio phandle for reading the otg id pin value - usb0_vbus_det-gpios : gpio phandle for detecting the presence of usb0 vbus +- usb0_vbus_power-supply: power-supply phandle for usb0 vbus presence detect - usb0_vbus-supply : regulator phandle for controller usb0 vbus - usb1_vbus-supply : regulator phandle for controller usb1 vbus - usb2_vbus-supply : regulator phandle for controller usb2 vbus diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index c0c1ad2..0fe9bff 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -209,6 +209,7 @@ config PHY_SUN4I_USB depends on ARCH_SUNXI && HAS_IOMEM && OF depends on RESET_CONTROLLER depends on EXTCON + depends on POWER_SUPPLY select GENERIC_PHY help Enable this to support the transceiver that is part of Allwinner diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 4ba9856..5138843 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -108,6 +109,9 @@ struct sun4i_usb_phy_data { bool phy0_poll; struct gpio_desc *id_det_gpio; struct gpio_desc *vbus_det_gpio; + struct power_supply *vbus_power_supply; + struct notifier_block vbus_power_nb; + bool vbus_power_nb_registered; int id_det_irq; int vbus_det_irq; int id_det; @@ -352,6 +356,30 @@ static struct phy_ops sun4i_usb_phy_ops = { .owner = THIS_MODULE, }; +static int sun4i_usb_phy0_get_vbus_det(struct sun4i_usb_phy_data *data) +{ + if (data->vbus_det_gpio) + return gpiod_get_value_cansleep(data->vbus_det_gpio); + + if (data->vbus_power_supply) { + union power_supply_propval val; + int r; + + r = power_supply_get_property(data->vbus_power_supply, + POWER_SUPPLY_PROP_PRESENT, &val); + if (r == 0) + return val.intval; + } + + /* Fallback: report vbus as high */ + return 1; +} + +static bool sun4i_usb_phy0_have_vbus_det(struct sun4i_usb_phy_data *data) +{ + return data->vbus_det_gpio || data->vbus_power_supply; +} + static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) { struct sun4i_usb_phy_data *data = @@ -360,10 +388,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) int id_det, vbus_det, id_notify = 0, vbus_notify = 0; id_det = gpiod_get_value_cansleep(data->id_det_gpio); - if (data->vbus_det_gpio) - vbus_det = gpiod_get_value_cansleep(data->vbus_det_gpio); - else - vbus_det = 1; /* Report vbus as high */ + vbus_det = sun4i_usb_phy0_get_vbus_det(data); mutex_lock(&phy0->mutex); @@ -378,7 +403,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) * without vbus detection report vbus low for long enough for * the musb-ip to end the current device session. */ - if (!data->vbus_det_gpio && id_det == 0) { + if (!sun4i_usb_phy0_have_vbus_det(data) && id_det == 0) { sun4i_usb_phy0_set_vbus_detect(phy0, 0); msleep(200); sun4i_usb_phy0_set_vbus_detect(phy0, 1); @@ -404,7 +429,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) * without vbus detection report vbus low for long enough to * the musb-ip to end the current host session. */ - if (!data->vbus_det_gpio && id_det == 1) { + if (!sun4i_usb_phy0_have_vbus_det(data) && id_det == 1) { mutex_lock(&phy0->mutex); sun4i_usb_phy0_set_vbus_detect(phy0, 0); msleep(1000); @@ -430,6 +455,20 @@ static irqreturn_t sun4i_usb_phy0_id_vbus_det_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static int sun4i_usb_phy0_vbus_notify(struct notifier_block *nb, + unsigned long val, void *v) +{ + struct sun4i_usb_phy_data *data = + container_of(nb, struct sun4i_usb_phy_data, vbus_power_nb); + struct power_supply *psy = v; + + /* Properties on the vbus_power_supply changed, scan vbus_det */ + if (val == PSY_EVENT_PROP_CHANGED && psy == data->vbus_power_supply) + mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); + + return NOTIFY_OK; +} + static struct phy *sun4i_usb_phy_xlate(struct device *dev, struct of_phandle_args *args) { @@ -446,6 +485,8 @@ static int sun4i_usb_phy_remove(struct platform_device *pdev) struct device *dev = &pdev->dev; struct sun4i_usb_phy_data *data = dev_get_drvdata(dev); + if (data->vbus_power_nb_registered) + power_supply_unreg_notifier(&data->vbus_power_nb); if (data->id_det_irq >= 0) devm_free_irq(dev, data->id_det_irq, data); if (data->vbus_det_irq >= 0) @@ -522,8 +563,18 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) data->vbus_det_gpio = NULL; } + if (of_find_property(np, "usb0_vbus_power-supply", NULL)) { + data->vbus_power_supply = devm_power_supply_get_by_phandle(dev, + "usb0_vbus_power-supply"); + if (IS_ERR(data->vbus_power_supply)) + return PTR_ERR(data->vbus_power_supply); + + if (!data->vbus_power_supply) + return -EPROBE_DEFER; + } + /* vbus_det without id_det makes no sense, and is not supported */ - if (data->vbus_det_gpio && !data->id_det_gpio) { + if (sun4i_usb_phy0_have_vbus_det(data) && !data->id_det_gpio) { dev_err(dev, "usb0_id_det missing or invalid\n"); return -ENODEV; } @@ -620,6 +671,17 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) } } + if (data->vbus_power_supply) { + data->vbus_power_nb.notifier_call = sun4i_usb_phy0_vbus_notify; + data->vbus_power_nb.priority = 0; + ret = power_supply_reg_notifier(&data->vbus_power_nb); + if (ret) { + sun4i_usb_phy_remove(pdev); /* Stop detect work */ + return ret; + } + data->vbus_power_nb_registered = true; + } + phy_provider = devm_of_phy_provider_register(dev, sun4i_usb_phy_xlate); if (IS_ERR(phy_provider)) { sun4i_usb_phy_remove(pdev); /* Stop detect work */ -- cgit v0.10.2 From 2c89e41f03fa9798405e07bae95760fc86a1068f Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 24 Jun 2015 10:40:53 +0200 Subject: phy: berlin: .owner field is setup by core There was big cleanup in past to remove this unneeded setting. Signed-off-by: Michal Simek Acked-by: Antoine Tenart Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c index c6fc95b..d7431f6 100644 --- a/drivers/phy/phy-berlin-usb.c +++ b/drivers/phy/phy-berlin-usb.c @@ -207,7 +207,6 @@ static struct platform_driver phy_berlin_usb_driver = { .probe = phy_berlin_usb_probe, .driver = { .name = "phy-berlin-usb", - .owner = THIS_MODULE, .of_match_table = phy_berlin_sata_of_match, }, }; -- cgit v0.10.2 From 456dedc9e70d2d99b928d215baa881c03369c613 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 24 Jun 2015 10:40:54 +0200 Subject: phy: berlin: Do not use sata name in usb phy driver copy and paste error from berlin sata phy driver. Signed-off-by: Michal Simek Acked-by: Antoine Tenart Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c index d7431f6..762f0fb 100644 --- a/drivers/phy/phy-berlin-usb.c +++ b/drivers/phy/phy-berlin-usb.c @@ -152,7 +152,7 @@ static struct phy_ops phy_berlin_usb_ops = { .owner = THIS_MODULE, }; -static const struct of_device_id phy_berlin_sata_of_match[] = { +static const struct of_device_id phy_berlin_usb_of_match[] = { { .compatible = "marvell,berlin2-usb-phy", .data = &phy_berlin_pll_dividers[0], @@ -163,12 +163,12 @@ static const struct of_device_id phy_berlin_sata_of_match[] = { }, { }, }; -MODULE_DEVICE_TABLE(of, phy_berlin_sata_of_match); +MODULE_DEVICE_TABLE(of, phy_berlin_usb_of_match); static int phy_berlin_usb_probe(struct platform_device *pdev) { const struct of_device_id *match = - of_match_device(phy_berlin_sata_of_match, &pdev->dev); + of_match_device(phy_berlin_usb_of_match, &pdev->dev); struct phy_berlin_usb_priv *priv; struct resource *res; struct phy *phy; @@ -207,7 +207,7 @@ static struct platform_driver phy_berlin_usb_driver = { .probe = phy_berlin_usb_probe, .driver = { .name = "phy-berlin-usb", - .of_match_table = phy_berlin_sata_of_match, + .of_match_table = phy_berlin_usb_of_match, }, }; module_platform_driver(phy_berlin_usb_driver); -- cgit v0.10.2 From 2508aaed39c94f61c11ee66787ed4702c8afbc67 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 24 Jun 2015 10:40:55 +0200 Subject: phy: berlin: Trivial coding style cleanup Remove unneeded space after tab. Signed-off-by: Michal Simek Acked-by: Antoine Tenart Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c index 762f0fb..0fe0d81 100644 --- a/drivers/phy/phy-berlin-usb.c +++ b/drivers/phy/phy-berlin-usb.c @@ -208,7 +208,7 @@ static struct platform_driver phy_berlin_usb_driver = { .driver = { .name = "phy-berlin-usb", .of_match_table = phy_berlin_usb_of_match, - }, + }, }; module_platform_driver(phy_berlin_usb_driver); -- cgit v0.10.2 From 511fdecc9bc98c7b498e72b0dfe8f34481334e4c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 14:38:10 +0900 Subject: phy: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-armada375-usb2.c b/drivers/phy/phy-armada375-usb2.c index 8ccc395..39c7d21 100644 --- a/drivers/phy/phy-armada375-usb2.c +++ b/drivers/phy/phy-armada375-usb2.c @@ -149,7 +149,6 @@ static struct platform_driver armada375_usb_phy_driver = { .driver = { .of_match_table = of_usb_cluster_table, .name = "armada-375-usb-cluster", - .owner = THIS_MODULE, } }; module_platform_driver(armada375_usb_phy_driver); -- cgit v0.10.2 From 219bf1599e1f6c0cbdc2fe775a97c00bf1ae392d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:26:27 +0900 Subject: phy: Drop owner assignment from platform_driver platform_driver does not need to set an owner because platform_driver_register() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c index 5e257ef..677c290 100644 --- a/drivers/phy/phy-miphy28lp.c +++ b/drivers/phy/phy-miphy28lp.c @@ -1268,7 +1268,6 @@ static struct platform_driver miphy28lp_driver = { .probe = miphy28lp_probe, .driver = { .name = "miphy28lp-phy", - .owner = THIS_MODULE, .of_match_table = miphy28lp_of_match, } }; diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.c b/drivers/phy/phy-qcom-ufs-qmp-14nm.c index f5fc50a..e1eea1b 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-14nm.c +++ b/drivers/phy/phy-qcom-ufs-qmp-14nm.c @@ -191,7 +191,6 @@ static struct platform_driver ufs_qcom_phy_qmp_14nm_driver = { .driver = { .of_match_table = ufs_qcom_phy_qmp_14nm_of_match, .name = "ufs_qcom_phy_qmp_14nm", - .owner = THIS_MODULE, }, }; diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c b/drivers/phy/phy-qcom-ufs-qmp-20nm.c index 8332f96..fde8c87 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-20nm.c +++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c @@ -247,7 +247,6 @@ static struct platform_driver ufs_qcom_phy_qmp_20nm_driver = { .driver = { .of_match_table = ufs_qcom_phy_qmp_20nm_of_match, .name = "ufs_qcom_phy_qmp_20nm", - .owner = THIS_MODULE, }, }; diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/phy-rockchip-usb.c index 7d4c336..bf78721 100644 --- a/drivers/phy/phy-rockchip-usb.c +++ b/drivers/phy/phy-rockchip-usb.c @@ -146,7 +146,6 @@ static struct platform_driver rockchip_usb_driver = { .probe = rockchip_usb_phy_probe, .driver = { .name = "rockchip-usb-phy", - .owner = THIS_MODULE, .of_match_table = rockchip_usb_phy_dt_ids, }, }; -- cgit v0.10.2 From 5ea75095fe6d683900ccc674fcac375e7df68005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 8 Jun 2015 08:20:05 +0200 Subject: usb: gadget: nokia: Add mass storage driver to g_nokia MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds removable mass storage support to g_nokia gadget (for N900). It means that at runtime block device can be exported or unexported. So it does not export anything by default and thus allows to use MyDocs partition as before... [ balbi@ti.com: make it build ] Signed-off-by: Pali Rohár Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig index d5a7102..ddef41f 100644 --- a/drivers/usb/gadget/legacy/Kconfig +++ b/drivers/usb/gadget/legacy/Kconfig @@ -346,6 +346,7 @@ config USB_G_NOKIA select USB_F_OBEX select USB_F_PHONET select USB_F_ECM + select USB_F_MASS_STORAGE help The Nokia composite gadget provides support for acm, obex and phonet in only one composite gadget driver. diff --git a/drivers/usb/gadget/legacy/nokia.c b/drivers/usb/gadget/legacy/nokia.c index 4bb498a..e3791b9 100644 --- a/drivers/usb/gadget/legacy/nokia.c +++ b/drivers/usb/gadget/legacy/nokia.c @@ -24,6 +24,7 @@ #include "u_phonet.h" #include "u_ecm.h" #include "gadget_chips.h" +#include "f_mass_storage.h" /* Defines */ @@ -34,6 +35,29 @@ USB_GADGET_COMPOSITE_OPTIONS(); USB_ETHERNET_MODULE_PARAMETERS(); +static struct fsg_module_parameters fsg_mod_data = { + .stall = 0, + .luns = 2, + .removable_count = 2, + .removable = { 1, 1, }, +}; + +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; + +#else + +/* + * Number of buffers we will use. + * 2 is usually enough for good buffering pipeline + */ +#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS + +#endif /* CONFIG_USB_DEBUG */ + +FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); + #define NOKIA_VENDOR_ID 0x0421 /* Nokia */ #define NOKIA_PRODUCT_ID 0x01c8 /* Nokia Gadget */ @@ -94,6 +118,8 @@ static struct usb_function *f_obex1_cfg2; static struct usb_function *f_obex2_cfg2; static struct usb_function *f_phonet_cfg1; static struct usb_function *f_phonet_cfg2; +static struct usb_function *f_msg_cfg1; +static struct usb_function *f_msg_cfg2; static struct usb_configuration nokia_config_500ma_driver = { @@ -117,6 +143,7 @@ static struct usb_function_instance *fi_ecm; static struct usb_function_instance *fi_obex1; static struct usb_function_instance *fi_obex2; static struct usb_function_instance *fi_phonet; +static struct usb_function_instance *fi_msg; static int nokia_bind_config(struct usb_configuration *c) { @@ -125,6 +152,8 @@ static int nokia_bind_config(struct usb_configuration *c) struct usb_function *f_obex1 = NULL; struct usb_function *f_ecm; struct usb_function *f_obex2 = NULL; + struct usb_function *f_msg; + struct fsg_opts *fsg_opts; int status = 0; int obex1_stat = -1; int obex2_stat = -1; @@ -160,6 +189,12 @@ static int nokia_bind_config(struct usb_configuration *c) goto err_get_ecm; } + f_msg = usb_get_function(fi_msg); + if (IS_ERR(f_msg)) { + status = PTR_ERR(f_msg); + goto err_get_msg; + } + if (!IS_ERR_OR_NULL(f_phonet)) { phonet_stat = usb_add_function(c, f_phonet); if (phonet_stat) @@ -187,21 +222,36 @@ static int nokia_bind_config(struct usb_configuration *c) pr_debug("could not bind ecm config %d\n", status); goto err_ecm; } + + fsg_opts = fsg_opts_from_func_inst(fi_msg); + + status = fsg_common_run_thread(fsg_opts->common); + if (status) + goto err_msg; + + status = usb_add_function(c, f_msg); + if (status) + goto err_msg; + if (c == &nokia_config_500ma_driver) { f_acm_cfg1 = f_acm; f_ecm_cfg1 = f_ecm; f_phonet_cfg1 = f_phonet; f_obex1_cfg1 = f_obex1; f_obex2_cfg1 = f_obex2; + f_msg_cfg1 = f_msg; } else { f_acm_cfg2 = f_acm; f_ecm_cfg2 = f_ecm; f_phonet_cfg2 = f_phonet; f_obex1_cfg2 = f_obex1; f_obex2_cfg2 = f_obex2; + f_msg_cfg2 = f_msg; } return status; +err_msg: + usb_remove_function(c, f_ecm); err_ecm: usb_remove_function(c, f_acm); err_conf: @@ -211,6 +261,8 @@ err_conf: usb_remove_function(c, f_obex1); if (!phonet_stat) usb_remove_function(c, f_phonet); + usb_put_function(f_msg); +err_get_msg: usb_put_function(f_ecm); err_get_ecm: usb_put_function(f_acm); @@ -227,6 +279,8 @@ err_get_acm: static int nokia_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; + struct fsg_opts *fsg_opts; + struct fsg_config fsg_config; int status; status = usb_string_ids_tab(cdev, strings_dev); @@ -267,11 +321,46 @@ static int nokia_bind(struct usb_composite_dev *cdev) goto err_acm_inst; } + fi_msg = usb_get_function_instance("mass_storage"); + if (IS_ERR(fi_msg)) { + status = PTR_ERR(fi_msg); + goto err_ecm_inst; + } + + /* set up mass storage function */ + fsg_config_from_params(&fsg_config, &fsg_mod_data, fsg_num_buffers); + fsg_config.vendor_name = "Nokia"; + fsg_config.product_name = "N900"; + + fsg_opts = fsg_opts_from_func_inst(fi_msg); + fsg_opts->no_configfs = true; + + status = fsg_common_set_num_buffers(fsg_opts->common, fsg_num_buffers); + if (status) + goto err_msg_inst; + + status = fsg_common_set_nluns(fsg_opts->common, fsg_config.nluns); + if (status) + goto err_msg_buf; + + status = fsg_common_set_cdev(fsg_opts->common, cdev, fsg_config.can_stall); + if (status) + goto err_msg_set_nluns; + + fsg_common_set_sysfs(fsg_opts->common, true); + + status = fsg_common_create_luns(fsg_opts->common, &fsg_config); + if (status) + goto err_msg_set_nluns; + + fsg_common_set_inquiry_string(fsg_opts->common, fsg_config.vendor_name, + fsg_config.product_name); + /* finally register the configuration */ status = usb_add_config(cdev, &nokia_config_500ma_driver, nokia_bind_config); if (status < 0) - goto err_ecm_inst; + goto err_msg_set_cdev; status = usb_add_config(cdev, &nokia_config_100ma_driver, nokia_bind_config); @@ -292,6 +381,14 @@ err_put_cfg1: if (!IS_ERR_OR_NULL(f_phonet_cfg1)) usb_put_function(f_phonet_cfg1); usb_put_function(f_ecm_cfg1); +err_msg_set_cdev: + fsg_common_remove_luns(fsg_opts->common); +err_msg_set_nluns: + fsg_common_free_luns(fsg_opts->common); +err_msg_buf: + fsg_common_free_buffers(fsg_opts->common); +err_msg_inst: + usb_put_function_instance(fi_msg); err_ecm_inst: usb_put_function_instance(fi_ecm); err_acm_inst: @@ -325,7 +422,10 @@ static int nokia_unbind(struct usb_composite_dev *cdev) usb_put_function(f_acm_cfg2); usb_put_function(f_ecm_cfg1); usb_put_function(f_ecm_cfg2); + usb_put_function(f_msg_cfg1); + usb_put_function(f_msg_cfg2); + usb_put_function_instance(fi_msg); usb_put_function_instance(fi_ecm); if (!IS_ERR(fi_obex2)) usb_put_function_instance(fi_obex2); -- cgit v0.10.2 From 5a350d53f4c4784cf6bb4d94e7b8d76ca4f96e9f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 29 Jun 2015 20:17:22 -0500 Subject: usb: dwc2: gadget: use | instead of + for bitmasks It's just a lot clearer to use | operator instead of + operator. Caught by coccicheck: " drivers/usb/dwc2/gadget.c:2883:26-27: WARNING: sum of probable bitmasks, consider | " Cc: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 4d47b7c..731b13d 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2880,7 +2880,7 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) epctl = readl(hs->regs + epreg); if (value) { - epctl |= DXEPCTL_STALL + DXEPCTL_SNAK; + epctl |= DXEPCTL_STALL | DXEPCTL_SNAK; if (epctl & DXEPCTL_EPENA) epctl |= DXEPCTL_EPDIS; } else { -- cgit v0.10.2 From e4f7566754675b2fd89ed32eee867d5f19bac934 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 30 Jun 2015 12:46:07 -0500 Subject: usb: dwc3: omap: drop dev_dbg() usage Some of the messages were plain unnecessary and some were actually errors. Fix it all up. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 6b486a3..e8a09a8 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -225,12 +225,10 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, switch (status) { case OMAP_DWC3_ID_GROUND: - dev_dbg(omap->dev, "ID GND\n"); - if (omap->vbus_reg) { ret = regulator_enable(omap->vbus_reg); if (ret) { - dev_dbg(omap->dev, "regulator enable failed\n"); + dev_err(omap->dev, "regulator enable failed\n"); return; } } @@ -245,8 +243,6 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, break; case OMAP_DWC3_VBUS_VALID: - dev_dbg(omap->dev, "VBUS Connect\n"); - val = dwc3_omap_read_utmi_ctrl(omap); val &= ~USBOTGSS_UTMI_OTG_CTRL_SESSEND; val |= USBOTGSS_UTMI_OTG_CTRL_IDDIG @@ -261,8 +257,6 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, regulator_disable(omap->vbus_reg); case OMAP_DWC3_VBUS_OFF: - dev_dbg(omap->dev, "VBUS Disconnect\n"); - val = dwc3_omap_read_utmi_ctrl(omap); val &= ~(USBOTGSS_UTMI_OTG_CTRL_SESSVALID | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID @@ -273,7 +267,7 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, break; default: - dev_dbg(omap->dev, "invalid state\n"); + dev_WARN(omap->dev, "invalid state\n"); } } @@ -284,37 +278,8 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) reg = dwc3_omap_read_irqmisc_status(omap); - if (reg & USBOTGSS_IRQMISC_DMADISABLECLR) { - dev_dbg(omap->dev, "DMA Disable was Cleared\n"); + if (reg & USBOTGSS_IRQMISC_DMADISABLECLR) omap->dma_status = false; - } - - if (reg & USBOTGSS_IRQMISC_OEVT) - dev_dbg(omap->dev, "OTG Event\n"); - - if (reg & USBOTGSS_IRQMISC_DRVVBUS_RISE) - dev_dbg(omap->dev, "DRVVBUS Rise\n"); - - if (reg & USBOTGSS_IRQMISC_CHRGVBUS_RISE) - dev_dbg(omap->dev, "CHRGVBUS Rise\n"); - - if (reg & USBOTGSS_IRQMISC_DISCHRGVBUS_RISE) - dev_dbg(omap->dev, "DISCHRGVBUS Rise\n"); - - if (reg & USBOTGSS_IRQMISC_IDPULLUP_RISE) - dev_dbg(omap->dev, "IDPULLUP Rise\n"); - - if (reg & USBOTGSS_IRQMISC_DRVVBUS_FALL) - dev_dbg(omap->dev, "DRVVBUS Fall\n"); - - if (reg & USBOTGSS_IRQMISC_CHRGVBUS_FALL) - dev_dbg(omap->dev, "CHRGVBUS Fall\n"); - - if (reg & USBOTGSS_IRQMISC_DISCHRGVBUS_FALL) - dev_dbg(omap->dev, "DISCHRGVBUS Fall\n"); - - if (reg & USBOTGSS_IRQMISC_IDPULLUP_FALL) - dev_dbg(omap->dev, "IDPULLUP Fall\n"); dwc3_omap_write_irqmisc_status(omap, reg); @@ -434,7 +399,7 @@ static void dwc3_omap_set_utmi_mode(struct dwc3_omap *omap) reg &= ~USBOTGSS_UTMI_OTG_CTRL_SW_MODE; break; default: - dev_dbg(omap->dev, "UNKNOWN utmi mode %d\n", utmi_mode); + dev_WARN(omap->dev, "UNKNOWN utmi mode %d\n", utmi_mode); } dwc3_omap_write_utmi_ctrl(omap, reg); -- cgit v0.10.2 From 9ff0fdca3b628d3f8719237cbc8f148379527108 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 30 Jun 2015 12:46:53 -0500 Subject: usb: dwc3: keystone: convert dev_dbg() to dev_err() that's an error condition, not a debugging message. Let's promote it appropriately. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c index fe3b933..2be268d 100644 --- a/drivers/usb/dwc3/dwc3-keystone.c +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -115,7 +115,7 @@ static int kdwc3_probe(struct platform_device *pdev) error = clk_prepare_enable(kdwc->clk); if (error < 0) { - dev_dbg(kdwc->dev, "unable to enable usb clock, err %d\n", + dev_err(kdwc->dev, "unable to enable usb clock, error %d\n", error); return error; } -- cgit v0.10.2 From 42f69a02e7ab42f1ec75b91faf05b86e75de794a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 30 Jun 2015 12:47:45 -0500 Subject: usb: dwc3: exynos: switch dev_dbg() to dev_info() that message is informing that the clock is missing. However, that's a valid condition for some setups; driver even ignores the error and continues just fine. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 7bd0a95..dd5cb55 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -145,7 +145,7 @@ static int dwc3_exynos_probe(struct platform_device *pdev) exynos->susp_clk = devm_clk_get(dev, "usbdrd30_susp_clk"); if (IS_ERR(exynos->susp_clk)) { - dev_dbg(dev, "no suspend clk specified\n"); + dev_info(dev, "no suspend clk specified\n"); exynos->susp_clk = NULL; } clk_prepare_enable(exynos->susp_clk); -- cgit v0.10.2 From 2babd0d148a365728649addaaa09bfb690ce6b83 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 30 Jun 2015 12:48:58 -0500 Subject: usb: dwc3: qcom: switch dev_dbg() to dev_info() those two messages are informing that the clock doesn't exist; that, however, is a valid situation and driver continues just fine by ignoring the error. Reviewed-by: Andy Gross Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 8c2e8ee..0880260 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -48,13 +48,13 @@ static int dwc3_qcom_probe(struct platform_device *pdev) qdwc->iface_clk = devm_clk_get(qdwc->dev, "iface"); if (IS_ERR(qdwc->iface_clk)) { - dev_dbg(qdwc->dev, "failed to get optional iface clock\n"); + dev_info(qdwc->dev, "failed to get optional iface clock\n"); qdwc->iface_clk = NULL; } qdwc->sleep_clk = devm_clk_get(qdwc->dev, "sleep"); if (IS_ERR(qdwc->sleep_clk)) { - dev_dbg(qdwc->dev, "failed to get optional sleep clock\n"); + dev_info(qdwc->dev, "failed to get optional sleep clock\n"); qdwc->sleep_clk = NULL; } -- cgit v0.10.2 From e746b06cc76afea568c7d53f83a834dc8d720da1 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 30 Jun 2015 12:50:46 -0500 Subject: usb: dwc3: st: remove two unnecessary messages the mode of operation is exposed through debugfs at all times. Because of that, we're removing the unnecessary messages. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-st.c b/drivers/usb/dwc3/dwc3-st.c index 4a1a543..de4d52f 100644 --- a/drivers/usb/dwc3/dwc3-st.c +++ b/drivers/usb/dwc3/dwc3-st.c @@ -135,8 +135,6 @@ static int st_dwc3_drd_init(struct st_dwc3 *dwc3_data) | USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2); val |= USB3_DEVICE_NOT_HOST; - - dev_dbg(dwc3_data->dev, "Configuring as Device\n"); break; case USB_DR_MODE_HOST: @@ -154,8 +152,6 @@ static int st_dwc3_drd_init(struct st_dwc3 *dwc3_data) */ val |= USB3_DELAY_VBUSVALID; - - dev_dbg(dwc3_data->dev, "Configuring as Host\n"); break; default: -- cgit v0.10.2 From 9fcfa463e17adc48865b1a4124d48d48e0b59556 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 30 Jun 2015 12:51:49 -0500 Subject: usb: dwc3: drop CONFIG_USB_DWC3_DEBUG now that we have no users of dev_dbg() in dwc3, we can safely remove CONFIG_USB_DWC3_DEBUG. If dev_dbg() is ever strictly necessary - and I don't see why it would, considering we want to rely on tracepoints for debug - we will depend on DYNAMIC_PRINTK to enable such messages. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index dede32e..5a42c45 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -104,11 +104,4 @@ config USB_DWC3_QCOM Recent Qualcomm SoCs ship with one DesignWare Core USB3 IP inside, say 'Y' or 'M' if you have one such device. -comment "Debugging features" - -config USB_DWC3_DEBUG - bool "Enable Debugging Messages" - help - Say Y here to enable debugging messages on DWC3 Driver. - endif diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index c7076e3..acc951d 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -1,8 +1,6 @@ # define_trace.h needs to know how to find our header CFLAGS_trace.o := -I$(src) -ccflags-$(CONFIG_USB_DWC3_DEBUG) := -DDEBUG - obj-$(CONFIG_USB_DWC3) += dwc3.o dwc3-y := core.o debug.o trace.o -- cgit v0.10.2 From e425be9304ce4da9cd231b55630ca941752635e9 Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Fri, 19 Jun 2015 12:05:05 +0200 Subject: usb: gadget: loopback: Remove out-of-date comment As loopback function has been reworked for ConfigFS composite gadget this comment is no longer valid. Signed-off-by: Krzysztof Opasiak Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_loopback.c b/drivers/usb/gadget/function/f_loopback.c index 39f49f1..6e2fe63 100644 --- a/drivers/usb/gadget/function/f_loopback.c +++ b/drivers/usb/gadget/function/f_loopback.c @@ -28,11 +28,6 @@ * This takes messages of various sizes written OUT to a device, and loops * them back so they can be read IN from it. It has been used by certain * test applications. It supports limited testing of data queueing logic. - * - * - * This is currently packaged as a configuration driver, which can't be - * combined with other functions to make composite devices. However, it - * can be combined with other independent configurations. */ struct f_loopback { struct usb_function function; -- cgit v0.10.2 From d3c1ac4a69667300996ea76fe25c33434372a2a8 Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Fri, 19 Jun 2015 12:16:45 +0200 Subject: usb: gadget: SourceSink: Remove out-of-date comment As SourceSink function has been reworked for ConfigFS composite gadget this comment is no longer valid. Signed-off-by: Krzysztof Opasiak Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c index 3a5ae99..e6af171 100644 --- a/drivers/usb/gadget/function/f_sourcesink.c +++ b/drivers/usb/gadget/function/f_sourcesink.c @@ -42,11 +42,6 @@ * queues are relatively independent, will receive a range of packet sizes, * and can often be made to run out completely. Those issues are important * when stress testing peripheral controller drivers. - * - * - * This is currently packaged as a configuration driver, which can't be - * combined with other functions to make composite devices. However, it - * can be combined with other independent configurations. */ struct f_sourcesink { struct usb_function function; -- cgit v0.10.2 From b8464bcf0a20970471e8f897fe4706fcc2702263 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Sat, 6 Jun 2015 07:02:53 +0530 Subject: usb: gadget: Convert use of __constant_cpu_to_le16 to cpu_to_le16 In big endian cases, macro cpu_to_le16 unfolds to __swab16 which provides special case for constants. In little endian cases, __constant_cpu_to_le16 and cpu_to_le16 expand directly to the same expression. So, replace __constant_cpu_to_le16 with cpu_to_le16 with the goal of getting rid of the definition of __constant_cpu_to_le16 completely. The semantic patch that performs this transformation is as follows: @@expression x;@@ - __constant_cpu_to_le16(x) + cpu_to_le16(x) Signed-off-by: Vaishali Thakkar Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c index f289caf..b8095bf 100644 --- a/drivers/usb/gadget/legacy/audio.c +++ b/drivers/usb/gadget/legacy/audio.c @@ -124,7 +124,7 @@ static struct usb_device_descriptor device_desc = { .bLength = sizeof device_desc, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = __constant_cpu_to_le16(0x200), + .bcdUSB = cpu_to_le16(0x200), #ifdef CONFIG_GADGET_UAC1 .bDeviceClass = USB_CLASS_PER_INTERFACE, @@ -141,8 +141,8 @@ static struct usb_device_descriptor device_desc = { * we support. (As does bNumConfigurations.) These values can * also be overridden by module parameters. */ - .idVendor = __constant_cpu_to_le16(AUDIO_VENDOR_NUM), - .idProduct = __constant_cpu_to_le16(AUDIO_PRODUCT_NUM), + .idVendor = cpu_to_le16(AUDIO_VENDOR_NUM), + .idProduct = cpu_to_le16(AUDIO_PRODUCT_NUM), /* .bcdDevice = f(hardware) */ /* .iManufacturer = DYNAMIC */ /* .iProduct = DYNAMIC */ diff --git a/drivers/usb/gadget/legacy/dbgp.c b/drivers/usb/gadget/legacy/dbgp.c index 204b10b..5231a32 100644 --- a/drivers/usb/gadget/legacy/dbgp.c +++ b/drivers/usb/gadget/legacy/dbgp.c @@ -35,10 +35,10 @@ static struct dbgp { static struct usb_device_descriptor device_desc = { .bLength = sizeof device_desc, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = __constant_cpu_to_le16(0x0200), + .bcdUSB = cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_VENDOR_SPEC, - .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_ID), - .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_ID), + .idVendor = cpu_to_le16(DRIVER_VENDOR_ID), + .idProduct = cpu_to_le16(DRIVER_PRODUCT_ID), .bNumConfigurations = 1, }; @@ -251,7 +251,7 @@ static int dbgp_configure_endpoints(struct usb_gadget *gadget) dbgp.i_ep->driver_data = gadget; i_desc.wMaxPacketSize = - __constant_cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE); + cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE); dbgp.o_ep = usb_ep_autoconfig(gadget, &o_desc); if (!dbgp.o_ep) { @@ -262,7 +262,7 @@ static int dbgp_configure_endpoints(struct usb_gadget *gadget) dbgp.o_ep->driver_data = gadget; o_desc.wMaxPacketSize = - __constant_cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE); + cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE); dbg_desc.bDebugInEndpoint = i_desc.bEndpointAddress; dbg_desc.bDebugOutEndpoint = o_desc.bEndpointAddress; diff --git a/drivers/usb/gadget/legacy/gmidi.c b/drivers/usb/gadget/legacy/gmidi.c index da19c48..650568d 100644 --- a/drivers/usb/gadget/legacy/gmidi.c +++ b/drivers/usb/gadget/legacy/gmidi.c @@ -88,10 +88,10 @@ MODULE_PARM_DESC(out_ports, "Number of MIDI output ports"); static struct usb_device_descriptor device_desc = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = __constant_cpu_to_le16(0x0200), + .bcdUSB = cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_PER_INTERFACE, - .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM), - .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM), + .idVendor = cpu_to_le16(DRIVER_VENDOR_NUM), + .idProduct = cpu_to_le16(DRIVER_PRODUCT_NUM), /* .iManufacturer = DYNAMIC */ /* .iProduct = DYNAMIC */ .bNumConfigurations = 1, diff --git a/drivers/usb/gadget/legacy/nokia.c b/drivers/usb/gadget/legacy/nokia.c index e3791b9..8902f45 100644 --- a/drivers/usb/gadget/legacy/nokia.c +++ b/drivers/usb/gadget/legacy/nokia.c @@ -90,10 +90,10 @@ static struct usb_gadget_strings *dev_strings[] = { static struct usb_device_descriptor device_desc = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = __constant_cpu_to_le16(0x0200), + .bcdUSB = cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_COMM, - .idVendor = __constant_cpu_to_le16(NOKIA_VENDOR_ID), - .idProduct = __constant_cpu_to_le16(NOKIA_PRODUCT_ID), + .idVendor = cpu_to_le16(NOKIA_VENDOR_ID), + .idProduct = cpu_to_le16(NOKIA_PRODUCT_ID), .bcdDevice = cpu_to_le16(NOKIA_VERSION_NUM), /* .iManufacturer = DYNAMIC */ /* .iProduct = DYNAMIC */ -- cgit v0.10.2 From ad4676ab58ae38e5597a2d6bc0d12e9b5e0b0d18 Mon Sep 17 00:00:00 2001 From: Diego Viola Date: Sun, 31 May 2015 15:52:41 -0300 Subject: usb: gadget: composite.c: i18n is not an acronym I18N should be spelled as i18n because it's not an acronym Signed-off-by: Diego Viola Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 58b4657..9ff3203 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -896,7 +896,7 @@ void usb_remove_config(struct usb_composite_dev *cdev, /* We support strings in multiple languages ... string descriptor zero * says which languages are supported. The typical case will be that - * only one language (probably English) is used, with I18N handled on + * only one language (probably English) is used, with i18n handled on * the host side. */ @@ -949,7 +949,7 @@ static int get_string(struct usb_composite_dev *cdev, struct usb_function *f; int len; - /* Yes, not only is USB's I18N support probably more than most + /* Yes, not only is USB's i18n support probably more than most * folk will ever care about ... also, it's all supported here. * (Except for UTF8 support for Unicode's "Astral Planes".) */ -- cgit v0.10.2 From b5c03bffa67727697252e913f64703e3404867ae Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Wed, 10 Jun 2015 16:04:25 +0530 Subject: usb: udc: Convert use of __constant_cpu_to_leXX to cpu_to_leXX In big endian cases, the macro cpu_to_le{16,32} unfolds to __swab{16,32} which provides special case for constants. In little endian cases, __constant_cpu_to_le{16,32} and cpu_to_le{16,32} expand directly to the same expression. So, replace __constant_cpu_to_le{16,32} with cpu_to_le{16,32} with the goal of getting rid of the definition of __constant_cpu_to_le{16,32} completely. The semantic patch that performs this transformation is as follows: @@expression x;@@ ( - __constant_cpu_to_le16(x) + cpu_to_le16(x) | - __constant_cpu_to_le32(x) + cpu_to_le32(x) ) Signed-off-by: Vaishali Thakkar Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index 195baf3..c2ed5da 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -1826,9 +1826,9 @@ net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat) if (!e || u.r.wLength > 2) goto do_stall; if (net2272_ep_read(e, EP_RSPSET) & (1 << ENDPOINT_HALT)) - status = __constant_cpu_to_le16(1); + status = cpu_to_le16(1); else - status = __constant_cpu_to_le16(0); + status = cpu_to_le16(0); /* don't bother with a request object! */ net2272_ep_write(&dev->ep[0], EP_IRQENB, 0); diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index 613547f..dcf5def 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -1793,7 +1793,7 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep, } /* prevent from using desc. - set HOST BUSY */ dma_desc->status |= PCH_UDC_BS_HST_BSY; - dma_desc->dataptr = __constant_cpu_to_le32(DMA_ADDR_INVALID); + dma_desc->dataptr = cpu_to_le32(DMA_ADDR_INVALID); req->td_data = dma_desc; req->td_data_last = dma_desc; req->chain_len = 1; -- cgit v0.10.2 From 5960387a2fb8314687351f6d8485cf62d7722b4e Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Wed, 1 Jul 2015 13:11:30 +0900 Subject: usb: dwc3: omap: Replace deprecated API of extcon This patch removes the deprecated notifier API of extcon framwork and then use the new extcon API with the unique id to indicate the each external connector (USB, USB-HOST). Alter deprecated API as following: - extcon_register_interest() -> extcon_register_notifier() - extcon_get_cable_state(*edev, char *) -> extcon_get_cable_state_(*edev, id) Cc: Felipe Balbi Cc: Greg Kroah-Hartman Signed-off-by: Chanwoo Choi Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index e8a09a8..a5a1b7c 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -128,8 +128,7 @@ struct dwc3_omap { u32 dma_status:1; - struct extcon_specific_cable_nb extcon_vbus_dev; - struct extcon_specific_cable_nb extcon_id_dev; + struct extcon_dev *edev; struct notifier_block vbus_nb; struct notifier_block id_nb; @@ -419,23 +418,23 @@ static int dwc3_omap_extcon_register(struct dwc3_omap *omap) } omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier; - ret = extcon_register_interest(&omap->extcon_vbus_dev, - edev->name, "USB", - &omap->vbus_nb); + ret = extcon_register_notifier(edev, EXTCON_USB, + &omap->vbus_nb); if (ret < 0) dev_vdbg(omap->dev, "failed to register notifier for USB\n"); omap->id_nb.notifier_call = dwc3_omap_id_notifier; - ret = extcon_register_interest(&omap->extcon_id_dev, - edev->name, "USB-HOST", - &omap->id_nb); + ret = extcon_register_notifier(edev, EXTCON_USB_HOST, + &omap->id_nb); if (ret < 0) dev_vdbg(omap->dev, "failed to register notifier for USB-HOST\n"); - if (extcon_get_cable_state(edev, "USB") == true) + if (extcon_get_cable_state_(edev, EXTCON_USB) == true) dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID); - if (extcon_get_cable_state(edev, "USB-HOST") == true) + if (extcon_get_cable_state_(edev, EXTCON_USB_HOST) == true) dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND); + + omap->edev = edev; } return 0; @@ -530,11 +529,8 @@ static int dwc3_omap_probe(struct platform_device *pdev) return 0; err3: - if (omap->extcon_vbus_dev.edev) - extcon_unregister_interest(&omap->extcon_vbus_dev); - if (omap->extcon_id_dev.edev) - extcon_unregister_interest(&omap->extcon_id_dev); - + extcon_unregister_notifier(omap->edev, EXTCON_USB, &omap->vbus_nb); + extcon_unregister_notifier(omap->edev, EXTCON_USB_HOST, &omap->id_nb); err2: dwc3_omap_disable_irqs(omap); @@ -551,10 +547,8 @@ static int dwc3_omap_remove(struct platform_device *pdev) { struct dwc3_omap *omap = platform_get_drvdata(pdev); - if (omap->extcon_vbus_dev.edev) - extcon_unregister_interest(&omap->extcon_vbus_dev); - if (omap->extcon_id_dev.edev) - extcon_unregister_interest(&omap->extcon_id_dev); + extcon_unregister_notifier(omap->edev, EXTCON_USB, &omap->vbus_nb); + extcon_unregister_notifier(omap->edev, EXTCON_USB_HOST, &omap->id_nb); dwc3_omap_disable_irqs(omap); of_platform_depopulate(omap->dev); pm_runtime_put_sync(&pdev->dev); -- cgit v0.10.2 From a2fd2423240fe1abd7a154a1cc0fd1624c339bff Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Wed, 1 Jul 2015 13:11:31 +0900 Subject: usb: phy: omap-otg: Replace deprecated API of extcon This patch removes the deprecated notifier API of extcon framwork and then use the new extcon API with the unique id to indicate the each external connector (USB, USB-HOST). Alter deprecated API as following: - extcon_register_interest() -> extcon_register_notifier() - extcon_get_cable_state(*edev, char *) -> extcon_get_cable_state_(*edev, id) [ balbi@ti.com : fix build break ] Cc: Greg Kroah-Hartman Signed-off-by: Chanwoo Choi Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-omap-otg.c b/drivers/usb/phy/phy-omap-otg.c index 56ee760..1270906 100644 --- a/drivers/usb/phy/phy-omap-otg.c +++ b/drivers/usb/phy/phy-omap-otg.c @@ -30,8 +30,7 @@ struct otg_device { void __iomem *base; bool id; bool vbus; - struct extcon_specific_cable_nb vbus_dev; - struct extcon_specific_cable_nb id_dev; + struct extcon_dev *extcon; struct notifier_block vbus_nb; struct notifier_block id_nb; }; @@ -106,6 +105,7 @@ static int omap_otg_probe(struct platform_device *pdev) extcon = extcon_get_extcon_dev(config->extcon); if (!extcon) return -EPROBE_DEFER; + otg_dev->extcon = extcon; otg_dev = devm_kzalloc(&pdev->dev, sizeof(*otg_dev), GFP_KERNEL); if (!otg_dev) @@ -118,20 +118,19 @@ static int omap_otg_probe(struct platform_device *pdev) otg_dev->id_nb.notifier_call = omap_otg_id_notifier; otg_dev->vbus_nb.notifier_call = omap_otg_vbus_notifier; - ret = extcon_register_interest(&otg_dev->id_dev, config->extcon, - "USB-HOST", &otg_dev->id_nb); + ret = extcon_register_notifier(extcon, EXTCON_USB_HOST, &otg_dev->id_nb); if (ret) return ret; - ret = extcon_register_interest(&otg_dev->vbus_dev, config->extcon, - "USB", &otg_dev->vbus_nb); + ret = extcon_register_notifier(extcon, EXTCON_USB, &otg_dev->vbus_nb); if (ret) { - extcon_unregister_interest(&otg_dev->id_dev); + extcon_unregister_notifier(extcon, EXTCON_USB_HOST, + &otg_dev->id_nb); return ret; } - otg_dev->id = extcon_get_cable_state(extcon, "USB-HOST"); - otg_dev->vbus = extcon_get_cable_state(extcon, "USB"); + otg_dev->id = extcon_get_cable_state_(extcon, EXTCON_USB_HOST); + otg_dev->vbus = extcon_get_cable_state_(extcon, EXTCON_USB); omap_otg_set_mode(otg_dev); rev = readl(otg_dev->base); @@ -147,9 +146,10 @@ static int omap_otg_probe(struct platform_device *pdev) static int omap_otg_remove(struct platform_device *pdev) { struct otg_device *otg_dev = platform_get_drvdata(pdev); + struct extcon_dev *edev = otg_dev->extcon; - extcon_unregister_interest(&otg_dev->id_dev); - extcon_unregister_interest(&otg_dev->vbus_dev); + extcon_unregister_notifier(edev, EXTCON_USB_HOST,&otg_dev->id_nb); + extcon_unregister_notifier(edev, EXTCON_USB, &otg_dev->vbus_nb); return 0; } -- cgit v0.10.2 From 860d2686fda7e4dceaa4e676e62adcdbfc7f7a2c Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Wed, 1 Jul 2015 13:11:32 +0900 Subject: usb: phy: tahvo: Use devm_extcon_dev_[allocate|register]() and replace deprecated API This patch uses the devm_extcon_dev_[allocate|register]() to manage the resource automatically and replace deprecated API as following: - extcon_[set|get]_cable_state(*edev, char *) -> extcon_[set|get]_cable_state_(*edev, id) Cc: Felipe Balbi Cc: Greg Kroah-Hartman Signed-off-by: Chanwoo Choi Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c index b40d6a8..ab5d364 100644 --- a/drivers/usb/phy/phy-tahvo.c +++ b/drivers/usb/phy/phy-tahvo.c @@ -57,7 +57,7 @@ struct tahvo_usb { struct clk *ick; int irq; int tahvo_mode; - struct extcon_dev extcon; + struct extcon_dev *extcon; }; static const unsigned int tahvo_cable[] = { @@ -121,7 +121,7 @@ static void check_vbus_state(struct tahvo_usb *tu) prev_state = tu->vbus_state; tu->vbus_state = reg & TAHVO_STAT_VBUS; if (prev_state != tu->vbus_state) { - extcon_set_cable_state(&tu->extcon, "USB", tu->vbus_state); + extcon_set_cable_state_(tu->extcon, EXTCON_USB, tu->vbus_state); sysfs_notify(&tu->pt_dev->dev.kobj, NULL, "vbus_state"); } } @@ -130,7 +130,7 @@ static void tahvo_usb_become_host(struct tahvo_usb *tu) { struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); - extcon_set_cable_state(&tu->extcon, "USB-HOST", true); + extcon_set_cable_state_(tu->extcon, EXTCON_USB_HOST, true); /* Power up the transceiver in USB host mode */ retu_write(rdev, TAHVO_REG_USBR, USBR_REGOUT | USBR_NSUSPEND | @@ -149,7 +149,7 @@ static void tahvo_usb_become_peripheral(struct tahvo_usb *tu) { struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); - extcon_set_cable_state(&tu->extcon, "USB-HOST", false); + extcon_set_cable_state_(tu->extcon, EXTCON_USB_HOST, false); /* Power up transceiver and set it in USB peripheral mode */ retu_write(rdev, TAHVO_REG_USBR, USBR_SLAVE_CONTROL | USBR_REGOUT | @@ -365,11 +365,13 @@ static int tahvo_usb_probe(struct platform_device *pdev) */ tu->vbus_state = retu_read(rdev, TAHVO_REG_IDSR) & TAHVO_STAT_VBUS; - tu->extcon.name = DRIVER_NAME; - tu->extcon.supported_cable = tahvo_cable; - tu->extcon.dev.parent = &pdev->dev; + tu->extcon = devm_extcon_dev_allocate(&pdev->dev, tahvo_cable); + if (IS_ERR(tu->extcon)) { + dev_err(&pdev->dev, "failed to allocate memory for extcon\n"); + return -ENOMEM; + } - ret = extcon_dev_register(&tu->extcon); + ret = devm_extcon_dev_register(&pdev->dev, tu->extcon); if (ret) { dev_err(&pdev->dev, "could not register extcon device: %d\n", ret); @@ -377,9 +379,9 @@ static int tahvo_usb_probe(struct platform_device *pdev) } /* Set the initial cable state. */ - extcon_set_cable_state(&tu->extcon, "USB-HOST", + extcon_set_cable_state_(tu->extcon, EXTCON_USB_HOST, tu->tahvo_mode == TAHVO_MODE_HOST); - extcon_set_cable_state(&tu->extcon, "USB", tu->vbus_state); + extcon_set_cable_state_(tu->extcon, EXTCON_USB, tu->vbus_state); /* Create OTG interface */ tahvo_usb_power_off(tu); @@ -396,7 +398,7 @@ static int tahvo_usb_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "cannot register USB transceiver: %d\n", ret); - goto err_extcon_unreg; + goto err_disable_clk; } dev_set_drvdata(&pdev->dev, tu); @@ -424,8 +426,6 @@ err_free_irq: free_irq(tu->irq, tu); err_remove_phy: usb_remove_phy(&tu->phy); -err_extcon_unreg: - extcon_dev_unregister(&tu->extcon); err_disable_clk: if (!IS_ERR(tu->ick)) clk_disable(tu->ick); @@ -440,7 +440,6 @@ static int tahvo_usb_remove(struct platform_device *pdev) sysfs_remove_group(&pdev->dev.kobj, &tahvo_attr_group); free_irq(tu->irq, tu); usb_remove_phy(&tu->phy); - extcon_dev_unregister(&tu->extcon); if (!IS_ERR(tu->ick)) clk_disable(tu->ick); -- cgit v0.10.2 From 50297b79b8fd426f678431a8e9dcee59afd33ec8 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Wed, 1 Jul 2015 13:11:33 +0900 Subject: usb: renesas_usbhs: Replace deprecated API of extcon This patch removes the deprecated API of extcon and then use the new extcon API with the unique id to indicate the each external connector (USB-HOST). - extcon_get_cable_state(*edev, char *) -> extcon_get_cable_state_(*edev, id) Cc: Greg Kroah-Hartman Cc: Felipe Balbi Cc: Yoshihiro Shimoda Cc: Sergei Shtylyov Cc: Yoshihiro Shimoda Cc: Peter Chen Cc: Varka Bhadram Cc: Takeshi Kihara Signed-off-by: Chanwoo Choi Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index e8bf408..7b98e1d 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -388,7 +388,7 @@ static void usbhsc_hotplug(struct usbhs_priv *priv) if (enable && !mod) { if (priv->edev) { - cable = extcon_get_cable_state(priv->edev, "USB-HOST"); + cable = extcon_get_cable_state_(priv->edev, EXTCON_USB_HOST); if ((cable > 0 && id != USBHS_HOST) || (!cable && id != USBHS_GADGET)) { dev_info(&pdev->dev, -- cgit v0.10.2 From 83b7b67c780500a1d5d87c44ee8963166154adfa Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Wed, 1 Jul 2015 13:11:34 +0900 Subject: usb: phy: msm-usb: Replace deprecated API of extcon This patch removes the deprecated notifier API of extcon framwork and then use the new extcon API with the unique id to indicate the each external connector (USB, USB-HOST). Alter deprecated API as following: - extcon_register_interest() -> extcon_register_notifier() - extcon_get_cable_state(*edev, char *) -> extcon_get_cable_state_(*edev, id) Cc: Felipe Balbi Cc: Greg Kroah-Hartman Signed-off-by: Chanwoo Choi Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 00c49bb..61d86d8 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1561,15 +1561,16 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) } if (!IS_ERR(ext_vbus)) { + motg->vbus.extcon = ext_vbus; motg->vbus.nb.notifier_call = msm_otg_vbus_notifier; - ret = extcon_register_interest(&motg->vbus.conn, ext_vbus->name, - "USB", &motg->vbus.nb); + ret = extcon_register_notifier(ext_vbus, EXTCON_USB, + &motg->vbus.nb); if (ret < 0) { dev_err(&pdev->dev, "register VBUS notifier failed\n"); return ret; } - ret = extcon_get_cable_state(ext_vbus, "USB"); + ret = extcon_get_cable_state_(ext_vbus, EXTCON_USB); if (ret) set_bit(B_SESS_VLD, &motg->inputs); else @@ -1577,15 +1578,16 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) } if (!IS_ERR(ext_id)) { + motg->id.extcon = ext_id; motg->id.nb.notifier_call = msm_otg_id_notifier; - ret = extcon_register_interest(&motg->id.conn, ext_id->name, - "USB-HOST", &motg->id.nb); + ret = extcon_register_notifier(ext_id, EXTCON_USB_HOST, + &motg->id.nb); if (ret < 0) { dev_err(&pdev->dev, "register ID notifier failed\n"); return ret; } - ret = extcon_get_cable_state(ext_id, "USB-HOST"); + ret = extcon_get_cable_state_(ext_id, EXTCON_USB_HOST); if (ret) clear_bit(ID, &motg->inputs); else @@ -1805,10 +1807,8 @@ static int msm_otg_remove(struct platform_device *pdev) if (phy->otg->host || phy->otg->gadget) return -EBUSY; - if (motg->id.conn.edev) - extcon_unregister_interest(&motg->id.conn); - if (motg->vbus.conn.edev) - extcon_unregister_interest(&motg->vbus.conn); + extcon_unregister_notifier(motg->id.extcon, EXTCON_USB_HOST, &motg->id.nb); + extcon_unregister_notifier(motg->vbus.extcon, EXTCON_USB, &motg->vbus.nb); msm_otg_debugfs_cleanup(); cancel_delayed_work_sync(&motg->chg_work); diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index e55a150..5df2c8f 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -128,7 +128,7 @@ struct msm_otg_platform_data { */ struct msm_usb_cable { struct notifier_block nb; - struct extcon_specific_cable_nb conn; + struct extcon_dev *extcon; }; /** -- cgit v0.10.2 From 2df033ca39b56605725384bac1579cdd30e052a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 6 Jul 2015 11:09:48 +0200 Subject: usb: dwc3: pci: make better use of gpiod API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Use this additional parameter and the _optional variant to simplify the driver and improve error handling. Also expand the comment to explain why it's not sensible to switch to devm_gpiod_get and why the gpiod_put is also necessary. Furthermore this is one caller less that stops us making the flags argument to gpiod_get*() mandatory. Tested-by: Heikki Krogerus Signed-off-by: Uwe Kleine-König Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 27e4fc8..f626179 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -83,17 +83,23 @@ static int dwc3_pci_quirks(struct pci_dev *pdev) acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev), acpi_dwc3_byt_gpios); - /* These GPIOs will turn on the USB2 PHY */ - gpio = gpiod_get(&pdev->dev, "cs"); - if (!IS_ERR(gpio)) { - gpiod_direction_output(gpio, 0); - gpiod_set_value_cansleep(gpio, 1); - gpiod_put(gpio); - } + /* + * These GPIOs will turn on the USB2 PHY. Note that we have to + * put the gpio descriptors again here because the phy driver + * might want to grab them, too. + */ + gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + + gpiod_set_value_cansleep(gpio, 1); + gpiod_put(gpio); + + gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); - gpio = gpiod_get(&pdev->dev, "reset"); - if (!IS_ERR(gpio)) { - gpiod_direction_output(gpio, 0); + if (gpio) { gpiod_set_value_cansleep(gpio, 1); gpiod_put(gpio); usleep_range(10000, 11000); -- cgit v0.10.2 From 88167fc0b22aac0fe7b9c4fadf9c251a9f864f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 6 Jul 2015 11:09:49 +0200 Subject: usb: pass flags parameter to gpiod_get functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Currently this parameter is made optional with the help of a cpp trick. To allow dropping this hack convert callers to explictly pass a value for flags. Acked-by: Felipe Balbi Acked-by: Robert Jarzmik Signed-off-by: Uwe Kleine-König Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index b51226a..042f06b 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -2422,7 +2422,7 @@ static int pxa_udc_probe(struct platform_device *pdev) } udc->udc_command = mach->udc_command; } else { - udc->gpiod = devm_gpiod_get(&pdev->dev, NULL); + udc->gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_ASIS); } regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index deee68e..ec6ecd0 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -218,11 +218,13 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop, clk_rate = 0; needs_vcc = of_property_read_bool(node, "vcc-supply"); - nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset"); + nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset", + GPIOD_ASIS); err = PTR_ERR_OR_ZERO(nop->gpiod_reset); if (!err) { nop->gpiod_vbus = devm_gpiod_get_optional(dev, - "vbus-detect"); + "vbus-detect", + GPIOD_ASIS); err = PTR_ERR_OR_ZERO(nop->gpiod_vbus); } } else if (pdata) { -- cgit v0.10.2 From d9972f470bcb40947dd91af90f17f9cb01db1f41 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 7 Jul 2015 13:45:23 -0500 Subject: usb: dwc3: core: remove unnecessary dev_warn() When a SoC supports both PHY interfaces but doesn't define HSPHY in DT/pdata, we will get an unnecessary dev_warn() which can mislead users into thinking that they're missing something. Instead, let's just silently rely on a correct default. If the HW default is wrong, then HSPHY is required and USB won't work, this will be motivation enough for engineers to patch their way into a working setup. Reported-by: Murali Karicheri Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ff5773c..064123e 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -455,8 +455,6 @@ static int dwc3_phy_setup(struct dwc3 *dwc) reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); } else { - dev_warn(dwc->dev, "HSPHY Interface not defined\n"); - /* Relying on default value. */ if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI)) break; -- cgit v0.10.2 From 7eaeac5c0e44921eb583d5b59b9c54741ecaa899 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 20 Jul 2015 14:46:15 -0500 Subject: usb: dwc3: gadget: add a trace when disabling EPs We have a "Enabling %s" trace when enabling an endpoint but that message felt lonely without a matching "Disabling %s". Add it. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 333a7c0..1f8f730 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -586,6 +586,8 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) struct dwc3 *dwc = dep->dwc; u32 reg; + dwc3_trace(trace_dwc3_gadget, "Disabling %s", dep->name); + dwc3_remove_requests(dwc, dep); /* make sure HW endpoint isn't stalled */ -- cgit v0.10.2 From aa7399744dd02537523b7bf9e3070600b6f79751 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 20 Jul 2015 14:48:13 -0500 Subject: usb: dwc3: gadget: defer endpoint name change We should only change endpoint names when we actually manage to enable/disable it. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 1f8f730..d97fcfa 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -547,6 +547,23 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, trb_link->ctrl |= DWC3_TRB_CTRL_HWO; } + switch (usb_endpoint_type(desc)) { + case USB_ENDPOINT_XFER_CONTROL: + strlcat(dep->name, "-control", sizeof(dep->name)); + break; + case USB_ENDPOINT_XFER_ISOC: + strlcat(dep->name, "-isoc", sizeof(dep->name)); + break; + case USB_ENDPOINT_XFER_BULK: + strlcat(dep->name, "-bulk", sizeof(dep->name)); + break; + case USB_ENDPOINT_XFER_INT: + strlcat(dep->name, "-int", sizeof(dep->name)); + break; + default: + dev_err(dwc->dev, "invalid endpoint transfer type\n"); + } + return 0; } @@ -604,6 +621,10 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) dep->type = 0; dep->flags = 0; + snprintf(dep->name, sizeof(dep->name), "ep%d%s", + dep->number >> 1, + (dep->number & 1) ? "in" : "out"); + return 0; } @@ -649,23 +670,6 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, return 0; } - switch (usb_endpoint_type(desc)) { - case USB_ENDPOINT_XFER_CONTROL: - strlcat(dep->name, "-control", sizeof(dep->name)); - break; - case USB_ENDPOINT_XFER_ISOC: - strlcat(dep->name, "-isoc", sizeof(dep->name)); - break; - case USB_ENDPOINT_XFER_BULK: - strlcat(dep->name, "-bulk", sizeof(dep->name)); - break; - case USB_ENDPOINT_XFER_INT: - strlcat(dep->name, "-int", sizeof(dep->name)); - break; - default: - dev_err(dwc->dev, "invalid endpoint transfer type\n"); - } - spin_lock_irqsave(&dwc->lock, flags); ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false, false); spin_unlock_irqrestore(&dwc->lock, flags); @@ -694,10 +698,6 @@ static int dwc3_gadget_ep_disable(struct usb_ep *ep) return 0; } - snprintf(dep->name, sizeof(dep->name), "ep%d%s", - dep->number >> 1, - (dep->number & 1) ? "in" : "out"); - spin_lock_irqsave(&dwc->lock, flags); ret = __dwc3_gadget_ep_disable(dep); spin_unlock_irqrestore(&dwc->lock, flags); -- cgit v0.10.2 From 903588a99c26ed6f103eaa0cfa4ccbe9cd779398 Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Mon, 20 Jul 2015 20:15:17 +0200 Subject: usb: gadget: mass_storage: Free buffers if create lun fails Creation of LUN 0 may fail (for example due to ENOMEM). As fsg_common_set_num_buffers() does some memory allocation we should free it before it becomes unavailable. Signed-off-by: Krzysztof Opasiak Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index f936268..f72102a 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -3524,6 +3524,9 @@ static struct usb_function_instance *fsg_alloc_inst(void) config.removable = true; rc = fsg_common_create_lun(opts->common, &config, 0, "lun.0", (const char **)&opts->func_inst.group.cg_item.ci_name); + if (rc) + goto release_buffers; + opts->lun0.lun = opts->common->luns[0]; opts->lun0.lun_id = 0; config_group_init_type_name(&opts->lun0.group, "lun.0", &fsg_lun_type); @@ -3534,6 +3537,8 @@ static struct usb_function_instance *fsg_alloc_inst(void) return &opts->func_inst; +release_buffers: + fsg_common_free_buffers(opts->common); release_luns: kfree(opts->common->luns); release_opts: -- cgit v0.10.2 From bab7a1f199fa617c7a0600c74ebbb514aed6dbe8 Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Mon, 20 Jul 2015 20:15:18 +0200 Subject: usb: gadget: mass_storage: Place EXPORT_SYMBOL_GPL() after func definition EXPORT_SYMBOL_GPL() is usually placed after function definition not before. Signed-off-by: Krzysztof Opasiak Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index f72102a..c3b62c7 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2761,12 +2761,12 @@ static void _fsg_common_remove_luns(struct fsg_common *common, int n) common->luns[i] = NULL; } } -EXPORT_SYMBOL_GPL(fsg_common_remove_luns); void fsg_common_remove_luns(struct fsg_common *common) { _fsg_common_remove_luns(common, common->nluns); } +EXPORT_SYMBOL_GPL(fsg_common_remove_luns); void fsg_common_free_luns(struct fsg_common *common) { -- cgit v0.10.2 From 75ddead2a77db61e818bc0cbe330a856a912f4d9 Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Mon, 20 Jul 2015 20:15:19 +0200 Subject: usb: gadget: storage-common: Set FSG_MAX_LUNS to 16 Mass storage spec allows up to 16 LUNs, so let's not add some more restrictive limits. Signed-off-by: Krzysztof Opasiak Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index c3b62c7..9e88e2b 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -54,7 +54,7 @@ * following fields: * * nluns Number of LUNs function have (anywhere from 1 - * to FSG_MAX_LUNS which is 8). + * to FSG_MAX_LUNS). * luns An array of LUN configuration values. This * should be filled for each LUN that * function will include (ie. for "nluns" diff --git a/drivers/usb/gadget/function/storage_common.h b/drivers/usb/gadget/function/storage_common.h index 70c8914..c3544e6 100644 --- a/drivers/usb/gadget/function/storage_common.h +++ b/drivers/usb/gadget/function/storage_common.h @@ -123,7 +123,7 @@ static inline bool fsg_lun_is_open(struct fsg_lun *curlun) #define FSG_BUFLEN ((u32)16384) /* Maximal number of LUNs supported in mass storage function */ -#define FSG_MAX_LUNS 8 +#define FSG_MAX_LUNS 16 enum fsg_buffer_state { BUF_STATE_EMPTY = 0, -- cgit v0.10.2 From 351169933ea22592fb42b97c76c4c130fe287cca Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Wed, 8 Jul 2015 17:57:40 +0300 Subject: usb: phy: qcom: New APQ8016/MSM8916 USB transceiver driver Driver handles PHY initialization, clock management, power management and workarounds required after resetting the hardware. Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt b/Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt new file mode 100644 index 0000000..2cb2168 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt @@ -0,0 +1,76 @@ +Qualcomm's APQ8016/MSM8916 USB transceiver controller + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,usb-8x16-phy". + +- reg: + Usage: required + Value type: + Definition: USB PHY base address and length of the register map + +- clocks: + Usage: required + Value type: + Definition: See clock-bindings.txt section "consumers". List of + two clock specifiers for interface and core controller + clocks. + +- clock-names: + Usage: required + Value type: + Definition: Must contain "iface" and "core" strings. + +- vddcx-supply: + Usage: required + Value type: + Definition: phandle to the regulator VDCCX supply node. + +- v1p8-supply: + Usage: required + Value type: + Definition: phandle to the regulator 1.8V supply node. + +- v3p3-supply: + Usage: required + Value type: + Definition: phandle to the regulator 3.3V supply node. + +- resets: + Usage: required + Value type: + Definition: See reset.txt section "consumers". PHY reset specifier. + +- reset-names: + Usage: required + Value type: + Definition: Must contain "phy" string. + +- switch-gpio: + Usage: optional + Value type: + Definition: Some boards are using Dual SPDT USB Switch, witch is + controlled by GPIO to de/multiplex D+/D- USB lines + between connectors. + +Example: + usb_phy: phy@78d9000 { + compatible = "qcom,usb-8x16-phy"; + reg = <0x78d9000 0x400>; + + vddcx-supply = <&pm8916_s1_corner>; + v1p8-supply = <&pm8916_l7>; + v3p3-supply = <&pm8916_l13>; + + clocks = <&gcc GCC_USB_HS_AHB_CLK>, + <&gcc GCC_USB_HS_SYSTEM_CLK>; + clock-names = "iface", "core"; + + resets = <&gcc GCC_USB2A_PHY_BCR>; + reset-names = "phy"; + + // D+/D- lines: 1 - Routed to HUB, 0 - Device connector + switch-gpio = <&pm8916_gpios 4 GPIO_ACTIVE_HIGH>; + }; + diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 869c0cfcad..7d3beee 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -152,6 +152,20 @@ config USB_MSM_OTG This driver is not supported on boards like trout which has an external PHY. +config USB_QCOM_8X16_PHY + tristate "Qualcomm APQ8016/MSM8916 on-chip USB PHY controller support" + depends on ARCH_QCOM || COMPILE_TEST + depends on RESET_CONTROLLER + select USB_PHY + select USB_ULPI_VIEWPORT + help + Enable this to support the USB transceiver on Qualcomm 8x16 chipsets. + It handles PHY initialization, clock management, power management, + and workarounds required after resetting the hardware. + + To compile this driver as a module, choose M here: the + module will be called phy-qcom-8x16-usb. + config USB_MV_OTG tristate "Marvell USB OTG support" depends on USB_EHCI_MV && USB_MV_UDC && PM diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index e36ab1d..19c0dcc 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_USB_EHCI_TEGRA) += phy-tegra-usb.o obj-$(CONFIG_USB_GPIO_VBUS) += phy-gpio-vbus-usb.o obj-$(CONFIG_USB_ISP1301) += phy-isp1301.o obj-$(CONFIG_USB_MSM_OTG) += phy-msm-usb.o +obj-$(CONFIG_USB_QCOM_8X16_PHY) += phy-qcom-8x16-usb.o obj-$(CONFIG_USB_MV_OTG) += phy-mv-usb.o obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-usb.o obj-$(CONFIG_USB_RCAR_PHY) += phy-rcar-usb.o diff --git a/drivers/usb/phy/phy-qcom-8x16-usb.c b/drivers/usb/phy/phy-qcom-8x16-usb.c new file mode 100644 index 0000000..5d357a9 --- /dev/null +++ b/drivers/usb/phy/phy-qcom-8x16-usb.c @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HSPHY_AHBBURST 0x0090 +#define HSPHY_AHBMODE 0x0098 +#define HSPHY_GENCONFIG 0x009c +#define HSPHY_GENCONFIG_2 0x00a0 + +#define HSPHY_USBCMD 0x0140 +#define HSPHY_ULPI_VIEWPORT 0x0170 +#define HSPHY_CTRL 0x0240 + +#define HSPHY_TXFIFO_IDLE_FORCE_DIS BIT(4) +#define HSPHY_SESS_VLD_CTRL_EN BIT(7) +#define HSPHY_POR_ASSERT BIT(0) +#define HSPHY_RETEN BIT(1) + +#define HSPHY_SESS_VLD_CTRL BIT(25) + +#define ULPI_PWR_CLK_MNG_REG 0x88 +#define ULPI_PWR_OTG_COMP_DISABLE BIT(0) + +#define ULPI_MISC_A 0x96 +#define ULPI_MISC_A_VBUSVLDEXTSEL BIT(1) +#define ULPI_MISC_A_VBUSVLDEXT BIT(0) + +#define HSPHY_3P3_MIN 3050000 /* uV */ +#define HSPHY_3P3_MAX 3300000 /* uV */ + +#define HSPHY_1P8_MIN 1800000 /* uV */ +#define HSPHY_1P8_MAX 1800000 /* uV */ + +#define HSPHY_VDD_MIN 5 +#define HSPHY_VDD_MAX 7 + +struct phy_8x16 { + struct usb_phy phy; + void __iomem *regs; + struct clk *core_clk; + struct clk *iface_clk; + struct regulator *v3p3; + struct regulator *v1p8; + struct regulator *vdd; + + struct reset_control *phy_reset; + + struct extcon_specific_cable_nb vbus_cable; + struct notifier_block vbus_notify; + + struct gpio_desc *switch_gpio; + struct notifier_block reboot_notify; +}; + +static int phy_8x16_regulators_enable(struct phy_8x16 *qphy) +{ + int ret; + + ret = regulator_set_voltage(qphy->vdd, HSPHY_VDD_MIN, HSPHY_VDD_MAX); + if (ret) + return ret; + + ret = regulator_enable(qphy->vdd); + if (ret) + return ret; + + ret = regulator_set_voltage(qphy->v3p3, HSPHY_3P3_MIN, HSPHY_3P3_MAX); + if (ret) + goto off_vdd; + + ret = regulator_enable(qphy->v3p3); + if (ret) + goto off_vdd; + + ret = regulator_set_voltage(qphy->v1p8, HSPHY_1P8_MIN, HSPHY_1P8_MAX); + if (ret) + goto off_3p3; + + ret = regulator_enable(qphy->v1p8); + if (ret) + goto off_3p3; + + return 0; + +off_3p3: + regulator_disable(qphy->v3p3); +off_vdd: + regulator_disable(qphy->vdd); + + return ret; +} + +static void phy_8x16_regulators_disable(struct phy_8x16 *qphy) +{ + regulator_disable(qphy->v1p8); + regulator_disable(qphy->v3p3); + regulator_disable(qphy->vdd); +} + +static int phy_8x16_notify_connect(struct usb_phy *phy, + enum usb_device_speed speed) +{ + struct phy_8x16 *qphy = container_of(phy, struct phy_8x16, phy); + u32 val; + + val = ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT; + usb_phy_io_write(&qphy->phy, val, ULPI_SET(ULPI_MISC_A)); + + val = readl(qphy->regs + HSPHY_USBCMD); + val |= HSPHY_SESS_VLD_CTRL; + writel(val, qphy->regs + HSPHY_USBCMD); + + return 0; +} + +static int phy_8x16_notify_disconnect(struct usb_phy *phy, + enum usb_device_speed speed) +{ + struct phy_8x16 *qphy = container_of(phy, struct phy_8x16, phy); + u32 val; + + val = ULPI_MISC_A_VBUSVLDEXT | ULPI_MISC_A_VBUSVLDEXTSEL; + usb_phy_io_write(&qphy->phy, val, ULPI_CLR(ULPI_MISC_A)); + + val = readl(qphy->regs + HSPHY_USBCMD); + val &= ~HSPHY_SESS_VLD_CTRL; + writel(val, qphy->regs + HSPHY_USBCMD); + + return 0; +} + +static int phy_8x16_vbus_on(struct phy_8x16 *qphy) +{ + phy_8x16_notify_connect(&qphy->phy, USB_SPEED_UNKNOWN); + + /* Switch D+/D- lines to Device connector */ + gpiod_set_value_cansleep(qphy->switch_gpio, 0); + + return 0; +} + +static int phy_8x16_vbus_off(struct phy_8x16 *qphy) +{ + phy_8x16_notify_disconnect(&qphy->phy, USB_SPEED_UNKNOWN); + + /* Switch D+/D- lines to USB HUB */ + gpiod_set_value_cansleep(qphy->switch_gpio, 1); + + return 0; +} + +static int phy_8x16_vbus_notify(struct notifier_block *nb, unsigned long event, + void *ptr) +{ + struct phy_8x16 *qphy = container_of(nb, struct phy_8x16, vbus_notify); + + if (event) + phy_8x16_vbus_on(qphy); + else + phy_8x16_vbus_off(qphy); + + return NOTIFY_DONE; +} + +static int phy_8x16_init(struct usb_phy *phy) +{ + struct phy_8x16 *qphy = container_of(phy, struct phy_8x16, phy); + u32 val, init[] = {0x44, 0x6B, 0x24, 0x13}; + u32 addr = ULPI_EXT_VENDOR_SPECIFIC; + int idx, state; + + for (idx = 0; idx < ARRAY_SIZE(init); idx++) + usb_phy_io_write(phy, init[idx], addr + idx); + + reset_control_reset(qphy->phy_reset); + + /* Assert USB HSPHY_POR */ + val = readl(qphy->regs + HSPHY_CTRL); + val |= HSPHY_POR_ASSERT; + writel(val, qphy->regs + HSPHY_CTRL); + + /* + * wait for minimum 10 microseconds as suggested in HPG. + * Use a slightly larger value since the exact value didn't + * work 100% of the time. + */ + usleep_range(12, 15); + + /* Deassert USB HSPHY_POR */ + val = readl(qphy->regs + HSPHY_CTRL); + val &= ~HSPHY_POR_ASSERT; + writel(val, qphy->regs + HSPHY_CTRL); + + usleep_range(10, 15); + + writel(0x00, qphy->regs + HSPHY_AHBBURST); + writel(0x08, qphy->regs + HSPHY_AHBMODE); + + /* workaround for rx buffer collision issue */ + val = readl(qphy->regs + HSPHY_GENCONFIG); + val &= ~HSPHY_TXFIFO_IDLE_FORCE_DIS; + writel(val, qphy->regs + HSPHY_GENCONFIG); + + val = readl(qphy->regs + HSPHY_GENCONFIG_2); + val |= HSPHY_SESS_VLD_CTRL_EN; + writel(val, qphy->regs + HSPHY_GENCONFIG_2); + + val = ULPI_PWR_OTG_COMP_DISABLE; + usb_phy_io_write(phy, val, ULPI_SET(ULPI_PWR_CLK_MNG_REG)); + + state = extcon_get_cable_state(qphy->vbus_cable.edev, "USB"); + if (state) + phy_8x16_vbus_on(qphy); + else + phy_8x16_vbus_off(qphy); + + val = usb_phy_io_read(&qphy->phy, ULPI_FUNC_CTRL); + val &= ~ULPI_FUNC_CTRL_OPMODE_MASK; + val |= ULPI_FUNC_CTRL_OPMODE_NORMAL; + usb_phy_io_write(&qphy->phy, val, ULPI_FUNC_CTRL); + + return 0; +} + +static void phy_8x16_shutdown(struct usb_phy *phy) +{ + u32 val; + + /* Put the controller in non-driving mode */ + val = usb_phy_io_read(phy, ULPI_FUNC_CTRL); + val &= ~ULPI_FUNC_CTRL_OPMODE_MASK; + val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING; + usb_phy_io_write(phy, val, ULPI_FUNC_CTRL); +} + +static int phy_8x16_read_devicetree(struct phy_8x16 *qphy) +{ + struct regulator_bulk_data regs[3]; + struct device *dev = qphy->phy.dev; + int ret; + + qphy->core_clk = devm_clk_get(dev, "core"); + if (IS_ERR(qphy->core_clk)) + return PTR_ERR(qphy->core_clk); + + qphy->iface_clk = devm_clk_get(dev, "iface"); + if (IS_ERR(qphy->iface_clk)) + return PTR_ERR(qphy->iface_clk); + + regs[0].supply = "v3p3"; + regs[1].supply = "v1p8"; + regs[2].supply = "vddcx"; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(regs), regs); + if (ret) + return ret; + + qphy->v3p3 = regs[0].consumer; + qphy->v1p8 = regs[1].consumer; + qphy->vdd = regs[2].consumer; + + qphy->phy_reset = devm_reset_control_get(dev, "phy"); + if (IS_ERR(qphy->phy_reset)) + return PTR_ERR(qphy->phy_reset); + + qphy->switch_gpio = devm_gpiod_get_optional(dev, "switch", + GPIOD_OUT_LOW); + if (IS_ERR(qphy->switch_gpio)) + return PTR_ERR(qphy->switch_gpio); + + return 0; +} + +static int phy_8x16_reboot_notify(struct notifier_block *this, + unsigned long code, void *unused) +{ + struct phy_8x16 *qphy; + + qphy = container_of(this, struct phy_8x16, reboot_notify); + + /* + * Ensure that D+/D- lines are routed to uB connector, so + * we could load bootloader/kernel at next reboot_notify + */ + gpiod_set_value_cansleep(qphy->switch_gpio, 0); + return NOTIFY_DONE; +} + +static int phy_8x16_probe(struct platform_device *pdev) +{ + struct extcon_dev *edev; + struct phy_8x16 *qphy; + struct resource *res; + struct usb_phy *phy; + int ret; + + qphy = devm_kzalloc(&pdev->dev, sizeof(*qphy), GFP_KERNEL); + if (!qphy) + return -ENOMEM; + + platform_set_drvdata(pdev, qphy); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + qphy->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!qphy->regs) + return -ENOMEM; + + phy = &qphy->phy; + phy->dev = &pdev->dev; + phy->label = dev_name(&pdev->dev); + phy->init = phy_8x16_init; + phy->shutdown = phy_8x16_shutdown; + phy->notify_connect = phy_8x16_notify_connect; + phy->notify_disconnect = phy_8x16_notify_disconnect; + phy->io_priv = qphy->regs + HSPHY_ULPI_VIEWPORT; + phy->io_ops = &ulpi_viewport_access_ops; + phy->type = USB_PHY_TYPE_USB2; + + ret = phy_8x16_read_devicetree(qphy); + if (ret < 0) + return ret; + + edev = extcon_get_edev_by_phandle(phy->dev, 0); + if (IS_ERR(edev)) + return PTR_ERR(edev); + + ret = clk_set_rate(qphy->core_clk, INT_MAX); + if (ret < 0) + dev_dbg(phy->dev, "Can't boost core clock\n"); + + ret = clk_prepare_enable(qphy->core_clk); + if (ret < 0) + return ret; + + ret = clk_prepare_enable(qphy->iface_clk); + if (ret < 0) + goto off_core; + + ret = phy_8x16_regulators_enable(qphy); + if (0 && ret) + goto off_clks; + + qphy->vbus_notify.notifier_call = phy_8x16_vbus_notify; + ret = extcon_register_interest(&qphy->vbus_cable, edev->name, + "USB", &qphy->vbus_notify); + if (ret < 0) + goto off_power; + + ret = usb_add_phy_dev(&qphy->phy); + if (ret) + goto off_extcon; + + qphy->reboot_notify.notifier_call = phy_8x16_reboot_notify; + register_reboot_notifier(&qphy->reboot_notify); + + return 0; + +off_extcon: + extcon_unregister_interest(&qphy->vbus_cable); +off_power: + phy_8x16_regulators_disable(qphy); +off_clks: + clk_disable_unprepare(qphy->iface_clk); +off_core: + clk_disable_unprepare(qphy->core_clk); + return ret; +} + +static int phy_8x16_remove(struct platform_device *pdev) +{ + struct phy_8x16 *qphy = platform_get_drvdata(pdev); + + unregister_reboot_notifier(&qphy->reboot_notify); + extcon_unregister_interest(&qphy->vbus_cable); + + /* + * Ensure that D+/D- lines are routed to uB connector, so + * we could load bootloader/kernel at next reboot_notify + */ + gpiod_set_value_cansleep(qphy->switch_gpio, 0); + + usb_remove_phy(&qphy->phy); + + clk_disable_unprepare(qphy->iface_clk); + clk_disable_unprepare(qphy->core_clk); + phy_8x16_regulators_disable(qphy); + return 0; +} + +static const struct of_device_id phy_8x16_dt_match[] = { + { .compatible = "qcom,usb-8x16-phy" }, + { } +}; +MODULE_DEVICE_TABLE(of, phy_8x16_dt_match); + +static struct platform_driver phy_8x16_driver = { + .probe = phy_8x16_probe, + .remove = phy_8x16_remove, + .driver = { + .name = "phy-qcom-8x16-usb", + .of_match_table = phy_8x16_dt_match, + }, +}; +module_platform_driver(phy_8x16_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Qualcomm APQ8016/MSM8916 chipsets USB transceiver driver"); -- cgit v0.10.2 From ccdf138fe3e243c70301fcb6a101e366b7daef07 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 4 May 2015 14:55:11 +0200 Subject: usb: gadget: add usb_gadget_activate/deactivate functions These functions allows to deactivate gadget to make it not visible to host and make it active again when gadget driver is finally ready. They are needed to fix usb_function_activate() and usb_function_deactivate() functions which currently are not working as usb_gadget_connect() is called immediately after function bind regardless to previous calls of usb_gadget_disconnect() function. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 4f3dfb7..15604bb 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -526,6 +526,9 @@ struct usb_gadget_ops { * @quirk_ep_out_aligned_size: epout requires buffer size to be aligned to * MaxPacketSize. * @is_selfpowered: if the gadget is self-powered. + * @deactivated: True if gadget is deactivated - in deactivated state it cannot + * be connected. + * @connected: True if gadget is connected. * * Gadgets have a mostly-portable "gadget driver" implementing device * functions, handling all usb configurations and interfaces. Gadget @@ -568,6 +571,8 @@ struct usb_gadget { unsigned a_alt_hnp_support:1; unsigned quirk_ep_out_aligned_size:1; unsigned is_selfpowered:1; + unsigned deactivated:1; + unsigned connected:1; }; #define work_to_gadget(w) (container_of((w), struct usb_gadget, work)) @@ -771,9 +776,24 @@ static inline int usb_gadget_vbus_disconnect(struct usb_gadget *gadget) */ static inline int usb_gadget_connect(struct usb_gadget *gadget) { + int ret; + if (!gadget->ops->pullup) return -EOPNOTSUPP; - return gadget->ops->pullup(gadget, 1); + + if (gadget->deactivated) { + /* + * If gadget is deactivated we only save new state. + * Gadget will be connected automatically after activation. + */ + gadget->connected = true; + return 0; + } + + ret = gadget->ops->pullup(gadget, 1); + if (!ret) + gadget->connected = 1; + return ret; } /** @@ -784,20 +804,88 @@ static inline int usb_gadget_connect(struct usb_gadget *gadget) * as a disconnect (when a VBUS session is active). Not all systems * support software pullup controls. * + * Returns zero on success, else negative errno. + */ +static inline int usb_gadget_disconnect(struct usb_gadget *gadget) +{ + int ret; + + if (!gadget->ops->pullup) + return -EOPNOTSUPP; + + if (gadget->deactivated) { + /* + * If gadget is deactivated we only save new state. + * Gadget will stay disconnected after activation. + */ + gadget->connected = false; + return 0; + } + + ret = gadget->ops->pullup(gadget, 0); + if (!ret) + gadget->connected = 0; + return ret; +} + +/** + * usb_gadget_deactivate - deactivate function which is not ready to work + * @gadget: the peripheral being deactivated + * * This routine may be used during the gadget driver bind() call to prevent * the peripheral from ever being visible to the USB host, unless later - * usb_gadget_connect() is called. For example, user mode components may + * usb_gadget_activate() is called. For example, user mode components may * need to be activated before the system can talk to hosts. * * Returns zero on success, else negative errno. */ -static inline int usb_gadget_disconnect(struct usb_gadget *gadget) +static inline int usb_gadget_deactivate(struct usb_gadget *gadget) { - if (!gadget->ops->pullup) - return -EOPNOTSUPP; - return gadget->ops->pullup(gadget, 0); + int ret; + + if (gadget->deactivated) + return 0; + + if (gadget->connected) { + ret = usb_gadget_disconnect(gadget); + if (ret) + return ret; + /* + * If gadget was being connected before deactivation, we want + * to reconnect it in usb_gadget_activate(). + */ + gadget->connected = true; + } + gadget->deactivated = true; + + return 0; } +/** + * usb_gadget_activate - activate function which is not ready to work + * @gadget: the peripheral being activated + * + * This routine activates gadget which was previously deactivated with + * usb_gadget_deactivate() call. It calls usb_gadget_connect() if needed. + * + * Returns zero on success, else negative errno. + */ +static inline int usb_gadget_activate(struct usb_gadget *gadget) +{ + if (!gadget->deactivated) + return 0; + + gadget->deactivated = false; + + /* + * If gadget has been connected before deactivation, or became connected + * while it was being deactivated, we call usb_gadget_connect(). + */ + if (gadget->connected) + return usb_gadget_connect(gadget); + + return 0; +} /*-------------------------------------------------------------------------*/ -- cgit v0.10.2 From 5601250bb1b4e736cf487d332f2d8d8833a84209 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 4 May 2015 14:55:12 +0200 Subject: usb: composite: fix usb_function_activate/deactivate functions Using usb_gadget_disconnect to make gadget temporarily invisible to host doesn't provide desired result, because gadget is connected immediately after binding regardless to previous usb_gadget_disconnect() calls. For this reason we use usb_gadget_deactivate() instead of usb_gadget_disconnect() to make it working as expected. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 9ff3203..86d4e8f 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -279,7 +279,7 @@ int usb_function_deactivate(struct usb_function *function) spin_lock_irqsave(&cdev->lock, flags); if (cdev->deactivations == 0) - status = usb_gadget_disconnect(cdev->gadget); + status = usb_gadget_deactivate(cdev->gadget); if (status == 0) cdev->deactivations++; @@ -311,7 +311,7 @@ int usb_function_activate(struct usb_function *function) else { cdev->deactivations--; if (cdev->deactivations == 0) - status = usb_gadget_connect(cdev->gadget); + status = usb_gadget_activate(cdev->gadget); } spin_unlock_irqrestore(&cdev->lock, flags); -- cgit v0.10.2 From d5bb9b81dbfa35d117ecb58022ee6e7e41e4772d Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 4 May 2015 14:55:13 +0200 Subject: usb: composite: add bind_deactivated flag to usb_function This patch introduces 'bind_deactivated' flag in struct usb_function. Functions which don't want to be activated automatically after bind should set this flag, and when they start to be ready to work they should call usb_function_activate(). When USB function sets 'bind_deactivated' flag, initial deactivation counter is incremented automatically, so there is no need to call usb_function_deactivate() in function bind. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 86d4e8f..36c6f47 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -209,6 +209,12 @@ int usb_add_function(struct usb_configuration *config, function->config = config; list_add_tail(&function->list, &config->functions); + if (function->bind_deactivated) { + value = usb_function_deactivate(function); + if (value) + goto done; + } + /* REVISIT *require* function->bind? */ if (function->bind) { value = function->bind(config, function); diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 2511469..1074b89 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -228,6 +228,8 @@ struct usb_function { struct list_head list; DECLARE_BITMAP(endpoints, 32); const struct usb_function_instance *fi; + + unsigned int bind_deactivated:1; }; int usb_add_function(struct usb_configuration *, struct usb_function *); -- cgit v0.10.2 From f277bf27cf5cd56bcd1c4b95ae140f61680a6e83 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 4 May 2015 14:55:14 +0200 Subject: usb: gadget: f_uvc: use bind_deactivated flag Use bind_deactivated flag instead of calling usb_function_deactivate() in function bind(). Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index cf0df8f..743be34 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -733,12 +733,6 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) uvc->control_req->complete = uvc_function_ep0_complete; uvc->control_req->context = uvc; - /* Avoid letting this gadget enumerate until the userspace server is - * active. - */ - if ((ret = usb_function_deactivate(f)) < 0) - goto error; - if (v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev)) { printk(KERN_INFO "v4l2_device_register failed\n"); goto error; @@ -949,6 +943,7 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) uvc->func.disable = uvc_function_disable; uvc->func.setup = uvc_function_setup; uvc->func.free_func = uvc_free; + uvc->func.bind_deactivated = true; return &uvc->func; } -- cgit v0.10.2 From 4cfbd95232dd6194c04d432d1a8ac45cec269d8b Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 4 May 2015 14:55:15 +0200 Subject: usb: gadget: f_obex: use bind_deactivated flag Use bind_deactivated flag instead of calling usb_function_deactivate() in function bind(). Field 'can_activate' in struct f_obex is no longer needed as setting 'bind_deactivated' flag makes us sure, that the function will be binded only if deactivation can be performed successfully. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_obex.c b/drivers/usb/gadget/function/f_obex.c index a1b79c5..5519f85 100644 --- a/drivers/usb/gadget/function/f_obex.c +++ b/drivers/usb/gadget/function/f_obex.c @@ -37,7 +37,6 @@ struct f_obex { u8 data_id; u8 cur_alt; u8 port_num; - u8 can_activate; }; static inline struct f_obex *func_to_obex(struct usb_function *f) @@ -268,9 +267,6 @@ static void obex_connect(struct gserial *g) struct usb_composite_dev *cdev = g->func.config->cdev; int status; - if (!obex->can_activate) - return; - status = usb_function_activate(&g->func); if (status) dev_dbg(&cdev->gadget->dev, @@ -284,9 +280,6 @@ static void obex_disconnect(struct gserial *g) struct usb_composite_dev *cdev = g->func.config->cdev; int status; - if (!obex->can_activate) - return; - status = usb_function_deactivate(&g->func); if (status) dev_dbg(&cdev->gadget->dev, @@ -378,17 +371,6 @@ static int obex_bind(struct usb_configuration *c, struct usb_function *f) if (status) goto fail; - /* Avoid letting this gadget enumerate until the userspace - * OBEX server is active. - */ - status = usb_function_deactivate(f); - if (status < 0) - WARNING(cdev, "obex ttyGS%d: can't prevent enumeration, %d\n", - obex->port_num, status); - else - obex->can_activate = true; - - dev_dbg(&cdev->gadget->dev, "obex ttyGS%d: %s speed IN/%s OUT/%s\n", obex->port_num, gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", @@ -529,6 +511,7 @@ static struct usb_function *obex_alloc(struct usb_function_instance *fi) obex->port.func.get_alt = obex_get_alt; obex->port.func.disable = obex_disable; obex->port.func.free_func = obex_free; + obex->port.func.bind_deactivated = true; return &obex->port.func; } -- cgit v0.10.2 From 744543c599c420bcddca08cd2e2713b82a008328 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 8 Jul 2015 16:41:38 +0200 Subject: usb: musb: sunxi: Add support for the Allwinner sunxi musb controller This is based on initial code to get the Allwinner sunxi musb controller supported by Chen-Yu Tsai and Roman Byshko. This adds support for the Allwinner sunxi musb controller in both host only and otg mode. Peripheral only mode is not supported, as no boards use that. This has been tested on a cubietruck (A20 SoC) and an UTOO P66 tablet (A13 SoC) with a variety of devices in host mode and with the g_serial gadget driver in peripheral mode, plugging otg / host cables in/out a lot of times in all possible imaginable plug orders. Signed-off-by: Hans de Goede Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt new file mode 100644 index 0000000..9254a6c --- /dev/null +++ b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt @@ -0,0 +1,27 @@ +Allwinner sun4i A10 musb DRC/OTG controller +------------------------------------------- + +Required properties: + - compatible : "allwinner,sun4i-a10-musb" + - reg : mmio address range of the musb controller + - clocks : clock specifier for the musb controller ahb gate clock + - interrupts : interrupt to which the musb controller is connected + - interrupt-names : must be "mc" + - phys : phy specifier for the otg phy + - phy-names : must be "usb" + - dr_mode : Dual-Role mode must be "host" or "otg" + - extcon : extcon specifier for the otg phy + +Example: + + usb_otg: usb@01c13000 { + compatible = "allwinner,sun4i-a10-musb"; + reg = <0x01c13000 0x0400>; + clocks = <&ahb_gates 0>; + interrupts = <38>; + interrupt-names = "mc"; + phys = <&usbphy 0>; + phy-names = "usb"; + extcon = <&usbphy 0>; + status = "disabled"; + }; diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 39db8b6..37081ed 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -5,7 +5,7 @@ # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller config USB_MUSB_HDRC - tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' + tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, AW, ...)' depends on (USB || USB_GADGET) help Say Y here if your system has a dual role high speed USB @@ -20,6 +20,8 @@ config USB_MUSB_HDRC Analog Devices parts using this IP include Blackfin BF54x, BF525 and BF527. + Allwinner SoCs using this IP include A10, A13, A20, ... + If you do not know what this is, please say N. To compile this driver as a module, choose M here; the @@ -60,6 +62,15 @@ endchoice comment "Platform Glue Layer" +config USB_MUSB_SUNXI + tristate "Allwinner (sunxi)" + depends on ARCH_SUNXI + depends on NOP_USB_XCEIV + depends on PHY_SUN4I_USB + depends on EXTCON + depends on GENERIC_PHY + select SUNXI_SRAM + config USB_MUSB_DAVINCI tristate "DaVinci" depends on ARCH_DAVINCI_DMx diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index ba49501..f95befe 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o obj-$(CONFIG_USB_MUSB_BLACKFIN) += blackfin.o obj-$(CONFIG_USB_MUSB_UX500) += ux500.o obj-$(CONFIG_USB_MUSB_JZ4740) += jz4740.o +obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o obj-$(CONFIG_USB_MUSB_AM335X_CHILD) += musb_am335x.o diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c new file mode 100644 index 0000000..00d7248 --- /dev/null +++ b/drivers/usb/musb/sunxi.c @@ -0,0 +1,703 @@ +/* + * Allwinner sun4i MUSB Glue Layer + * + * Copyright (C) 2015 Hans de Goede + * + * Based on code from + * Allwinner Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "musb_core.h" + +/* + * Register offsets, note sunxi musb has a different layout then most + * musb implementations, we translate the layout in musb_readb & friends. + */ +#define SUNXI_MUSB_POWER 0x0040 +#define SUNXI_MUSB_DEVCTL 0x0041 +#define SUNXI_MUSB_INDEX 0x0042 +#define SUNXI_MUSB_VEND0 0x0043 +#define SUNXI_MUSB_INTRTX 0x0044 +#define SUNXI_MUSB_INTRRX 0x0046 +#define SUNXI_MUSB_INTRTXE 0x0048 +#define SUNXI_MUSB_INTRRXE 0x004a +#define SUNXI_MUSB_INTRUSB 0x004c +#define SUNXI_MUSB_INTRUSBE 0x0050 +#define SUNXI_MUSB_FRAME 0x0054 +#define SUNXI_MUSB_TXFIFOSZ 0x0090 +#define SUNXI_MUSB_TXFIFOADD 0x0092 +#define SUNXI_MUSB_RXFIFOSZ 0x0094 +#define SUNXI_MUSB_RXFIFOADD 0x0096 +#define SUNXI_MUSB_FADDR 0x0098 +#define SUNXI_MUSB_TXFUNCADDR 0x0098 +#define SUNXI_MUSB_TXHUBADDR 0x009a +#define SUNXI_MUSB_TXHUBPORT 0x009b +#define SUNXI_MUSB_RXFUNCADDR 0x009c +#define SUNXI_MUSB_RXHUBADDR 0x009e +#define SUNXI_MUSB_RXHUBPORT 0x009f +#define SUNXI_MUSB_CONFIGDATA 0x00c0 + +/* VEND0 bits */ +#define SUNXI_MUSB_VEND0_PIO_MODE 0 + +/* flags */ +#define SUNXI_MUSB_FL_ENABLED 0 +#define SUNXI_MUSB_FL_HOSTMODE 1 +#define SUNXI_MUSB_FL_HOSTMODE_PEND 2 +#define SUNXI_MUSB_FL_VBUS_ON 3 +#define SUNXI_MUSB_FL_PHY_ON 4 + +/* Our read/write methods need access and do not get passed in a musb ref :| */ +static struct musb *sunxi_musb; + +struct sunxi_glue { + struct device *dev; + struct platform_device *musb; + struct clk *clk; + struct phy *phy; + struct platform_device *usb_phy; + struct usb_phy *xceiv; + unsigned long flags; + struct work_struct work; + struct extcon_dev *extcon; + struct notifier_block host_nb; +}; + +/* phy_power_on / off may sleep, so we use a workqueue */ +static void sunxi_musb_work(struct work_struct *work) +{ + struct sunxi_glue *glue = container_of(work, struct sunxi_glue, work); + bool vbus_on, phy_on; + + if (!test_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags)) + return; + + if (test_and_clear_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags)) { + struct musb *musb = platform_get_drvdata(glue->musb); + unsigned long flags; + u8 devctl; + + spin_lock_irqsave(&musb->lock, flags); + + devctl = readb(musb->mregs + SUNXI_MUSB_DEVCTL); + if (test_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags)) { + set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + musb->xceiv->otg->default_a = 1; + musb->xceiv->otg->state = OTG_STATE_A_IDLE; + MUSB_HST_MODE(musb); + devctl |= MUSB_DEVCTL_SESSION; + } else { + clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + musb->xceiv->otg->default_a = 0; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; + MUSB_DEV_MODE(musb); + devctl &= ~MUSB_DEVCTL_SESSION; + } + writeb(devctl, musb->mregs + SUNXI_MUSB_DEVCTL); + + spin_unlock_irqrestore(&musb->lock, flags); + } + + vbus_on = test_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + phy_on = test_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags); + + if (phy_on != vbus_on) { + if (vbus_on) { + phy_power_on(glue->phy); + set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags); + } else { + phy_power_off(glue->phy); + clear_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags); + } + } +} + +static void sunxi_musb_set_vbus(struct musb *musb, int is_on) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + if (is_on) + set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + else + clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + + schedule_work(&glue->work); +} + +static void sunxi_musb_pre_root_reset_end(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + sun4i_usb_phy_set_squelch_detect(glue->phy, false); +} + +static void sunxi_musb_post_root_reset_end(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + sun4i_usb_phy_set_squelch_detect(glue->phy, true); +} + +static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci) +{ + struct musb *musb = __hci; + unsigned long flags; + + spin_lock_irqsave(&musb->lock, flags); + + musb->int_usb = readb(musb->mregs + SUNXI_MUSB_INTRUSB); + if (musb->int_usb) + writeb(musb->int_usb, musb->mregs + SUNXI_MUSB_INTRUSB); + + /* + * sunxi musb often signals babble on low / full speed device + * disconnect, without ever raising MUSB_INTR_DISCONNECT, since + * normally babble never happens treat it as disconnect. + */ + if ((musb->int_usb & MUSB_INTR_BABBLE) && is_host_active(musb)) { + musb->int_usb &= ~MUSB_INTR_BABBLE; + musb->int_usb |= MUSB_INTR_DISCONNECT; + } + + if ((musb->int_usb & MUSB_INTR_RESET) && !is_host_active(musb)) { + /* ep0 FADDR must be 0 when (re)entering peripheral mode */ + musb_ep_select(musb->mregs, 0); + musb_writeb(musb->mregs, MUSB_FADDR, 0); + } + + musb->int_tx = readw(musb->mregs + SUNXI_MUSB_INTRTX); + if (musb->int_tx) + writew(musb->int_tx, musb->mregs + SUNXI_MUSB_INTRTX); + + musb->int_rx = readw(musb->mregs + SUNXI_MUSB_INTRRX); + if (musb->int_rx) + writew(musb->int_rx, musb->mregs + SUNXI_MUSB_INTRRX); + + musb_interrupt(musb); + + spin_unlock_irqrestore(&musb->lock, flags); + + return IRQ_HANDLED; +} + +static int sunxi_musb_host_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct sunxi_glue *glue = container_of(nb, struct sunxi_glue, host_nb); + + if (event) + set_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags); + else + clear_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags); + + set_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags); + schedule_work(&glue->work); + + return NOTIFY_DONE; +} + +static int sunxi_musb_init(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + int ret; + + sunxi_musb = musb; + musb->phy = glue->phy; + musb->xceiv = glue->xceiv; + + ret = sunxi_sram_claim(musb->controller->parent); + if (ret) + return ret; + + ret = clk_prepare_enable(glue->clk); + if (ret) + goto error_sram_release; + + writeb(SUNXI_MUSB_VEND0_PIO_MODE, musb->mregs + SUNXI_MUSB_VEND0); + + /* Register notifier before calling phy_init() */ + if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) { + ret = extcon_register_notifier(glue->extcon, EXTCON_USB_HOST, + &glue->host_nb); + if (ret) + goto error_clk_disable; + } + + ret = phy_init(glue->phy); + if (ret) + goto error_unregister_notifier; + + if (musb->port_mode == MUSB_PORT_MODE_HOST) { + ret = phy_power_on(glue->phy); + if (ret) + goto error_phy_exit; + set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags); + /* Stop musb work from turning vbus off again */ + set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + } + + musb->isr = sunxi_musb_interrupt; + + /* Stop the musb-core from doing runtime pm (not supported on sunxi) */ + pm_runtime_get(musb->controller); + + return 0; + +error_phy_exit: + phy_exit(glue->phy); +error_unregister_notifier: + if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) + extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, + &glue->host_nb); +error_clk_disable: + clk_disable_unprepare(glue->clk); +error_sram_release: + sunxi_sram_release(musb->controller->parent); + return ret; +} + +static int sunxi_musb_exit(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + pm_runtime_put(musb->controller); + + cancel_work_sync(&glue->work); + if (test_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags)) + phy_power_off(glue->phy); + + phy_exit(glue->phy); + + if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) + extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, + &glue->host_nb); + + clk_disable_unprepare(glue->clk); + sunxi_sram_release(musb->controller->parent); + + return 0; +} + +static void sunxi_musb_enable(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + /* musb_core does not call us in a balanced manner */ + if (test_and_set_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags)) + return; + + schedule_work(&glue->work); +} + +static void sunxi_musb_disable(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + clear_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags); +} + +/* + * sunxi musb register layout + * 0x00 - 0x17 fifo regs, 1 long per fifo + * 0x40 - 0x57 generic control regs (power - frame) + * 0x80 - 0x8f ep control regs (addressed through hw_ep->regs, indexed) + * 0x90 - 0x97 fifo control regs (indexed) + * 0x98 - 0x9f multipoint / busctl regs (indexed) + * 0xc0 configdata reg + */ + +static u32 sunxi_musb_fifo_offset(u8 epnum) +{ + return (epnum * 4); +} + +static u32 sunxi_musb_ep_offset(u8 epnum, u16 offset) +{ + WARN_ONCE(offset != 0, + "sunxi_musb_ep_offset called with non 0 offset\n"); + + return 0x80; /* indexed, so ignore epnum */ +} + +static u32 sunxi_musb_busctl_offset(u8 epnum, u16 offset) +{ + return SUNXI_MUSB_TXFUNCADDR + offset; +} + +static u8 sunxi_musb_readb(const void __iomem *addr, unsigned offset) +{ + if (addr == sunxi_musb->mregs) { + /* generic control or fifo control reg access */ + switch (offset) { + case MUSB_FADDR: + return readb(addr + SUNXI_MUSB_FADDR); + case MUSB_POWER: + return readb(addr + SUNXI_MUSB_POWER); + case MUSB_INTRUSB: + return readb(addr + SUNXI_MUSB_INTRUSB); + case MUSB_INTRUSBE: + return readb(addr + SUNXI_MUSB_INTRUSBE); + case MUSB_INDEX: + return readb(addr + SUNXI_MUSB_INDEX); + case MUSB_TESTMODE: + return 0; /* No testmode on sunxi */ + case MUSB_DEVCTL: + return readb(addr + SUNXI_MUSB_DEVCTL); + case MUSB_TXFIFOSZ: + return readb(addr + SUNXI_MUSB_TXFIFOSZ); + case MUSB_RXFIFOSZ: + return readb(addr + SUNXI_MUSB_RXFIFOSZ); + case MUSB_CONFIGDATA + 0x10: /* See musb_read_configdata() */ + return readb(addr + SUNXI_MUSB_CONFIGDATA); + /* Offset for these is fixed by sunxi_musb_busctl_offset() */ + case SUNXI_MUSB_TXFUNCADDR: + case SUNXI_MUSB_TXHUBADDR: + case SUNXI_MUSB_TXHUBPORT: + case SUNXI_MUSB_RXFUNCADDR: + case SUNXI_MUSB_RXHUBADDR: + case SUNXI_MUSB_RXHUBPORT: + /* multipoint / busctl reg access */ + return readb(addr + offset); + default: + dev_err(sunxi_musb->controller->parent, + "Error unknown readb offset %u\n", offset); + return 0; + } + } else if (addr == (sunxi_musb->mregs + 0x80)) { + /* ep control reg access */ + /* sunxi has a 2 byte hole before the txtype register */ + if (offset >= MUSB_TXTYPE) + offset += 2; + return readb(addr + offset); + } + + dev_err(sunxi_musb->controller->parent, + "Error unknown readb at 0x%x bytes offset\n", + (int)(addr - sunxi_musb->mregs)); + return 0; +} + +static void sunxi_musb_writeb(void __iomem *addr, unsigned offset, u8 data) +{ + if (addr == sunxi_musb->mregs) { + /* generic control or fifo control reg access */ + switch (offset) { + case MUSB_FADDR: + return writeb(data, addr + SUNXI_MUSB_FADDR); + case MUSB_POWER: + return writeb(data, addr + SUNXI_MUSB_POWER); + case MUSB_INTRUSB: + return writeb(data, addr + SUNXI_MUSB_INTRUSB); + case MUSB_INTRUSBE: + return writeb(data, addr + SUNXI_MUSB_INTRUSBE); + case MUSB_INDEX: + return writeb(data, addr + SUNXI_MUSB_INDEX); + case MUSB_TESTMODE: + if (data) + dev_warn(sunxi_musb->controller->parent, + "sunxi-musb does not have testmode\n"); + return; + case MUSB_DEVCTL: + return writeb(data, addr + SUNXI_MUSB_DEVCTL); + case MUSB_TXFIFOSZ: + return writeb(data, addr + SUNXI_MUSB_TXFIFOSZ); + case MUSB_RXFIFOSZ: + return writeb(data, addr + SUNXI_MUSB_RXFIFOSZ); + /* Offset for these is fixed by sunxi_musb_busctl_offset() */ + case SUNXI_MUSB_TXFUNCADDR: + case SUNXI_MUSB_TXHUBADDR: + case SUNXI_MUSB_TXHUBPORT: + case SUNXI_MUSB_RXFUNCADDR: + case SUNXI_MUSB_RXHUBADDR: + case SUNXI_MUSB_RXHUBPORT: + /* multipoint / busctl reg access */ + return writeb(data, addr + offset); + default: + dev_err(sunxi_musb->controller->parent, + "Error unknown writeb offset %u\n", offset); + return; + } + } else if (addr == (sunxi_musb->mregs + 0x80)) { + /* ep control reg access */ + if (offset >= MUSB_TXTYPE) + offset += 2; + return writeb(data, addr + offset); + } + + dev_err(sunxi_musb->controller->parent, + "Error unknown writeb at 0x%x bytes offset\n", + (int)(addr - sunxi_musb->mregs)); +} + +static u16 sunxi_musb_readw(const void __iomem *addr, unsigned offset) +{ + if (addr == sunxi_musb->mregs) { + /* generic control or fifo control reg access */ + switch (offset) { + case MUSB_INTRTX: + return readw(addr + SUNXI_MUSB_INTRTX); + case MUSB_INTRRX: + return readw(addr + SUNXI_MUSB_INTRRX); + case MUSB_INTRTXE: + return readw(addr + SUNXI_MUSB_INTRTXE); + case MUSB_INTRRXE: + return readw(addr + SUNXI_MUSB_INTRRXE); + case MUSB_FRAME: + return readw(addr + SUNXI_MUSB_FRAME); + case MUSB_TXFIFOADD: + return readw(addr + SUNXI_MUSB_TXFIFOADD); + case MUSB_RXFIFOADD: + return readw(addr + SUNXI_MUSB_RXFIFOADD); + case MUSB_HWVERS: + return 0; /* sunxi musb version is not known */ + default: + dev_err(sunxi_musb->controller->parent, + "Error unknown readw offset %u\n", offset); + return 0; + } + } else if (addr == (sunxi_musb->mregs + 0x80)) { + /* ep control reg access */ + return readw(addr + offset); + } + + dev_err(sunxi_musb->controller->parent, + "Error unknown readw at 0x%x bytes offset\n", + (int)(addr - sunxi_musb->mregs)); + return 0; +} + +static void sunxi_musb_writew(void __iomem *addr, unsigned offset, u16 data) +{ + if (addr == sunxi_musb->mregs) { + /* generic control or fifo control reg access */ + switch (offset) { + case MUSB_INTRTX: + return writew(data, addr + SUNXI_MUSB_INTRTX); + case MUSB_INTRRX: + return writew(data, addr + SUNXI_MUSB_INTRRX); + case MUSB_INTRTXE: + return writew(data, addr + SUNXI_MUSB_INTRTXE); + case MUSB_INTRRXE: + return writew(data, addr + SUNXI_MUSB_INTRRXE); + case MUSB_FRAME: + return writew(data, addr + SUNXI_MUSB_FRAME); + case MUSB_TXFIFOADD: + return writew(data, addr + SUNXI_MUSB_TXFIFOADD); + case MUSB_RXFIFOADD: + return writew(data, addr + SUNXI_MUSB_RXFIFOADD); + default: + dev_err(sunxi_musb->controller->parent, + "Error unknown writew offset %u\n", offset); + return; + } + } else if (addr == (sunxi_musb->mregs + 0x80)) { + /* ep control reg access */ + return writew(data, addr + offset); + } + + dev_err(sunxi_musb->controller->parent, + "Error unknown writew at 0x%x bytes offset\n", + (int)(addr - sunxi_musb->mregs)); +} + +static const struct musb_platform_ops sunxi_musb_ops = { + .quirks = MUSB_INDEXED_EP, + .init = sunxi_musb_init, + .exit = sunxi_musb_exit, + .enable = sunxi_musb_enable, + .disable = sunxi_musb_disable, + .fifo_offset = sunxi_musb_fifo_offset, + .ep_offset = sunxi_musb_ep_offset, + .busctl_offset = sunxi_musb_busctl_offset, + .readb = sunxi_musb_readb, + .writeb = sunxi_musb_writeb, + .readw = sunxi_musb_readw, + .writew = sunxi_musb_writew, + .set_vbus = sunxi_musb_set_vbus, + .pre_root_reset_end = sunxi_musb_pre_root_reset_end, + .post_root_reset_end = sunxi_musb_post_root_reset_end, +}; + +/* Allwinner OTG supports up to 5 endpoints */ +#define SUNXI_MUSB_MAX_EP_NUM 6 +#define SUNXI_MUSB_RAM_BITS 11 + +static struct musb_fifo_cfg sunxi_musb_mode_cfg[] = { + MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512), + MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512), + MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512), + MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512), + MUSB_EP_FIFO_SINGLE(5, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(5, FIFO_RX, 512), +}; + +static struct musb_hdrc_config sunxi_musb_hdrc_config = { + .fifo_cfg = sunxi_musb_mode_cfg, + .fifo_cfg_size = ARRAY_SIZE(sunxi_musb_mode_cfg), + .multipoint = true, + .dyn_fifo = true, + .soft_con = true, + .num_eps = SUNXI_MUSB_MAX_EP_NUM, + .ram_bits = SUNXI_MUSB_RAM_BITS, + .dma = 0, +}; + +static int sunxi_musb_probe(struct platform_device *pdev) +{ + struct musb_hdrc_platform_data pdata; + struct platform_device_info pinfo; + struct sunxi_glue *glue; + struct device_node *np = pdev->dev.of_node; + int ret; + + if (!np) { + dev_err(&pdev->dev, "Error no device tree node found\n"); + return -EINVAL; + } + + glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); + if (!glue) + return -ENOMEM; + + memset(&pdata, 0, sizeof(pdata)); + switch (of_usb_get_dr_mode(np)) { +#if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_HOST + case USB_DR_MODE_HOST: + pdata.mode = MUSB_PORT_MODE_HOST; + break; +#endif +#ifdef CONFIG_USB_MUSB_DUAL_ROLE + case USB_DR_MODE_OTG: + glue->extcon = extcon_get_edev_by_phandle(&pdev->dev, 0); + if (IS_ERR(glue->extcon)) { + if (PTR_ERR(glue->extcon) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_err(&pdev->dev, "Invalid or missing extcon\n"); + return PTR_ERR(glue->extcon); + } + pdata.mode = MUSB_PORT_MODE_DUAL_ROLE; + break; +#endif + default: + dev_err(&pdev->dev, "Invalid or missing 'dr_mode' property\n"); + return -EINVAL; + } + pdata.platform_ops = &sunxi_musb_ops; + pdata.config = &sunxi_musb_hdrc_config; + + glue->dev = &pdev->dev; + INIT_WORK(&glue->work, sunxi_musb_work); + glue->host_nb.notifier_call = sunxi_musb_host_notifier; + + glue->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(glue->clk)) { + dev_err(&pdev->dev, "Error getting clock: %ld\n", + PTR_ERR(glue->clk)); + return PTR_ERR(glue->clk); + } + + glue->phy = devm_phy_get(&pdev->dev, "usb"); + if (IS_ERR(glue->phy)) { + if (PTR_ERR(glue->phy) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_err(&pdev->dev, "Error getting phy %ld\n", + PTR_ERR(glue->phy)); + return PTR_ERR(glue->phy); + } + + glue->usb_phy = usb_phy_generic_register(); + if (IS_ERR(glue->usb_phy)) { + dev_err(&pdev->dev, "Error registering usb-phy %ld\n", + PTR_ERR(glue->usb_phy)); + return PTR_ERR(glue->usb_phy); + } + + glue->xceiv = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); + if (IS_ERR(glue->xceiv)) { + ret = PTR_ERR(glue->xceiv); + dev_err(&pdev->dev, "Error getting usb-phy %d\n", ret); + goto err_unregister_usb_phy; + } + + platform_set_drvdata(pdev, glue); + + memset(&pinfo, 0, sizeof(pinfo)); + pinfo.name = "musb-hdrc"; + pinfo.id = PLATFORM_DEVID_AUTO; + pinfo.parent = &pdev->dev; + pinfo.res = pdev->resource; + pinfo.num_res = pdev->num_resources; + pinfo.data = &pdata; + pinfo.size_data = sizeof(pdata); + + glue->musb = platform_device_register_full(&pinfo); + if (IS_ERR(glue->musb)) { + ret = PTR_ERR(glue->musb); + dev_err(&pdev->dev, "Error registering musb dev: %d\n", ret); + goto err_unregister_usb_phy; + } + + return 0; + +err_unregister_usb_phy: + usb_phy_generic_unregister(glue->usb_phy); + return ret; +} + +static int sunxi_musb_remove(struct platform_device *pdev) +{ + struct sunxi_glue *glue = platform_get_drvdata(pdev); + struct platform_device *usb_phy = glue->usb_phy; + + platform_device_unregister(glue->musb); /* Frees glue ! */ + usb_phy_generic_unregister(usb_phy); + + return 0; +} + +static const struct of_device_id sunxi_musb_match[] = { + { .compatible = "allwinner,sun4i-a10-musb", }, + {} +}; + +static struct platform_driver sunxi_musb_driver = { + .probe = sunxi_musb_probe, + .remove = sunxi_musb_remove, + .driver = { + .name = "musb-sunxi", + .of_match_table = sunxi_musb_match, + }, +}; +module_platform_driver(sunxi_musb_driver); + +MODULE_DESCRIPTION("Allwinner sunxi MUSB Glue Layer"); +MODULE_AUTHOR("Hans de Goede "); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 132e23775779cc895c37f7883c33a60a1a8a7cdd Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 8 Jul 2015 16:41:39 +0200 Subject: usb: musb: sunxi: Add support for musb controller in A31 SoC The A31 SoC uses the same musb controller as found in earlier SoCs, but it is hooked up slightly different. Its SRAM is private and no longer controlled through the SRAM controller, and its reset is controlled via a separate reset controller. This commit adds support for this setup. Signed-off-by: Hans de Goede Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt index 9254a6c..fde180b 100644 --- a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt +++ b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt @@ -2,9 +2,10 @@ Allwinner sun4i A10 musb DRC/OTG controller ------------------------------------------- Required properties: - - compatible : "allwinner,sun4i-a10-musb" + - compatible : "allwinner,sun4i-a10-musb" or "allwinner,sun6i-a31-musb" - reg : mmio address range of the musb controller - clocks : clock specifier for the musb controller ahb gate clock + - reset : reset specifier for the ahb reset (A31 and newer only) - interrupts : interrupt to which the musb controller is connected - interrupt-names : must be "mc" - phys : phy specifier for the otg phy diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c index 00d7248..df2f75e 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +71,8 @@ #define SUNXI_MUSB_FL_HOSTMODE_PEND 2 #define SUNXI_MUSB_FL_VBUS_ON 3 #define SUNXI_MUSB_FL_PHY_ON 4 +#define SUNXI_MUSB_FL_HAS_SRAM 5 +#define SUNXI_MUSB_FL_HAS_RESET 6 /* Our read/write methods need access and do not get passed in a musb ref :| */ static struct musb *sunxi_musb; @@ -78,6 +81,7 @@ struct sunxi_glue { struct device *dev; struct platform_device *musb; struct clk *clk; + struct reset_control *rst; struct phy *phy; struct platform_device *usb_phy; struct usb_phy *xceiv; @@ -229,14 +233,22 @@ static int sunxi_musb_init(struct musb *musb) musb->phy = glue->phy; musb->xceiv = glue->xceiv; - ret = sunxi_sram_claim(musb->controller->parent); - if (ret) - return ret; + if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags)) { + ret = sunxi_sram_claim(musb->controller->parent); + if (ret) + return ret; + } ret = clk_prepare_enable(glue->clk); if (ret) goto error_sram_release; + if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) { + ret = reset_control_deassert(glue->rst); + if (ret) + goto error_clk_disable; + } + writeb(SUNXI_MUSB_VEND0_PIO_MODE, musb->mregs + SUNXI_MUSB_VEND0); /* Register notifier before calling phy_init() */ @@ -244,7 +256,7 @@ static int sunxi_musb_init(struct musb *musb) ret = extcon_register_notifier(glue->extcon, EXTCON_USB_HOST, &glue->host_nb); if (ret) - goto error_clk_disable; + goto error_reset_assert; } ret = phy_init(glue->phy); @@ -273,10 +285,14 @@ error_unregister_notifier: if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, &glue->host_nb); +error_reset_assert: + if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) + reset_control_assert(glue->rst); error_clk_disable: clk_disable_unprepare(glue->clk); error_sram_release: - sunxi_sram_release(musb->controller->parent); + if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags)) + sunxi_sram_release(musb->controller->parent); return ret; } @@ -296,8 +312,12 @@ static int sunxi_musb_exit(struct musb *musb) extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, &glue->host_nb); + if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) + reset_control_assert(glue->rst); + clk_disable_unprepare(glue->clk); - sunxi_sram_release(musb->controller->parent); + if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags)) + sunxi_sram_release(musb->controller->parent); return 0; } @@ -617,6 +637,12 @@ static int sunxi_musb_probe(struct platform_device *pdev) INIT_WORK(&glue->work, sunxi_musb_work); glue->host_nb.notifier_call = sunxi_musb_host_notifier; + if (of_device_is_compatible(np, "allwinner,sun4i-a10-musb")) + set_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags); + + if (of_device_is_compatible(np, "allwinner,sun6i-a31-musb")) + set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags); + glue->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(glue->clk)) { dev_err(&pdev->dev, "Error getting clock: %ld\n", @@ -624,6 +650,17 @@ static int sunxi_musb_probe(struct platform_device *pdev) return PTR_ERR(glue->clk); } + if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) { + glue->rst = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(glue->rst)) { + if (PTR_ERR(glue->rst) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_err(&pdev->dev, "Error getting reset %ld\n", + PTR_ERR(glue->rst)); + return PTR_ERR(glue->rst); + } + } + glue->phy = devm_phy_get(&pdev->dev, "usb"); if (IS_ERR(glue->phy)) { if (PTR_ERR(glue->phy) == -EPROBE_DEFER) @@ -685,6 +722,7 @@ static int sunxi_musb_remove(struct platform_device *pdev) static const struct of_device_id sunxi_musb_match[] = { { .compatible = "allwinner,sun4i-a10-musb", }, + { .compatible = "allwinner,sun6i-a31-musb", }, {} }; -- cgit v0.10.2 From d91de093d94eca6e280e50c24b172ed598bb5724 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 8 Jul 2015 16:41:40 +0200 Subject: usb: musb: sunxi: Add support for musb controller in A33 SoC The A33 SoC uses the same musb controller as found on the A31 and later, but allwinner has removed the configdata register, this commit adds special handling for this. Signed-off-by: Hans de Goede Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt index fde180b..862cd7c 100644 --- a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt +++ b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt @@ -2,7 +2,8 @@ Allwinner sun4i A10 musb DRC/OTG controller ------------------------------------------- Required properties: - - compatible : "allwinner,sun4i-a10-musb" or "allwinner,sun6i-a31-musb" + - compatible : "allwinner,sun4i-a10-musb", "allwinner,sun6i-a31-musb" + or "allwinner,sun8i-a33-musb" - reg : mmio address range of the musb controller - clocks : clock specifier for the musb controller ahb gate clock - reset : reset specifier for the ahb reset (A31 and newer only) diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c index df2f75e..f9f6304 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c @@ -73,6 +73,7 @@ #define SUNXI_MUSB_FL_PHY_ON 4 #define SUNXI_MUSB_FL_HAS_SRAM 5 #define SUNXI_MUSB_FL_HAS_RESET 6 +#define SUNXI_MUSB_FL_NO_CONFIGDATA 7 /* Our read/write methods need access and do not get passed in a musb ref :| */ static struct musb *sunxi_musb; @@ -370,6 +371,8 @@ static u32 sunxi_musb_busctl_offset(u8 epnum, u16 offset) static u8 sunxi_musb_readb(const void __iomem *addr, unsigned offset) { + struct sunxi_glue *glue; + if (addr == sunxi_musb->mregs) { /* generic control or fifo control reg access */ switch (offset) { @@ -392,6 +395,12 @@ static u8 sunxi_musb_readb(const void __iomem *addr, unsigned offset) case MUSB_RXFIFOSZ: return readb(addr + SUNXI_MUSB_RXFIFOSZ); case MUSB_CONFIGDATA + 0x10: /* See musb_read_configdata() */ + glue = dev_get_drvdata(sunxi_musb->controller->parent); + /* A33 saves a reg, and we get to hardcode this */ + if (test_bit(SUNXI_MUSB_FL_NO_CONFIGDATA, + &glue->flags)) + return 0xde; + return readb(addr + SUNXI_MUSB_CONFIGDATA); /* Offset for these is fixed by sunxi_musb_busctl_offset() */ case SUNXI_MUSB_TXFUNCADDR: @@ -643,6 +652,11 @@ static int sunxi_musb_probe(struct platform_device *pdev) if (of_device_is_compatible(np, "allwinner,sun6i-a31-musb")) set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags); + if (of_device_is_compatible(np, "allwinner,sun8i-a33-musb")) { + set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags); + set_bit(SUNXI_MUSB_FL_NO_CONFIGDATA, &glue->flags); + } + glue->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(glue->clk)) { dev_err(&pdev->dev, "Error getting clock: %ld\n", @@ -723,6 +737,7 @@ static int sunxi_musb_remove(struct platform_device *pdev) static const struct of_device_id sunxi_musb_match[] = { { .compatible = "allwinner,sun4i-a10-musb", }, { .compatible = "allwinner,sun6i-a31-musb", }, + { .compatible = "allwinner,sun8i-a33-musb", }, {} }; -- cgit v0.10.2 From 8486a0bba6fc13ae60a8e402cf77c60a7d4e7a04 Mon Sep 17 00:00:00 2001 From: Macpaul Lin Date: Thu, 9 Jul 2015 15:18:38 +0800 Subject: usb: add usb_otg20_descriptor for OTG 2.0 and above OTG 2.0 introduces bcdOTG in otg descriptor to identify the OTG and EH supplement release number with which the OTG device is compliant, this patch adds structure usb_otg20_descriptor for OTG 2.0 and above. Signed-off-by: Macpaul Lin Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h index aa33fd1..aec6899 100644 --- a/include/uapi/linux/usb/ch9.h +++ b/include/uapi/linux/usb/ch9.h @@ -674,6 +674,17 @@ struct usb_otg_descriptor { __u8 bmAttributes; /* support for HNP, SRP, etc */ } __attribute__ ((packed)); +/* USB_DT_OTG (from OTG 2.0 supplement) */ +struct usb_otg20_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bmAttributes; /* support for HNP, SRP and ADP, etc */ + __le16 bcdOTG; /* OTG and EH supplement release number + * in binary-coded decimal(i.e. 2.0 is 0200H) + */ +} __attribute__ ((packed)); + /* from usb_otg_descriptor.bmAttributes */ #define USB_OTG_SRP (1 << 0) #define USB_OTG_HNP (1 << 1) /* swap host/device roles */ -- cgit v0.10.2 From 5d701cef9b40188c11c39be3a401bc4feeb154b8 Mon Sep 17 00:00:00 2001 From: Macpaul Lin Date: Thu, 9 Jul 2015 15:18:39 +0800 Subject: usb: add USB_OTG_ADP definition Add USB_OTG_ADP definition for usb_otg_descriptor.bmAttributes. Signed-off-by: Macpaul Lin Signed-off-by: Li Jun Acked-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h index aec6899..f7adc6e 100644 --- a/include/uapi/linux/usb/ch9.h +++ b/include/uapi/linux/usb/ch9.h @@ -688,6 +688,7 @@ struct usb_otg20_descriptor { /* from usb_otg_descriptor.bmAttributes */ #define USB_OTG_SRP (1 << 0) #define USB_OTG_HNP (1 << 1) /* swap host/device roles */ +#define USB_OTG_ADP (1 << 2) /* support ADP */ /*-------------------------------------------------------------------------*/ -- cgit v0.10.2 From 6a88bbe8e30d4beb2320b5a7452242a1fe7889c5 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:40 +0800 Subject: usb: otg: add usb_otg_caps structure for otg capabilities This patch adds a structure usb_otg_caps to cover all otg related capabilities of the device, including otg revision, and if hnp/srp/adp is supported. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h index 52661c5..bd1dcf8 100644 --- a/include/linux/usb/otg.h +++ b/include/linux/usb/otg.h @@ -41,6 +41,21 @@ struct usb_otg { }; +/** + * struct usb_otg_caps - describes the otg capabilities of the device + * @otg_rev: The OTG revision number the device is compliant with, it's + * in binary-coded decimal (i.e. 2.0 is 0200H). + * @hnp_support: Indicates if the device supports HNP. + * @srp_support: Indicates if the device supports SRP. + * @adp_support: Indicates if the device supports ADP. + */ +struct usb_otg_caps { + u16 otg_rev; + bool hnp_support; + bool srp_support; + bool adp_support; +}; + extern const char *usb_otg_state_string(enum usb_otg_state state); /* Context: can sleep */ -- cgit v0.10.2 From 84704bb3d183e55d042bf57043552f2649443a64 Mon Sep 17 00:00:00 2001 From: Macpaul Lin Date: Thu, 9 Jul 2015 15:18:41 +0800 Subject: usb: add usb_otg_caps to usb_gadget structure. Add usb_otg_caps pointer to usb_gadget structure to indicate its otg capabilities. Signed-off-by: Macpaul Lin Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 15604bb..fffceaf 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -511,6 +511,7 @@ struct usb_gadget_ops { * @dev: Driver model state for this abstract device. * @out_epnum: last used out ep number * @in_epnum: last used in ep number + * @otg_caps: OTG capabilities of this gadget. * @sg_supported: true if we can handle scatter-gather * @is_otg: True if the USB device port uses a Mini-AB jack, so that the * gadget driver must provide a USB OTG descriptor. @@ -562,6 +563,7 @@ struct usb_gadget { struct device dev; unsigned out_epnum; unsigned in_epnum; + struct usb_otg_caps *otg_caps; unsigned sg_supported:1; unsigned is_otg:1; -- cgit v0.10.2 From 53e6242db8d60da0587d36951cc9434d1a1c21dd Mon Sep 17 00:00:00 2001 From: Macpaul Lin Date: Thu, 9 Jul 2015 15:18:42 +0800 Subject: usb: gadget: composite: add USB_DT_OTG request handling Copy usb_otg_descriptor from config's descriptor if host requests USB_DT_OTG. Signed-off-by: Macpaul Lin Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 36c6f47..b474499 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -19,6 +19,7 @@ #include #include +#include #include #include "u_os_desc.h" @@ -1540,6 +1541,32 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min(w_length, (u16) value); } break; + case USB_DT_OTG: + if (gadget_is_otg(gadget)) { + struct usb_configuration *config; + int otg_desc_len = 0; + + if (cdev->config) + config = cdev->config; + else + config = list_first_entry( + &cdev->configs, + struct usb_configuration, list); + if (!config) + goto done; + + if (gadget->otg_caps && + (gadget->otg_caps->otg_rev >= 0x0200)) + otg_desc_len += sizeof( + struct usb_otg20_descriptor); + else + otg_desc_len += sizeof( + struct usb_otg_descriptor); + + value = min_t(int, w_length, otg_desc_len); + memcpy(req->buf, config->descriptors[0], value); + } + break; } break; -- cgit v0.10.2 From b5513dede7c90ba2370ab5eb547568a22991907b Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:43 +0800 Subject: doc: dt-binding: usb: add otg related properties Add otg version, srp, hnp and adp support for usb OTG port, then those OTG features don't have to be decided by usb gadget drivers. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt index 477d5bb..bba8257 100644 --- a/Documentation/devicetree/bindings/usb/generic.txt +++ b/Documentation/devicetree/bindings/usb/generic.txt @@ -11,6 +11,19 @@ Optional properties: "peripheral" and "otg". In case this attribute isn't passed via DT, USB DRD controllers should default to OTG. + - otg-rev: tells usb driver the release number of the OTG and EH supplement + with which the device and its descriptors are compliant, + in binary-coded decimal (i.e. 2.0 is 0200H). This + property is used if any real OTG features(HNP/SRP/ADP) + is enabled, if ADP is required, otg-rev should be + 0x0200 or above. + - hnp-disable: tells OTG controllers we want to disable OTG HNP, normally HNP + is the basic function of real OTG except you want it + to be a srp-capable only B device. + - srp-disable: tells OTG controllers we want to disable OTG SRP, SRP is + optional for OTG device. + - adp-disable: tells OTG controllers we want to disable OTG ADP, ADP is + optional for OTG device. This is an attribute to a USB controller such as: @@ -21,4 +34,6 @@ dwc3@4a030000 { usb-phy = <&usb2_phy>, <&usb3,phy>; maximum-speed = "super-speed"; dr_mode = "otg"; + otg-rev = <0x0200>; + adp-disable; }; -- cgit v0.10.2 From 929412d94f2b75fe2a662afa2977bfb6a233c1c3 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:44 +0800 Subject: usb: common: add API to update usb otg capabilities by device tree Check property of usb hardware to update otg version and disable SRP, HNP and ADP if its disable flag is present. Reviewed-by: Roger Quadros Signed-off-by: Li Jun Signed-off-by: Felipe Balbi diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c index b530fd4..9e39286 100644 --- a/drivers/usb/common/common.c +++ b/drivers/usb/common/common.c @@ -154,6 +154,62 @@ bool of_usb_host_tpl_support(struct device_node *np) return false; } EXPORT_SYMBOL_GPL(of_usb_host_tpl_support); + +/** + * of_usb_update_otg_caps - to update usb otg capabilities according to + * the passed properties in DT. + * @np: Pointer to the given device_node + * @otg_caps: Pointer to the target usb_otg_caps to be set + * + * The function updates the otg capabilities + */ +int of_usb_update_otg_caps(struct device_node *np, + struct usb_otg_caps *otg_caps) +{ + u32 otg_rev; + + if (!otg_caps) + return -EINVAL; + + if (!of_property_read_u32(np, "otg-rev", &otg_rev)) { + switch (otg_rev) { + case 0x0100: + case 0x0120: + case 0x0130: + case 0x0200: + /* Choose the lesser one if it's already been set */ + if (otg_caps->otg_rev) + otg_caps->otg_rev = min_t(u16, otg_rev, + otg_caps->otg_rev); + else + otg_caps->otg_rev = otg_rev; + break; + default: + pr_err("%s: unsupported otg-rev: 0x%x\n", + np->full_name, otg_rev); + return -EINVAL; + } + } else { + /* + * otg-rev is mandatory for otg properties, if not passed + * we set it to be 0 and assume it's a legacy otg device. + * Non-dt platform can set it afterwards. + */ + otg_caps->otg_rev = 0; + } + + if (of_find_property(np, "hnp-disable", NULL)) + otg_caps->hnp_support = false; + if (of_find_property(np, "srp-disable", NULL)) + otg_caps->srp_support = false; + if (of_find_property(np, "adp-disable", NULL) || + (otg_caps->otg_rev < 0x0200)) + otg_caps->adp_support = false; + + return 0; +} +EXPORT_SYMBOL_GPL(of_usb_update_otg_caps); + #endif MODULE_LICENSE("GPL"); diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index cfe0528..8c5a818 100644 --- a/include/linux/usb/of.h +++ b/include/linux/usb/of.h @@ -15,6 +15,8 @@ enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np); enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np); bool of_usb_host_tpl_support(struct device_node *np); +int of_usb_update_otg_caps(struct device_node *np, + struct usb_otg_caps *otg_caps); #else static inline enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np) { @@ -30,6 +32,11 @@ static inline bool of_usb_host_tpl_support(struct device_node *np) { return false; } +static inline int of_usb_update_otg_caps(struct device_node *np, + struct usb_otg_caps *otg_caps) +{ + return 0; +} #endif #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT) -- cgit v0.10.2 From 79742351c89b76ebcf82b73103aed50f98ac2ee4 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:45 +0800 Subject: usb: chipidea: set usb otg capabilities Init and update otg capabilities by DT, set gadget's otg capabilities accordingly. Acked-by: Peter Chen Reviewed-by: Roger Quadros Signed-off-by: Li Jun Signed-off-by: Felipe Balbi diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 74fea4f..1e6d5f0 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -560,6 +560,8 @@ static irqreturn_t ci_irq(int irq, void *data) static int ci_get_platdata(struct device *dev, struct ci_hdrc_platform_data *platdata) { + int ret; + if (!platdata->phy_mode) platdata->phy_mode = of_usb_get_phy_mode(dev->of_node); @@ -588,6 +590,19 @@ static int ci_get_platdata(struct device *dev, of_usb_host_tpl_support(dev->of_node); } + if (platdata->dr_mode == USB_DR_MODE_OTG) { + /* We can support HNP and SRP of OTG 2.0 */ + platdata->ci_otg_caps.otg_rev = 0x0200; + platdata->ci_otg_caps.hnp_support = true; + platdata->ci_otg_caps.srp_support = true; + + /* Update otg capabilities by DT properties */ + ret = of_usb_update_otg_caps(dev->of_node, + &platdata->ci_otg_caps); + if (ret) + return ret; + } + if (of_usb_get_maximum_speed(dev->of_node) == USB_SPEED_FULL) platdata->flags |= CI_HDRC_FORCE_FULLSPEED; diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 764f668..b7cca3e 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1827,6 +1827,7 @@ static irqreturn_t udc_irq(struct ci_hdrc *ci) static int udc_start(struct ci_hdrc *ci) { struct device *dev = ci->dev; + struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps; int retval = 0; spin_lock_init(&ci->lock); @@ -1834,8 +1835,12 @@ static int udc_start(struct ci_hdrc *ci) ci->gadget.ops = &usb_gadget_ops; ci->gadget.speed = USB_SPEED_UNKNOWN; ci->gadget.max_speed = USB_SPEED_HIGH; - ci->gadget.is_otg = ci->is_otg ? 1 : 0; ci->gadget.name = ci->platdata->name; + ci->gadget.otg_caps = otg_caps; + + if (otg_caps->hnp_support || otg_caps->srp_support || + otg_caps->adp_support) + ci->gadget.is_otg = 1; INIT_LIST_HEAD(&ci->gadget.ep_list); diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index ab94f78..e10cefc 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -34,6 +34,7 @@ struct ci_hdrc_platform_data { #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 void (*notify_event) (struct ci_hdrc *ci, unsigned event); struct regulator *reg_vbus; + struct usb_otg_caps ci_otg_caps; bool tpl_support; }; -- cgit v0.10.2 From b0930d4cafb487a663ac6780a0369d1a0f461bc2 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:46 +0800 Subject: usb: chipidea: update ci_otg_is_fsm_mode conditions After introduce usb otg properties, update ci_otg_is_fsm_mode conditions to be depending on both usb hardware properties and usb driver config, also resolve a compile issue in debug.c after the API change. Acked-by: Peter Chen Signed-off-by: Li Jun Signed-off-by: Felipe Balbi diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 6d6200e..f243f0b 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -406,8 +406,11 @@ static inline u32 hw_test_and_write(struct ci_hdrc *ci, enum ci_hw_regs reg, static inline bool ci_otg_is_fsm_mode(struct ci_hdrc *ci) { #ifdef CONFIG_USB_OTG_FSM + struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps; + return ci->is_otg && ci->roles[CI_ROLE_HOST] && - ci->roles[CI_ROLE_GADGET]; + ci->roles[CI_ROLE_GADGET] && (otg_caps->srp_support || + otg_caps->hnp_support || otg_caps->adp_support); #else return false; #endif diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index 5b7061a..3869c6d 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "ci.h" #include "udc.h" -- cgit v0.10.2 From d1606dfb98e59221332704c05f5908d9116456ab Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:47 +0800 Subject: usb: gadget: add usb otg descriptor allocate and init interface Allocate usb otg descriptor and initialize it according to gadget's otg capabilities, if usb_otg_caps is not set, keep settings as current gadget drivers. With this 2 new interfaces, gadget can use usb_otg_descriptor for OTG 1.x, and usb_otg20_descriptor for OTG 2.0 or above, and otg features can be decided by the combination of usb hardware property and driver config. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index 34e12fc..0fafa7a 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -20,6 +20,7 @@ #include #include #include +#include /** * usb_descriptor_fillbuf - fill buffer with descriptors @@ -195,3 +196,58 @@ void usb_free_all_descriptors(struct usb_function *f) usb_free_descriptors(f->ss_descriptors); } EXPORT_SYMBOL_GPL(usb_free_all_descriptors); + +struct usb_descriptor_header *usb_otg_descriptor_alloc( + struct usb_gadget *gadget) +{ + struct usb_descriptor_header *otg_desc; + unsigned length = 0; + + if (gadget->otg_caps && (gadget->otg_caps->otg_rev >= 0x0200)) + length = sizeof(struct usb_otg20_descriptor); + else + length = sizeof(struct usb_otg_descriptor); + + otg_desc = kzalloc(length, GFP_KERNEL); + return otg_desc; +} +EXPORT_SYMBOL_GPL(usb_otg_descriptor_alloc); + +int usb_otg_descriptor_init(struct usb_gadget *gadget, + struct usb_descriptor_header *otg_desc) +{ + struct usb_otg_descriptor *otg1x_desc; + struct usb_otg20_descriptor *otg20_desc; + struct usb_otg_caps *otg_caps = gadget->otg_caps; + u8 otg_attributes = 0; + + if (!otg_desc) + return -EINVAL; + + if (otg_caps && otg_caps->otg_rev) { + if (otg_caps->hnp_support) + otg_attributes |= USB_OTG_HNP; + if (otg_caps->srp_support) + otg_attributes |= USB_OTG_SRP; + if (otg_caps->adp_support && (otg_caps->otg_rev >= 0x0200)) + otg_attributes |= USB_OTG_ADP; + } else { + otg_attributes = USB_OTG_SRP | USB_OTG_HNP; + } + + if (otg_caps && (otg_caps->otg_rev >= 0x0200)) { + otg20_desc = (struct usb_otg20_descriptor *)otg_desc; + otg20_desc->bLength = sizeof(struct usb_otg20_descriptor); + otg20_desc->bDescriptorType = USB_DT_OTG; + otg20_desc->bmAttributes = otg_attributes; + otg20_desc->bcdOTG = cpu_to_le16(otg_caps->otg_rev); + } else { + otg1x_desc = (struct usb_otg_descriptor *)otg_desc; + otg1x_desc->bLength = sizeof(struct usb_otg_descriptor); + otg1x_desc->bDescriptorType = USB_DT_OTG; + otg1x_desc->bmAttributes = otg_attributes; + } + + return 0; +} +EXPORT_SYMBOL_GPL(usb_otg_descriptor_init); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index fffceaf..cea0511 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -1092,6 +1092,10 @@ int usb_assign_descriptors(struct usb_function *f, struct usb_descriptor_header **ss); void usb_free_all_descriptors(struct usb_function *f); +struct usb_descriptor_header *usb_otg_descriptor_alloc( + struct usb_gadget *gadget); +int usb_otg_descriptor_init(struct usb_gadget *gadget, + struct usb_descriptor_header *otg_desc); /*-------------------------------------------------------------------------*/ /* utility to simplify map/unmap of usb_requests to/from DMA */ -- cgit v0.10.2 From 41ce84c86d0a04ef70a9608bd744afb122b6d103 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:48 +0800 Subject: usb: gadget: configfs: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations, free it while composite unbind. If otg capability is not defined, keep its otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 289e201..294eb74 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -41,6 +41,8 @@ int check_user_usb_string(const char *name, #define MAX_NAME_LEN 40 #define MAX_USB_STRING_LANGS 2 +static const struct usb_descriptor_header *otg_desc[2]; + struct gadget_info { struct config_group group; struct config_group functions_group; @@ -55,9 +57,6 @@ struct gadget_info { struct list_head available_func; const char *udc_name; -#ifdef CONFIG_USB_OTG - struct usb_otg_descriptor otg; -#endif struct usb_composite_driver composite; struct usb_composite_dev cdev; bool use_os_desc; @@ -1376,6 +1375,19 @@ static int configfs_composite_bind(struct usb_gadget *gadget, memcpy(cdev->qw_sign, gi->qw_sign, OS_STRING_QW_SIGN_LEN); } + if (gadget_is_otg(gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(gadget); + if (!usb_desc) { + ret = -ENOMEM; + goto err_comp_cleanup; + } + usb_otg_descriptor_init(gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + /* Go through all configs, attach all functions */ list_for_each_entry(c, &gi->cdev.configs, list) { struct config_usb_cfg *cfg; @@ -1383,6 +1395,9 @@ static int configfs_composite_bind(struct usb_gadget *gadget, struct usb_function *tmp; struct gadget_config_name *cn; + if (gadget_is_otg(gadget)) + c->descriptors = otg_desc; + cfg = container_of(c, struct config_usb_cfg, c); if (!list_empty(&cfg->string_list)) { i = 0; @@ -1437,6 +1452,8 @@ static void configfs_composite_unbind(struct usb_gadget *gadget) cdev = get_gadget_data(gadget); gi = container_of(cdev, struct gadget_info, cdev); + kfree(otg_desc[0]); + otg_desc[0] = NULL; purge_configs_funcs(gi); composite_dev_cleanup(cdev); usb_ep_autoconfig_reset(cdev->gadget); @@ -1510,12 +1527,6 @@ static struct config_group *gadgets_make( if (!gi->composite.gadget_driver.function) goto err; -#ifdef CONFIG_USB_OTG - gi->otg.bLength = sizeof(struct usb_otg_descriptor); - gi->otg.bDescriptorType = USB_DT_OTG; - gi->otg.bmAttributes = USB_OTG_SRP | USB_OTG_HNP; -#endif - config_group_init_type_name(&gi->group, name, &gadget_root_type); return &gi->group; -- cgit v0.10.2 From 9b95236eebdbdf2ff68517cc32390683f4114a37 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:49 +0800 Subject: usb: gadget: ether: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations, free it while ether unbind. If otg capability is not defined, keep its otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/ether.c b/drivers/usb/gadget/legacy/ether.c index a3323dc..31e9160 100644 --- a/drivers/usb/gadget/legacy/ether.c +++ b/drivers/usb/gadget/legacy/ether.c @@ -171,20 +171,7 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1, }; -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - /* REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; +static const struct usb_descriptor_header *otg_desc[2]; static struct usb_string strings_dev[] = { [USB_GADGET_MANUFACTURER_IDX].s = "", @@ -416,17 +403,28 @@ static int eth_bind(struct usb_composite_dev *cdev) device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + if (gadget_is_otg(gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(gadget); + if (!usb_desc) + goto fail1; + usb_otg_descriptor_init(gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + /* register our configuration(s); RNDIS first, if it's used */ if (has_rndis()) { status = usb_add_config(cdev, &rndis_config_driver, rndis_do_config); if (status < 0) - goto fail1; + goto fail2; } status = usb_add_config(cdev, ð_config_driver, eth_do_config); if (status < 0) - goto fail1; + goto fail2; usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n", @@ -434,6 +432,9 @@ static int eth_bind(struct usb_composite_dev *cdev) return 0; +fail2: + kfree(otg_desc[0]); + otg_desc[0] = NULL; fail1: if (has_rndis()) usb_put_function_instance(fi_rndis); @@ -463,6 +464,9 @@ static int eth_unbind(struct usb_composite_dev *cdev) usb_put_function(f_geth); usb_put_function_instance(fi_geth); } + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v0.10.2 From 578aa8a2b12cb4cc3cfdb6ccd56af9f5f0dd6118 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:50 +0800 Subject: usb: gadget: acm_ms: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/acm_ms.c b/drivers/usb/gadget/legacy/acm_ms.c index 1194b09..4d8adb4 100644 --- a/drivers/usb/gadget/legacy/acm_ms.c +++ b/drivers/usb/gadget/legacy/acm_ms.c @@ -58,21 +58,7 @@ static struct usb_device_descriptor device_desc = { /*.bNumConfigurations = DYNAMIC*/ }; -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - /* - * REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; +static const struct usb_descriptor_header *otg_desc[2]; /* string IDs are assigned dynamically */ static struct usb_string strings_dev[] = { @@ -225,10 +211,21 @@ static int acm_ms_bind(struct usb_composite_dev *cdev) device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + if (gadget_is_otg(gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(gadget); + if (!usb_desc) + goto fail_string_ids; + usb_otg_descriptor_init(gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + /* register our configuration */ status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config); if (status < 0) - goto fail_string_ids; + goto fail_otg_desc; usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n", @@ -236,6 +233,9 @@ static int acm_ms_bind(struct usb_composite_dev *cdev) return 0; /* error recovery */ +fail_otg_desc: + kfree(otg_desc[0]); + otg_desc[0] = NULL; fail_string_ids: fsg_common_remove_luns(opts->common); fail_set_cdev: @@ -255,6 +255,9 @@ static int acm_ms_unbind(struct usb_composite_dev *cdev) usb_put_function_instance(fi_msg); usb_put_function(f_acm); usb_put_function_instance(f_acm_inst); + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v0.10.2 From 56023ce0fd7025154494d139b2c9891d75fee622 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:51 +0800 Subject: usb: gadget: audio: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c index b8095bf..9b2c1c6 100644 --- a/drivers/usb/gadget/legacy/audio.c +++ b/drivers/usb/gadget/legacy/audio.c @@ -150,20 +150,7 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1, }; -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - /* REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; +static const struct usb_descriptor_header *otg_desc[2]; /*-------------------------------------------------------------------------*/ @@ -259,14 +246,28 @@ static int audio_bind(struct usb_composite_dev *cdev) device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + if (gadget_is_otg(cdev->gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(cdev->gadget); + if (!usb_desc) + goto fail; + usb_otg_descriptor_init(cdev->gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + status = usb_add_config(cdev, &audio_config_driver, audio_do_config); if (status < 0) - goto fail; + goto fail_otg_desc; usb_composite_overwrite_options(cdev, &coverwrite); INFO(cdev, "%s, version: %s\n", DRIVER_DESC, DRIVER_VERSION); return 0; +fail_otg_desc: + kfree(otg_desc[0]); + otg_desc[0] = NULL; fail: #ifndef CONFIG_GADGET_UAC1 usb_put_function_instance(fi_uac2); @@ -289,6 +290,9 @@ static int audio_unbind(struct usb_composite_dev *cdev) if (!IS_ERR_OR_NULL(fi_uac2)) usb_put_function_instance(fi_uac2); #endif + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v0.10.2 From ab6796ae98330389754b82d37bed89029d1dab51 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:52 +0800 Subject: usb: gadget: cdc2: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/cdc2.c b/drivers/usb/gadget/legacy/cdc2.c index afd3e37..ecd8c8d 100644 --- a/drivers/usb/gadget/legacy/cdc2.c +++ b/drivers/usb/gadget/legacy/cdc2.c @@ -60,21 +60,7 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1, }; -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - /* REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; - +static const struct usb_descriptor_header *otg_desc[2]; /* string IDs are assigned dynamically */ static struct usb_string strings_dev[] = { @@ -193,10 +179,21 @@ static int cdc_bind(struct usb_composite_dev *cdev) device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + if (gadget_is_otg(gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(gadget); + if (!usb_desc) + goto fail1; + usb_otg_descriptor_init(gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + /* register our configuration */ status = usb_add_config(cdev, &cdc_config_driver, cdc_do_config); if (status < 0) - goto fail1; + goto fail2; usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n", @@ -204,6 +201,9 @@ static int cdc_bind(struct usb_composite_dev *cdev) return 0; +fail2: + kfree(otg_desc[0]); + otg_desc[0] = NULL; fail1: usb_put_function_instance(fi_serial); fail: @@ -219,6 +219,9 @@ static int cdc_unbind(struct usb_composite_dev *cdev) usb_put_function(f_ecm); if (!IS_ERR_OR_NULL(fi_ecm)) usb_put_function_instance(fi_ecm); + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v0.10.2 From 75c9310a050b77a6788addf8060b533ab2d9de00 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:53 +0800 Subject: usb: gadget: g_ffs: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/g_ffs.c b/drivers/usb/gadget/legacy/g_ffs.c index e821931..320a81b 100644 --- a/drivers/usb/gadget/legacy/g_ffs.c +++ b/drivers/usb/gadget/legacy/g_ffs.c @@ -88,21 +88,7 @@ MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol"); module_param_array_named(functions, func_names, charp, &func_num, 0); MODULE_PARM_DESC(functions, "USB Functions list"); -static const struct usb_descriptor_header *gfs_otg_desc[] = { - (const struct usb_descriptor_header *) - &(const struct usb_otg_descriptor) { - .bLength = sizeof(struct usb_otg_descriptor), - .bDescriptorType = USB_DT_OTG, - - /* - * REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, - }, - - NULL -}; +static const struct usb_descriptor_header *gfs_otg_desc[2]; /* String IDs are assigned dynamically */ static struct usb_string gfs_strings[] = { @@ -412,6 +398,17 @@ static int gfs_bind(struct usb_composite_dev *cdev) goto error_rndis; gfs_dev_desc.iProduct = gfs_strings[USB_GADGET_PRODUCT_IDX].id; + if (gadget_is_otg(cdev->gadget) && !gfs_otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(cdev->gadget); + if (!usb_desc) + goto error_rndis; + usb_otg_descriptor_init(cdev->gadget, usb_desc); + gfs_otg_desc[0] = usb_desc; + gfs_otg_desc[1] = NULL; + } + for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) { struct gfs_configuration *c = gfs_configurations + i; int sid = USB_GADGET_FIRST_AVAIL_IDX + i; @@ -432,6 +429,8 @@ static int gfs_bind(struct usb_composite_dev *cdev) /* TODO */ error_unbind: + kfree(gfs_otg_desc[0]); + gfs_otg_desc[0] = NULL; error_rndis: #ifdef CONFIG_USB_FUNCTIONFS_RNDIS usb_put_function_instance(fi_rndis); @@ -473,6 +472,9 @@ static int gfs_unbind(struct usb_composite_dev *cdev) for (i = 0; i < N_CONF * func_num; ++i) usb_put_function(*(f_ffs[0] + i)); + kfree(gfs_otg_desc[0]); + gfs_otg_desc[0] = NULL; + return 0; } -- cgit v0.10.2 From d9e1867917ccf43ebe6f0e43e19958cbdeb0d8f2 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:54 +0800 Subject: usb: gadget: hid: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c index 2baa572..e4874d3 100644 --- a/drivers/usb/gadget/legacy/hid.c +++ b/drivers/usb/gadget/legacy/hid.c @@ -68,21 +68,7 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1, }; -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - /* REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; - +static const struct usb_descriptor_header *otg_desc[2]; /* string IDs are assigned dynamically */ static struct usb_string strings_dev[] = { @@ -186,16 +172,30 @@ static int hid_bind(struct usb_composite_dev *cdev) device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + if (gadget_is_otg(gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(gadget); + if (!usb_desc) + goto put; + usb_otg_descriptor_init(gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + /* register our configuration */ status = usb_add_config(cdev, &config_driver, do_config); if (status < 0) - goto put; + goto free_otg_desc; usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); return 0; +free_otg_desc: + kfree(otg_desc[0]); + otg_desc[0] = NULL; put: list_for_each_entry(m, &hidg_func_list, node) { if (m == n) @@ -213,6 +213,10 @@ static int hid_unbind(struct usb_composite_dev *cdev) usb_put_function(n->f); usb_put_function_instance(n->fi); } + + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v0.10.2 From d867889797615761975e693881a12283ebc92b0f Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:55 +0800 Subject: usb: gadget: mass_storage: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/mass_storage.c b/drivers/usb/gadget/legacy/mass_storage.c index e7bfb08..ab1a42c 100644 --- a/drivers/usb/gadget/legacy/mass_storage.c +++ b/drivers/usb/gadget/legacy/mass_storage.c @@ -64,21 +64,7 @@ static struct usb_device_descriptor msg_device_desc = { .bNumConfigurations = 1, }; -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - /* - * REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; +static const struct usb_descriptor_header *otg_desc[2]; static struct usb_string strings_dev[] = { [USB_GADGET_MANUFACTURER_IDX].s = "", @@ -214,9 +200,20 @@ static int msg_bind(struct usb_composite_dev *cdev) goto fail_string_ids; msg_device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + if (gadget_is_otg(cdev->gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(cdev->gadget); + if (!usb_desc) + goto fail_string_ids; + usb_otg_descriptor_init(cdev->gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + status = usb_add_config(cdev, &msg_config_driver, msg_do_config); if (status < 0) - goto fail_string_ids; + goto fail_otg_desc; usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&cdev->gadget->dev, @@ -224,6 +221,9 @@ static int msg_bind(struct usb_composite_dev *cdev) set_bit(0, &msg_registered); return 0; +fail_otg_desc: + kfree(otg_desc[0]); + otg_desc[0] = NULL; fail_string_ids: fsg_common_remove_luns(opts->common); fail_set_cdev: @@ -243,6 +243,9 @@ static int msg_unbind(struct usb_composite_dev *cdev) if (!IS_ERR(fi_msg)) usb_put_function_instance(fi_msg); + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v0.10.2 From 21ddc2a860ca69eb92ab0c48c05187f89aa6a39a Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:56 +0800 Subject: usb: gadget: multi: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/multi.c b/drivers/usb/gadget/legacy/multi.c index b21b51f..c38ead1 100644 --- a/drivers/usb/gadget/legacy/multi.c +++ b/drivers/usb/gadget/legacy/multi.c @@ -78,21 +78,7 @@ static struct usb_device_descriptor device_desc = { .idProduct = cpu_to_le16(MULTI_PRODUCT_NUM), }; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &(struct usb_otg_descriptor){ - .bLength = sizeof(struct usb_otg_descriptor), - .bDescriptorType = USB_DT_OTG, - - /* - * REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, - }, - NULL, -}; - +static const struct usb_descriptor_header *otg_desc[2]; enum { MULTI_STRING_RNDIS_CONFIG_IDX = USB_GADGET_FIRST_AVAIL_IDX, @@ -429,14 +415,25 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) goto fail_string_ids; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + if (gadget_is_otg(gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(gadget); + if (!usb_desc) + goto fail_string_ids; + usb_otg_descriptor_init(gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + /* register configurations */ status = rndis_config_register(cdev); if (unlikely(status < 0)) - goto fail_string_ids; + goto fail_otg_desc; status = cdc_config_register(cdev); if (unlikely(status < 0)) - goto fail_string_ids; + goto fail_otg_desc; usb_composite_overwrite_options(cdev, &coverwrite); /* we're done */ @@ -445,6 +442,9 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) /* error recovery */ +fail_otg_desc: + kfree(otg_desc[0]); + otg_desc[0] = NULL; fail_string_ids: fsg_common_remove_luns(fsg_opts->common); fail_set_cdev: @@ -490,6 +490,9 @@ static int multi_unbind(struct usb_composite_dev *cdev) usb_put_function(f_ecm); usb_put_function_instance(fi_ecm); #endif + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v0.10.2 From 1156e91dd7cc3a579544286d07fd46f0162e3ec6 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:57 +0800 Subject: usb: gadget: ncm: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/ncm.c b/drivers/usb/gadget/legacy/ncm.c index 6ce7421..2bae438 100644 --- a/drivers/usb/gadget/legacy/ncm.c +++ b/drivers/usb/gadget/legacy/ncm.c @@ -69,20 +69,7 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1, }; -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - /* REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; +static const struct usb_descriptor_header *otg_desc[2]; /* string IDs are assigned dynamically */ static struct usb_string strings_dev[] = { @@ -171,16 +158,30 @@ static int gncm_bind(struct usb_composite_dev *cdev) device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + if (gadget_is_otg(gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(gadget); + if (!usb_desc) + goto fail; + usb_otg_descriptor_init(gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + status = usb_add_config(cdev, &ncm_config_driver, ncm_do_config); if (status < 0) - goto fail; + goto fail1; usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, "%s\n", DRIVER_DESC); return 0; +fail1: + kfree(otg_desc[0]); + otg_desc[0] = NULL; fail: usb_put_function_instance(f_ncm_inst); return status; @@ -192,6 +193,9 @@ static int gncm_unbind(struct usb_composite_dev *cdev) usb_put_function(f_ncm); if (!IS_ERR_OR_NULL(f_ncm_inst)) usb_put_function_instance(f_ncm_inst); + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v0.10.2 From 93d39afdb8f99a11d1cbd04f4670226494bf03da Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:58 +0800 Subject: usb: gadget: printer: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Reviewed-by: Roger Quadros Signed-off-by: Li Jun Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/printer.c b/drivers/usb/gadget/legacy/printer.c index 1ce7df1..0c1fc06 100644 --- a/drivers/usb/gadget/legacy/printer.c +++ b/drivers/usb/gadget/legacy/printer.c @@ -82,16 +82,7 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1 }; -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - .bmAttributes = USB_OTG_SRP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; +static const struct usb_descriptor_header *otg_desc[2]; /*-------------------------------------------------------------------------*/ @@ -136,7 +127,6 @@ static int printer_do_config(struct usb_configuration *c) usb_gadget_set_selfpowered(gadget); if (gadget_is_otg(gadget)) { - otg_descriptor.bmAttributes |= USB_OTG_HNP; printer_cfg_driver.descriptors = otg_desc; printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; } @@ -174,21 +164,39 @@ static int printer_bind(struct usb_composite_dev *cdev) opts->q_len = QLEN; ret = usb_string_ids_tab(cdev, strings); - if (ret < 0) { - usb_put_function_instance(fi_printer); - return ret; - } + if (ret < 0) + goto fail_put_func_inst; + device_desc.iManufacturer = strings[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings[USB_GADGET_PRODUCT_IDX].id; device_desc.iSerialNumber = strings[USB_GADGET_SERIAL_IDX].id; - ret = usb_add_config(cdev, &printer_cfg_driver, printer_do_config); - if (ret) { - usb_put_function_instance(fi_printer); - return ret; + if (gadget_is_otg(cdev->gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(cdev->gadget); + if (!usb_desc) { + ret = -ENOMEM; + goto fail_put_func_inst; + } + usb_otg_descriptor_init(cdev->gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; } + + ret = usb_add_config(cdev, &printer_cfg_driver, printer_do_config); + if (ret) + goto fail_free_otg_desc; + usb_composite_overwrite_options(cdev, &coverwrite); return ret; + +fail_free_otg_desc: + kfree(otg_desc[0]); + otg_desc[0] = NULL; +fail_put_func_inst: + usb_put_function_instance(fi_printer); + return ret; } static int printer_unbind(struct usb_composite_dev *cdev) @@ -196,6 +204,9 @@ static int printer_unbind(struct usb_composite_dev *cdev) usb_put_function(f_printer); usb_put_function_instance(fi_printer); + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v0.10.2 From 3dcc7053087fb58c799cd964a00a5396bec3bc9e Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:59 +0800 Subject: usb: gadget: serial: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Reviewed-by: Roger Quadros Signed-off-by: Li Jun Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/serial.c b/drivers/usb/gadget/legacy/serial.c index 8b7528f..9836d16 100644 --- a/drivers/usb/gadget/legacy/serial.c +++ b/drivers/usb/gadget/legacy/serial.c @@ -79,20 +79,7 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1, }; -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - /* REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; +static const struct usb_descriptor_header *otg_desc[2]; /*-------------------------------------------------------------------------*/ @@ -191,6 +178,18 @@ static int gs_bind(struct usb_composite_dev *cdev) serial_config_driver.iConfiguration = status; if (gadget_is_otg(cdev->gadget)) { + if (!otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(cdev->gadget); + if (!usb_desc) { + status = -ENOMEM; + goto fail; + } + usb_otg_descriptor_init(cdev->gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } serial_config_driver.descriptors = otg_desc; serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; } @@ -208,13 +207,15 @@ static int gs_bind(struct usb_composite_dev *cdev) "gser"); } if (status < 0) - goto fail; + goto fail1; usb_composite_overwrite_options(cdev, &coverwrite); INFO(cdev, "%s\n", GS_VERSION_NAME); return 0; - +fail1: + kfree(otg_desc[0]); + otg_desc[0] = NULL; fail: return status; } @@ -227,6 +228,10 @@ static int gs_unbind(struct usb_composite_dev *cdev) usb_put_function(f_serial[i]); usb_put_function_instance(fi_serial[i]); } + + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v0.10.2 From 9e832bf7c011965b378bd963955e315bd0c23aa4 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:19:00 +0800 Subject: usb: gadget: zero: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Reviewed-by: Roger Quadros Signed-off-by: Li Jun Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/zero.c b/drivers/usb/gadget/legacy/zero.c index c986e8a..37a4100 100644 --- a/drivers/usb/gadget/legacy/zero.c +++ b/drivers/usb/gadget/legacy/zero.c @@ -121,24 +121,7 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 2, }; -#ifdef CONFIG_USB_OTG -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - /* REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; -#else -#define otg_desc NULL -#endif +static const struct usb_descriptor_header *otg_desc[2]; /* string IDs are assigned dynamically */ /* default serial number takes at least two packets */ @@ -341,6 +324,18 @@ static int zero_bind(struct usb_composite_dev *cdev) /* support OTG systems */ if (gadget_is_otg(cdev->gadget)) { + if (!otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(cdev->gadget); + if (!usb_desc) { + status = -ENOMEM; + goto err_conf_flb; + } + usb_otg_descriptor_init(cdev->gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } sourcesink_driver.descriptors = otg_desc; sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; loopback_driver.descriptors = otg_desc; @@ -359,12 +354,12 @@ static int zero_bind(struct usb_composite_dev *cdev) } status = usb_add_function(&sourcesink_driver, func_ss); if (status) - goto err_conf_flb; + goto err_free_otg_desc; usb_ep_autoconfig_reset(cdev->gadget); status = usb_add_function(&loopback_driver, func_lb); if (status) - goto err_conf_flb; + goto err_free_otg_desc; usb_ep_autoconfig_reset(cdev->gadget); usb_composite_overwrite_options(cdev, &coverwrite); @@ -373,6 +368,9 @@ static int zero_bind(struct usb_composite_dev *cdev) return 0; +err_free_otg_desc: + kfree(otg_desc[0]); + otg_desc[0] = NULL; err_conf_flb: usb_put_function(func_lb); func_lb = NULL; @@ -397,6 +395,9 @@ static int zero_unbind(struct usb_composite_dev *cdev) if (!IS_ERR_OR_NULL(func_lb)) usb_put_function(func_lb); usb_put_function_instance(func_inst_lb); + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v0.10.2 From b5a2875605cac14a7d7744ec8254547a26c02612 Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Mon, 13 Jul 2015 16:30:18 +0100 Subject: usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS These changes allow a PHY driver to trigger a VBUS interrupt and to provide the value of VBUS. Reviewed-by: Laurent Pinchart Signed-off-by: Phil Edworthy Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index dc2aa32..494dfe0 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -21,6 +21,7 @@ #include #include #include +#include #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 * -- cgit v0.10.2 From 49bda21266fdf195142e8b5dea057f09e96ada9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pecio?= Date: Sun, 26 Jul 2015 11:14:34 +0200 Subject: USB: pl2303: fix baud-rate divisor calculations This commit fixes the following issues: 1. The 9th bit of buf was believed to be the LSB of divisor's exponent, but the hardware interprets it as MSB (9th bit) of the mantissa. The exponent is actually one bit shorter and applies to base 4, not 2 as previously believed. 2. Loop iterations doubled the exponent instead of incrementing. 3. The exponent wasn't checked for overflow. 4. The function returned requested rate instead of actual rate. Due to issue #2, the old code deviated from the wrong formula described in #1 and actually yielded correct rates when divisor was lower than 4096 by using exponents of 0, 2 or 4 base-2, interpreted as 0, 1, 2 base-4 with the 9th mantissa bit clear. However, at 93.75 kbaud or less the rate turned out too slow due to #2 or too fast due to #2 and #3. I tested this patch by sending and validating 0x00,0x01,..,0xff to an FTDI dongle at 234, 987, 2401, 9601, 31415, 115199, 250k, 500k, 750k, 1M, 1.5M, 3M+1 baud. All rates passed. I also used pv to check speed at some rates unsupported by FTDI: 45 (the lowest possible), 2M, 4M, 5M and 6M-1. Looked sane. Signed-off-by: Michal Pecio Fixes: 399aa9a75ad3 ("USB: pl2303: use divisors for unsupported baud rates") Cc: stable # v3.18 [johan: update summary ] Signed-off-by: Johan Hovold diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index f5257af..ae682e4 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -362,21 +362,38 @@ static speed_t pl2303_encode_baud_rate_direct(unsigned char buf[4], static speed_t pl2303_encode_baud_rate_divisor(unsigned char buf[4], speed_t baud) { - unsigned int tmp; + unsigned int baseline, mantissa, exponent; /* * Apparently the formula is: - * baudrate = 12M * 32 / (2^buf[1]) / buf[0] + * baudrate = 12M * 32 / (mantissa * 4^exponent) + * where + * mantissa = buf[8:0] + * exponent = buf[11:9] */ - tmp = 12000000 * 32 / baud; + baseline = 12000000 * 32; + mantissa = baseline / baud; + if (mantissa == 0) + mantissa = 1; /* Avoid dividing by zero if baud > 32*12M. */ + exponent = 0; + while (mantissa >= 512) { + if (exponent < 7) { + mantissa >>= 2; /* divide by 4 */ + exponent++; + } else { + /* Exponent is maxed. Trim mantissa and leave. */ + mantissa = 511; + break; + } + } + buf[3] = 0x80; buf[2] = 0; - buf[1] = (tmp >= 256); - while (tmp >= 256) { - tmp >>= 2; - buf[1] <<= 1; - } - buf[0] = tmp; + buf[1] = exponent << 1 | mantissa >> 8; + buf[0] = mantissa & 0xff; + + /* Calculate and return the exact baud rate. */ + baud = (baseline / mantissa) >> (exponent << 1); return baud; } -- cgit v0.10.2 From b2fb5b1a0f50d3ebc12342c8d8dead245e9c9d4e Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 27 Jul 2015 12:25:27 +0530 Subject: usb: dwc3: ep0: Fix mem corruption on OUT transfers of more than 512 bytes DWC3 uses bounce buffer to handle non max packet aligned OUT transfers and the size of bounce buffer is 512 bytes. However if the host initiates OUT transfers of size more than 512 bytes (and non max packet aligned), the driver throws a WARN dump but still programs the TRB to receive more than 512 bytes. This will cause bounce buffer to overflow and corrupt the adjacent memory locations which can be fatal. Fix it by programming the TRB to receive a maximum of DWC3_EP0_BOUNCE_SIZE (512) bytes. Cc: # 3.4+ Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 69e769c..06ecd1e 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -820,6 +820,11 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, unsigned maxp = ep0->endpoint.maxpacket; transfer_size += (maxp - (transfer_size % maxp)); + + /* Maximum of DWC3_EP0_BOUNCE_SIZE can only be received */ + if (transfer_size > DWC3_EP0_BOUNCE_SIZE) + transfer_size = DWC3_EP0_BOUNCE_SIZE; + transferred = min_t(u32, ur->length, transfer_size - length); memcpy(ur->buf, dwc->ep0_bounce, transferred); @@ -941,11 +946,14 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, return; } - WARN_ON(req->request.length > DWC3_EP0_BOUNCE_SIZE); - maxpacket = dep->endpoint.maxpacket; transfer_size = roundup(req->request.length, maxpacket); + if (transfer_size > DWC3_EP0_BOUNCE_SIZE) { + dev_WARN(dwc->dev, "bounce buf can't handle req len\n"); + transfer_size = DWC3_EP0_BOUNCE_SIZE; + } + dwc->ep0_bounced = true; /* -- cgit v0.10.2 From 2e5464da4e7dc55e1751d2beb3e6e78f35020756 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 27 Jul 2015 12:25:28 +0530 Subject: usb: dwc3: ep0: use _roundup_ to calculate the transfer size No functional change. Used _roundup_ macro to calculate the transfer size aligned to maxpacket in dwc3_ep0_complete_data. It also makes it similar to how transfer size is calculated in __dwc3_ep0_do_control_data. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 06ecd1e..672d55a 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -816,10 +816,8 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, length = trb->size & DWC3_TRB_SIZE_MASK; if (dwc->ep0_bounced) { - unsigned transfer_size = ur->length; unsigned maxp = ep0->endpoint.maxpacket; - - transfer_size += (maxp - (transfer_size % maxp)); + unsigned transfer_size = roundup(ur->length, maxp); /* Maximum of DWC3_EP0_BOUNCE_SIZE can only be received */ if (transfer_size > DWC3_EP0_BOUNCE_SIZE) -- cgit v0.10.2 From 8a3442205630d52b1b1777efe07c80832aa5ee73 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 27 Jul 2015 12:25:29 +0530 Subject: usb: dwc3: ep0: preparation for handling non maxpacket aligned transfers > 512 No functional change. This is in preparation for handling non maxpacket aligned transfers greater than bounce buffer size. This is basically to avoid code duplication when using chained TRB transfers to handle non maxpacket aligned transfers greater than bounce buffer size. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 672d55a..396c2af 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -783,7 +783,11 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, struct usb_request *ur; struct dwc3_trb *trb; struct dwc3_ep *ep0; - u32 transferred; + unsigned transfer_size = 0; + unsigned maxp; + unsigned remaining_ur_length; + void *buf; + u32 transferred = 0; u32 status; u32 length; u8 epnum; @@ -812,20 +816,24 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, } ur = &r->request; + buf = ur->buf; + remaining_ur_length = ur->length; length = trb->size & DWC3_TRB_SIZE_MASK; + maxp = ep0->endpoint.maxpacket; + if (dwc->ep0_bounced) { - unsigned maxp = ep0->endpoint.maxpacket; - unsigned transfer_size = roundup(ur->length, maxp); + transfer_size = roundup((ur->length - transfer_size), + maxp); /* Maximum of DWC3_EP0_BOUNCE_SIZE can only be received */ if (transfer_size > DWC3_EP0_BOUNCE_SIZE) transfer_size = DWC3_EP0_BOUNCE_SIZE; - transferred = min_t(u32, ur->length, - transfer_size - length); - memcpy(ur->buf, dwc->ep0_bounce, transferred); + transferred = min_t(u32, remaining_ur_length, + transfer_size - length); + memcpy(buf, dwc->ep0_bounce, transferred); } else { transferred = ur->length - length; } @@ -934,7 +942,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, DWC3_TRBCTL_CONTROL_DATA); } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) && (dep->number == 0)) { - u32 transfer_size; + u32 transfer_size = 0; u32 maxpacket; ret = usb_gadget_map_request(&dwc->gadget, &req->request, @@ -945,7 +953,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, } maxpacket = dep->endpoint.maxpacket; - transfer_size = roundup(req->request.length, maxpacket); + transfer_size = roundup((req->request.length - transfer_size), + maxpacket); if (transfer_size > DWC3_EP0_BOUNCE_SIZE) { dev_WARN(dwc->dev, "bounce buf can't handle req len\n"); -- cgit v0.10.2 From 368ca113ca0a41bbf60be6886bbbd238523c6fba Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 27 Jul 2015 12:25:30 +0530 Subject: usb: dwc3; ep0: Modify _dwc3_ep0_start_trans_ API to take 'chain' parameter No functional change. Added a new parameter in _dwc3_ep0_start_trans_ to indicate whether the TRB is a chained TRB or last TRB. This is in preparation for adding chained TRB support for ep0. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 396c2af..3f709a3 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -56,7 +56,7 @@ static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state) } static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, - u32 len, u32 type) + u32 len, u32 type, bool chain) { struct dwc3_gadget_ep_cmd_params params; struct dwc3_trb *trb; @@ -302,7 +302,7 @@ void dwc3_ep0_out_start(struct dwc3 *dwc) int ret; ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8, - DWC3_TRBCTL_CONTROL_SETUP); + DWC3_TRBCTL_CONTROL_SETUP, false); WARN_ON(ret < 0); } @@ -855,7 +855,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, ret = dwc3_ep0_start_trans(dwc, epnum, dwc->ctrl_req_addr, 0, - DWC3_TRBCTL_CONTROL_DATA); + DWC3_TRBCTL_CONTROL_DATA, false); WARN_ON(ret < 0); } } @@ -939,7 +939,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, if (req->request.length == 0) { ret = dwc3_ep0_start_trans(dwc, dep->number, dwc->ctrl_req_addr, 0, - DWC3_TRBCTL_CONTROL_DATA); + DWC3_TRBCTL_CONTROL_DATA, false); } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) && (dep->number == 0)) { u32 transfer_size = 0; @@ -970,7 +970,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, */ ret = dwc3_ep0_start_trans(dwc, dep->number, dwc->ep0_bounce_addr, transfer_size, - DWC3_TRBCTL_CONTROL_DATA); + DWC3_TRBCTL_CONTROL_DATA, false); } else { ret = usb_gadget_map_request(&dwc->gadget, &req->request, dep->number); @@ -980,7 +980,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, } ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma, - req->request.length, DWC3_TRBCTL_CONTROL_DATA); + req->request.length, DWC3_TRBCTL_CONTROL_DATA, + false); } WARN_ON(ret < 0); @@ -995,7 +996,7 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) : DWC3_TRBCTL_CONTROL_STATUS2; return dwc3_ep0_start_trans(dwc, dep->number, - dwc->ctrl_req_addr, 0, type); + dwc->ctrl_req_addr, 0, type, false); } static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep) -- cgit v0.10.2 From 2abd9d5fa60f90cd99801687904f528156d31e18 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 27 Jul 2015 12:25:31 +0530 Subject: usb: dwc3: ep0: Add chained TRB support Add chained TRB support to ep0. Now TRB's can be chained just by invoking _dwc3_ep0_start_trans_ with 'chain' parameter set to true. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 3f709a3..ebf2621 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -70,7 +70,10 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, return 0; } - trb = dwc->ep0_trb; + trb = &dwc->ep0_trb[dep->free_slot]; + + if (chain) + dep->free_slot++; trb->bpl = lower_32_bits(buf_dma); trb->bph = upper_32_bits(buf_dma); @@ -78,10 +81,17 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, trb->ctrl = type; trb->ctrl |= (DWC3_TRB_CTRL_HWO - | DWC3_TRB_CTRL_LST - | DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_ISP_IMI); + if (chain) + trb->ctrl |= DWC3_TRB_CTRL_CHN; + else + trb->ctrl |= (DWC3_TRB_CTRL_IOC + | DWC3_TRB_CTRL_LST); + + if (chain) + return 0; + memset(¶ms, 0, sizeof(params)); params.param0 = upper_32_bits(dwc->ep0_trb_addr); params.param1 = lower_32_bits(dwc->ep0_trb_addr); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index d97fcfa..2feed9e 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2687,7 +2687,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err0; } - dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb), + dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2, &dwc->ep0_trb_addr, GFP_KERNEL); if (!dwc->ep0_trb) { dev_err(dwc->dev, "failed to allocate ep0 trb\n"); -- cgit v0.10.2 From c0bd5456a470223e331a9e9e93b4a7425ecfaabb Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 27 Jul 2015 12:25:32 +0530 Subject: usb: dwc3: ep0: handle non maxpacket aligned transfers > 512 Use chained TRB mechanism to handle non maxpacket aligned transfers greater than bounce buffer size. With this the first TRB will be programmed to receive 'ALIGN(ur->length - maxp, maxp)' data and the second TRB will be programmed to receive the remaining data using bounce buffer. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index ebf2621..5320e93 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -834,13 +834,26 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, maxp = ep0->endpoint.maxpacket; if (dwc->ep0_bounced) { + /* + * Handle the first TRB before handling the bounce buffer if + * the request length is greater than the bounce buffer size + */ + if (ur->length > DWC3_EP0_BOUNCE_SIZE) { + transfer_size = ALIGN(ur->length - maxp, maxp); + transferred = transfer_size - length; + buf = (u8 *)buf + transferred; + ur->actual += transferred; + remaining_ur_length -= transferred; + + trb++; + length = trb->size & DWC3_TRB_SIZE_MASK; + + ep0->free_slot = 0; + } + transfer_size = roundup((ur->length - transfer_size), maxp); - /* Maximum of DWC3_EP0_BOUNCE_SIZE can only be received */ - if (transfer_size > DWC3_EP0_BOUNCE_SIZE) - transfer_size = DWC3_EP0_BOUNCE_SIZE; - transferred = min_t(u32, remaining_ur_length, transfer_size - length); memcpy(buf, dwc->ep0_bounce, transferred); @@ -963,21 +976,22 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, } maxpacket = dep->endpoint.maxpacket; - transfer_size = roundup((req->request.length - transfer_size), - maxpacket); - if (transfer_size > DWC3_EP0_BOUNCE_SIZE) { - dev_WARN(dwc->dev, "bounce buf can't handle req len\n"); - transfer_size = DWC3_EP0_BOUNCE_SIZE; + if (req->request.length > DWC3_EP0_BOUNCE_SIZE) { + transfer_size = ALIGN(req->request.length - maxpacket, + maxpacket); + ret = dwc3_ep0_start_trans(dwc, dep->number, + req->request.dma, + transfer_size, + DWC3_TRBCTL_CONTROL_DATA, + true); } + transfer_size = roundup((req->request.length - transfer_size), + maxpacket); + dwc->ep0_bounced = true; - /* - * REVISIT in case request length is bigger than - * DWC3_EP0_BOUNCE_SIZE we will need two chained - * TRBs to handle the transfer. - */ ret = dwc3_ep0_start_trans(dwc, dep->number, dwc->ep0_bounce_addr, transfer_size, DWC3_TRBCTL_CONTROL_DATA, false); -- cgit v0.10.2 From ffd9a0fcbbed300b55f84e8397e96c2edd06cbdf Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Tue, 28 Jul 2015 07:19:58 +0200 Subject: usb: gadget: add 'quirk_altset_not_supp' to usb_gadget Due to some UDC controllers may not support altsettings, usb gadget layer needs to provide a generic way to inform gadget functions about non-standard hardware limitations. This patch adds 'quirk_altset_not_supp' field to struct usb_gadget and helper function gadget_is_altset_supported(). It also sets 'quirk_altset_not_supp' to 1 in pxa25x_udc and pxa27x_udc drivers, which have such limitation. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index f6cbe66..27f9442 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -1176,6 +1176,7 @@ static void udc_reinit(struct pxa25x_udc *dev) INIT_LIST_HEAD (&dev->gadget.ep_list); INIT_LIST_HEAD (&dev->gadget.ep0->ep_list); dev->ep0state = EP0_IDLE; + dev->gadget.quirk_altset_not_supp = 1; /* basic endpoint records init */ for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) { diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index 042f06b..670ac0b 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -1710,6 +1710,7 @@ static void udc_init_data(struct pxa_udc *dev) INIT_LIST_HEAD(&dev->gadget.ep_list); INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); dev->udc_usb_ep[0].pxa_ep = &dev->pxa_ep[0]; + dev->gadget.quirk_altset_not_supp = 1; ep0_idle(dev); /* PXA endpoints init */ diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index cea0511..31be84b 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -572,6 +572,7 @@ struct usb_gadget { unsigned a_hnp_support:1; unsigned a_alt_hnp_support:1; unsigned quirk_ep_out_aligned_size:1; + unsigned quirk_altset_not_supp:1; unsigned is_selfpowered:1; unsigned deactivated:1; unsigned connected:1; @@ -610,6 +611,16 @@ usb_ep_align_maybe(struct usb_gadget *g, struct usb_ep *ep, size_t len) } /** + * gadget_is_altset_supported - return true iff the hardware supports + * altsettings + * @g: controller to check for quirk + */ +static inline int gadget_is_altset_supported(struct usb_gadget *g) +{ + return !g->quirk_altset_not_supp; +} + +/** * gadget_is_dualspeed - return true iff the hardware handles high speed * @g: controller that might support both high and full speeds */ -- cgit v0.10.2 From 02ded1b0d8e73dad7d2626c960ef20fb7dc30753 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Tue, 28 Jul 2015 07:19:59 +0200 Subject: usb: gadget: add 'quirk_stall_not_supp' to usb_gadget Due to some UDC controllers may not support stalling, usb gadget layer needs to provide a generic way to inform gadget functions about non-standard hardware limitations. This patch adds 'quirk_stall_not_supp' field to struct usb_gadget and helper function gadget_is_stall_supported(). It also sets 'quirk_stall_not_supp' to 1 in at91_udc driver, which has such limitation. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index fc42264..32f50a79 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -825,6 +825,7 @@ static void udc_reinit(struct at91_udc *udc) INIT_LIST_HEAD(&udc->gadget.ep_list); INIT_LIST_HEAD(&udc->gadget.ep0->ep_list); + udc->gadget.quirk_stall_not_supp = 1; for (i = 0; i < NUM_ENDPOINTS; i++) { struct at91_ep *ep = &udc->ep[i]; diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 31be84b..f195a76 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -573,6 +573,7 @@ struct usb_gadget { unsigned a_alt_hnp_support:1; unsigned quirk_ep_out_aligned_size:1; unsigned quirk_altset_not_supp:1; + unsigned quirk_stall_not_supp:1; unsigned is_selfpowered:1; unsigned deactivated:1; unsigned connected:1; @@ -621,6 +622,15 @@ static inline int gadget_is_altset_supported(struct usb_gadget *g) } /** + * gadget_is_stall_supported - return true iff the hardware supports stalling + * @g: controller to check for quirk + */ +static inline int gadget_is_stall_supported(struct usb_gadget *g) +{ + return !g->quirk_stall_not_supp; +} + +/** * gadget_is_dualspeed - return true iff the hardware handles high speed * @g: controller that might support both high and full speeds */ -- cgit v0.10.2 From ca1023c81dd10f76a5d0a8be2fdbe724fe7a126a Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Tue, 28 Jul 2015 07:20:00 +0200 Subject: usb: gadget: add 'quirk_zlp_not_supp' to usb_gadget Due to some UDC controllers may not support zlp, usb gadget layer needs to provide a generic way to inform gadget functions about non-standard hardware limitations. This patch adds 'quirk_zlp_not_supp' field to struct usb_gadget and helper function gadget_is_zlp_supported(). It also sets 'quirk_zlp_not_supp' to 1 in musb UDC driver, which has such limitation. [ balbi@ti.com : make it build ] Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 625d482f..9e18178 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -2075,6 +2075,7 @@ __acquires(musb->lock) musb->g.b_hnp_enable = 0; musb->g.a_alt_hnp_support = 0; musb->g.a_hnp_support = 0; + musb->g.quirk_zlp_not_supp = 1; /* Normal reset, as B-Device; * or else after HNP, as A-Device diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index f195a76..353a720 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -574,6 +574,7 @@ struct usb_gadget { unsigned quirk_ep_out_aligned_size:1; unsigned quirk_altset_not_supp:1; unsigned quirk_stall_not_supp:1; + unsigned quirk_zlp_not_supp:1; unsigned is_selfpowered:1; unsigned deactivated:1; unsigned connected:1; @@ -631,6 +632,15 @@ static inline int gadget_is_stall_supported(struct usb_gadget *g) } /** + * gadget_is_zlp_supported - return true iff the hardware supports zlp + * @g: controller to check for quirk + */ +static inline int gadget_is_zlp_supported(struct usb_gadget *g) +{ + return !g->quirk_zlp_not_supp; +} + +/** * gadget_is_dualspeed - return true iff the hardware handles high speed * @g: controller that might support both high and full speeds */ -- cgit v0.10.2 From a4cc42157f3f8c3dd5562b91c7430376912c6fb8 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Tue, 28 Jul 2015 07:20:01 +0200 Subject: usb: gadget: f_mass_storage: check quirk instead of UDC name Use generic mechanism to check if UDC controller supports stalling. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 9e88e2b..a229194 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2836,7 +2836,8 @@ int fsg_common_set_cdev(struct fsg_common *common, * halt bulk endpoints correctly. If one of them is present, * disable stalls. */ - common->can_stall = can_stall && !(gadget_is_at91(common->gadget)); + common->can_stall = can_stall && + gadget_is_stall_supported(common->gadget); return 0; } -- cgit v0.10.2 From 7a896d40525349e7d52307fb957882696e09466c Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Tue, 28 Jul 2015 07:20:02 +0200 Subject: usb: gadget: f_ecm/f_ncm: check quirk instead of UDC name Use generic mechanism to check if UDC controller supports zlp. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c index 798760f..7b7424f 100644 --- a/drivers/usb/gadget/function/f_ecm.c +++ b/drivers/usb/gadget/function/f_ecm.c @@ -585,8 +585,8 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) /* Enable zlps by default for ECM conformance; * override for musb_hdrc (avoids txdma ovhead). */ - ecm->port.is_zlp_ok = !(gadget_is_musbhdrc(cdev->gadget) - ); + ecm->port.is_zlp_ok = + gadget_is_zlp_supported(cdev->gadget); ecm->port.cdc_filter = DEFAULT_FILTER; DBG(cdev, "activate ecm\n"); net = gether_connect(&ecm->port); diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index bdcda9f..3f05c6bd 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -853,9 +853,8 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) /* Enable zlps by default for NCM conformance; * override for musb_hdrc (avoids txdma ovhead) */ - ncm->port.is_zlp_ok = !( - gadget_is_musbhdrc(cdev->gadget) - ); + ncm->port.is_zlp_ok = + gadget_is_zlp_supported(cdev->gadget); ncm->port.cdc_filter = DEFAULT_FILTER; DBG(cdev, "activate ncm\n"); net = gether_connect(&ncm->port); -- cgit v0.10.2 From 736d093b5985c1f6583460c8eea1be3c9ee5635e Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Tue, 28 Jul 2015 07:20:03 +0200 Subject: usb: gadget: apply generic altsetting support check mechanism Replace calls of gadget_supports_altsettings() function (which check altset support by comparing UDC controller name with hardcoded names) with gadget_is_altset_supported() which checks generic quirk bitfield. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_obex.c b/drivers/usb/gadget/function/f_obex.c index 5519f85..2682d59 100644 --- a/drivers/usb/gadget/function/f_obex.c +++ b/drivers/usb/gadget/function/f_obex.c @@ -297,7 +297,7 @@ static inline bool can_support_obex(struct usb_configuration *c) * * Altsettings are mandatory, however... */ - if (!gadget_supports_altsettings(c->cdev->gadget)) + if (!gadget_is_altset_supported(c->cdev->gadget)) return false; /* everything else is *probably* fine ... */ diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index 334b389..1384f00 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -259,7 +259,7 @@ void gether_disconnect(struct gether *); /* Some controllers can't support CDC Ethernet (ECM) ... */ static inline bool can_support_ecm(struct usb_gadget *gadget) { - if (!gadget_supports_altsettings(gadget)) + if (!gadget_is_altset_supported(gadget)) return false; /* Everything else is *presumably* fine ... but this is a bit diff --git a/drivers/usb/gadget/legacy/nokia.c b/drivers/usb/gadget/legacy/nokia.c index 8902f45..264c97e 100644 --- a/drivers/usb/gadget/legacy/nokia.c +++ b/drivers/usb/gadget/legacy/nokia.c @@ -292,7 +292,7 @@ static int nokia_bind(struct usb_composite_dev *cdev) nokia_config_500ma_driver.iConfiguration = status; nokia_config_100ma_driver.iConfiguration = status; - if (!gadget_supports_altsettings(gadget)) { + if (!gadget_is_altset_supported(gadget)) { status = -ENODEV; goto err_usb; } -- cgit v0.10.2 From 6f98f545b0b4effdf67e83e214a4eb13cd41fba2 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Tue, 28 Jul 2015 11:10:22 +0300 Subject: usb: phy: msm: Add D+/D- lines route control apq8016-sbc board is using Dual SPDT USB Switch (TC7USB40MU), witch is controlled by GPIO to de/multiplex D+/D- USB lines to USB2513B Hub and uB connector. Add support for this. Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt index bd8d9e7..8654a3e 100644 --- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt @@ -52,6 +52,10 @@ Required properties: Optional properties: - dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg" +- switch-gpio: A phandle + gpio-specifier pair. Some boards are using Dual + SPDT USB Switch, witch is cotrolled by GPIO to de/multiplex + D+/D- USB lines between connectors. + - qcom,phy-init-sequence: PHY configuration sequence values. This is related to Device Mode Eye Diagram test. Start address at which these values will be written is ULPI_EXT_VENDOR_SPECIFIC. Value of -1 is reserved as diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 61d86d8..c58c3c0 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -32,6 +33,7 @@ #include #include #include +#include #include #include @@ -1471,6 +1473,14 @@ static int msm_otg_vbus_notifier(struct notifier_block *nb, unsigned long event, else clear_bit(B_SESS_VLD, &motg->inputs); + if (test_bit(B_SESS_VLD, &motg->inputs)) { + /* Switch D+/D- lines to Device connector */ + gpiod_set_value_cansleep(motg->switch_gpio, 0); + } else { + /* Switch D+/D- lines to Hub */ + gpiod_set_value_cansleep(motg->switch_gpio, 1); + } + schedule_work(&motg->sm_work); return NOTIFY_DONE; @@ -1546,6 +1556,11 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) motg->manual_pullup = of_property_read_bool(node, "qcom,manual-pullup"); + motg->switch_gpio = devm_gpiod_get_optional(&pdev->dev, "switch", + GPIOD_OUT_LOW); + if (IS_ERR(motg->switch_gpio)) + return PTR_ERR(motg->switch_gpio); + ext_id = ERR_PTR(-ENODEV); ext_vbus = ERR_PTR(-ENODEV); if (of_property_read_bool(node, "extcon")) { @@ -1617,6 +1632,19 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) return 0; } +static int msm_otg_reboot_notify(struct notifier_block *this, + unsigned long code, void *unused) +{ + struct msm_otg *motg = container_of(this, struct msm_otg, reboot); + + /* + * Ensure that D+/D- lines are routed to uB connector, so + * we could load bootloader/kernel at next reboot + */ + gpiod_set_value_cansleep(motg->switch_gpio, 0); + return NOTIFY_DONE; +} + static int msm_otg_probe(struct platform_device *pdev) { struct regulator_bulk_data regs[3]; @@ -1781,6 +1809,17 @@ static int msm_otg_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Can not create mode change file\n"); } + if (test_bit(B_SESS_VLD, &motg->inputs)) { + /* Switch D+/D- lines to Device connector */ + gpiod_set_value_cansleep(motg->switch_gpio, 0); + } else { + /* Switch D+/D- lines to Hub */ + gpiod_set_value_cansleep(motg->switch_gpio, 1); + } + + motg->reboot.notifier_call = msm_otg_reboot_notify; + register_reboot_notifier(&motg->reboot); + pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); @@ -1807,6 +1846,14 @@ static int msm_otg_remove(struct platform_device *pdev) if (phy->otg->host || phy->otg->gadget) return -EBUSY; + unregister_reboot_notifier(&motg->reboot); + + /* + * Ensure that D+/D- lines are routed to uB connector, so + * we could load bootloader/kernel at next reboot + */ + gpiod_set_value_cansleep(motg->switch_gpio, 0); + extcon_unregister_notifier(motg->id.extcon, EXTCON_USB_HOST, &motg->id.nb); extcon_unregister_notifier(motg->vbus.extcon, EXTCON_USB, &motg->vbus.nb); diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index 5df2c8f..8c8f685 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -155,6 +155,10 @@ struct msm_usb_cable { * starting controller using usbcmd run/stop bit. * @vbus: VBUS signal state trakining, using extcon framework * @id: ID signal state trakining, using extcon framework + * @switch_gpio: Descriptor for GPIO used to control external Dual + * SPDT USB Switch. + * @reboot: Used to inform the driver to route USB D+/D- line to Device + * connector */ struct msm_otg { struct usb_phy phy; @@ -188,6 +192,9 @@ struct msm_otg { struct msm_usb_cable vbus; struct msm_usb_cable id; + + struct gpio_desc *switch_gpio; + struct notifier_block reboot; }; #endif -- cgit v0.10.2 From 1c99cabfc95d3b08fbf06d558ebfa76b5303710c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 30 Jul 2015 00:29:23 +0300 Subject: usb: gadget: fotg210-udc: remove duplicate conditions We handle the "if (!req->req.length)" condition at the start of the function and return. We can delete this dead code. Signed-off-by: Dan Carpenter Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c index 1137e33..a99ed6d 100644 --- a/drivers/usb/gadget/udc/fotg210-udc.c +++ b/drivers/usb/gadget/udc/fotg210-udc.c @@ -384,25 +384,15 @@ static void fotg210_ep0_queue(struct fotg210_ep *ep, return; } if (ep->dir_in) { /* if IN */ - if (req->req.length) { - fotg210_start_dma(ep, req); - } else { - pr_err("%s : req->req.length = 0x%x\n", - __func__, req->req.length); - } + fotg210_start_dma(ep, req); if ((req->req.length == req->req.actual) || (req->req.actual < ep->ep.maxpacket)) fotg210_done(ep, req, 0); } else { /* OUT */ - if (!req->req.length) { - fotg210_done(ep, req, 0); - } else { - u32 value = ioread32(ep->fotg210->reg + - FOTG210_DMISGR0); + u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR0); - value &= ~DMISGR0_MCX_OUT_INT; - iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR0); - } + value &= ~DMISGR0_MCX_OUT_INT; + iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR0); } } -- cgit v0.10.2 From 5feb5d2003499b1094d898c010a7604d7afddc4c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 30 Jul 2015 00:30:58 +0300 Subject: usb: gadget: m66592-udc: forever loop in set_feature() There is an "&&" vs "||" typo here so this loops 3000 times or if we get unlucky it could loop forever. Fixes: ceaa0a6eeadf ('usb: gadget: m66592-udc: add support for TEST_MODE') Signed-off-by: Dan Carpenter Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c index 309706f..9704053 100644 --- a/drivers/usb/gadget/udc/m66592-udc.c +++ b/drivers/usb/gadget/udc/m66592-udc.c @@ -1052,7 +1052,7 @@ static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) tmp = m66592_read(m66592, M66592_INTSTS0) & M66592_CTSQ; udelay(1); - } while (tmp != M66592_CS_IDST || timeout-- > 0); + } while (tmp != M66592_CS_IDST && timeout-- > 0); if (tmp == M66592_CS_IDST) m66592_bset(m66592, -- cgit v0.10.2 From 8078f314b8c8012cf36e5decc75378b803bfba4d Mon Sep 17 00:00:00 2001 From: Sanjay Singh Rawat Date: Wed, 22 Jul 2015 16:29:46 +0530 Subject: usb: gadget: f_mass_storage: stop thread in bind failure case After the worker thread is launched, bind function is doing further configuration. In case of failure stop the thread. Acked-by: Michal Nazarewicz Signed-off-by: Sanjay Singh Rawat Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index a229194..f94a8e2 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -3081,7 +3081,7 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) /* New interface */ i = usb_interface_id(c, f); if (i < 0) - return i; + goto fail; fsg_intf_desc.bInterfaceNumber = i; fsg->interface_number = i; @@ -3124,7 +3124,14 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) autoconf_fail: ERROR(fsg, "unable to autoconfigure all endpoints\n"); - return -ENOTSUPP; + i = -ENOTSUPP; +fail: + /* terminate the thread */ + if (fsg->common->state != FSG_STATE_TERMINATED) { + raise_exception(fsg->common, FSG_STATE_EXIT); + wait_for_completion(&fsg->common->thread_notifier); + } + return i; } /****************************** ALLOCATE FUNCTION *************************/ -- cgit v0.10.2 From 913e4a90b6f9687ac0f543e7b632753e4f51c441 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 30 Jul 2015 13:13:03 +0800 Subject: usb: gadget: f_uac2: finalize wMaxPacketSize according to bandwidth According to USB Audio Device 2.0 Spec, Ch4.10.1.1: wMaxPacketSize is defined as follows: Maximum packet size this endpoint is capable of sending or receiving when this configuration is selected. This is determined by the audio bandwidth constraints of the endpoint. In current code, the wMaxPacketSize is defined as the maximum packet size for ISO endpoint, and it will let the host reserve much more space than it really needs, so that we can't let more endpoints work together at one frame. We find this issue when we try to let 4 f_uac2 gadgets work together [1] at FS connection. [1]http://www.spinics.net/lists/linux-usb/msg123478.html Acked-by: Daniel Mack Cc: andrzej.p@samsung.com Cc: Daniel Mack Cc: tiwai@suse.de Cc: #v3.18+ Cc: Alan Stern Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 6d3eb8b..b568024 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -975,6 +975,29 @@ free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep) "%s:%d Error!\n", __func__, __LINE__); } +static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, + struct usb_endpoint_descriptor *ep_desc, + unsigned int factor, bool is_playback) +{ + int chmask, srate, ssize; + u16 max_packet_size; + + if (is_playback) { + chmask = uac2_opts->p_chmask; + srate = uac2_opts->p_srate; + ssize = uac2_opts->p_ssize; + } else { + chmask = uac2_opts->c_chmask; + srate = uac2_opts->c_srate; + ssize = uac2_opts->c_ssize; + } + + max_packet_size = num_channels(chmask) * ssize * + DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))); + ep_desc->wMaxPacketSize = cpu_to_le16(min(max_packet_size, + le16_to_cpu(ep_desc->wMaxPacketSize))); +} + static int afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) { @@ -1070,10 +1093,14 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) uac2->p_prm.uac2 = uac2; uac2->c_prm.uac2 = uac2; + /* Calculate wMaxPacketSize according to audio bandwidth */ + set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true); + set_ep_max_packet_size(uac2_opts, &fs_epout_desc, 1000, false); + set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true); + set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false); + hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; - hs_epout_desc.wMaxPacketSize = fs_epout_desc.wMaxPacketSize; hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; - hs_epin_desc.wMaxPacketSize = fs_epin_desc.wMaxPacketSize; ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL); if (ret) -- cgit v0.10.2 From c3ece7e70dd8fab4fd3e4b9a74ad2df4cfa22e11 Mon Sep 17 00:00:00 2001 From: "Peter E. Berger" Date: Fri, 31 Jul 2015 01:55:05 -0500 Subject: USB: io_ti: Increase insufficient timeout for firmware downloads The io_ti driver fails to download firmware to Edgeport devices such as the EP/416 and EP/421 (devices with on-board E2PROM). One of the problems is that the default 1 second timeout in ti_vsend_sync() is insufficient for download operations. This patch increases the download timeout to 10 seconds. Signed-off-by: Peter E. Berger Signed-off-by: Johan Hovold diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index ddbb8fe..69378a7 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -210,6 +210,10 @@ static int edge_create_sysfs_attrs(struct usb_serial_port *port); static int edge_remove_sysfs_attrs(struct usb_serial_port *port); +/* Timeouts in msecs: firmware downloads take longer */ +#define TI_VSEND_TIMEOUT_DEFAULT 1000 +#define TI_VSEND_TIMEOUT_FW_DOWNLOAD 10000 + static int ti_vread_sync(struct usb_device *dev, __u8 request, __u16 value, __u16 index, u8 *data, int size) { @@ -228,14 +232,14 @@ static int ti_vread_sync(struct usb_device *dev, __u8 request, return 0; } -static int ti_vsend_sync(struct usb_device *dev, __u8 request, - __u16 value, __u16 index, u8 *data, int size) +static int ti_vsend_sync(struct usb_device *dev, u8 request, u16 value, + u16 index, u8 *data, int size, int timeout) { int status; status = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT), - value, index, data, size, 1000); + value, index, data, size, timeout); if (status < 0) return status; if (status != size) { @@ -250,7 +254,8 @@ static int send_cmd(struct usb_device *dev, __u8 command, __u8 moduleid, __u16 value, u8 *data, int size) { - return ti_vsend_sync(dev, command, value, moduleid, data, size); + return ti_vsend_sync(dev, command, value, moduleid, data, size, + TI_VSEND_TIMEOUT_DEFAULT); } /* clear tx/rx buffers and fifo in TI UMP */ @@ -378,9 +383,9 @@ static int write_boot_mem(struct edgeport_serial *serial, } for (i = 0; i < length; ++i) { - status = ti_vsend_sync(serial->serial->dev, - UMPC_MEMORY_WRITE, buffer[i], - (__u16)(i + start_address), NULL, 0); + status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE, + buffer[i], (u16)(i + start_address), NULL, + 0, TI_VSEND_TIMEOUT_DEFAULT); if (status) return status; } @@ -421,10 +426,9 @@ static int write_i2c_mem(struct edgeport_serial *serial, * regardless of host byte order. */ be_start_address = swab16((u16)start_address); - status = ti_vsend_sync(serial->serial->dev, - UMPC_MEMORY_WRITE, (__u16)address_type, - be_start_address, - buffer, write_length); + status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE, + (u16)address_type, be_start_address, + buffer, write_length, TI_VSEND_TIMEOUT_DEFAULT); if (status) { dev_dbg(dev, "%s - ERROR %d\n", __func__, status); return status; @@ -454,9 +458,8 @@ static int write_i2c_mem(struct edgeport_serial *serial, */ be_start_address = swab16((u16)start_address); status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE, - (__u16)address_type, - be_start_address, - buffer, write_length); + (u16)address_type, be_start_address, buffer, + write_length, TI_VSEND_TIMEOUT_DEFAULT); if (status) { dev_err(dev, "%s - ERROR %d\n", __func__, status); return status; @@ -1129,7 +1132,8 @@ static int download_fw(struct edgeport_serial *serial) /* Reset UMP -- Back to BOOT MODE */ status = ti_vsend_sync(serial->serial->dev, UMPC_HARDWARE_RESET, - 0, 0, NULL, 0); + 0, 0, NULL, 0, + TI_VSEND_TIMEOUT_DEFAULT); dev_dbg(dev, "%s - HARDWARE RESET return %d\n", __func__, status); @@ -1229,7 +1233,9 @@ static int download_fw(struct edgeport_serial *serial) /* Tell firmware to copy download image into I2C */ status = ti_vsend_sync(serial->serial->dev, - UMPC_COPY_DNLD_TO_I2C, 0, 0, NULL, 0); + UMPC_COPY_DNLD_TO_I2C, + 0, 0, NULL, 0, + TI_VSEND_TIMEOUT_FW_DOWNLOAD); dev_dbg(dev, "%s - Update complete 0x%x\n", __func__, status); if (status) { -- cgit v0.10.2 From c0e34831c8d9d8bf24f7bc9e12663e3daf1646ef Mon Sep 17 00:00:00 2001 From: "Peter E. Berger" Date: Fri, 31 Jul 2015 01:55:06 -0500 Subject: USB: io_ti: Fix firmware version handling The io_ti driver fails to download firmware to Edgeport devices such as the EP/416, even when the on-disk firmware image (/lib/firmware/edgeport/down3.bin) is more current than the version on the EP/416. The current download code is broken in a few ways. Notably it mis-uses global variables OperationalMajorVersion and OperationalMinorVersion (reading their values before they've been properly initialized and subsequently initializing them multiple times without synchronization). This patch drops the global variables and replaces the redundant calls to request_firmware()/release_firmware() in download_fw() with a single call pair in edge_startup(); the firmware image pointer is then passed to download_fw() and build_i2c_fw_hdr(). Signed-off-by: Peter E. Berger Signed-off-by: Johan Hovold diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 69378a7..b562665 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -71,6 +71,25 @@ struct product_info { __u8 hardware_type; /* Type of hardware */ } __attribute__((packed)); +/* + * Edgeport firmware header + * + * "build_number" has been set to 0 in all three of the images I have + * seen, and Digi Tech Support suggests that it is safe to ignore it. + * + * "length" is the number of bytes of actual data following the header. + * + * "checksum" is the low order byte resulting from adding the values of + * all the data bytes. + */ +struct edgeport_fw_hdr { + u8 major_version; + u8 minor_version; + __le16 build_number; + __le16 length; + u8 checksum; +} __packed; + struct edgeport_port { __u16 uart_base; __u16 dma_address; @@ -101,6 +120,7 @@ struct edgeport_serial { struct mutex es_lock; int num_ports_open; struct usb_serial *serial; + int fw_version; }; @@ -187,10 +207,6 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static unsigned char OperationalMajorVersion; -static unsigned char OperationalMinorVersion; -static unsigned short OperationalBuildNumber; - static int closing_wait = EDGE_CLOSING_WAIT; static bool ignore_cpu_rev; static int default_uart_mode; /* RS232 */ @@ -751,18 +767,17 @@ exit: } /* Build firmware header used for firmware update */ -static int build_i2c_fw_hdr(__u8 *header, struct device *dev) +static int build_i2c_fw_hdr(u8 *header, struct device *dev, + const struct firmware *fw) { __u8 *buffer; int buffer_size; int i; - int err; __u8 cs = 0; struct ti_i2c_desc *i2c_header; struct ti_i2c_image_header *img_header; struct ti_i2c_firmware_rec *firmware_rec; - const struct firmware *fw; - const char *fw_name = "edgeport/down3.bin"; + struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data; /* In order to update the I2C firmware we must change the type 2 record * to type 0xF2. This will force the UMP to come up in Boot Mode. @@ -785,24 +800,11 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev) // Set entire image of 0xffs memset(buffer, 0xff, buffer_size); - err = request_firmware(&fw, fw_name, dev); - if (err) { - dev_err(dev, "Failed to load image \"%s\" err %d\n", - fw_name, err); - kfree(buffer); - return err; - } - - /* Save Download Version Number */ - OperationalMajorVersion = fw->data[0]; - OperationalMinorVersion = fw->data[1]; - OperationalBuildNumber = fw->data[2] | (fw->data[3] << 8); - /* Copy version number into firmware record */ firmware_rec = (struct ti_i2c_firmware_rec *)buffer; - firmware_rec->Ver_Major = OperationalMajorVersion; - firmware_rec->Ver_Minor = OperationalMinorVersion; + firmware_rec->Ver_Major = fw_hdr->major_version; + firmware_rec->Ver_Minor = fw_hdr->minor_version; /* Pointer to fw_down memory image */ img_header = (struct ti_i2c_image_header *)&fw->data[4]; @@ -811,8 +813,6 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev) &fw->data[4 + sizeof(struct ti_i2c_image_header)], le16_to_cpu(img_header->Length)); - release_firmware(fw); - for (i=0; i < buffer_size; i++) { cs = (__u8)(cs + buffer[i]); } @@ -826,8 +826,8 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev) i2c_header->Type = I2C_DESC_TYPE_FIRMWARE_BLANK; i2c_header->Size = cpu_to_le16(buffer_size); i2c_header->CheckSum = cs; - firmware_rec->Ver_Major = OperationalMajorVersion; - firmware_rec->Ver_Minor = OperationalMinorVersion; + firmware_rec->Ver_Major = fw_hdr->major_version; + firmware_rec->Ver_Minor = fw_hdr->minor_version; return 0; } @@ -934,7 +934,8 @@ static int ti_cpu_rev(struct edge_ti_manuf_descriptor *desc) * This routine downloads the main operating code into the TI5052, using the * boot code already burned into E2PROM or ROM. */ -static int download_fw(struct edgeport_serial *serial) +static int download_fw(struct edgeport_serial *serial, + const struct firmware *fw) { struct device *dev = &serial->serial->dev->dev; int status = 0; @@ -943,6 +944,17 @@ static int download_fw(struct edgeport_serial *serial) struct usb_interface_descriptor *interface; int download_cur_ver; int download_new_ver; + struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data; + + if (fw->size < sizeof(struct edgeport_fw_hdr)) { + dev_err(&serial->serial->interface->dev, + "Incomplete firmware header.\n"); + return -EINVAL; + } + + /* If on-board version is newer, "fw_version" will be updated below. */ + serial->fw_version = (fw_hdr->major_version << 8) + + fw_hdr->minor_version; /* This routine is entered by both the BOOT mode and the Download mode * We can determine which code is running by the reading the config @@ -1050,14 +1062,13 @@ static int download_fw(struct edgeport_serial *serial) version in I2c */ download_cur_ver = (firmware_version->Ver_Major << 8) + (firmware_version->Ver_Minor); - download_new_ver = (OperationalMajorVersion << 8) + - (OperationalMinorVersion); + download_new_ver = (fw_hdr->major_version << 8) + + (fw_hdr->minor_version); dev_dbg(dev, "%s - >> FW Versions Device %d.%d Driver %d.%d\n", __func__, firmware_version->Ver_Major, firmware_version->Ver_Minor, - OperationalMajorVersion, - OperationalMinorVersion); + fw_hdr->major_version, fw_hdr->minor_version); /* Check if we have an old version in the I2C and update if necessary */ @@ -1066,8 +1077,8 @@ static int download_fw(struct edgeport_serial *serial) __func__, firmware_version->Ver_Major, firmware_version->Ver_Minor, - OperationalMajorVersion, - OperationalMinorVersion); + fw_hdr->major_version, + fw_hdr->minor_version); record = kmalloc(1, GFP_KERNEL); if (!record) { @@ -1143,6 +1154,9 @@ static int download_fw(struct edgeport_serial *serial) kfree(rom_desc); kfree(ti_manuf_desc); return -ENODEV; + } else { + /* Same or newer fw version is already loaded */ + serial->fw_version = download_cur_ver; } kfree(firmware_version); } @@ -1181,7 +1195,7 @@ static int download_fw(struct edgeport_serial *serial) * UMP Ram to I2C and the firmware will update the * record type from 0xf2 to 0x02. */ - status = build_i2c_fw_hdr(header, dev); + status = build_i2c_fw_hdr(header, dev, fw); if (status) { kfree(vheader); kfree(header); @@ -1284,9 +1298,6 @@ static int download_fw(struct edgeport_serial *serial) __u8 cs = 0; __u8 *buffer; int buffer_size; - int err; - const struct firmware *fw; - const char *fw_name = "edgeport/down3.bin"; /* Validate Hardware version number * Read Manufacturing Descriptor from TI Based Edgeport @@ -1334,16 +1345,7 @@ static int download_fw(struct edgeport_serial *serial) /* Initialize the buffer to 0xff (pad the buffer) */ memset(buffer, 0xff, buffer_size); - - err = request_firmware(&fw, fw_name, dev); - if (err) { - dev_err(dev, "Failed to load image \"%s\" err %d\n", - fw_name, err); - kfree(buffer); - return err; - } memcpy(buffer, &fw->data[4], fw->size - 4); - release_firmware(fw); for (i = sizeof(struct ti_i2c_image_header); i < buffer_size; i++) { @@ -1358,7 +1360,9 @@ static int download_fw(struct edgeport_serial *serial) header->CheckSum = cs; /* Download the operational code */ - dev_dbg(dev, "%s - Downloading operational code image (TI UMP)\n", __func__); + dev_dbg(dev, "%s - Downloading operational code image version %d.%d (TI UMP)\n", + __func__, + fw_hdr->major_version, fw_hdr->minor_version); status = download_code(serial, buffer, buffer_size); kfree(buffer); @@ -2383,6 +2387,9 @@ static int edge_startup(struct usb_serial *serial) { struct edgeport_serial *edge_serial; int status; + const struct firmware *fw; + const char *fw_name = "edgeport/down3.bin"; + struct device *dev = &serial->interface->dev; /* create our private serial structure */ edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL); @@ -2393,7 +2400,16 @@ static int edge_startup(struct usb_serial *serial) edge_serial->serial = serial; usb_set_serial_data(serial, edge_serial); - status = download_fw(edge_serial); + status = request_firmware(&fw, fw_name, dev); + if (status) { + dev_err(dev, "Failed to load image \"%s\" err %d\n", + fw_name, status); + kfree(edge_serial); + return status; + } + + status = download_fw(edge_serial, fw); + release_firmware(fw); if (status) { kfree(edge_serial); return status; -- cgit v0.10.2 From dcb8e99dbc8a8a7825e39a43e79558d46b20d1e5 Mon Sep 17 00:00:00 2001 From: "Peter E. Berger" Date: Fri, 31 Jul 2015 01:55:07 -0500 Subject: USB: io_ti: Add firmware image sanity checks Do what we can to verify that the driver's firmware image is valid (before attempting to download it to the Edgeport) by adding a new function, check_fw_sanity(), and a call to it in in download_fw(). Note: It looks like some Edgeports (models like the EP/416 with on-board E2PROM) may be able to function even if the on-disk firmware image is bad or missing, iff their local E2PROM versions are valid. But most Edgeport models (I've tried EP/1 and EP/8) do not appear to have this capability and they always rely on the on-disk firmware image. I tested an implementation that calls the new check_fw_sanity() function at the top of download_fw() and, rather than simply returning an error if the firmware image is bad or missing, it saves the result and defers the decision until later when it may find that it is running on a E2PROM-equipped device with a valid image. But I think this is messier than it is worth (adding still more messiness to the already very messy download_fw()) for such a marginal possible benefit. So, at least for now, I have chosen the much simpler approach of returning an error whenever edge_startup() fails to load an on-disk firmware image, or check_fw_sanity() indicates that it is unusable. Signed-off-by: Peter E. Berger [johan: drop redundant checksum mask ] Signed-off-by: Johan Hovold diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index b562665..422423671 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -928,6 +928,41 @@ static int ti_cpu_rev(struct edge_ti_manuf_descriptor *desc) return TI_GET_CPU_REVISION(desc->CpuRev_BoardRev); } +static int check_fw_sanity(struct edgeport_serial *serial, + const struct firmware *fw) +{ + u16 length_total; + u8 checksum = 0; + int pos; + struct device *dev = &serial->serial->interface->dev; + struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data; + + if (fw->size < sizeof(struct edgeport_fw_hdr)) { + dev_err(dev, "incomplete fw header\n"); + return -EINVAL; + } + + length_total = le16_to_cpu(fw_hdr->length) + + sizeof(struct edgeport_fw_hdr); + + if (fw->size != length_total) { + dev_err(dev, "bad fw size (expected: %u, got: %zu)\n", + length_total, fw->size); + return -EINVAL; + } + + for (pos = sizeof(struct edgeport_fw_hdr); pos < fw->size; ++pos) + checksum += fw->data[pos]; + + if (checksum != fw_hdr->checksum) { + dev_err(dev, "bad fw checksum (expected: 0x%x, got: 0x%x)\n", + fw_hdr->checksum, checksum); + return -EINVAL; + } + + return 0; +} + /** * DownloadTIFirmware - Download run-time operating firmware to the TI5052 * @@ -946,11 +981,8 @@ static int download_fw(struct edgeport_serial *serial, int download_new_ver; struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data; - if (fw->size < sizeof(struct edgeport_fw_hdr)) { - dev_err(&serial->serial->interface->dev, - "Incomplete firmware header.\n"); + if (check_fw_sanity(serial, fw)) return -EINVAL; - } /* If on-board version is newer, "fw_version" will be updated below. */ serial->fw_version = (fw_hdr->major_version << 8) + -- cgit v0.10.2 From 26c78daade0fbeef7f20bae3c5508a7c571078cd Mon Sep 17 00:00:00 2001 From: "Peter E. Berger" Date: Fri, 31 Jul 2015 01:55:08 -0500 Subject: USB: io_ti: Add heartbeat to keep idle EP/416 ports from disconnecting When using Edgeport/416 models with newer firmware (sometime after firmware version 4.80.0), idle ports are automatically bounced (disconnected and then reconnected) approximately every 60 seconds. This breaks programs (e.g: minicom) where idle periods are common, normal and expected. I confirmed with the manufacturer (Digi International) that Edgeport/416 models now ship from the factory with firmware that expects periodic "heartbeat" queries from the driver to keep idle ports alive. This patch implements heartbeat support using the mechanism Digi suggested (periodically requesting an I2C descriptor address) that appears effective on Edgeports running the newer firmware (that require it) and benign on Edgeport devices running older firmware. Since we know that Edgeport firmware version 4.80 (the version distributed in /lib/firmware/down3.bin and used for Edgeports that are either running still older versions or have no onboard non-volatile firmware image) does not require heartbeat support, this patch schedules heartbeats only on Edgeport/416 devices, and only if they are running firmware versions newer than 4.80. Signed-off-by: Peter E. Berger [johan: minor style changes ] Signed-off-by: Johan Hovold diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 422423671..0ac1b10 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -120,7 +120,9 @@ struct edgeport_serial { struct mutex es_lock; int num_ports_open; struct usb_serial *serial; + struct delayed_work heartbeat_work; int fw_version; + bool use_heartbeat; }; @@ -225,6 +227,22 @@ static void edge_send(struct usb_serial_port *port, struct tty_struct *tty); static int edge_create_sysfs_attrs(struct usb_serial_port *port); static int edge_remove_sysfs_attrs(struct usb_serial_port *port); +/* + * Some release of Edgeport firmware "down3.bin" after version 4.80 + * introduced code to automatically disconnect idle devices on some + * Edgeport models after periods of inactivity, typically ~60 seconds. + * This occurs without regard to whether ports on the device are open + * or not. Digi International Tech Support suggested: + * + * 1. Adding driver "heartbeat" code to reset the firmware timer by + * requesting a descriptor record every 15 seconds, which should be + * effective with newer firmware versions that require it, and benign + * with older versions that do not. In practice 40 seconds seems often + * enough. + * 2. The heartbeat code is currently required only on Edgeport/416 models. + */ +#define FW_HEARTBEAT_VERSION_CUTOFF ((4 << 8) + 80) +#define FW_HEARTBEAT_SECS 40 /* Timeouts in msecs: firmware downloads take longer */ #define TI_VSEND_TIMEOUT_DEFAULT 1000 @@ -2415,6 +2433,36 @@ static void edge_break(struct tty_struct *tty, int break_state) __func__, status); } +static void edge_heartbeat_schedule(struct edgeport_serial *edge_serial) +{ + if (!edge_serial->use_heartbeat) + return; + + schedule_delayed_work(&edge_serial->heartbeat_work, + FW_HEARTBEAT_SECS * HZ); +} + +static void edge_heartbeat_work(struct work_struct *work) +{ + struct edgeport_serial *serial; + struct ti_i2c_desc *rom_desc; + + serial = container_of(work, struct edgeport_serial, + heartbeat_work.work); + + rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); + + /* Descriptor address request is enough to reset the firmware timer */ + if (!rom_desc || !get_descriptor_addr(serial, I2C_DESC_TYPE_ION, + rom_desc)) { + dev_err(&serial->serial->interface->dev, + "%s - Incomplete heartbeat\n", __func__); + } + kfree(rom_desc); + + edge_heartbeat_schedule(serial); +} + static int edge_startup(struct usb_serial *serial) { struct edgeport_serial *edge_serial; @@ -2422,6 +2470,7 @@ static int edge_startup(struct usb_serial *serial) const struct firmware *fw; const char *fw_name = "edgeport/down3.bin"; struct device *dev = &serial->interface->dev; + u16 product_id; /* create our private serial structure */ edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL); @@ -2447,6 +2496,20 @@ static int edge_startup(struct usb_serial *serial) return status; } + product_id = le16_to_cpu( + edge_serial->serial->dev->descriptor.idProduct); + + /* Currently only the EP/416 models require heartbeat support */ + if (edge_serial->fw_version > FW_HEARTBEAT_VERSION_CUTOFF) { + if (product_id == ION_DEVICE_ID_TI_EDGEPORT_416 || + product_id == ION_DEVICE_ID_TI_EDGEPORT_416B) { + edge_serial->use_heartbeat = true; + } + } + + INIT_DELAYED_WORK(&edge_serial->heartbeat_work, edge_heartbeat_work); + edge_heartbeat_schedule(edge_serial); + return 0; } @@ -2456,7 +2519,10 @@ static void edge_disconnect(struct usb_serial *serial) static void edge_release(struct usb_serial *serial) { - kfree(usb_get_serial_data(serial)); + struct edgeport_serial *edge_serial = usb_get_serial_data(serial); + + cancel_delayed_work_sync(&edge_serial->heartbeat_work); + kfree(edge_serial); } static int edge_port_probe(struct usb_serial_port *port) @@ -2560,6 +2626,25 @@ static int edge_remove_sysfs_attrs(struct usb_serial_port *port) return 0; } +#ifdef CONFIG_PM +static int edge_suspend(struct usb_serial *serial, pm_message_t message) +{ + struct edgeport_serial *edge_serial = usb_get_serial_data(serial); + + cancel_delayed_work_sync(&edge_serial->heartbeat_work); + + return 0; +} + +static int edge_resume(struct usb_serial *serial) +{ + struct edgeport_serial *edge_serial = usb_get_serial_data(serial); + + edge_heartbeat_schedule(edge_serial); + + return 0; +} +#endif static struct usb_serial_driver edgeport_1port_device = { .driver = { @@ -2592,6 +2677,10 @@ static struct usb_serial_driver edgeport_1port_device = { .read_int_callback = edge_interrupt_callback, .read_bulk_callback = edge_bulk_in_callback, .write_bulk_callback = edge_bulk_out_callback, +#ifdef CONFIG_PM + .suspend = edge_suspend, + .resume = edge_resume, +#endif }; static struct usb_serial_driver edgeport_2port_device = { @@ -2625,6 +2714,10 @@ static struct usb_serial_driver edgeport_2port_device = { .read_int_callback = edge_interrupt_callback, .read_bulk_callback = edge_bulk_in_callback, .write_bulk_callback = edge_bulk_out_callback, +#ifdef CONFIG_PM + .suspend = edge_suspend, + .resume = edge_resume, +#endif }; static struct usb_serial_driver * const serial_drivers[] = { -- cgit v0.10.2 From 55d811211b139ed097ddaf40d173c258f133c130 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 13 Jul 2015 11:03:50 +0200 Subject: usb: gadget: ffs: call functionfs_unbind() if _ffs_func_bind() fails Function ffs_do_functionfs_bind() calls functionfs_bind() which allocates usb request and increments refcounts. These things needs to be cleaned up by if further steps of initialization fail by calling functionfs_unbind(). Signed-off-by: Robert Baldyga Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 6e7be91..adc6d52 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -2897,11 +2897,17 @@ static int ffs_func_bind(struct usb_configuration *c, struct usb_function *f) { struct f_fs_opts *ffs_opts = ffs_do_functionfs_bind(f, c); + struct ffs_function *func = ffs_func_from_usb(f); + int ret; if (IS_ERR(ffs_opts)) return PTR_ERR(ffs_opts); - return _ffs_func_bind(c, f); + ret = _ffs_func_bind(c, f); + if (ret && !--ffs_opts->refcnt) + functionfs_unbind(func->ffs); + + return ret; } -- cgit v0.10.2 From 4ef7a4a1f097b2c17f4f2873a1595aa0aca9f6b4 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 13 Jul 2015 11:03:51 +0200 Subject: usb: gadget: midi: avoid redundant f_midi_set_alt() call Function midi registers two interfaces with single set_alt() function which means that f_midi_set_alt() is called twice when configuration is set. That means that endpoint initialization and ep request allocation is done two times. To avoid this problem we do such things only once, for interface number 1 (MIDI Streaming interface). Signed-off-by: Robert Baldyga Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index ad50a67..a287a48 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -329,6 +329,10 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt) unsigned i; int err; + /* For Control Device interface we do nothing */ + if (intf == 0) + return 0; + err = f_midi_start_ep(midi, f, midi->in_ep); if (err) return err; -- cgit v0.10.2 From 6fd82b69796cc8f313f160ac55bfd24cedc60fed Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 13 Jul 2015 11:03:52 +0200 Subject: usb: isp1760: udc: add missing usb_ep_set_maxpacket_limit() Since maxpacket_limit was introduced all UDC drivers should use usb_ep_set_maxpacket_limit() function instead of setting maxpacket value manually. ep.maxpacket_limit contains actual maximum maxpacket value supported by hardware which is needed by epautoconf. Signed-off-by: Robert Baldyga Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/isp1760/isp1760-udc.c b/drivers/usb/isp1760/isp1760-udc.c index 18ebf5b..3699962 100644 --- a/drivers/usb/isp1760/isp1760-udc.c +++ b/drivers/usb/isp1760/isp1760-udc.c @@ -1382,11 +1382,11 @@ static void isp1760_udc_init_eps(struct isp1760_udc *udc) * This fits in the 8kB FIFO without double-buffering. */ if (ep_num == 0) { - ep->ep.maxpacket = 64; + usb_ep_set_maxpacket_limit(&ep->ep, 64); ep->maxpacket = 64; udc->gadget.ep0 = &ep->ep; } else { - ep->ep.maxpacket = 512; + usb_ep_set_maxpacket_limit(&ep->ep, 512); ep->maxpacket = 0; list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); } -- cgit v0.10.2 From cb009d6e0b800e3834cd5e306df90d84e08f9cf7 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 13 Jul 2015 11:03:53 +0200 Subject: staging: emxx_udc: add missing usb_ep_set_maxpacket_limit() Since maxpacket_limit was introduced all UDC drivers should use usb_ep_set_maxpacket_limit() function instead of setting maxpacket value manually. ep.maxpacket_limit contains actual maximum maxpacket value supported by hardware which is needed by epautoconf. Signed-off-by: Robert Baldyga Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c index 4178d96..3b7aa36 100644 --- a/drivers/staging/emxx_udc/emxx_udc.c +++ b/drivers/staging/emxx_udc/emxx_udc.c @@ -3203,7 +3203,8 @@ static void __init nbu2ss_drv_ep_init(struct nbu2ss_udc *udc) ep->ep.name = gp_ep_name[i]; ep->ep.ops = &nbu2ss_ep_ops; - ep->ep.maxpacket = (i == 0 ? EP0_PACKETSIZE : EP_PACKETSIZE); + usb_ep_set_maxpacket_limit(&ep->ep, + i == 0 ? EP0_PACKETSIZE : EP_PACKETSIZE); list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); INIT_LIST_HEAD(&ep->queue); -- cgit v0.10.2 From 7674cba55ad66b2565f8abe8d081a6ea4269bfb6 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 13 Jul 2015 11:03:54 +0200 Subject: usb: gadget: atmel_usba_udc: add missing ret value check Add missing return value check. In case of error print debug message and return error code. Signed-off-by: Robert Baldyga Acked-by: Nicolas Ferre Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 4095cce..37d414e 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -1989,6 +1989,10 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, ep->can_isoc = of_property_read_bool(pp, "atmel,can-isoc"); ret = of_property_read_string(pp, "name", &name); + if (ret) { + dev_err(&pdev->dev, "of_probe: name error(%d)\n", ret); + goto err; + } ep->ep.name = name; ep->ep_regs = udc->regs + USBA_EPT_BASE(i); -- cgit v0.10.2 From 5542f58c95aef67bc9016855f7c0bd6117b43100 Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Fri, 31 Jul 2015 13:37:45 +0200 Subject: usb: gadget: mass_storage: Fix freeing luns sysfs implementation Use device_is_registered() instad of sysfs flag to determine if we should free sysfs representation of particular LUN. sysfs flag in fsg common determines if luns attributes should be exposed using sysfs. This flag is used when creating and freeing luns. Unfortunately there is no guarantee that this flag will not be changed between creation and removal of particular LUN. Especially because of lun.0 which is created during allocating instance of function. This may lead to resource leak or NULL pointer dereference: [ 62.539925] Unable to handle kernel NULL pointer dereference at virtual address 00000044 [ 62.548014] pgd = ec994000 [ 62.550679] [00000044] *pgd=6d7be831, *pte=00000000, *ppte=00000000 [ 62.556933] Internal error: Oops: 17 [#1] PREEMPT SMP ARM [ 62.562310] Modules linked in: g_mass_storage(+) [ 62.566916] CPU: 2 PID: 613 Comm: insmod Not tainted 4.2.0-rc4-00077-ge29ee91-dirty #125 [ 62.574984] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [ 62.581061] task: eca56e80 ti: eca76000 task.ti: eca76000 [ 62.586450] PC is at kernfs_find_ns+0x8/0xe8 [ 62.590698] LR is at kernfs_find_and_get_ns+0x30/0x48 [ 62.595732] pc : [] lr : [] psr: 40010053 [ 62.595732] sp : eca77c40 ip : eca77c38 fp : 000008c1 [ 62.607187] r10: 00000001 r9 : c0082f38 r8 : ed41ce40 [ 62.612395] r7 : c05c1484 r6 : 00000000 r5 : 00000000 r4 : c0814488 [ 62.618904] r3 : 00000000 r2 : 00000000 r1 : c05c1484 r0 : 00000000 [ 62.625417] Flags: nZcv IRQs on FIQs off Mode SVC_32 ISA ARM Segment user [ 62.632620] Control: 10c5387d Table: 6c99404a DAC: 00000015 [ 62.638348] Process insmod (pid: 613, stack limit = 0xeca76210) [ 62.644251] Stack: (0xeca77c40 to 0xeca78000) [ 62.648594] 7c40: c0814488 00000000 00000000 c05c1484 ed41ce40 c0127b88 00000000 c0824888 [ 62.656753] 7c60: ed41d038 ed41d030 ed41d000 c012af4c 00000000 c0824858 ed41d038 c02e3314 [ 62.664912] 7c80: ed41d030 00000000 ed41ce04 c02d9e8c c070eda8 eca77cb4 000008c1 c058317c [ 62.673071] 7ca0: 000008c1 ed41d030 ed41ce00 ed41ce04 ed41d000 c02da044 ed41cf48 c0375870 [ 62.681230] 7cc0: ed9d3c04 ed9d3c00 ed52df80 bf000940 fffffff0 c03758f4 c03758c0 00000000 [ 62.689389] 7ce0: bf000564 c03614e0 ed9d3c04 bf000194 c0082f38 00000001 00000000 c0000100 [ 62.697548] 7d00: c0814488 c0814488 c086b1dc c05893a8 00000000 ed7e8320 00000000 c0128b88 [ 62.705707] 7d20: ed8a6b40 00000000 00000000 ed410500 ed8a6b40 c0594818 ed7e8320 00000000 [ 62.713867] 7d40: 00000000 c0129f20 00000000 c082c444 ed8a6b40 c012a684 00001000 00000000 [ 62.722026] 7d60: c0594818 c082c444 00000000 00000000 ed52df80 ed52df80 00000000 00000000 [ 62.730185] 7d80: 00000000 00000000 00000001 00000002 ed8e9b70 ed52df80 bf0006d0 00000000 [ 62.738345] 7da0: ed8e9b70 ed410500 ed618340 c036129c ed8c1c00 bf0006d0 c080b158 ed8c1c00 [ 62.746504] 7dc0: bf0006d0 c080b158 ed8c1c08 ed410500 c0082f38 ed618340 000008c1 c03640ac [ 62.754663] 7de0: 00000000 bf0006d0 c082c8dc c080b158 c080b158 c03642d4 00000000 bf003000 [ 62.762822] 7e00: 00000000 c0009784 00000000 00000001 00000000 c05849b0 00000002 ee7ab780 [ 62.770981] 7e20: 00000002 ed4105c0 0000c53e 000000d0 c0808600 eca77e5c 00000004 00000000 [ 62.779140] 7e40: bf000000 c0095680 c08075a0 ee001f00 ed4105c0 c00cadc0 ed52df80 bf000780 [ 62.787300] 7e60: ed4105c0 bf000780 00000001 bf0007c8 c0082f38 ed618340 000008c1 c0083e24 [ 62.795459] 7e80: 00000001 bf000780 00000001 eca77f58 00000001 bf000780 00000001 c00857f4 [ 62.803618] 7ea0: bf00078c 00007fff 00000000 c00835b4 eca77f58 00000000 c0082fac eca77f58 [ 62.811777] 7ec0: f05038c0 0003b008 bf000904 00000000 00000000 bf00078c 6e72656b 00006c65 [ 62.819936] 7ee0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 62.828095] 7f00: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 62.836255] 7f20: 00000000 00000000 00000000 00000000 00000000 00000000 00000003 0003b008 [ 62.844414] 7f40: 0000017b c000f5c8 eca76000 00000000 0003b008 c0085df8 f04ef000 0001b8a9 [ 62.852573] 7f60: f0503258 f05030c2 f0509fe8 00000968 00000dc8 00000000 00000000 00000000 [ 62.860732] 7f80: 00000029 0000002a 00000011 00000000 0000000a 00000000 33f6eb00 0003b008 [ 62.868892] 7fa0: bef01cac c000f400 33f6eb00 0003b008 00000003 0003b008 00000000 00000003 [ 62.877051] 7fc0: 33f6eb00 0003b008 bef01cac 0000017b 00000000 0003b008 0000000b 0003b008 [ 62.885210] 7fe0: bef01ae0 bef01ad0 0001dc23 b6e8c162 800b0070 00000003 c0c0c0c0 c0c0c0c0 [ 62.893380] [] (kernfs_find_ns) from [] (pm_qos_latency_tolerance_attr_group+0x0/0x10) [ 62.903005] Code: e28dd00c e8bd80f0 e92d41f0 e2923000 (e1d0e4b4) [ 62.909115] ---[ end trace 02fb4373ef095c7b ]--- Acked-by: Michal Nazarewicz Signed-off-by: Krzysztof Opasiak Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index f94a8e2..9870913 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2742,9 +2742,9 @@ error_release: } EXPORT_SYMBOL_GPL(fsg_common_set_num_buffers); -void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs) +void fsg_common_remove_lun(struct fsg_lun *lun) { - if (sysfs) + if (device_is_registered(&lun->dev)) device_unregister(&lun->dev); fsg_lun_close(lun); kfree(lun); @@ -2757,7 +2757,7 @@ static void _fsg_common_remove_luns(struct fsg_common *common, int n) for (i = 0; i < n; ++i) if (common->luns[i]) { - fsg_common_remove_lun(common->luns[i], common->sysfs); + fsg_common_remove_lun(common->luns[i]); common->luns[i] = NULL; } } @@ -2950,7 +2950,7 @@ int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, return 0; error_lun: - if (common->sysfs) + if (device_is_registered(&lun->dev)) device_unregister(&lun->dev); fsg_lun_close(lun); common->luns[id] = NULL; @@ -3038,7 +3038,7 @@ static void fsg_common_release(struct kref *ref) if (!lun) continue; fsg_lun_close(lun); - if (common->sysfs) + if (device_is_registered(&lun->dev)) device_unregister(&lun->dev); kfree(lun); } @@ -3363,7 +3363,7 @@ static void fsg_lun_drop(struct config_group *group, struct config_item *item) unregister_gadget_item(gadget); } - fsg_common_remove_lun(lun_opts->lun, fsg_opts->common->sysfs); + fsg_common_remove_lun(lun_opts->lun); fsg_opts->common->luns[lun_opts->lun_id] = NULL; lun_opts->lun_id = 0; mutex_unlock(&fsg_opts->lock); diff --git a/drivers/usb/gadget/function/f_mass_storage.h b/drivers/usb/gadget/function/f_mass_storage.h index b4866fc..37bc94c 100644 --- a/drivers/usb/gadget/function/f_mass_storage.h +++ b/drivers/usb/gadget/function/f_mass_storage.h @@ -137,7 +137,7 @@ void fsg_common_free_buffers(struct fsg_common *common); int fsg_common_set_cdev(struct fsg_common *common, struct usb_composite_dev *cdev, bool can_stall); -void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs); +void fsg_common_remove_lun(struct fsg_lun *lun); void fsg_common_remove_luns(struct fsg_common *common); -- cgit v0.10.2 From dd02ea5a33059e4a753ae8bb877b698c54ee2907 Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Fri, 31 Jul 2015 13:46:07 +0200 Subject: usb: gadget: mass_storage: Use static array for luns This patch replace dynamicly allocated luns array with static one. This simplifies the code of mass storage function and modules. Signed-off-by: Krzysztof Opasiak Acked-by: Michal Nazarewicz diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 9870913..04c3bb6 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -279,9 +279,8 @@ struct fsg_common { int cmnd_size; u8 cmnd[MAX_COMMAND_SIZE]; - unsigned int nluns; unsigned int lun; - struct fsg_lun **luns; + struct fsg_lun *luns[FSG_MAX_LUNS]; struct fsg_lun *curlun; unsigned int bulk_out_maxpacket; @@ -490,6 +489,16 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) spin_unlock(&common->lock); } +static int _fsg_common_get_max_lun(struct fsg_common *common) +{ + int i = ARRAY_SIZE(common->luns) - 1; + + while (i >= 0 && !common->luns[i]) + --i; + + return i; +} + static int fsg_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) { @@ -533,7 +542,7 @@ static int fsg_setup(struct usb_function *f, w_length != 1) return -EDOM; VDBG(fsg, "get max LUN\n"); - *(u8 *)req->buf = fsg->common->nluns - 1; + *(u8 *)req->buf = _fsg_common_get_max_lun(fsg->common); /* Respond with data/status */ req->length = min((u16)1, w_length); @@ -2131,8 +2140,9 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) } /* Is the CBW meaningful? */ - if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN || - cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { + if (cbw->Lun >= ARRAY_SIZE(common->luns) || + cbw->Flags & ~US_BULK_FLAG_IN || cbw->Length <= 0 || + cbw->Length > MAX_COMMAND_SIZE) { DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " "cmdlen %u\n", cbw->Lun, cbw->Flags, cbw->Length); @@ -2159,7 +2169,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) if (common->data_size == 0) common->data_dir = DATA_DIR_NONE; common->lun = cbw->Lun; - if (common->lun < common->nluns) + if (common->lun < ARRAY_SIZE(common->luns)) common->curlun = common->luns[common->lun]; else common->curlun = NULL; @@ -2307,7 +2317,7 @@ reset: } common->running = 1; - for (i = 0; i < common->nluns; ++i) + for (i = 0; i < ARRAY_SIZE(common->luns); ++i) if (common->luns[i]) common->luns[i]->unit_attention_data = SS_RESET_OCCURRED; @@ -2409,7 +2419,7 @@ static void handle_exception(struct fsg_common *common) if (old_state == FSG_STATE_ABORT_BULK_OUT) common->state = FSG_STATE_STATUS_PHASE; else { - for (i = 0; i < common->nluns; ++i) { + for (i = 0; i < ARRAY_SIZE(common->luns); ++i) { curlun = common->luns[i]; if (!curlun) continue; @@ -2453,7 +2463,7 @@ static void handle_exception(struct fsg_common *common) * a waste of time. Ditto for the INTERFACE_CHANGE and * CONFIG_CHANGE cases. */ - /* for (i = 0; i < common->nluns; ++i) */ + /* for (i = 0; i < common->ARRAY_SIZE(common->luns); ++i) */ /* if (common->luns[i]) */ /* common->luns[i]->unit_attention_data = */ /* SS_RESET_OCCURRED; */ @@ -2552,12 +2562,11 @@ static int fsg_main_thread(void *common_) if (!common->ops || !common->ops->thread_exits || common->ops->thread_exits(common) < 0) { - struct fsg_lun **curlun_it = common->luns; - unsigned i = common->nluns; + int i; down_write(&common->filesem); - for (; i--; ++curlun_it) { - struct fsg_lun *curlun = *curlun_it; + for (i = 0; i < ARRAY_SIZE(common->luns); --i) { + struct fsg_lun *curlun = common->luns[i]; if (!curlun || !fsg_lun_is_open(curlun)) continue; @@ -2676,6 +2685,7 @@ static struct fsg_common *fsg_common_setup(struct fsg_common *common) init_completion(&common->thread_notifier); init_waitqueue_head(&common->fsg_wait); common->state = FSG_STATE_TERMINATED; + memset(common->luns, 0, sizeof(common->luns)); return common; } @@ -2764,42 +2774,10 @@ static void _fsg_common_remove_luns(struct fsg_common *common, int n) void fsg_common_remove_luns(struct fsg_common *common) { - _fsg_common_remove_luns(common, common->nluns); + _fsg_common_remove_luns(common, ARRAY_SIZE(common->luns)); } EXPORT_SYMBOL_GPL(fsg_common_remove_luns); -void fsg_common_free_luns(struct fsg_common *common) -{ - fsg_common_remove_luns(common); - kfree(common->luns); - common->luns = NULL; -} -EXPORT_SYMBOL_GPL(fsg_common_free_luns); - -int fsg_common_set_nluns(struct fsg_common *common, int nluns) -{ - struct fsg_lun **curlun; - - /* Find out how many LUNs there should be */ - if (nluns < 1 || nluns > FSG_MAX_LUNS) { - pr_err("invalid number of LUNs: %u\n", nluns); - return -EINVAL; - } - - curlun = kcalloc(FSG_MAX_LUNS, sizeof(*curlun), GFP_KERNEL); - if (unlikely(!curlun)) - return -ENOMEM; - - if (common->luns) - fsg_common_free_luns(common); - - common->luns = curlun; - common->nluns = nluns; - - return 0; -} -EXPORT_SYMBOL_GPL(fsg_common_set_nluns); - void fsg_common_set_ops(struct fsg_common *common, const struct fsg_operations *ops) { @@ -2881,7 +2859,7 @@ int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, char *pathbuf, *p; int rc = -ENOMEM; - if (!common->nluns || !common->luns) + if (id >= ARRAY_SIZE(common->luns)) return -ENODEV; if (common->luns[id]) @@ -2965,14 +2943,16 @@ int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg) char buf[8]; /* enough for 100000000 different numbers, decimal */ int i, rc; - for (i = 0; i < common->nluns; ++i) { + fsg_common_remove_luns(common); + + for (i = 0; i < cfg->nluns; ++i) { snprintf(buf, sizeof(buf), "lun%d", i); rc = fsg_common_create_lun(common, &cfg->luns[i], i, buf, NULL); if (rc) goto fail; } - pr_info("Number of LUNs=%d\n", common->nluns); + pr_info("Number of LUNs=%d\n", cfg->nluns); return 0; @@ -3021,6 +3001,7 @@ EXPORT_SYMBOL_GPL(fsg_common_run_thread); static void fsg_common_release(struct kref *ref) { struct fsg_common *common = container_of(ref, struct fsg_common, ref); + int i; /* If the thread isn't already dead, tell it to exit now */ if (common->state != FSG_STATE_TERMINATED) { @@ -3028,22 +3009,14 @@ static void fsg_common_release(struct kref *ref) wait_for_completion(&common->thread_notifier); } - if (likely(common->luns)) { - struct fsg_lun **lun_it = common->luns; - unsigned i = common->nluns; - - /* In error recovery common->nluns may be zero. */ - for (; i; --i, ++lun_it) { - struct fsg_lun *lun = *lun_it; - if (!lun) - continue; - fsg_lun_close(lun); + for (i = 0; i < ARRAY_SIZE(common->luns); ++i) { + struct fsg_lun *lun = common->luns[i]; + if (!lun) + continue; + fsg_lun_close(lun); if (device_is_registered(&lun->dev)) - device_unregister(&lun->dev); - kfree(lun); - } - - kfree(common->luns); + device_unregister(&lun->dev); + kfree(lun); } _fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers); @@ -3057,6 +3030,7 @@ static void fsg_common_release(struct kref *ref) static int fsg_bind(struct usb_configuration *c, struct usb_function *f) { struct fsg_dev *fsg = fsg_from_func(f); + struct fsg_common *common = fsg->common; struct usb_gadget *gadget = c->cdev->gadget; int i; struct usb_ep *ep; @@ -3064,6 +3038,13 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) int ret; struct fsg_opts *opts; + /* Don't allow to bind if we don't have at least one LUN */ + ret = _fsg_common_get_max_lun(common); + if (ret < 0) { + pr_err("There should be at least one LUN.\n"); + return -EINVAL; + } + opts = fsg_opts_from_func_inst(f->fi); if (!opts->no_configfs) { ret = fsg_common_set_cdev(fsg->common, c->cdev, @@ -3517,14 +3498,11 @@ static struct usb_function_instance *fsg_alloc_inst(void) rc = PTR_ERR(opts->common); goto release_opts; } - rc = fsg_common_set_nluns(opts->common, FSG_MAX_LUNS); - if (rc) - goto release_opts; rc = fsg_common_set_num_buffers(opts->common, CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS); if (rc) - goto release_luns; + goto release_opts; pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); @@ -3547,8 +3525,6 @@ static struct usb_function_instance *fsg_alloc_inst(void) release_buffers: fsg_common_free_buffers(opts->common); -release_luns: - kfree(opts->common->luns); release_opts: kfree(opts); return ERR_PTR(rc); @@ -3574,23 +3550,12 @@ static struct usb_function *fsg_alloc(struct usb_function_instance *fi) struct fsg_opts *opts = fsg_opts_from_func_inst(fi); struct fsg_common *common = opts->common; struct fsg_dev *fsg; - unsigned nluns, i; fsg = kzalloc(sizeof(*fsg), GFP_KERNEL); if (unlikely(!fsg)) return ERR_PTR(-ENOMEM); mutex_lock(&opts->lock); - if (!opts->refcnt) { - for (nluns = i = 0; i < FSG_MAX_LUNS; ++i) - if (common->luns[i]) - nluns = i + 1; - if (!nluns) - pr_warn("No LUNS defined, continuing anyway\n"); - else - common->nluns = nluns; - pr_info("Number of LUNs=%u\n", common->nluns); - } opts->refcnt++; mutex_unlock(&opts->lock); diff --git a/drivers/usb/gadget/function/f_mass_storage.h b/drivers/usb/gadget/function/f_mass_storage.h index 37bc94c..445df67 100644 --- a/drivers/usb/gadget/function/f_mass_storage.h +++ b/drivers/usb/gadget/function/f_mass_storage.h @@ -141,10 +141,6 @@ void fsg_common_remove_lun(struct fsg_lun *lun); void fsg_common_remove_luns(struct fsg_common *common); -void fsg_common_free_luns(struct fsg_common *common); - -int fsg_common_set_nluns(struct fsg_common *common, int nluns); - void fsg_common_set_ops(struct fsg_common *common, const struct fsg_operations *ops); diff --git a/drivers/usb/gadget/legacy/acm_ms.c b/drivers/usb/gadget/legacy/acm_ms.c index 4d8adb4..4b158e2 100644 --- a/drivers/usb/gadget/legacy/acm_ms.c +++ b/drivers/usb/gadget/legacy/acm_ms.c @@ -186,10 +186,6 @@ static int acm_ms_bind(struct usb_composite_dev *cdev) if (status) goto fail; - status = fsg_common_set_nluns(opts->common, config.nluns); - if (status) - goto fail_set_nluns; - status = fsg_common_set_cdev(opts->common, cdev, config.can_stall); if (status) goto fail_set_cdev; @@ -239,8 +235,6 @@ fail_otg_desc: fail_string_ids: fsg_common_remove_luns(opts->common); fail_set_cdev: - fsg_common_free_luns(opts->common); -fail_set_nluns: fsg_common_free_buffers(opts->common); fail: usb_put_function_instance(fi_msg); diff --git a/drivers/usb/gadget/legacy/mass_storage.c b/drivers/usb/gadget/legacy/mass_storage.c index ab1a42c..bda3c51 100644 --- a/drivers/usb/gadget/legacy/mass_storage.c +++ b/drivers/usb/gadget/legacy/mass_storage.c @@ -177,10 +177,6 @@ static int msg_bind(struct usb_composite_dev *cdev) if (status) goto fail; - status = fsg_common_set_nluns(opts->common, config.nluns); - if (status) - goto fail_set_nluns; - fsg_common_set_ops(opts->common, &ops); status = fsg_common_set_cdev(opts->common, cdev, config.can_stall); @@ -227,8 +223,6 @@ fail_otg_desc: fail_string_ids: fsg_common_remove_luns(opts->common); fail_set_cdev: - fsg_common_free_luns(opts->common); -fail_set_nluns: fsg_common_free_buffers(opts->common); fail: usb_put_function_instance(fi_msg); diff --git a/drivers/usb/gadget/legacy/multi.c b/drivers/usb/gadget/legacy/multi.c index c38ead1..4fe794d 100644 --- a/drivers/usb/gadget/legacy/multi.c +++ b/drivers/usb/gadget/legacy/multi.c @@ -393,10 +393,6 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) if (status) goto fail2; - status = fsg_common_set_nluns(fsg_opts->common, config.nluns); - if (status) - goto fail_set_nluns; - status = fsg_common_set_cdev(fsg_opts->common, cdev, config.can_stall); if (status) goto fail_set_cdev; @@ -448,8 +444,6 @@ fail_otg_desc: fail_string_ids: fsg_common_remove_luns(fsg_opts->common); fail_set_cdev: - fsg_common_free_luns(fsg_opts->common); -fail_set_nluns: fsg_common_free_buffers(fsg_opts->common); fail2: usb_put_function_instance(fi_msg); diff --git a/drivers/usb/gadget/legacy/nokia.c b/drivers/usb/gadget/legacy/nokia.c index 264c97e..c20f3b5 100644 --- a/drivers/usb/gadget/legacy/nokia.c +++ b/drivers/usb/gadget/legacy/nokia.c @@ -339,19 +339,15 @@ static int nokia_bind(struct usb_composite_dev *cdev) if (status) goto err_msg_inst; - status = fsg_common_set_nluns(fsg_opts->common, fsg_config.nluns); - if (status) - goto err_msg_buf; - status = fsg_common_set_cdev(fsg_opts->common, cdev, fsg_config.can_stall); if (status) - goto err_msg_set_nluns; + goto err_msg_buf; fsg_common_set_sysfs(fsg_opts->common, true); status = fsg_common_create_luns(fsg_opts->common, &fsg_config); if (status) - goto err_msg_set_nluns; + goto err_msg_buf; fsg_common_set_inquiry_string(fsg_opts->common, fsg_config.vendor_name, fsg_config.product_name); @@ -360,7 +356,7 @@ static int nokia_bind(struct usb_composite_dev *cdev) status = usb_add_config(cdev, &nokia_config_500ma_driver, nokia_bind_config); if (status < 0) - goto err_msg_set_cdev; + goto err_msg_luns; status = usb_add_config(cdev, &nokia_config_100ma_driver, nokia_bind_config); @@ -381,10 +377,8 @@ err_put_cfg1: if (!IS_ERR_OR_NULL(f_phonet_cfg1)) usb_put_function(f_phonet_cfg1); usb_put_function(f_ecm_cfg1); -err_msg_set_cdev: +err_msg_luns: fsg_common_remove_luns(fsg_opts->common); -err_msg_set_nluns: - fsg_common_free_luns(fsg_opts->common); err_msg_buf: fsg_common_free_buffers(fsg_opts->common); err_msg_inst: -- cgit v0.10.2 From 8cd50626823c00ca7472b2f61cb8c0eb9798ddc0 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Fri, 31 Jul 2015 16:36:28 +0800 Subject: Doc: ABI: testing: configfs-usb-gadget-loopback Fix the name of attribute Cc: Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/Documentation/ABI/testing/configfs-usb-gadget-loopback b/Documentation/ABI/testing/configfs-usb-gadget-loopback index 9aae5bf..06beefbc 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-loopback +++ b/Documentation/ABI/testing/configfs-usb-gadget-loopback @@ -5,4 +5,4 @@ Description: The attributes: qlen - depth of loopback queue - bulk_buflen - buffer length + buflen - buffer length -- cgit v0.10.2 From 4bc58eb16bb2352854b9c664cc36c1c68d2bfbb7 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Fri, 31 Jul 2015 16:36:29 +0800 Subject: Doc: ABI: testing: configfs-usb-gadget-sourcesink Fix the name of attribute Cc: Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/Documentation/ABI/testing/configfs-usb-gadget-sourcesink b/Documentation/ABI/testing/configfs-usb-gadget-sourcesink index 29477c3..bc7ff73 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-sourcesink +++ b/Documentation/ABI/testing/configfs-usb-gadget-sourcesink @@ -9,4 +9,4 @@ Description: isoc_maxpacket - 0 - 1023 (fs), 0 - 1024 (hs/ss) isoc_mult - 0..2 (hs/ss only) isoc_maxburst - 0..15 (ss only) - qlen - buffer length + buflen - buffer length -- cgit v0.10.2 From f811a38300be3cdb603171aea5ad3fb42b71ca53 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Fri, 31 Jul 2015 16:36:30 +0800 Subject: doc: usb: gadget-testing: using the updated testusb.c testusb.c at http://www.linux-usb.org/usbtest/ is out of date, using the one at the kernel source folder. Cc: Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/Documentation/usb/gadget-testing.txt b/Documentation/usb/gadget-testing.txt index 5926780..b24d3ef 100644 --- a/Documentation/usb/gadget-testing.txt +++ b/Documentation/usb/gadget-testing.txt @@ -237,9 +237,7 @@ Testing the LOOPBACK function ----------------------------- device: run the gadget -host: test-usb - -http://www.linux-usb.org/usbtest/testusb.c +host: test-usb (tools/usb/testusb.c) 8. MASS STORAGE function ======================== @@ -586,9 +584,8 @@ Testing the SOURCESINK function ------------------------------- device: run the gadget -host: test-usb +host: test-usb (tools/usb/testusb.c) -http://www.linux-usb.org/usbtest/testusb.c 16. UAC1 function ================= -- cgit v0.10.2 From 3d772c4adbf94ce6971be2e9272157f831bccb8f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 31 Jul 2015 10:01:41 +0200 Subject: phy-sun4i-sub: Move vbus-detect helper functions up in the file Move vbus-detect helper functions up in the file, just moving some code around, no functional changes what so ever. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 5138843..27ae89e 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -294,6 +294,30 @@ static int sun4i_usb_phy_exit(struct phy *_phy) return 0; } +static int sun4i_usb_phy0_get_vbus_det(struct sun4i_usb_phy_data *data) +{ + if (data->vbus_det_gpio) + return gpiod_get_value_cansleep(data->vbus_det_gpio); + + if (data->vbus_power_supply) { + union power_supply_propval val; + int r; + + r = power_supply_get_property(data->vbus_power_supply, + POWER_SUPPLY_PROP_PRESENT, &val); + if (r == 0) + return val.intval; + } + + /* Fallback: report vbus as high */ + return 1; +} + +static bool sun4i_usb_phy0_have_vbus_det(struct sun4i_usb_phy_data *data) +{ + return data->vbus_det_gpio || data->vbus_power_supply; +} + static int sun4i_usb_phy_power_on(struct phy *_phy) { struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); @@ -356,30 +380,6 @@ static struct phy_ops sun4i_usb_phy_ops = { .owner = THIS_MODULE, }; -static int sun4i_usb_phy0_get_vbus_det(struct sun4i_usb_phy_data *data) -{ - if (data->vbus_det_gpio) - return gpiod_get_value_cansleep(data->vbus_det_gpio); - - if (data->vbus_power_supply) { - union power_supply_propval val; - int r; - - r = power_supply_get_property(data->vbus_power_supply, - POWER_SUPPLY_PROP_PRESENT, &val); - if (r == 0) - return val.intval; - } - - /* Fallback: report vbus as high */ - return 1; -} - -static bool sun4i_usb_phy0_have_vbus_det(struct sun4i_usb_phy_data *data) -{ - return data->vbus_det_gpio || data->vbus_power_supply; -} - static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) { struct sun4i_usb_phy_data *data = -- cgit v0.10.2 From 8083526e0585e23447ac9ea94ca3f6d32d6dee8f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 31 Jul 2015 10:01:42 +0200 Subject: phy-sun4i-usb: Only check vbus-det on power-on on boards with vbus-det data->vbus_det is always 1 on boards without a (working) vbus-det, skip the vbus_det test on such boards. This fixes the sun4i usb phy code never turning on Vbus on such boards. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 27ae89e..e2eb688d 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -328,7 +328,8 @@ static int sun4i_usb_phy_power_on(struct phy *_phy) return 0; /* For phy0 only turn on Vbus if we don't have an ext. Vbus */ - if (phy->index == 0 && data->vbus_det) + if (phy->index == 0 && sun4i_usb_phy0_have_vbus_det(data) && + data->vbus_det) return 0; ret = regulator_enable(phy->vbus); -- cgit v0.10.2 From 42ad8f6721720513f3569a67b157fcff068aa92d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 5 Jun 2015 08:27:03 +0800 Subject: phy: ulpi_phy: Add const qualifier to ops The ops is never changed in ulpi_phy_create(), so make it const. Signed-off-by: Axel Lin Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/ulpi_phy.h b/drivers/phy/ulpi_phy.h index ac49fb6..f2ebe49 100644 --- a/drivers/phy/ulpi_phy.h +++ b/drivers/phy/ulpi_phy.h @@ -5,7 +5,7 @@ * and it's controller, which is always the parent. */ static inline struct phy -*ulpi_phy_create(struct ulpi *ulpi, struct phy_ops *ops) +*ulpi_phy_create(struct ulpi *ulpi, const struct phy_ops *ops) { struct phy *phy; int ret; -- cgit v0.10.2 From 4a9e5ca1a54a3cb4a5f85359f646638cec567607 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 15 Jul 2015 15:33:51 +0800 Subject: phy: Constify struct phy_ops variables The phy_ops variables are never modified after initialized in these drivers, so make them const. Signed-off-by: Axel Lin Acked-by: Patrice Chotard Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-armada375-usb2.c b/drivers/phy/phy-armada375-usb2.c index 39c7d21..1a3db28 100644 --- a/drivers/phy/phy-armada375-usb2.c +++ b/drivers/phy/phy-armada375-usb2.c @@ -51,7 +51,7 @@ static int armada375_usb_phy_init(struct phy *phy) return 0; } -static struct phy_ops armada375_usb_phy_ops = { +static const struct phy_ops armada375_usb_phy_ops = { .init = armada375_usb_phy_init, .owner = THIS_MODULE, }; diff --git a/drivers/phy/phy-bcm-kona-usb2.c b/drivers/phy/phy-bcm-kona-usb2.c index ef2dc1a..7b67fe4 100644 --- a/drivers/phy/phy-bcm-kona-usb2.c +++ b/drivers/phy/phy-bcm-kona-usb2.c @@ -91,7 +91,7 @@ static int bcm_kona_usb_phy_power_off(struct phy *gphy) return 0; } -static struct phy_ops ops = { +static const struct phy_ops ops = { .init = bcm_kona_usb_phy_init, .power_on = bcm_kona_usb_phy_power_on, .power_off = bcm_kona_usb_phy_power_off, diff --git a/drivers/phy/phy-berlin-sata.c b/drivers/phy/phy-berlin-sata.c index 6f3e06d..0062027 100644 --- a/drivers/phy/phy-berlin-sata.c +++ b/drivers/phy/phy-berlin-sata.c @@ -176,7 +176,7 @@ static struct phy *phy_berlin_sata_phy_xlate(struct device *dev, return priv->phys[i]->phy; } -static struct phy_ops phy_berlin_sata_ops = { +static const struct phy_ops phy_berlin_sata_ops = { .power_on = phy_berlin_sata_power_on, .power_off = phy_berlin_sata_power_off, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c index 0fe0d81..204ee59 100644 --- a/drivers/phy/phy-berlin-usb.c +++ b/drivers/phy/phy-berlin-usb.c @@ -147,7 +147,7 @@ static int phy_berlin_usb_power_on(struct phy *phy) return 0; } -static struct phy_ops phy_berlin_usb_ops = { +static const struct phy_ops phy_berlin_usb_ops = { .power_on = phy_berlin_usb_power_on, .owner = THIS_MODULE, }; diff --git a/drivers/phy/phy-brcmstb-sata.c b/drivers/phy/phy-brcmstb-sata.c index b7e303d..8a2cb16 100644 --- a/drivers/phy/phy-brcmstb-sata.c +++ b/drivers/phy/phy-brcmstb-sata.c @@ -122,7 +122,7 @@ static int brcm_sata_phy_init(struct phy *phy) return 0; } -static struct phy_ops phy_ops_28nm = { +static const struct phy_ops phy_ops_28nm = { .init = brcm_sata_phy_init, .owner = THIS_MODULE, }; diff --git a/drivers/phy/phy-dm816x-usb.c b/drivers/phy/phy-dm816x-usb.c index 7b42555..b4bbef6 100644 --- a/drivers/phy/phy-dm816x-usb.c +++ b/drivers/phy/phy-dm816x-usb.c @@ -113,7 +113,7 @@ static int dm816x_usb_phy_init(struct phy *x) return 0; } -static struct phy_ops ops = { +static const struct phy_ops ops = { .init = dm816x_usb_phy_init, .owner = THIS_MODULE, }; diff --git a/drivers/phy/phy-exynos-dp-video.c b/drivers/phy/phy-exynos-dp-video.c index 179cbf9..34b0615 100644 --- a/drivers/phy/phy-exynos-dp-video.c +++ b/drivers/phy/phy-exynos-dp-video.c @@ -48,7 +48,7 @@ static int exynos_dp_video_phy_power_off(struct phy *phy) EXYNOS5_PHY_ENABLE, 0); } -static struct phy_ops exynos_dp_video_phy_ops = { +static const struct phy_ops exynos_dp_video_phy_ops = { .power_on = exynos_dp_video_phy_power_on, .power_off = exynos_dp_video_phy_power_off, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c index df7519a..2a54cab 100644 --- a/drivers/phy/phy-exynos-mipi-video.c +++ b/drivers/phy/phy-exynos-mipi-video.c @@ -124,7 +124,7 @@ static struct phy *exynos_mipi_video_phy_xlate(struct device *dev, return state->phys[args->args[0]].phy; } -static struct phy_ops exynos_mipi_video_phy_ops = { +static const struct phy_ops exynos_mipi_video_phy_ops = { .power_on = exynos_mipi_video_phy_power_on, .power_off = exynos_mipi_video_phy_power_off, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-exynos5-usbdrd.c b/drivers/phy/phy-exynos5-usbdrd.c index d72ef15..20696f5 100644 --- a/drivers/phy/phy-exynos5-usbdrd.c +++ b/drivers/phy/phy-exynos5-usbdrd.c @@ -537,7 +537,7 @@ static struct phy *exynos5_usbdrd_phy_xlate(struct device *dev, return phy_drd->phys[args->args[0]].phy; } -static struct phy_ops exynos5_usbdrd_phy_ops = { +static const struct phy_ops exynos5_usbdrd_phy_ops = { .init = exynos5_usbdrd_phy_init, .exit = exynos5_usbdrd_phy_exit, .power_on = exynos5_usbdrd_phy_power_on, diff --git a/drivers/phy/phy-exynos5250-sata.c b/drivers/phy/phy-exynos5250-sata.c index bc858cc..60e13af 100644 --- a/drivers/phy/phy-exynos5250-sata.c +++ b/drivers/phy/phy-exynos5250-sata.c @@ -154,7 +154,7 @@ static int exynos_sata_phy_init(struct phy *phy) return ret; } -static struct phy_ops exynos_sata_phy_ops = { +static const struct phy_ops exynos_sata_phy_ops = { .init = exynos_sata_phy_init, .power_on = exynos_sata_phy_power_on, .power_off = exynos_sata_phy_power_off, diff --git a/drivers/phy/phy-hix5hd2-sata.c b/drivers/phy/phy-hix5hd2-sata.c index d6b2265..e5ab3aa 100644 --- a/drivers/phy/phy-hix5hd2-sata.c +++ b/drivers/phy/phy-hix5hd2-sata.c @@ -129,7 +129,7 @@ static int hix5hd2_sata_phy_init(struct phy *phy) return 0; } -static struct phy_ops hix5hd2_sata_phy_ops = { +static const struct phy_ops hix5hd2_sata_phy_ops = { .init = hix5hd2_sata_phy_init, .owner = THIS_MODULE, }; diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c index 677c290..c47b56b 100644 --- a/drivers/phy/phy-miphy28lp.c +++ b/drivers/phy/phy-miphy28lp.c @@ -1132,7 +1132,7 @@ static struct phy *miphy28lp_xlate(struct device *dev, return miphy_phy->phy; } -static struct phy_ops miphy28lp_ops = { +static const struct phy_ops miphy28lp_ops = { .init = miphy28lp_init, .owner = THIS_MODULE, }; diff --git a/drivers/phy/phy-miphy365x.c b/drivers/phy/phy-miphy365x.c index 0ff354d..00a686a 100644 --- a/drivers/phy/phy-miphy365x.c +++ b/drivers/phy/phy-miphy365x.c @@ -510,7 +510,7 @@ static struct phy *miphy365x_xlate(struct device *dev, return miphy_phy->phy; } -static struct phy_ops miphy365x_ops = { +static const struct phy_ops miphy365x_ops = { .init = miphy365x_init, .owner = THIS_MODULE, }; diff --git a/drivers/phy/phy-mvebu-sata.c b/drivers/phy/phy-mvebu-sata.c index 03b94f9..768ce92 100644 --- a/drivers/phy/phy-mvebu-sata.c +++ b/drivers/phy/phy-mvebu-sata.c @@ -75,7 +75,7 @@ static int phy_mvebu_sata_power_off(struct phy *phy) return 0; } -static struct phy_ops phy_mvebu_sata_ops = { +static const struct phy_ops phy_mvebu_sata_ops = { .power_on = phy_mvebu_sata_power_on, .power_off = phy_mvebu_sata_power_off, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c index c1a4686..0fe8058 100644 --- a/drivers/phy/phy-omap-usb2.c +++ b/drivers/phy/phy-omap-usb2.c @@ -137,7 +137,7 @@ static int omap_usb_init(struct phy *x) return 0; } -static struct phy_ops ops = { +static const struct phy_ops ops = { .init = omap_usb_init, .power_on = omap_usb_power_on, .power_off = omap_usb_power_off, diff --git a/drivers/phy/phy-qcom-apq8064-sata.c b/drivers/phy/phy-qcom-apq8064-sata.c index 4b243f7..69ce2af 100644 --- a/drivers/phy/phy-qcom-apq8064-sata.c +++ b/drivers/phy/phy-qcom-apq8064-sata.c @@ -204,7 +204,7 @@ static int qcom_apq8064_sata_phy_exit(struct phy *generic_phy) return 0; } -static struct phy_ops qcom_apq8064_sata_phy_ops = { +static const struct phy_ops qcom_apq8064_sata_phy_ops = { .init = qcom_apq8064_sata_phy_init, .exit = qcom_apq8064_sata_phy_exit, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-qcom-ipq806x-sata.c b/drivers/phy/phy-qcom-ipq806x-sata.c index 6f2fe26..0ad127c 100644 --- a/drivers/phy/phy-qcom-ipq806x-sata.c +++ b/drivers/phy/phy-qcom-ipq806x-sata.c @@ -126,7 +126,7 @@ static int qcom_ipq806x_sata_phy_exit(struct phy *generic_phy) return 0; } -static struct phy_ops qcom_ipq806x_sata_phy_ops = { +static const struct phy_ops qcom_ipq806x_sata_phy_ops = { .init = qcom_ipq806x_sata_phy_init, .exit = qcom_ipq806x_sata_phy_exit, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-qcom-ufs-i.h b/drivers/phy/phy-qcom-ufs-i.h index 591a391..2bd5ce4 100644 --- a/drivers/phy/phy-qcom-ufs-i.h +++ b/drivers/phy/phy-qcom-ufs-i.h @@ -150,7 +150,7 @@ int ufs_qcom_phy_remove(struct phy *generic_phy, struct ufs_qcom_phy *ufs_qcom_phy); struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev, struct ufs_qcom_phy *common_cfg, - struct phy_ops *ufs_qcom_phy_gen_ops, + const struct phy_ops *ufs_qcom_phy_gen_ops, struct ufs_qcom_phy_specific_ops *phy_spec_ops); int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, struct ufs_qcom_phy_calibration *tbl_A, int tbl_size_A, diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.c b/drivers/phy/phy-qcom-ufs-qmp-14nm.c index e1eea1b..56631e7 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-14nm.c +++ b/drivers/phy/phy-qcom-ufs-qmp-14nm.c @@ -115,7 +115,7 @@ static int ufs_qcom_phy_qmp_14nm_is_pcs_ready(struct ufs_qcom_phy *phy_common) return err; } -static struct phy_ops ufs_qcom_phy_qmp_14nm_phy_ops = { +static const struct phy_ops ufs_qcom_phy_qmp_14nm_phy_ops = { .init = ufs_qcom_phy_qmp_14nm_init, .exit = ufs_qcom_phy_exit, .power_on = ufs_qcom_phy_power_on, diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c b/drivers/phy/phy-qcom-ufs-qmp-20nm.c index fde8c87..b16ea77 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-20nm.c +++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c @@ -171,7 +171,7 @@ static int ufs_qcom_phy_qmp_20nm_is_pcs_ready(struct ufs_qcom_phy *phy_common) return err; } -static struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = { +static const struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = { .init = ufs_qcom_phy_qmp_20nm_init, .exit = ufs_qcom_phy_exit, .power_on = ufs_qcom_phy_power_on, diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/phy-qcom-ufs.c index f9c618f..49a1ed0 100644 --- a/drivers/phy/phy-qcom-ufs.c +++ b/drivers/phy/phy-qcom-ufs.c @@ -77,7 +77,7 @@ EXPORT_SYMBOL_GPL(ufs_qcom_phy_calibrate); struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev, struct ufs_qcom_phy *common_cfg, - struct phy_ops *ufs_qcom_phy_gen_ops, + const struct phy_ops *ufs_qcom_phy_gen_ops, struct ufs_qcom_phy_specific_ops *phy_spec_ops) { int err; diff --git a/drivers/phy/phy-rcar-gen2.c b/drivers/phy/phy-rcar-gen2.c index 39d9b29..6e0d9fa 100644 --- a/drivers/phy/phy-rcar-gen2.c +++ b/drivers/phy/phy-rcar-gen2.c @@ -184,7 +184,7 @@ static int rcar_gen2_phy_power_off(struct phy *p) return 0; } -static struct phy_ops rcar_gen2_phy_ops = { +static const struct phy_ops rcar_gen2_phy_ops = { .init = rcar_gen2_phy_init, .exit = rcar_gen2_phy_exit, .power_on = rcar_gen2_phy_power_on, diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/phy-rockchip-usb.c index bf78721..5a5c073 100644 --- a/drivers/phy/phy-rockchip-usb.c +++ b/drivers/phy/phy-rockchip-usb.c @@ -84,7 +84,7 @@ static int rockchip_usb_phy_power_on(struct phy *_phy) return 0; } -static struct phy_ops ops = { +static const struct phy_ops ops = { .power_on = rockchip_usb_phy_power_on, .power_off = rockchip_usb_phy_power_off, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c index 55b6994..f278a9c 100644 --- a/drivers/phy/phy-samsung-usb2.c +++ b/drivers/phy/phy-samsung-usb2.c @@ -71,7 +71,7 @@ static int samsung_usb2_phy_power_off(struct phy *phy) return 0; } -static struct phy_ops samsung_usb2_phy_ops = { +static const struct phy_ops samsung_usb2_phy_ops = { .power_on = samsung_usb2_phy_power_on, .power_off = samsung_usb2_phy_power_off, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-spear1310-miphy.c b/drivers/phy/phy-spear1310-miphy.c index 45d0005..ed67e98 100644 --- a/drivers/phy/phy-spear1310-miphy.c +++ b/drivers/phy/phy-spear1310-miphy.c @@ -179,7 +179,7 @@ static const struct of_device_id spear1310_miphy_of_match[] = { }; MODULE_DEVICE_TABLE(of, spear1310_miphy_of_match); -static struct phy_ops spear1310_miphy_ops = { +static const struct phy_ops spear1310_miphy_ops = { .init = spear1310_miphy_init, .exit = spear1310_miphy_exit, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-spear1340-miphy.c b/drivers/phy/phy-spear1340-miphy.c index 494240d..97280c0 100644 --- a/drivers/phy/phy-spear1340-miphy.c +++ b/drivers/phy/phy-spear1340-miphy.c @@ -189,7 +189,7 @@ static const struct of_device_id spear1340_miphy_of_match[] = { }; MODULE_DEVICE_TABLE(of, spear1340_miphy_of_match); -static struct phy_ops spear1340_miphy_ops = { +static const struct phy_ops spear1340_miphy_ops = { .init = spear1340_miphy_init, .exit = spear1340_miphy_exit, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-stih41x-usb.c b/drivers/phy/phy-stih41x-usb.c index c093b47..0ac7463 100644 --- a/drivers/phy/phy-stih41x-usb.c +++ b/drivers/phy/phy-stih41x-usb.c @@ -112,7 +112,7 @@ static int stih41x_usb_phy_power_off(struct phy *phy) return 0; } -static struct phy_ops stih41x_usb_phy_ops = { +static const struct phy_ops stih41x_usb_phy_ops = { .init = stih41x_usb_phy_init, .power_on = stih41x_usb_phy_power_on, .power_off = stih41x_usb_phy_power_off, diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index e2eb688d..623c714 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -373,7 +373,7 @@ void sun4i_usb_phy_set_squelch_detect(struct phy *_phy, bool enabled) sun4i_usb_phy_write(phy, PHY_SQUELCH_DETECT, enabled ? 0 : 2, 2); } -static struct phy_ops sun4i_usb_phy_ops = { +static const struct phy_ops sun4i_usb_phy_ops = { .init = sun4i_usb_phy_init, .exit = sun4i_usb_phy_exit, .power_on = sun4i_usb_phy_power_on, diff --git a/drivers/phy/phy-sun9i-usb.c b/drivers/phy/phy-sun9i-usb.c index 0095914..ac4f31a 100644 --- a/drivers/phy/phy-sun9i-usb.c +++ b/drivers/phy/phy-sun9i-usb.c @@ -114,7 +114,7 @@ static int sun9i_usb_phy_exit(struct phy *_phy) return 0; } -static struct phy_ops sun9i_usb_phy_ops = { +static const struct phy_ops sun9i_usb_phy_ops = { .init = sun9i_usb_phy_init, .exit = sun9i_usb_phy_exit, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c index 53f295c..2038f19 100644 --- a/drivers/phy/phy-ti-pipe3.c +++ b/drivers/phy/phy-ti-pipe3.c @@ -279,7 +279,7 @@ static int ti_pipe3_exit(struct phy *x) return 0; } -static struct phy_ops ops = { +static const struct phy_ops ops = { .init = ti_pipe3_init, .exit = ti_pipe3_exit, .power_on = ti_pipe3_power_on, diff --git a/drivers/phy/phy-tusb1210.c b/drivers/phy/phy-tusb1210.c index 07efdd3..2535d79 100644 --- a/drivers/phy/phy-tusb1210.c +++ b/drivers/phy/phy-tusb1210.c @@ -53,7 +53,7 @@ static int tusb1210_power_off(struct phy *phy) return 0; } -static struct phy_ops phy_ops = { +static const struct phy_ops phy_ops = { .power_on = tusb1210_power_on, .power_off = tusb1210_power_off, .owner = THIS_MODULE, -- cgit v0.10.2 From d3cb25a12138a09bc948c0091d3d42e519980659 Mon Sep 17 00:00:00 2001 From: Pengyu Ma Date: Mon, 3 Aug 2015 11:28:24 +0800 Subject: usb: gadget: udc: fix spin_lock in pch_udc When remove module g_serial on quark platform, the following Warning on: Modules linked in: usb_f_acm u_serial g_serial(-) pch_udc libcomposite configfs udc_core ad7298 industrialio_triggered_buffer kfifo_buf tpm_i2c_infineon indus CPU: 0 PID: 369 Comm: modprobe Not tainted 3.14.29ltsi-WR7.0.0.0_standard #6 Hardware name: Intel Corp. QUARK/CrossHill, BIOS 0x010100F5 01/01/2014 f641df0c f641df0c f641dec8 c15ac7fa f641defc c103084f c16c2356 f641df28 00000171 c16b855c 000009dd c15b2d6f 000009dd c15b2d6f f6bd2000 faae5480 00000000 f641df14 c10308a3 00000009 f641df0c c16c2356 f641df28 f641df2c Call Trace: [] dump_stack+0x16/0x18 [] warn_slowpath_common+0x7f/0xa0 [] ? preempt_count_sub+0x6f/0xc0 [] ? preempt_count_sub+0x6f/0xc0 [] warn_slowpath_fmt+0x33/0x40 [] preempt_count_sub+0x6f/0xc0 [] pch_udc_pcd_pullup+0x32/0xa0 [pch_udc] [] usb_gadget_remove_driver+0x29/0x60 [udc_core] [] usb_gadget_unregister_driver+0x59/0x80 [udc_core] [] usb_composite_unregister+0x10/0x20 [libcomposite] [] cleanup+0xd/0xf [g_serial] [] SyS_delete_module+0xf7/0x150 [] ? ____fput+0xd/0x10 [] ? task_work_run+0x6e/0xa0 [] syscall_call+0x7/0x7 g_serial module on quark is depended on pch_udc module, ttyGSX cann't recieve data and warning on when remove g_serial. It was unlocked before the modification of the structure it was protecting, fix it as "lock -> unlock" to resolve this. Signed-off-by: Pengyu Ma Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index dcf5def..e071c62 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -620,9 +620,9 @@ static inline void pch_udc_vbus_session(struct pch_udc_dev *dev, dev->vbus_session = 1; } else { if (dev->driver && dev->driver->disconnect) { - spin_unlock(&dev->lock); - dev->driver->disconnect(&dev->gadget); spin_lock(&dev->lock); + dev->driver->disconnect(&dev->gadget); + spin_unlock(&dev->lock); } pch_udc_set_disconnect(dev); dev->vbus_session = 0; @@ -1191,9 +1191,9 @@ static int pch_udc_pcd_pullup(struct usb_gadget *gadget, int is_on) pch_udc_reconnect(dev); } else { if (dev->driver && dev->driver->disconnect) { - spin_unlock(&dev->lock); - dev->driver->disconnect(&dev->gadget); spin_lock(&dev->lock); + dev->driver->disconnect(&dev->gadget); + spin_unlock(&dev->lock); } pch_udc_set_disconnect(dev); } @@ -1488,11 +1488,11 @@ static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req, req->dma_mapped = 0; } ep->halted = 1; - spin_unlock(&dev->lock); + spin_lock(&dev->lock); if (!ep->in) pch_udc_ep_clear_rrdy(ep); usb_gadget_giveback_request(&ep->ep, &req->req); - spin_lock(&dev->lock); + spin_unlock(&dev->lock); ep->halted = halted; } @@ -2414,7 +2414,7 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev) dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IDX].ep; else /* OUT */ dev->gadget.ep0 = &ep->ep; - spin_unlock(&dev->lock); + spin_lock(&dev->lock); /* If Mass storage Reset */ if ((dev->setup_data.bRequestType == 0x21) && (dev->setup_data.bRequest == 0xFF)) @@ -2422,7 +2422,7 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev) /* call gadget with setup data received */ setup_supported = dev->driver->setup(&dev->gadget, &dev->setup_data); - spin_lock(&dev->lock); + spin_unlock(&dev->lock); if (dev->setup_data.bRequestType & USB_DIR_IN) { ep->td_data->status = (ep->td_data->status & @@ -2594,9 +2594,9 @@ static void pch_udc_svc_ur_interrupt(struct pch_udc_dev *dev) empty_req_queue(ep); } if (dev->driver) { - spin_unlock(&dev->lock); - usb_gadget_udc_reset(&dev->gadget, dev->driver); spin_lock(&dev->lock); + usb_gadget_udc_reset(&dev->gadget, dev->driver); + spin_unlock(&dev->lock); } } @@ -2675,9 +2675,9 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) dev->ep[i].halted = 0; } dev->stall = 0; - spin_unlock(&dev->lock); - ret = dev->driver->setup(&dev->gadget, &dev->setup_data); spin_lock(&dev->lock); + ret = dev->driver->setup(&dev->gadget, &dev->setup_data); + spin_unlock(&dev->lock); } /** @@ -2712,9 +2712,9 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev) dev->stall = 0; /* call gadget zero with setup data received */ - spin_unlock(&dev->lock); - ret = dev->driver->setup(&dev->gadget, &dev->setup_data); spin_lock(&dev->lock); + ret = dev->driver->setup(&dev->gadget, &dev->setup_data); + spin_unlock(&dev->lock); } /** @@ -2747,18 +2747,18 @@ static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr) if (dev_intr & UDC_DEVINT_US) { if (dev->driver && dev->driver->suspend) { - spin_unlock(&dev->lock); - dev->driver->suspend(&dev->gadget); spin_lock(&dev->lock); + dev->driver->suspend(&dev->gadget); + spin_unlock(&dev->lock); } vbus = pch_vbus_gpio_get_value(dev); if ((dev->vbus_session == 0) && (vbus != 1)) { if (dev->driver && dev->driver->disconnect) { - spin_unlock(&dev->lock); - dev->driver->disconnect(&dev->gadget); spin_lock(&dev->lock); + dev->driver->disconnect(&dev->gadget); + spin_unlock(&dev->lock); } pch_udc_reconnect(dev); } else if ((dev->vbus_session == 0) -- cgit v0.10.2 From 2f0bb2a0e7f5161e83615fb1283c5079566ed6a7 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 3 Aug 2015 05:37:10 -0700 Subject: usb: musb: Allow building in all the DMA code With recent changes to MUSB code, we can now now get rid of the Kconfig choise for the DMA code and allow building in any of the desired DMA code. This makes life easier for distros. Signed-off-by: Tony Lindgren Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 37081ed..1f2037b 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -124,19 +124,20 @@ config USB_MUSB_JZ4740 config USB_MUSB_AM335X_CHILD tristate -choice - prompt 'MUSB DMA mode' - default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM || USB_MUSB_JZ4740 - default USB_UX500_DMA if USB_MUSB_UX500 - default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN - default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI - default USB_TUSB_OMAP_DMA if USB_MUSB_TUSB6010 - default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X \ - || USB_MUSB_DSPS +comment "MUSB DMA mode" + +config MUSB_PIO_ONLY + bool 'Disable DMA (always use PIO)' help - Unfortunately, only one option can be enabled here. Ideally one - should be able to build all these drivers into one kernel to - allow using DMA on multiplatform kernels. + All data is copied between memory and FIFO by the CPU. + DMA controllers are ignored. + + Do not choose this unless DMA support for your SOC or board + is unavailable (or unstable). When DMA is enabled at compile time, + you can still disable it at run time using the "use_dma=n" module + parameter. + +if !MUSB_PIO_ONLY config USB_UX500_DMA bool 'ST Ericsson Ux500' @@ -168,17 +169,6 @@ config USB_TUSB_OMAP_DMA help Enable DMA transfers on TUSB 6010 when OMAP DMA is available. -config MUSB_PIO_ONLY - bool 'Disable DMA (always use PIO)' - help - All data is copied between memory and FIFO by the CPU. - DMA controllers are ignored. - - Do not choose this unless DMA support for your SOC or board - is unavailable (or unstable). When DMA is enabled at compile time, - you can still disable it at run time using the "use_dma=n" module - parameter. - -endchoice +endif # !MUSB_PIO_ONLY endif # USB_MUSB_HDRC -- cgit v0.10.2 From a24b071bb4ac37ef51a0ed4765f89be05a617677 Mon Sep 17 00:00:00 2001 From: Fupan Li Date: Mon, 3 Aug 2015 19:19:43 +0800 Subject: usb: gadget: f_printer: fix deadlock caused by nested spinlock Function printer_func_disable() has called spinlock on printer_dev->lock, and it'll call function chain of printer_reset_interface() | +---dwc3_gadget_ep_disable() | +---__dwc3_gadget_ep_disable() | +---dwc3_remove_requests() | +---dwc3_gadget_giveback() | +---rx_complete() in the protected block. However, rx_complete() in f_printer.c calls spinlock on printer_dev->lock again, which will cause system hang. The following steps can reproduce this hang: 1. Build the test program from Documentation/usb/gadget_printer.txt as g_printer 2. Plug in the USB device to a host(such as Ubuntu). 3. on the USB device system run: #modprobe g_printer.ko #./g_printer -read_data 4. Unplug the USB device from the host The system will hang later. In order to avoid this deadlock, moving the spinlock from printer_func_disable() into printer_reset_interface() and excluding the block of calling dwc3_gadget_ep_disable(), in which the critical resource will be protected by its spinlock in rx_complete(). This commit will fix the system hang with the following calltrace: INFO: rcu_preempt detected stalls on CPUs/tasks: { 3} (detected by 0, t=21006 jiffies, g=524, c=523, q=2) sending NMI to all CPUs: NMI backtrace for cpu 3 CPU: 3 PID: 718 Comm: irq/22-dwc3 Not tainted 3.10.38-ltsi-WR6.0.0.11_standard #2 Hardware name: Intel Corp. VALLEYVIEW B3 PLATFORM/NOTEBOOK, BIOS BYTICRB1.86C.0092.R32.1410021707 10/02/2014 task: f44f4c20 ti: f40f6000 task.ti: f40f6000 EIP: 0060:[] EFLAGS: 00000097 CPU: 3 EIP is at _raw_spin_lock_irqsave+0x35/0x40 EAX: 00000076 EBX: f80fad00 ECX: 00000076 EDX: 00000075 ESI: 00000096 EDI: ffffff94 EBP: f40f7e20 ESP: f40f7e18 DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 CR0: 8005003b CR2: b77ac000 CR3: 01c30000 CR4: 001007f0 DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 DR6: ffff0ff0 DR7: 00000400 Stack: f474a720 f80fad00 f40f7e3c f80f93cc c135d486 00000000 f474a720 f468fb00 f4bea894 f40f7e54 f7e35f19 ffffff00 f468fb00 f468fb24 00000086 f40f7e64 f7e36577 f468fb00 f4bea810 f40f7e74 f7e365a8 f468fb00 f4bea894 f40f7e9c Call Trace: [] rx_complete+0x1c/0xb0 [g_printer] [] ? vsnprintf+0x166/0x390 [] dwc3_gadget_giveback+0xc9/0xf0 [dwc3] [] dwc3_remove_requests+0x57/0x70 [dwc3] [] __dwc3_gadget_ep_disable+0x18/0x60 [dwc3] [] dwc3_gadget_ep_disable+0x89/0xf0 [dwc3] [] printer_reset_interface+0x31/0x50 [g_printer] [] printer_func_disable+0x20/0x30 [g_printer] [] composite_disconnect+0x4b/0x90 [libcomposite] [] dwc3_disconnect_gadget+0x38/0x43 [dwc3] [] dwc3_gadget_disconnect_interrupt+0x3e/0x5a [dwc3] [] dwc3_thread_interrupt+0x5c8/0x610 [dwc3] [] irq_thread_fn+0x18/0x30 [] irq_thread+0x100/0x130 [] ? irq_finalize_oneshot.part.29+0xb0/0xb0 [] ? wake_threads_waitq+0x40/0x40 [] ? irq_thread_dtor+0xb0/0xb0 [] kthread+0x94/0xa0 [] ret_from_kernel_thread+0x1b/0x28 [] ? kthread_create_on_node+0xc0/0xc0 Signed-off-by: Fupan Li Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index 44173df..a91c18a 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -804,6 +804,8 @@ done: static void printer_reset_interface(struct printer_dev *dev) { + unsigned long flags; + if (dev->interface < 0) return; @@ -815,9 +817,11 @@ static void printer_reset_interface(struct printer_dev *dev) if (dev->out_ep->desc) usb_ep_disable(dev->out_ep); + spin_lock_irqsave(&dev->lock, flags); dev->in_ep->desc = NULL; dev->out_ep->desc = NULL; dev->interface = -1; + spin_unlock_irqrestore(&dev->lock, flags); } /* Change our operational Interface. */ @@ -1131,13 +1135,10 @@ static int printer_func_set_alt(struct usb_function *f, static void printer_func_disable(struct usb_function *f) { struct printer_dev *dev = func_to_printer(f); - unsigned long flags; DBG(dev, "%s\n", __func__); - spin_lock_irqsave(&dev->lock, flags); printer_reset_interface(dev); - spin_unlock_irqrestore(&dev->lock, flags); } static inline struct f_printer_opts -- cgit v0.10.2 From 3f217e9e96daa3d7741bab705fe9c7798d9951a9 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Fri, 31 Jul 2015 10:41:00 +0800 Subject: usb: chipidea: add ci->is_otg condition for otg judgement Since some chipidea based controller is not otg capable, add ci->is_otg condition when setting is_otg flag for gadget. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Acked-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index b7cca3e..f5fbe78 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1838,8 +1838,8 @@ static int udc_start(struct ci_hdrc *ci) ci->gadget.name = ci->platdata->name; ci->gadget.otg_caps = otg_caps; - if (otg_caps->hnp_support || otg_caps->srp_support || - otg_caps->adp_support) + if (ci->is_otg && (otg_caps->hnp_support || otg_caps->srp_support || + otg_caps->adp_support)) ci->gadget.is_otg = 1; INIT_LIST_HEAD(&ci->gadget.ep_list); -- cgit v0.10.2 From a2e66ad34c10b27c6e408db50e6472c2aae2b5e8 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Wed, 29 Jul 2015 09:08:53 +0200 Subject: Documentation: sysfs-bus-usb: s/CONFIG_PM_RUNTIME/CONFIG_PM/ PM_RUNTIME has been replaced with PM by commit 464ed18ebdb6 ("PM: Eliminate CONFIG_PM_RUNTIME") hence substitute the reference on PM_RUNTIME with PM and re-arrange the text to 80 column break. Signed-off-by: Valentin Rothberg Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index e935625..864637f 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -118,12 +118,12 @@ What: /sys/bus/usb/devices/.../power/usb3_hardware_lpm Date: June 2015 Contact: Kevin Strasser Description: - If CONFIG_PM_RUNTIME is set and a USB 3.0 lpm-capable device is - plugged in to a xHCI host which supports link PM, it will check - if U1 and U2 exit latencies have been set in the BOS - descriptor; if the check is is passed and the host supports - USB3 hardware LPM, USB3 hardware LPM will be enabled for the - device and the USB device directory will contain a file named + If CONFIG_PM is set and a USB 3.0 lpm-capable device is plugged + in to a xHCI host which supports link PM, it will check if U1 + and U2 exit latencies have been set in the BOS descriptor; if + the check is is passed and the host supports USB3 hardware LPM, + USB3 hardware LPM will be enabled for the device and the USB + device directory will contain a file named power/usb3_hardware_lpm. The file holds a string value (enable or disable) indicating whether or not USB3 hardware LPM is enabled for the device. -- cgit v0.10.2 From 4b68b50fd45e2f429da574c74d9a3788a861434f Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:01:31 +0000 Subject: usb: phy: phy-mxs-usb: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index 3fcc048..4d863eb 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -506,11 +506,7 @@ static int mxs_phy_probe(struct platform_device *pdev) device_set_wakeup_capable(&pdev->dev, true); - ret = usb_add_phy_dev(&mxs_phy->phy); - if (ret) - return ret; - - return 0; + return usb_add_phy_dev(&mxs_phy->phy); } static int mxs_phy_remove(struct platform_device *pdev) -- cgit v0.10.2 From c5673f5ce4c0faa97df419877bcdebbd76d43151 Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:02:03 +0000 Subject: usb: phy: phy-keystone: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-keystone.c b/drivers/usb/phy/phy-keystone.c index e0556f7..01d4e4c 100644 --- a/drivers/usb/phy/phy-keystone.c +++ b/drivers/usb/phy/phy-keystone.c @@ -96,11 +96,7 @@ static int keystone_usbphy_probe(struct platform_device *pdev) platform_set_drvdata(pdev, k_phy); - ret = usb_add_phy_dev(&k_phy->usb_phy_gen.phy); - if (ret) - return ret; - - return 0; + return usb_add_phy_dev(&k_phy->usb_phy_gen.phy); } static int keystone_usbphy_remove(struct platform_device *pdev) -- cgit v0.10.2 From 7f352964852ede9e95d18fd3825c5200fb48b3a5 Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:02:28 +0000 Subject: usb: musb: musb_dsps: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 1334a3d..a0cfead 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -482,11 +482,7 @@ static int dsps_musb_init(struct musb *musb) dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, val); } - ret = dsps_musb_dbg_init(musb, glue); - if (ret) - return ret; - - return 0; + return dsps_musb_dbg_init(musb, glue); } static int dsps_musb_exit(struct musb *musb) -- cgit v0.10.2 From 0f4315a8f1a73f130bbc5dde134b704ea6dda56c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 4 Aug 2015 11:02:45 -0500 Subject: usb: gadget: f_uac2: fix build warning commit 913e4a90b6f9 ("usb: gadget: f_uac2: finalize wMaxPacketSize according to bandwidth") added a possible build warning when calling min(). In order to fix the warning, we just make sure to call min_t() and tell that its arguments should be u16. Cc: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index b568024..c35a2a1 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -994,7 +994,7 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, max_packet_size = num_channels(chmask) * ssize * DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))); - ep_desc->wMaxPacketSize = cpu_to_le16(min(max_packet_size, + ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_packet_size, le16_to_cpu(ep_desc->wMaxPacketSize))); } -- cgit v0.10.2 From cc476b42a39d5a66d94f46cade972dcb8ee278df Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:13 +0200 Subject: usb: gadget: encapsulate endpoint claiming mechanism So far it was necessary for usb functions to set ep->driver_data in endpoint obtained from autoconfig to non-null value, to indicate that endpoint is claimed by function (in autoconfig it was checked if endpoint has set this field to non-null value, and if it has, it was assumed that it is claimed). It could cause bugs because if some function doesn't set this field autoconfig could return the same endpoint more than one time. To help to avoid such bugs this patch adds claimed flag to struct usb_ep, and encapsulates endpoint claiming mechanism inside usb_ep_autoconfig_ss() and usb_ep_autoconfig_reset(), so now usb functions don't need to perform any additional actions to mark endpoint obtained from autoconfig as claimed. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 919cdfd..8e00ca7 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -53,7 +53,7 @@ ep_matches ( int num_req_streams = 0; /* endpoint already claimed? */ - if (NULL != ep->driver_data) + if (ep->claimed) return 0; /* only support ep0 for portable CONTROL traffic */ @@ -240,7 +240,7 @@ find_ep (struct usb_gadget *gadget, const char *name) * updated with the assigned number of streams if it is * different from the original value. To prevent the endpoint * from being returned by a later autoconfig call, claim it by - * assigning ep->driver_data to some non-null value. + * assigning ep->claimed to true. * * On failure, this returns a null endpoint descriptor. */ @@ -323,6 +323,7 @@ struct usb_ep *usb_ep_autoconfig_ss( found_ep: ep->desc = NULL; ep->comp_desc = NULL; + ep->claimed = true; return ep; } EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss); @@ -354,7 +355,7 @@ EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss); * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value * is initialized as if the endpoint were used at full speed. To prevent * the endpoint from being returned by a later autoconfig call, claim it - * by assigning ep->driver_data to some non-null value. + * by assigning ep->claimed to true. * * On failure, this returns a null endpoint descriptor. */ @@ -373,7 +374,7 @@ EXPORT_SYMBOL_GPL(usb_ep_autoconfig); * * Use this for devices where one configuration may need to assign * endpoint resources very differently from the next one. It clears - * state such as ep->driver_data and the record of assigned endpoints + * state such as ep->claimed and the record of assigned endpoints * used by usb_ep_autoconfig(). */ void usb_ep_autoconfig_reset (struct usb_gadget *gadget) @@ -381,7 +382,7 @@ void usb_ep_autoconfig_reset (struct usb_gadget *gadget) struct usb_ep *ep; list_for_each_entry (ep, &gadget->ep_list, ep_list) { - ep->driver_data = NULL; + ep->claimed = false; } gadget->in_epnum = 0; gadget->out_epnum = 0; diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 353a720..68fb5e8 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -173,6 +173,7 @@ struct usb_ep { const char *name; const struct usb_ep_ops *ops; struct list_head ep_list; + bool claimed; unsigned maxpacket:16; unsigned maxpacket_limit:16; unsigned max_streams:16; -- cgit v0.10.2 From 734b5a2addd333829a6d647ee14a3609c7a87c44 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:14 +0200 Subject: usb: gadget: add endpoint capabilities flags Introduce struct usb_ep_caps which contains information about capabilities of usb endpoints - supported transfer types and directions. This structure should be filled by UDC driver for each of its endpoints, and will be used in epautoconf in new ep matching mechanism which will replace ugly guessing of endpoint capabilities basing on its name. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 68fb5e8..a9a4959 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -141,10 +141,29 @@ struct usb_ep_ops { }; /** + * struct usb_ep_caps - endpoint capabilities description + * @type_control:Endpoint supports control type (reserved for ep0). + * @type_iso:Endpoint supports isochronous transfers. + * @type_bulk:Endpoint supports bulk transfers. + * @type_int:Endpoint supports interrupt transfers. + * @dir_in:Endpoint supports IN direction. + * @dir_out:Endpoint supports OUT direction. + */ +struct usb_ep_caps { + unsigned type_control:1; + unsigned type_iso:1; + unsigned type_bulk:1; + unsigned type_int:1; + unsigned dir_in:1; + unsigned dir_out:1; +}; + +/** * struct usb_ep - device side representation of USB endpoint * @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk" * @ops: Function pointers used to access hardware-specific operations. * @ep_list:the gadget's ep_list holds all of its endpoints + * @caps:The structure describing types and directions supported by endoint. * @maxpacket:The maximum packet size used on this endpoint. The initial * value can sometimes be reduced (hardware allowing), according to * the endpoint descriptor used to configure the endpoint. @@ -167,12 +186,14 @@ struct usb_ep_ops { * gadget->ep_list. the control endpoint (gadget->ep0) is not in that list, * and is accessed only in response to a driver setup() callback. */ + struct usb_ep { void *driver_data; const char *name; const struct usb_ep_ops *ops; struct list_head ep_list; + struct usb_ep_caps caps; bool claimed; unsigned maxpacket:16; unsigned maxpacket_limit:16; -- cgit v0.10.2 From 80e6e3847f851fc05e63265050115e29e2a50d7e Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:15 +0200 Subject: usb: gadget: add endpoint capabilities helper macros Add macros useful while initializing array of endpoint capabilities structures. These macros makes structure initialization more compact to decrease number of code lines and increase readability of code. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index a9a4959..82b5bcb 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -158,6 +158,26 @@ struct usb_ep_caps { unsigned dir_out:1; }; +#define USB_EP_CAPS_TYPE_CONTROL 0x01 +#define USB_EP_CAPS_TYPE_ISO 0x02 +#define USB_EP_CAPS_TYPE_BULK 0x04 +#define USB_EP_CAPS_TYPE_INT 0x08 +#define USB_EP_CAPS_TYPE_ALL \ + (USB_EP_CAPS_TYPE_ISO | USB_EP_CAPS_TYPE_BULK | USB_EP_CAPS_TYPE_INT) +#define USB_EP_CAPS_DIR_IN 0x01 +#define USB_EP_CAPS_DIR_OUT 0x02 +#define USB_EP_CAPS_DIR_ALL (USB_EP_CAPS_DIR_IN | USB_EP_CAPS_DIR_OUT) + +#define USB_EP_CAPS(_type, _dir) \ + { \ + .type_control = !!(_type & USB_EP_CAPS_TYPE_CONTROL), \ + .type_iso = !!(_type & USB_EP_CAPS_TYPE_ISO), \ + .type_bulk = !!(_type & USB_EP_CAPS_TYPE_BULK), \ + .type_int = !!(_type & USB_EP_CAPS_TYPE_INT), \ + .dir_in = !!(_dir & USB_EP_CAPS_DIR_IN), \ + .dir_out = !!(_dir & USB_EP_CAPS_DIR_OUT), \ + } + /** * struct usb_ep - device side representation of USB endpoint * @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk" -- cgit v0.10.2 From 68b5c947515a252b9e416e419fca4c1382912948 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:16 +0200 Subject: staging: emxx_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Fixed typo in "epc-nulk" to "epc-bulk". Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c index 3b7aa36..b6b76ff 100644 --- a/drivers/staging/emxx_udc/emxx_udc.c +++ b/drivers/staging/emxx_udc/emxx_udc.c @@ -3153,36 +3153,46 @@ static const struct usb_gadget_ops nbu2ss_gadget_ops = { .ioctl = nbu2ss_gad_ioctl, }; -static const char g_ep0_name[] = "ep0"; -static const char g_ep1_name[] = "ep1-bulk"; -static const char g_ep2_name[] = "ep2-bulk"; -static const char g_ep3_name[] = "ep3in-int"; -static const char g_ep4_name[] = "ep4-iso"; -static const char g_ep5_name[] = "ep5-iso"; -static const char g_ep6_name[] = "ep6-bulk"; -static const char g_ep7_name[] = "ep7-bulk"; -static const char g_ep8_name[] = "ep8in-int"; -static const char g_ep9_name[] = "ep9-iso"; -static const char g_epa_name[] = "epa-iso"; -static const char g_epb_name[] = "epb-bulk"; -static const char g_epc_name[] = "epc-nulk"; -static const char g_epd_name[] = "epdin-int"; - -static const char *gp_ep_name[NUM_ENDPOINTS] = { - g_ep0_name, - g_ep1_name, - g_ep2_name, - g_ep3_name, - g_ep4_name, - g_ep5_name, - g_ep6_name, - g_ep7_name, - g_ep8_name, - g_ep9_name, - g_epa_name, - g_epb_name, - g_epc_name, - g_epd_name, +static const struct { + const char *name; + const struct usb_ep_caps caps; +} ep_info[NUM_ENDPOINTS] = { +#define EP_INFO(_name, _caps) \ + { \ + .name = _name, \ + .caps = _caps, \ + } + + EP_INFO("ep0", + USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep1-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep2-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep3in-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep4-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep5-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep6-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep7-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep8in-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep9-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)), + EP_INFO("epa-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)), + EP_INFO("epb-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)), + EP_INFO("epc-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)), + EP_INFO("epdin-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), + +#undef EP_INFO }; /*-------------------------------------------------------------------------*/ @@ -3200,7 +3210,8 @@ static void __init nbu2ss_drv_ep_init(struct nbu2ss_udc *udc) ep->desc = NULL; ep->ep.driver_data = NULL; - ep->ep.name = gp_ep_name[i]; + ep->ep.name = ep_info[i].name; + ep->ep.caps = ep_info[i].caps; ep->ep.ops = &nbu2ss_ep_ops; usb_ep_set_maxpacket_limit(&ep->ep, -- cgit v0.10.2 From a7e3f1410855db6b67ec29a386e74be2df3cc311 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:17 +0200 Subject: usb: chipidea: udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index f5fbe78..c592b6f 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1624,6 +1624,20 @@ static int init_eps(struct ci_hdrc *ci) hwep->ep.name = hwep->name; hwep->ep.ops = &usb_ep_ops; + + if (i == 0) { + hwep->ep.caps.type_control = true; + } else { + hwep->ep.caps.type_iso = true; + hwep->ep.caps.type_bulk = true; + hwep->ep.caps.type_int = true; + } + + if (j == TX) + hwep->ep.caps.dir_in = true; + else + hwep->ep.caps.dir_out = true; + /* * for ep0: maxP defined in desc, for other * eps, maxP is set by epautoconfig() called -- cgit v0.10.2 From 2954522f135246287c36524bc96e9dae8c40f8a9 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:18 +0200 Subject: usb: dwc2: gadget: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 731b13d..3ee5b4c 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3289,6 +3289,19 @@ static void s3c_hsotg_initep(struct dwc2_hsotg *hsotg, usb_ep_set_maxpacket_limit(&hs_ep->ep, epnum ? 1024 : EP0_MPS_LIMIT); hs_ep->ep.ops = &s3c_hsotg_ep_ops; + if (epnum == 0) { + hs_ep->ep.caps.type_control = true; + } else { + hs_ep->ep.caps.type_iso = true; + hs_ep->ep.caps.type_bulk = true; + hs_ep->ep.caps.type_int = true; + } + + if (dir_in) + hs_ep->ep.caps.dir_in = true; + else + hs_ep->ep.caps.dir_out = true; + /* * if we're using dma, we need to set the next-endpoint pointer * to be something valid. -- cgit v0.10.2 From a474d3b73ba7f22844e672ac004f01cd9b8be159 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:19 +0200 Subject: usb: dwc3: gadget: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 2feed9e..0c25704 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1715,6 +1715,17 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, return ret; } + if (epnum == 0 || epnum == 1) { + dep->endpoint.caps.type_control = true; + } else { + dep->endpoint.caps.type_iso = true; + dep->endpoint.caps.type_bulk = true; + dep->endpoint.caps.type_int = true; + } + + dep->endpoint.caps.dir_in = !!direction; + dep->endpoint.caps.dir_out = !direction; + INIT_LIST_HEAD(&dep->request_list); INIT_LIST_HEAD(&dep->req_queued); } -- cgit v0.10.2 From 6f02ac5ac9bba538593e4359dd5e83c4d42822fe Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:20 +0200 Subject: usb: gadget: amd5536udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/amd5536udc.c b/drivers/usb/gadget/udc/amd5536udc.c index de7e5e2..fdacddb 100644 --- a/drivers/usb/gadget/udc/amd5536udc.c +++ b/drivers/usb/gadget/udc/amd5536udc.c @@ -138,15 +138,82 @@ static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect, /* endpoint names used for print */ static const char ep0_string[] = "ep0in"; -static const char *const ep_string[] = { - ep0_string, - "ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk", - "ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk", - "ep11in-bulk", "ep12in-bulk", "ep13in-bulk", "ep14in-bulk", - "ep15in-bulk", "ep0out", "ep1out-bulk", "ep2out-bulk", "ep3out-bulk", - "ep4out-bulk", "ep5out-bulk", "ep6out-bulk", "ep7out-bulk", - "ep8out-bulk", "ep9out-bulk", "ep10out-bulk", "ep11out-bulk", - "ep12out-bulk", "ep13out-bulk", "ep14out-bulk", "ep15out-bulk" +static const struct { + const char *name; + const struct usb_ep_caps caps; +} ep_info[] = { +#define EP_INFO(_name, _caps) \ + { \ + .name = _name, \ + .caps = _caps, \ + } + + EP_INFO(ep0_string, + USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep1in-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep2in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep3in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep4in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep5in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep6in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep7in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep8in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep9in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep10in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep11in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep12in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep13in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep14in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep15in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep0out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep1out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep2out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep3out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep4out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep5out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep6out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep7out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep8out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep9out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep10out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep11out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep12out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep13out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep14out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep15out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + +#undef EP_INFO }; /* DMA usage flag */ @@ -1517,7 +1584,8 @@ static void udc_setup_endpoints(struct udc *dev) for (tmp = 0; tmp < UDC_EP_NUM; tmp++) { ep = &dev->ep[tmp]; ep->dev = dev; - ep->ep.name = ep_string[tmp]; + ep->ep.name = ep_info[tmp].name; + ep->ep.caps = ep_info[tmp].caps; ep->num = tmp; /* txfifo size is calculated at enable time */ ep->txfifo = dev->txfifo; -- cgit v0.10.2 From b9ed96d7d579416a8fd2e1cef66541bfdad2720f Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:21 +0200 Subject: usb: gadget: at91_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index 32f50a79..d0d1894 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -59,15 +59,34 @@ #define DRIVER_VERSION "3 May 2006" static const char driver_name [] = "at91_udc"; -static const char * const ep_names[] = { - "ep0", - "ep1", - "ep2", - "ep3-int", - "ep4", - "ep5", + +static const struct { + const char *name; + const struct usb_ep_caps caps; +} ep_info[] = { +#define EP_INFO(_name, _caps) \ + { \ + .name = _name, \ + .caps = _caps, \ + } + + EP_INFO("ep0", + USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep1", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep2", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep3-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep4", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep5", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + +#undef EP_INFO }; -#define ep0name ep_names[0] + +#define ep0name ep_info[0].name #define VBUS_POLL_TIMEOUT msecs_to_jiffies(1000) @@ -1831,7 +1850,8 @@ static int at91udc_probe(struct platform_device *pdev) for (i = 0; i < NUM_ENDPOINTS; i++) { ep = &udc->ep[i]; - ep->ep.name = ep_names[i]; + ep->ep.name = ep_info[i].name; + ep->ep.caps = ep_info[i].caps; ep->ep.ops = &at91_ep_ops; ep->udc = udc; ep->int_mask = BIT(i); -- cgit v0.10.2 From 1b0ba527702268992a62227dde4911477f057ca5 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:22 +0200 Subject: usb: gadget: bcm63xx_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c index 9db968b..8cbb003 100644 --- a/drivers/usb/gadget/udc/bcm63xx_udc.c +++ b/drivers/usb/gadget/udc/bcm63xx_udc.c @@ -44,9 +44,29 @@ #define DRV_MODULE_NAME "bcm63xx_udc" static const char bcm63xx_ep0name[] = "ep0"; -static const char *const bcm63xx_ep_name[] = { - bcm63xx_ep0name, - "ep1in-bulk", "ep2out-bulk", "ep3in-int", "ep4out-int", + +static const struct { + const char *name; + const struct usb_ep_caps caps; +} bcm63xx_ep_info[] = { +#define EP_INFO(_name, _caps) \ + { \ + .name = _name, \ + .caps = _caps, \ + } + + EP_INFO(bcm63xx_ep0name, + USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep1in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep2out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep3in-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep4out-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_OUT)), + +#undef EP_INFO }; static bool use_fullspeed; @@ -943,7 +963,8 @@ static int bcm63xx_init_udc_hw(struct bcm63xx_udc *udc) for (i = 0; i < BCM63XX_NUM_EP; i++) { struct bcm63xx_ep *bep = &udc->bep[i]; - bep->ep.name = bcm63xx_ep_name[i]; + bep->ep.name = bcm63xx_ep_info[i].name; + bep->ep.caps = bcm63xx_ep_info[i].caps; bep->ep_num = i; bep->ep.ops = &bcm63xx_udc_ep_ops; list_add_tail(&bep->ep.ep_list, &udc->gadget.ep_list); -- cgit v0.10.2 From b079dd6156a6544e0383642a9ec97d17485aa244 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:23 +0200 Subject: usb: gadget: bdc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c index b04980c..f9a8f57 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_ep.c +++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c @@ -1952,12 +1952,18 @@ static int init_ep(struct bdc *bdc, u32 epnum, u32 dir) ep->bdc = bdc; ep->dir = dir; + if (dir) + ep->usb_ep.caps.dir_in = true; + else + ep->usb_ep.caps.dir_out = true; + /* ep->ep_num is the index inside bdc_ep */ if (epnum == 1) { ep->ep_num = 1; bdc->bdc_ep_array[ep->ep_num] = ep; snprintf(ep->name, sizeof(ep->name), "ep%d", epnum - 1); usb_ep_set_maxpacket_limit(&ep->usb_ep, EP0_MAX_PKT_SIZE); + ep->usb_ep.caps.type_control = true; ep->comp_desc = NULL; bdc->gadget.ep0 = &ep->usb_ep; } else { @@ -1971,6 +1977,9 @@ static int init_ep(struct bdc *bdc, u32 epnum, u32 dir) dir & 1 ? "in" : "out"); usb_ep_set_maxpacket_limit(&ep->usb_ep, 1024); + ep->usb_ep.caps.type_iso = true; + ep->usb_ep.caps.type_bulk = true; + ep->usb_ep.caps.type_int = true; ep->usb_ep.max_streams = 0; list_add_tail(&ep->usb_ep.ep_list, &bdc->gadget.ep_list); } -- cgit v0.10.2 From 7a3b8e7098946b44c014f3df0ceef27fb273c142 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:24 +0200 Subject: usb: gadget: dummy-hcd: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 181112c..1379ad4 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -127,23 +127,87 @@ static inline struct dummy_request *usb_request_to_dummy_request static const char ep0name[] = "ep0"; -static const char *const ep_name[] = { - ep0name, /* everyone has ep0 */ +static const struct { + const char *name; + const struct usb_ep_caps caps; +} ep_info[] = { +#define EP_INFO(_name, _caps) \ + { \ + .name = _name, \ + .caps = _caps, \ + } + /* everyone has ep0 */ + EP_INFO(ep0name, + USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)), /* act like a pxa250: fifteen fixed function endpoints */ - "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int", - "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int", - "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso", - "ep15in-int", - + EP_INFO("ep1in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep2out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep3in-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep4out-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep5in-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep6in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep7out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep8in-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep9out-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep10in-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep11in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep12out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep13in-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep14out-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep15in-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), /* or like sa1100: two fixed function endpoints */ - "ep1out-bulk", "ep2in-bulk", - + EP_INFO("ep1out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep2in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), /* and now some generic EPs so we have enough in multi config */ - "ep3out", "ep4in", "ep5out", "ep6out", "ep7in", "ep8out", "ep9in", - "ep10out", "ep11out", "ep12in", "ep13out", "ep14in", "ep15out", + EP_INFO("ep3out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep4in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep5out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep6out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep7in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep8out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep9in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep10out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep11out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep12in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep13out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep14in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep15out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + +#undef EP_INFO }; -#define DUMMY_ENDPOINTS ARRAY_SIZE(ep_name) + +#define DUMMY_ENDPOINTS ARRAY_SIZE(ep_info) /*-------------------------------------------------------------------------*/ @@ -938,9 +1002,10 @@ static void init_dummy_udc_hw(struct dummy *dum) for (i = 0; i < DUMMY_ENDPOINTS; i++) { struct dummy_ep *ep = &dum->ep[i]; - if (!ep_name[i]) + if (!ep_info[i].name) break; - ep->ep.name = ep_name[i]; + ep->ep.name = ep_info[i].name; + ep->ep.caps = ep_info[i].caps; ep->ep.ops = &dummy_ep_ops; list_add_tail(&ep->ep.ep_list, &dum->gadget.ep_list); ep->halted = ep->wedged = ep->already_seen = @@ -1684,7 +1749,7 @@ static void dummy_timer(unsigned long _dum_hcd) } for (i = 0; i < DUMMY_ENDPOINTS; i++) { - if (!ep_name[i]) + if (!ep_info[i].name) break; dum->ep[i].already_seen = 0; } -- cgit v0.10.2 From 8d29237a436dc8e2b5c44dd0ca662a680f16deb5 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:25 +0200 Subject: usb: gadget: fotg210-udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c index a99ed6d..6ba122c 100644 --- a/drivers/usb/gadget/udc/fotg210-udc.c +++ b/drivers/usb/gadget/udc/fotg210-udc.c @@ -1143,6 +1143,17 @@ static int fotg210_udc_probe(struct platform_device *pdev) ep->ep.name = fotg210_ep_name[i]; ep->ep.ops = &fotg210_ep_ops; usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0); + + if (i == 0) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } + + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; } usb_ep_set_maxpacket_limit(&fotg210->ep[0]->ep, 0x40); fotg210->gadget.ep0 = &fotg210->ep[0]->ep; -- cgit v0.10.2 From e8fc42f6a19af320d7a4718c05c3f249bf5d3151 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:26 +0200 Subject: usb: gadget: fsl_qe_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index e0822f1..5fb6f8b 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -2417,6 +2417,17 @@ static int qe_ep_config(struct qe_udc *udc, unsigned char pipe_num) strcpy(ep->name, ep_name[pipe_num]); ep->ep.name = ep_name[pipe_num]; + if (pipe_num == 0) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } + + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; + ep->ep.ops = &qe_ep_ops; ep->stopped = 1; usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0); -- cgit v0.10.2 From 60a28c63712f190b45e9d8f0ca593c927970fd51 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:27 +0200 Subject: usb: gadget: fsl_udc_core: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index c60022b..aab5221 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -2313,6 +2313,19 @@ static int struct_ep_setup(struct fsl_udc *udc, unsigned char index, ep->ep.ops = &fsl_ep_ops; ep->stopped = 0; + if (index == 0) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } + + if (index & 1) + ep->ep.caps.dir_in = true; + else + ep->ep.caps.dir_out = true; + /* for ep0: maxP defined in desc * for other eps, maxP is set by epautoconfig() called by gadget layer */ -- cgit v0.10.2 From 455d11c93582c4167f55af0969b83821450be120 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:28 +0200 Subject: usb: gadget: fusb300_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/fusb300_udc.c b/drivers/usb/gadget/udc/fusb300_udc.c index 3970f45..948845c 100644 --- a/drivers/usb/gadget/udc/fusb300_udc.c +++ b/drivers/usb/gadget/udc/fusb300_udc.c @@ -1450,6 +1450,17 @@ static int fusb300_probe(struct platform_device *pdev) ep->ep.name = fusb300_ep_name[i]; ep->ep.ops = &fusb300_ep_ops; usb_ep_set_maxpacket_limit(&ep->ep, HS_BULK_MAX_PACKET_SIZE); + + if (i == 0) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } + + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; } usb_ep_set_maxpacket_limit(&fusb300->ep[0]->ep, HS_CTL_MAX_PACKET_SIZE); fusb300->ep[0]->epnum = 0; -- cgit v0.10.2 From b0bf5fbfbd30ffbb9e45169f78412f0596e16412 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:29 +0200 Subject: usb: gadget: goku_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c index 9e8d842..46b8d14 100644 --- a/drivers/usb/gadget/udc/goku_udc.c +++ b/drivers/usb/gadget/udc/goku_udc.c @@ -1257,6 +1257,14 @@ static void udc_reinit (struct goku_udc *dev) INIT_LIST_HEAD (&ep->queue); ep_reset(NULL, ep); + + if (i == 0) + ep->ep.caps.type_control = true; + else + ep->ep.caps.type_bulk = true; + + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; } dev->ep[0].reg_mode = NULL; -- cgit v0.10.2 From 892269925991b449ae47dcc0debb324ae451022e Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:30 +0200 Subject: usb: gadget: gr_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c index c886887..8aa2593 100644 --- a/drivers/usb/gadget/udc/gr_udc.c +++ b/drivers/usb/gadget/udc/gr_udc.c @@ -2018,12 +2018,23 @@ static int gr_ep_init(struct gr_udc *dev, int num, int is_in, u32 maxplimit) usb_ep_set_maxpacket_limit(&ep->ep, MAX_CTRL_PL_SIZE); ep->bytes_per_buffer = MAX_CTRL_PL_SIZE; + + ep->ep.caps.type_control = true; } else { usb_ep_set_maxpacket_limit(&ep->ep, (u16)maxplimit); list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); + + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; } list_add_tail(&ep->ep_list, &dev->ep_list); + if (is_in) + ep->ep.caps.dir_in = true; + else + ep->ep.caps.dir_out = true; + ep->tailbuf = dma_alloc_coherent(dev->dev, ep->ep.maxpacket_limit, &ep->tailbuf_paddr, GFP_ATOMIC); if (!ep->tailbuf) -- cgit v0.10.2 From 4d75c8bd613c5ba99ee02cfe38610c82e7fe8362 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:31 +0200 Subject: usb: gadget: lpc32xx_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index 3b6a785..00b5006 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -2575,6 +2575,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep0", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 0, @@ -2586,6 +2588,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep1-int", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 2, @@ -2597,6 +2601,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep2-bulk", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 4, @@ -2608,6 +2614,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep3-iso", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 1023, .hwep_num_base = 6, @@ -2619,6 +2627,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep4-int", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 8, @@ -2630,6 +2640,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep5-bulk", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 10, @@ -2641,6 +2653,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep6-iso", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 1023, .hwep_num_base = 12, @@ -2652,6 +2666,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep7-int", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 14, @@ -2663,6 +2679,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep8-bulk", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 16, @@ -2674,6 +2692,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep9-iso", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 1023, .hwep_num_base = 18, @@ -2685,6 +2705,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep10-int", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 20, @@ -2696,6 +2718,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep11-bulk", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 22, @@ -2707,6 +2731,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep12-iso", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 1023, .hwep_num_base = 24, @@ -2718,6 +2744,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep13-int", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 26, @@ -2729,6 +2757,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep14-bulk", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 28, @@ -2740,6 +2770,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep15-bulk", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 1023, .hwep_num_base = 30, -- cgit v0.10.2 From 8ddbf94fd5b536b3adf5ffa631c5951718e7301d Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:32 +0200 Subject: usb: gadget: m66592-udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c index 9704053..b1cfa96 100644 --- a/drivers/usb/gadget/udc/m66592-udc.c +++ b/drivers/usb/gadget/udc/m66592-udc.c @@ -1644,6 +1644,17 @@ static int m66592_probe(struct platform_device *pdev) ep->ep.name = m66592_ep_name[i]; ep->ep.ops = &m66592_ep_ops; usb_ep_set_maxpacket_limit(&ep->ep, 512); + + if (i == 0) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } + + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; } usb_ep_set_maxpacket_limit(&m66592->ep[0].ep, 64); m66592->ep[0].pipenum = 0; -- cgit v0.10.2 From c12a30629f8b5fe8c2aba42c3128df702bbc9e83 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:33 +0200 Subject: usb: gadget: mv_u3d_core: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c index ea35a24..4c48969 100644 --- a/drivers/usb/gadget/udc/mv_u3d_core.c +++ b/drivers/usb/gadget/udc/mv_u3d_core.c @@ -1324,6 +1324,9 @@ static int mv_u3d_eps_init(struct mv_u3d *u3d) ep->ep.ops = &mv_u3d_ep_ops; ep->wedge = 0; usb_ep_set_maxpacket_limit(&ep->ep, MV_U3D_EP0_MAX_PKT_SIZE); + ep->ep.caps.type_control = true; + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; ep->ep_num = 0; ep->ep.desc = &mv_u3d_ep0_desc; INIT_LIST_HEAD(&ep->queue); @@ -1339,14 +1342,20 @@ static int mv_u3d_eps_init(struct mv_u3d *u3d) if (i & 1) { snprintf(name, sizeof(name), "ep%din", i >> 1); ep->direction = MV_U3D_EP_DIR_IN; + ep->ep.caps.dir_in = true; } else { snprintf(name, sizeof(name), "ep%dout", i >> 1); ep->direction = MV_U3D_EP_DIR_OUT; + ep->ep.caps.dir_out = true; } ep->u3d = u3d; strncpy(ep->name, name, sizeof(ep->name)); ep->ep.name = ep->name; + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + ep->ep.ops = &mv_u3d_ep_ops; usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0); ep->ep_num = i / 2; -- cgit v0.10.2 From 43710a8dba9ae607decdeaf7a56a51dd5b42184e Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:34 +0200 Subject: usb: gadget: mv_udc_core: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index 5da37c9..339af51 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -1257,6 +1257,9 @@ static int eps_init(struct mv_udc *udc) ep->wedge = 0; ep->stopped = 0; usb_ep_set_maxpacket_limit(&ep->ep, EP0_MAX_PKT_SIZE); + ep->ep.caps.type_control = true; + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; ep->ep_num = 0; ep->ep.desc = &mv_ep0_desc; INIT_LIST_HEAD(&ep->queue); @@ -1269,14 +1272,20 @@ static int eps_init(struct mv_udc *udc) if (i % 2) { snprintf(name, sizeof(name), "ep%din", i / 2); ep->direction = EP_DIR_IN; + ep->ep.caps.dir_in = true; } else { snprintf(name, sizeof(name), "ep%dout", i / 2); ep->direction = EP_DIR_OUT; + ep->ep.caps.dir_out = true; } ep->udc = udc; strncpy(ep->name, name, sizeof(ep->name)); ep->ep.name = ep->name; + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + ep->ep.ops = &mv_ep_ops; ep->stopped = 0; usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0); -- cgit v0.10.2 From f95aec51da16250841a4254db36f9771446cdbb6 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:35 +0200 Subject: usb: gadget: net2272: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index c2ed5da..18f5ebd 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -1404,6 +1404,17 @@ net2272_usb_reinit(struct net2272 *dev) else ep->fifo_size = 64; net2272_ep_reset(ep); + + if (i == 0) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } + + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; } usb_ep_set_maxpacket_limit(&dev->ep[0].ep, 64); -- cgit v0.10.2 From c23c3c3c3059f3dc47268cd7a28b96b9efdbc1ea Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:36 +0200 Subject: usb: gadget: net2280: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index 2bee912..872ca25 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -74,19 +74,58 @@ static const char driver_desc[] = DRIVER_DESC; static const u32 ep_bit[9] = { 0, 17, 2, 19, 4, 1, 18, 3, 20 }; static const char ep0name[] = "ep0"; -static const char *const ep_name[] = { - ep0name, - "ep-a", "ep-b", "ep-c", "ep-d", - "ep-e", "ep-f", "ep-g", "ep-h", -}; -/* Endpoint names for usb3380 advance mode */ -static const char *const ep_name_adv[] = { - ep0name, - "ep1in", "ep2out", "ep3in", "ep4out", - "ep1out", "ep2in", "ep3out", "ep4in", +#define EP_INFO(_name, _caps) \ + { \ + .name = _name, \ + .caps = _caps, \ + } + +static const struct { + const char *name; + const struct usb_ep_caps caps; +} ep_info_dft[] = { /* Default endpoint configuration */ + EP_INFO(ep0name, + USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-a", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-b", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-c", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-d", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-e", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-f", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-g", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-h", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), +}, ep_info_adv[] = { /* Endpoints for usb3380 advance mode */ + EP_INFO(ep0name, + USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep1in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep2out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep3in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep4out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep1out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep2in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep3out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep4in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), }; +#undef EP_INFO + /* mode 0 == ep-{a,b,c,d} 1K fifo each * mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable * mode 2 == ep-a 2K fifo, ep-{b,c} 1K each, ep-d unavailable @@ -2055,7 +2094,8 @@ static void usb_reinit_228x(struct net2280 *dev) for (tmp = 0; tmp < 7; tmp++) { struct net2280_ep *ep = &dev->ep[tmp]; - ep->ep.name = ep_name[tmp]; + ep->ep.name = ep_info_dft[tmp].name; + ep->ep.caps = ep_info_dft[tmp].caps; ep->dev = dev; ep->num = tmp; @@ -2095,7 +2135,10 @@ static void usb_reinit_338x(struct net2280 *dev) for (i = 0; i < dev->n_ep; i++) { struct net2280_ep *ep = &dev->ep[i]; - ep->ep.name = dev->enhanced_mode ? ep_name_adv[i] : ep_name[i]; + ep->ep.name = dev->enhanced_mode ? ep_info_adv[i].name : + ep_info_dft[i].name; + ep->ep.caps = dev->enhanced_mode ? ep_info_adv[i].caps : + ep_info_dft[i].caps; ep->dev = dev; ep->num = i; -- cgit v0.10.2 From 7d4ba80d3a91222de577b652a8936f935de8b409 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:37 +0200 Subject: usb: gadget: omap_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c index e2fcdb8..9b7d394 100644 --- a/drivers/usb/gadget/udc/omap_udc.c +++ b/drivers/usb/gadget/udc/omap_udc.c @@ -2579,6 +2579,28 @@ omap_ep_setup(char *name, u8 addr, u8 type, ep->double_buf = dbuf; ep->udc = udc; + switch (type) { + case USB_ENDPOINT_XFER_CONTROL: + ep->ep.caps.type_control = true; + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; + break; + case USB_ENDPOINT_XFER_ISOC: + ep->ep.caps.type_iso = true; + break; + case USB_ENDPOINT_XFER_BULK: + ep->ep.caps.type_bulk = true; + break; + case USB_ENDPOINT_XFER_INT: + ep->ep.caps.type_int = true; + break; + }; + + if (addr & USB_DIR_IN) + ep->ep.caps.dir_in = true; + else + ep->ep.caps.dir_out = true; + ep->ep.name = ep->name; ep->ep.ops = &omap_ep_ops; ep->maxpacket = maxp; -- cgit v0.10.2 From 85a4ed003b39f70ba478e613a9be2c334f1079e7 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:38 +0200 Subject: usb: gadget: pch_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index e071c62..e5f4c52 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -2895,11 +2895,21 @@ static void pch_udc_pcd_reinit(struct pch_udc_dev *dev) ep->in = ~i & 1; ep->ep.name = ep_string[i]; ep->ep.ops = &pch_udc_ep_ops; - if (ep->in) + if (ep->in) { ep->offset_addr = ep->num * UDC_EP_REG_SHIFT; - else + ep->ep.caps.dir_in = true; + } else { ep->offset_addr = (UDC_EPINT_OUT_SHIFT + ep->num) * UDC_EP_REG_SHIFT; + ep->ep.caps.dir_out = true; + } + if (i == UDC_EP0IN_IDX || i == UDC_EP0OUT_IDX) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } /* need to set ep->ep.maxpacket and set Default Configuration?*/ usb_ep_set_maxpacket_limit(&ep->ep, UDC_BULK_MAX_PKT_SIZE); list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); -- cgit v0.10.2 From 36411b6b042d350a43fe1e0d3ce78fbda30f4f02 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:39 +0200 Subject: usb: gadget: pxa25x_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index 27f9442..b4d25dc 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -1822,6 +1822,8 @@ static struct pxa25x_udc memory = { .name = ep0name, .ops = &pxa25x_ep_ops, .maxpacket = EP0_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, + USB_EP_CAPS_DIR_ALL), }, .dev = &memory, .reg_udccs = &UDCCS0, @@ -1834,6 +1836,8 @@ static struct pxa25x_udc memory = { .name = "ep1in-bulk", .ops = &pxa25x_ep_ops, .maxpacket = BULK_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_IN), }, .dev = &memory, .fifo_size = BULK_FIFO_SIZE, @@ -1847,6 +1851,8 @@ static struct pxa25x_udc memory = { .name = "ep2out-bulk", .ops = &pxa25x_ep_ops, .maxpacket = BULK_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_OUT), }, .dev = &memory, .fifo_size = BULK_FIFO_SIZE, @@ -1862,6 +1868,8 @@ static struct pxa25x_udc memory = { .name = "ep3in-iso", .ops = &pxa25x_ep_ops, .maxpacket = ISO_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_IN), }, .dev = &memory, .fifo_size = ISO_FIFO_SIZE, @@ -1875,6 +1883,8 @@ static struct pxa25x_udc memory = { .name = "ep4out-iso", .ops = &pxa25x_ep_ops, .maxpacket = ISO_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_OUT), }, .dev = &memory, .fifo_size = ISO_FIFO_SIZE, @@ -1889,6 +1899,8 @@ static struct pxa25x_udc memory = { .name = "ep5in-int", .ops = &pxa25x_ep_ops, .maxpacket = INT_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, + USB_EP_CAPS_DIR_IN), }, .dev = &memory, .fifo_size = INT_FIFO_SIZE, @@ -1904,6 +1916,8 @@ static struct pxa25x_udc memory = { .name = "ep6in-bulk", .ops = &pxa25x_ep_ops, .maxpacket = BULK_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_IN), }, .dev = &memory, .fifo_size = BULK_FIFO_SIZE, @@ -1917,6 +1931,8 @@ static struct pxa25x_udc memory = { .name = "ep7out-bulk", .ops = &pxa25x_ep_ops, .maxpacket = BULK_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_OUT), }, .dev = &memory, .fifo_size = BULK_FIFO_SIZE, @@ -1931,6 +1947,8 @@ static struct pxa25x_udc memory = { .name = "ep8in-iso", .ops = &pxa25x_ep_ops, .maxpacket = ISO_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_IN), }, .dev = &memory, .fifo_size = ISO_FIFO_SIZE, @@ -1944,6 +1962,8 @@ static struct pxa25x_udc memory = { .name = "ep9out-iso", .ops = &pxa25x_ep_ops, .maxpacket = ISO_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_OUT), }, .dev = &memory, .fifo_size = ISO_FIFO_SIZE, @@ -1958,6 +1978,8 @@ static struct pxa25x_udc memory = { .name = "ep10in-int", .ops = &pxa25x_ep_ops, .maxpacket = INT_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, + USB_EP_CAPS_DIR_IN), }, .dev = &memory, .fifo_size = INT_FIFO_SIZE, @@ -1973,6 +1995,8 @@ static struct pxa25x_udc memory = { .name = "ep11in-bulk", .ops = &pxa25x_ep_ops, .maxpacket = BULK_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_IN), }, .dev = &memory, .fifo_size = BULK_FIFO_SIZE, @@ -1986,6 +2010,8 @@ static struct pxa25x_udc memory = { .name = "ep12out-bulk", .ops = &pxa25x_ep_ops, .maxpacket = BULK_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_OUT), }, .dev = &memory, .fifo_size = BULK_FIFO_SIZE, @@ -2000,6 +2026,8 @@ static struct pxa25x_udc memory = { .name = "ep13in-iso", .ops = &pxa25x_ep_ops, .maxpacket = ISO_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_IN), }, .dev = &memory, .fifo_size = ISO_FIFO_SIZE, @@ -2013,6 +2041,8 @@ static struct pxa25x_udc memory = { .name = "ep14out-iso", .ops = &pxa25x_ep_ops, .maxpacket = ISO_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_OUT), }, .dev = &memory, .fifo_size = ISO_FIFO_SIZE, @@ -2027,6 +2057,8 @@ static struct pxa25x_udc memory = { .name = "ep15in-int", .ops = &pxa25x_ep_ops, .maxpacket = INT_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, + USB_EP_CAPS_DIR_IN), }, .dev = &memory, .fifo_size = INT_FIFO_SIZE, -- cgit v0.10.2 From a180e3da97a323510071b2b5e42b5dc07df239da Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:40 +0200 Subject: usb: gadget: pxa27x_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pxa27x_udc.h b/drivers/usb/gadget/udc/pxa27x_udc.h index 11e1423..cea2cb7 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.h +++ b/drivers/usb/gadget/udc/pxa27x_udc.h @@ -234,25 +234,35 @@ /* * Endpoint definition helpers */ -#define USB_EP_DEF(addr, bname, dir, type, maxpkt) \ -{ .usb_ep = { .name = bname, .ops = &pxa_ep_ops, .maxpacket = maxpkt, }, \ +#define USB_EP_DEF(addr, bname, dir, type, maxpkt, ctype, cdir) \ +{ .usb_ep = { .name = bname, .ops = &pxa_ep_ops, .maxpacket = maxpkt, \ + .caps = USB_EP_CAPS(ctype, cdir), }, \ .desc = { .bEndpointAddress = addr | (dir ? USB_DIR_IN : 0), \ - .bmAttributes = type, \ + .bmAttributes = USB_ENDPOINT_XFER_ ## type, \ .wMaxPacketSize = maxpkt, }, \ .dev = &memory \ } -#define USB_EP_BULK(addr, bname, dir) \ - USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_BULK, BULK_FIFO_SIZE) -#define USB_EP_ISO(addr, bname, dir) \ - USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_ISOC, ISO_FIFO_SIZE) -#define USB_EP_INT(addr, bname, dir) \ - USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_INT, INT_FIFO_SIZE) -#define USB_EP_IN_BULK(n) USB_EP_BULK(n, "ep" #n "in-bulk", 1) -#define USB_EP_OUT_BULK(n) USB_EP_BULK(n, "ep" #n "out-bulk", 0) -#define USB_EP_IN_ISO(n) USB_EP_ISO(n, "ep" #n "in-iso", 1) -#define USB_EP_OUT_ISO(n) USB_EP_ISO(n, "ep" #n "out-iso", 0) -#define USB_EP_IN_INT(n) USB_EP_INT(n, "ep" #n "in-int", 1) -#define USB_EP_CTRL USB_EP_DEF(0, "ep0", 0, 0, EP0_FIFO_SIZE) +#define USB_EP_BULK(addr, bname, dir, cdir) \ + USB_EP_DEF(addr, bname, dir, BULK, BULK_FIFO_SIZE, \ + USB_EP_CAPS_TYPE_BULK, cdir) +#define USB_EP_ISO(addr, bname, dir, cdir) \ + USB_EP_DEF(addr, bname, dir, ISOC, ISO_FIFO_SIZE, \ + USB_EP_CAPS_TYPE_ISO, cdir) +#define USB_EP_INT(addr, bname, dir, cdir) \ + USB_EP_DEF(addr, bname, dir, INT, INT_FIFO_SIZE, \ + USB_EP_CAPS_TYPE_INT, cdir) +#define USB_EP_IN_BULK(n) USB_EP_BULK(n, "ep" #n "in-bulk", 1, \ + USB_EP_CAPS_DIR_IN) +#define USB_EP_OUT_BULK(n) USB_EP_BULK(n, "ep" #n "out-bulk", 0, \ + USB_EP_CAPS_DIR_OUT) +#define USB_EP_IN_ISO(n) USB_EP_ISO(n, "ep" #n "in-iso", 1, \ + USB_EP_CAPS_DIR_IN) +#define USB_EP_OUT_ISO(n) USB_EP_ISO(n, "ep" #n "out-iso", 0, \ + USB_EP_CAPS_DIR_OUT) +#define USB_EP_IN_INT(n) USB_EP_INT(n, "ep" #n "in-int", 1, \ + USB_EP_CAPS_DIR_IN) +#define USB_EP_CTRL USB_EP_DEF(0, "ep0", 0, CONTROL, EP0_FIFO_SIZE, \ + USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL) #define PXA_EP_DEF(_idx, _addr, dir, _type, maxpkt, _config, iface, altset) \ { \ -- cgit v0.10.2 From 0ec8026d7afee625f52631708d84435ea4735da6 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:41 +0200 Subject: usb: gadget: r8a66597-udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index 0293f71..baa0609 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -1935,6 +1935,16 @@ static int r8a66597_probe(struct platform_device *pdev) ep->ep.name = r8a66597_ep_name[i]; ep->ep.ops = &r8a66597_ep_ops; usb_ep_set_maxpacket_limit(&ep->ep, 512); + + if (i == 0) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; } usb_ep_set_maxpacket_limit(&r8a66597->ep[0].ep, 64); r8a66597->ep[0].pipenum = 0; -- cgit v0.10.2 From bc1b9f300ae06c64fcd056fb959b3d709ad2ef33 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:42 +0200 Subject: usb: gadget: s3c-hsudc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/s3c-hsudc.c b/drivers/usb/gadget/udc/s3c-hsudc.c index 85a712a..e9def42 100644 --- a/drivers/usb/gadget/udc/s3c-hsudc.c +++ b/drivers/usb/gadget/udc/s3c-hsudc.c @@ -1005,6 +1005,21 @@ static void s3c_hsudc_initep(struct s3c_hsudc *hsudc, hsep->stopped = 0; hsep->wedge = 0; + if (epnum == 0) { + hsep->ep.caps.type_control = true; + hsep->ep.caps.dir_in = true; + hsep->ep.caps.dir_out = true; + } else { + hsep->ep.caps.type_iso = true; + hsep->ep.caps.type_bulk = true; + hsep->ep.caps.type_int = true; + } + + if (epnum & 1) + hsep->ep.caps.dir_in = true; + else + hsep->ep.caps.dir_out = true; + set_index(hsudc, epnum); writel(hsep->ep.maxpacket, hsudc->regs + S3C_MPR); } -- cgit v0.10.2 From 0648772d51c0ff3949397cb0cbcf2435ee32c550 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:43 +0200 Subject: usb: gadget: s3c2410_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c index 5d9aa81..eb3571e 100644 --- a/drivers/usb/gadget/udc/s3c2410_udc.c +++ b/drivers/usb/gadget/udc/s3c2410_udc.c @@ -1691,6 +1691,8 @@ static struct s3c2410_udc memory = { .name = ep0name, .ops = &s3c2410_ep_ops, .maxpacket = EP0_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, + USB_EP_CAPS_DIR_ALL), }, .dev = &memory, }, @@ -1702,6 +1704,8 @@ static struct s3c2410_udc memory = { .name = "ep1-bulk", .ops = &s3c2410_ep_ops, .maxpacket = EP_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .dev = &memory, .fifo_size = EP_FIFO_SIZE, @@ -1714,6 +1718,8 @@ static struct s3c2410_udc memory = { .name = "ep2-bulk", .ops = &s3c2410_ep_ops, .maxpacket = EP_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .dev = &memory, .fifo_size = EP_FIFO_SIZE, @@ -1726,6 +1732,8 @@ static struct s3c2410_udc memory = { .name = "ep3-bulk", .ops = &s3c2410_ep_ops, .maxpacket = EP_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .dev = &memory, .fifo_size = EP_FIFO_SIZE, @@ -1738,6 +1746,8 @@ static struct s3c2410_udc memory = { .name = "ep4-bulk", .ops = &s3c2410_ep_ops, .maxpacket = EP_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .dev = &memory, .fifo_size = EP_FIFO_SIZE, -- cgit v0.10.2 From 927d9f77fe3d5f9261eeb465e2b60768e400ffc9 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:44 +0200 Subject: usb: gadget: udc-xilinx: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index 1f24274..1cbb0ac 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -1317,12 +1317,21 @@ static void xudc_eps_init(struct xusb_udc *udc) snprintf(ep->name, EPNAME_SIZE, "ep%d", ep_number); ep->ep_usb.name = ep->name; ep->ep_usb.ops = &xusb_ep_ops; + + ep->ep_usb.caps.type_iso = true; + ep->ep_usb.caps.type_bulk = true; + ep->ep_usb.caps.type_int = true; } else { ep->ep_usb.name = ep0name; usb_ep_set_maxpacket_limit(&ep->ep_usb, EP0_MAX_PACKET); ep->ep_usb.ops = &xusb_ep0_ops; + + ep->ep_usb.caps.type_control = true; } + ep->ep_usb.caps.dir_in = true; + ep->ep_usb.caps.dir_out = true; + ep->udc = udc; ep->epnumber = ep_number; ep->desc = NULL; -- cgit v0.10.2 From eb4cbc19526d62657b838d6f0b694a000e5b4c81 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:45 +0200 Subject: usb: isp1760: udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/isp1760/isp1760-udc.c b/drivers/usb/isp1760/isp1760-udc.c index 3699962..1c3d0fd 100644 --- a/drivers/usb/isp1760/isp1760-udc.c +++ b/drivers/usb/isp1760/isp1760-udc.c @@ -1383,13 +1383,24 @@ static void isp1760_udc_init_eps(struct isp1760_udc *udc) */ if (ep_num == 0) { usb_ep_set_maxpacket_limit(&ep->ep, 64); + ep->ep.caps.type_control = true; + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; ep->maxpacket = 64; udc->gadget.ep0 = &ep->ep; } else { usb_ep_set_maxpacket_limit(&ep->ep, 512); + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; ep->maxpacket = 0; list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); } + + if (is_in) + ep->ep.caps.dir_in = true; + else + ep->ep.caps.dir_out = true; } } -- cgit v0.10.2 From 8501955e888662ca56775eec2eb804e7bc7fce0d Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:46 +0200 Subject: usb: musb: gadget: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 9e18178..4150baf 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1729,6 +1729,7 @@ init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in) INIT_LIST_HEAD(&ep->end_point.ep_list); if (!epnum) { usb_ep_set_maxpacket_limit(&ep->end_point, 64); + ep->end_point.caps.type_control = true; ep->end_point.ops = &musb_g_ep0_ops; musb->g.ep0 = &ep->end_point; } else { @@ -1736,9 +1737,20 @@ init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in) usb_ep_set_maxpacket_limit(&ep->end_point, hw_ep->max_packet_sz_tx); else usb_ep_set_maxpacket_limit(&ep->end_point, hw_ep->max_packet_sz_rx); + ep->end_point.caps.type_iso = true; + ep->end_point.caps.type_bulk = true; + ep->end_point.caps.type_int = true; ep->end_point.ops = &musb_ep_ops; list_add_tail(&ep->end_point.ep_list, &musb->g.ep_list); } + + if (!epnum || hw_ep->is_shared_fifo) { + ep->end_point.caps.dir_in = true; + ep->end_point.caps.dir_out = true; + } else if (is_in) + ep->end_point.caps.dir_in = true; + else + ep->end_point.caps.dir_out = true; } /* -- cgit v0.10.2 From 916f7ac5dbc312969a90bc35a5f4fcbfc2965d60 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:47 +0200 Subject: usb: renesas: gadget: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 494dfe0..de4f97d 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -1103,12 +1103,18 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) if (usbhsg_is_dcp(uep)) { gpriv->gadget.ep0 = &uep->ep; usb_ep_set_maxpacket_limit(&uep->ep, 64); + uep->ep.caps.type_control = true; } /* init normal pipe */ else { usb_ep_set_maxpacket_limit(&uep->ep, 512); + uep->ep.caps.type_iso = true; + uep->ep.caps.type_bulk = true; + uep->ep.caps.type_int = true; list_add_tail(&uep->ep.ep_list, &gpriv->gadget.ep_list); } + uep->ep.caps.dir_in = true; + uep->ep.caps.dir_out = true; } ret = usb_add_gadget_udc(dev, &gpriv->gadget); -- cgit v0.10.2 From 47bef386511517449e2f24a89a41084af53616f8 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:48 +0200 Subject: usb: gadget: atmel_usba_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 37d414e..267d84f 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -2067,6 +2067,17 @@ static struct usba_ep * usba_udc_pdata(struct platform_device *pdev, ep->can_dma = pdata->ep[i].can_dma; ep->can_isoc = pdata->ep[i].can_isoc; + if (i == 0) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = ep->can_isoc; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } + + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; + if (i) list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); } -- cgit v0.10.2 From b86f33a3a371a4c3aa8dbb2f4125634a4e0d09dc Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:49 +0200 Subject: usb: gadget: epautoconf: add endpoint capabilities flags verification Introduce endpoint matching mechanism basing on endpoint capabilities flags. We check if endpoint supports transfer type and direction requested in ep descriptor. Since we have this new endpoint matching mechanism there is no need to have old code guessing endpoint capabilities basing on its name, so we are getting rid of it. Remove also the obsolete comment. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 8e00ca7..af4b10a 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -22,22 +22,6 @@ #include "gadget_chips.h" -/* - * This should work with endpoints from controller drivers sharing the - * same endpoint naming convention. By example: - * - * - ep1, ep2, ... address is fixed, not direction or type - * - ep1in, ep2out, ... address and direction are fixed, not type - * - ep1-bulk, ep2-bulk, ... address and type are fixed, not direction - * - ep1in-bulk, ep2out-iso, ... all three are fixed - * - ep-* ... no functionality restrictions - * - * Type suffixes are "-bulk", "-iso", or "-int". Numbers are decimal. - * Less common restrictions are implied by gadget_is_*(). - * - * NOTE: each endpoint is unidirectional, as specified by its USB - * descriptor; and isn't specific to a configuration or altsetting. - */ static int ep_matches ( struct usb_gadget *gadget, @@ -47,7 +31,6 @@ ep_matches ( ) { u8 type; - const char *tmp; u16 max; int num_req_streams = 0; @@ -56,58 +39,39 @@ ep_matches ( if (ep->claimed) return 0; - /* only support ep0 for portable CONTROL traffic */ type = usb_endpoint_type(desc); - if (USB_ENDPOINT_XFER_CONTROL == type) - return 0; - - /* some other naming convention */ - if ('e' != ep->name[0]) + switch (type) { + case USB_ENDPOINT_XFER_CONTROL: + /* only support ep0 for portable CONTROL traffic */ return 0; + case USB_ENDPOINT_XFER_ISOC: + if (!ep->caps.type_iso) + return 0; + break; + case USB_ENDPOINT_XFER_BULK: + if (!ep->caps.type_bulk) + return 0; + break; + case USB_ENDPOINT_XFER_INT: + /* bulk endpoints handle interrupt transfers, + * except the toggle-quirky iso-synch kind + */ + if (!ep->caps.type_int && !ep->caps.type_bulk) + return 0; + /* for now, avoid PXA "interrupt-in"; + * it's documented as never using DATA1. + */ + if (gadget_is_pxa(gadget) && ep->caps.type_int) + return 0; + break; + } - /* type-restriction: "-iso", "-bulk", or "-int". - * direction-restriction: "in", "out". - */ - if ('-' != ep->name[2]) { - tmp = strrchr (ep->name, '-'); - if (tmp) { - switch (type) { - case USB_ENDPOINT_XFER_INT: - /* bulk endpoints handle interrupt transfers, - * except the toggle-quirky iso-synch kind - */ - if ('s' == tmp[2]) // == "-iso" - return 0; - /* for now, avoid PXA "interrupt-in"; - * it's documented as never using DATA1. - */ - if (gadget_is_pxa (gadget) - && 'i' == tmp [1]) - return 0; - break; - case USB_ENDPOINT_XFER_BULK: - if ('b' != tmp[1]) // != "-bulk" - return 0; - break; - case USB_ENDPOINT_XFER_ISOC: - if ('s' != tmp[2]) // != "-iso" - return 0; - } - } else { - tmp = ep->name + strlen (ep->name); - } - - /* direction-restriction: "..in-..", "out-.." */ - tmp--; - if (!isdigit (*tmp)) { - if (desc->bEndpointAddress & USB_DIR_IN) { - if ('n' != *tmp) - return 0; - } else { - if ('t' != *tmp) - return 0; - } - } + if (usb_endpoint_dir_in(desc)) { + if (!ep->caps.dir_in) + return 0; + } else { + if (!ep->caps.dir_out) + return 0; } /* -- cgit v0.10.2 From b58713d53a8f41d57b24c93de0b1c7e9550ba70f Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:50 +0200 Subject: usb: gadget: epautoconf: remove pxa quirk from ep_matches() The same effect can be achieved by using capabilities flags, so now we can get rid of handling of hardware specific limitations in generic code. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index af4b10a..4f66e9d 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -58,11 +58,6 @@ ep_matches ( */ if (!ep->caps.type_int && !ep->caps.type_bulk) return 0; - /* for now, avoid PXA "interrupt-in"; - * it's documented as never using DATA1. - */ - if (gadget_is_pxa(gadget) && ep->caps.type_int) - return 0; break; } diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index b4d25dc..b82cb14 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -1899,8 +1899,7 @@ static struct pxa25x_udc memory = { .name = "ep5in-int", .ops = &pxa25x_ep_ops, .maxpacket = INT_FIFO_SIZE, - .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, - USB_EP_CAPS_DIR_IN), + .caps = USB_EP_CAPS(0, 0), }, .dev = &memory, .fifo_size = INT_FIFO_SIZE, @@ -1978,8 +1977,7 @@ static struct pxa25x_udc memory = { .name = "ep10in-int", .ops = &pxa25x_ep_ops, .maxpacket = INT_FIFO_SIZE, - .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, - USB_EP_CAPS_DIR_IN), + .caps = USB_EP_CAPS(0, 0), }, .dev = &memory, .fifo_size = INT_FIFO_SIZE, @@ -2057,8 +2055,7 @@ static struct pxa25x_udc memory = { .name = "ep15in-int", .ops = &pxa25x_ep_ops, .maxpacket = INT_FIFO_SIZE, - .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, - USB_EP_CAPS_DIR_IN), + .caps = USB_EP_CAPS(0, 0), }, .dev = &memory, .fifo_size = INT_FIFO_SIZE, -- cgit v0.10.2 From 5dbe135a153837ce9367bdfacf7aabfc6fb76f4b Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:51 +0200 Subject: usb: gadget: epautoconf: remove ep and desc configuration from ep_matches() As function ep_matches() is used to match endpoint with usb descriptor it's highly unintuitive that it modifies endpoint and descriptor structures fields. This patch moves code configuring ep and desc from ep_matches() to usb_ep_autoconfig_ss(), so now function ep_matches() does nothing more than its name suggests. [ balbi@ti.com : fix build warning ] Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 4f66e9d..52658fe 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -82,13 +82,6 @@ ep_matches ( } - /* - * If the protocol driver hasn't yet decided on wMaxPacketSize - * and wants to know the maximum possible, provide the info. - */ - if (desc->wMaxPacketSize == 0) - desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket_limit); - /* endpoint maxpacket size is an input parameter, except for bulk * where it's an output parameter representing the full speed limit. * the usb spec fixes high speed bulk maxpacket at 512 bytes. @@ -119,31 +112,6 @@ ep_matches ( /* MATCH!! */ - /* report address */ - desc->bEndpointAddress &= USB_DIR_IN; - if (isdigit (ep->name [2])) { - u8 num = simple_strtoul (&ep->name [2], NULL, 10); - desc->bEndpointAddress |= num; - } else if (desc->bEndpointAddress & USB_DIR_IN) { - if (++gadget->in_epnum > 15) - return 0; - desc->bEndpointAddress = USB_DIR_IN | gadget->in_epnum; - } else { - if (++gadget->out_epnum > 15) - return 0; - desc->bEndpointAddress |= gadget->out_epnum; - } - - /* report (variable) full speed bulk maxpacket */ - if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) { - int size = ep->maxpacket_limit; - - /* min() doesn't work on bitfields with gcc-3.5 */ - if (size > 64) - size = 64; - desc->wMaxPacketSize = cpu_to_le16(size); - } - ep->address = desc->bEndpointAddress; return 1; } @@ -280,6 +248,40 @@ struct usb_ep *usb_ep_autoconfig_ss( /* Fail */ return NULL; found_ep: + + /* + * If the protocol driver hasn't yet decided on wMaxPacketSize + * and wants to know the maximum possible, provide the info. + */ + if (desc->wMaxPacketSize == 0) + desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket_limit); + + /* report address */ + desc->bEndpointAddress &= USB_DIR_IN; + if (isdigit(ep->name[2])) { + u8 num = simple_strtoul(&ep->name[2], NULL, 10); + desc->bEndpointAddress |= num; + } else if (desc->bEndpointAddress & USB_DIR_IN) { + if (++gadget->in_epnum > 15) + return NULL; + desc->bEndpointAddress = USB_DIR_IN | gadget->in_epnum; + } else { + if (++gadget->out_epnum > 15) + return NULL; + desc->bEndpointAddress |= gadget->out_epnum; + } + + /* report (variable) full speed bulk maxpacket */ + if ((type == USB_ENDPOINT_XFER_BULK) && !ep_comp) { + int size = ep->maxpacket_limit; + + /* min() doesn't work on bitfields with gcc-3.5 */ + if (size > 64) + size = 64; + desc->wMaxPacketSize = cpu_to_le16(size); + } + + ep->address = desc->bEndpointAddress; ep->desc = NULL; ep->comp_desc = NULL; ep->claimed = true; -- cgit v0.10.2 From b4629a7bdfd8fcafc90ded7e6a1f88099105842d Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Tue, 4 Aug 2015 10:59:17 +0200 Subject: usb: ehci-platform: Fix using multiple controllers from OF When using OF defined controllers the platform data struct is shared between all devices, so it can't be used for device specific settings. However it is currently used for the OF properties needs-reset-on-resume and has-transaction-translator. To fix this issue move setting hcd->has_tt to the probe and move pdata->reset_on_resume to the private data. Signed-off-by: Alban Bedel Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 2593def..5c3c085 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -45,6 +45,7 @@ struct ehci_platform_priv { struct reset_control *rst; struct phy **phys; int num_phys; + bool reset_on_resume; }; static const char hcd_name[] = "ehci-platform"; @@ -56,7 +57,6 @@ static int ehci_platform_reset(struct usb_hcd *hcd) struct ehci_hcd *ehci = hcd_to_ehci(hcd); int retval; - hcd->has_tt = pdata->has_tt; ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug; if (pdata->pre_setup) { @@ -193,11 +193,11 @@ static int ehci_platform_probe(struct platform_device *dev) if (of_property_read_bool(dev->dev.of_node, "needs-reset-on-resume")) - pdata->reset_on_resume = 1; + priv->reset_on_resume = true; if (of_property_read_bool(dev->dev.of_node, "has-transaction-translator")) - pdata->has_tt = 1; + hcd->has_tt = 1; priv->num_phys = of_count_phandle_with_args(dev->dev.of_node, "phys", "#phy-cells"); @@ -247,6 +247,10 @@ static int ehci_platform_probe(struct platform_device *dev) ehci->big_endian_desc = 1; if (pdata->big_endian_mmio) ehci->big_endian_mmio = 1; + if (pdata->has_tt) + hcd->has_tt = 1; + if (pdata->reset_on_resume) + priv->reset_on_resume = true; #ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO if (ehci->big_endian_mmio) { @@ -359,6 +363,7 @@ static int ehci_platform_resume(struct device *dev) struct usb_ehci_pdata *pdata = dev_get_platdata(dev); struct platform_device *pdev = container_of(dev, struct platform_device, dev); + struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); if (pdata->power_on) { int err = pdata->power_on(pdev); @@ -366,7 +371,7 @@ static int ehci_platform_resume(struct device *dev) return err; } - ehci_resume(hcd, pdata->reset_on_resume); + ehci_resume(hcd, priv->reset_on_resume); return 0; } #endif /* CONFIG_PM_SLEEP */ -- cgit v0.10.2 From 135551ea1abd5038d14825514df7e259fd500033 Mon Sep 17 00:00:00 2001 From: Kris Borer Date: Tue, 4 Aug 2015 08:39:31 -0400 Subject: usb: devio: remove assignment from if condition Fix five occurrences of the checkpatch.pl error: ERROR: do not use assignment in if condition The semantic patch that makes this change is: // @@ identifier i; expression E; statement S1, S2; @@ + i = E; if ( - (i = E) + i ) S1 else S2 @@ identifier i; expression E; statement S; constant c; binary operator b; @@ + i = E; if ( - (i = E) + i b c ) S // Signed-off-by: Kris Borer Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 986abde..ed6d1d5 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1082,7 +1082,8 @@ static int proc_bulk(struct usb_dev_state *ps, void __user *arg) ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); if (ret) return ret; - if (!(tbuf = kmalloc(len1, GFP_KERNEL))) { + tbuf = kmalloc(len1, GFP_KERNEL); + if (!tbuf) { ret = -ENOMEM; goto done; } @@ -1224,7 +1225,8 @@ static int proc_setintf(struct usb_dev_state *ps, void __user *arg) if (copy_from_user(&setintf, arg, sizeof(setintf))) return -EFAULT; - if ((ret = checkintf(ps, setintf.interface))) + ret = checkintf(ps, setintf.interface); + if (ret) return ret; destroy_async_on_interface(ps, setintf.interface); @@ -1393,7 +1395,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb number_of_packets = uurb->number_of_packets; isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * number_of_packets; - if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) + isopkt = kmalloc(isofrmlen, GFP_KERNEL); + if (!isopkt) return -ENOMEM; if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) { ret = -EFAULT; @@ -1904,7 +1907,8 @@ static int proc_releaseinterface(struct usb_dev_state *ps, void __user *arg) if (get_user(ifnum, (unsigned int __user *)arg)) return -EFAULT; - if ((ret = releaseintf(ps, ifnum)) < 0) + ret = releaseintf(ps, ifnum); + if (ret < 0) return ret; destroy_async_on_interface (ps, ifnum); return 0; @@ -1919,7 +1923,8 @@ static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl) struct usb_driver *driver = NULL; /* alloc buffer */ - if ((size = _IOC_SIZE(ctl->ioctl_code)) > 0) { + size = _IOC_SIZE(ctl->ioctl_code); + if (size > 0) { buf = kmalloc(size, GFP_KERNEL); if (buf == NULL) return -ENOMEM; -- cgit v0.10.2 From 082155eabfabd9148cc7e81c995e2c482075ccc3 Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:01:31 +0000 Subject: usb: phy: phy-mxs-usb: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index 3fcc048..4d863eb 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -506,11 +506,7 @@ static int mxs_phy_probe(struct platform_device *pdev) device_set_wakeup_capable(&pdev->dev, true); - ret = usb_add_phy_dev(&mxs_phy->phy); - if (ret) - return ret; - - return 0; + return usb_add_phy_dev(&mxs_phy->phy); } static int mxs_phy_remove(struct platform_device *pdev) -- cgit v0.10.2 From a9c5d8feb9e751a7521f1a5fa0d56901824e2ad8 Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:02:03 +0000 Subject: usb: phy: phy-keystone: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/phy/phy-keystone.c b/drivers/usb/phy/phy-keystone.c index e0556f7..01d4e4c 100644 --- a/drivers/usb/phy/phy-keystone.c +++ b/drivers/usb/phy/phy-keystone.c @@ -96,11 +96,7 @@ static int keystone_usbphy_probe(struct platform_device *pdev) platform_set_drvdata(pdev, k_phy); - ret = usb_add_phy_dev(&k_phy->usb_phy_gen.phy); - if (ret) - return ret; - - return 0; + return usb_add_phy_dev(&k_phy->usb_phy_gen.phy); } static int keystone_usbphy_remove(struct platform_device *pdev) -- cgit v0.10.2 From e94a7369a9293de2674de322d1e5253d63ba42ff Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:02:28 +0000 Subject: usb: musb: musb_dsps: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 1334a3d..a0cfead 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -482,11 +482,7 @@ static int dsps_musb_init(struct musb *musb) dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, val); } - ret = dsps_musb_dbg_init(musb, glue); - if (ret) - return ret; - - return 0; + return dsps_musb_dbg_init(musb, glue); } static int dsps_musb_exit(struct musb *musb) -- cgit v0.10.2 From 16f9c3fd25b957f4df0fd5d9bf70249495c1a421 Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:02:55 +0000 Subject: usb: host: ehci-st: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-st.c b/drivers/usb/host/ehci-st.c index 7e4bd39..b7c5cfa 100644 --- a/drivers/usb/host/ehci-st.c +++ b/drivers/usb/host/ehci-st.c @@ -54,7 +54,6 @@ static int st_ehci_platform_reset(struct usb_hcd *hcd) struct platform_device *pdev = to_platform_device(hcd->self.controller); struct usb_ehci_pdata *pdata = dev_get_platdata(&pdev->dev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; u32 threshold; /* Set EHCI packet buffer IN/OUT threshold to 128 bytes */ @@ -62,11 +61,7 @@ static int st_ehci_platform_reset(struct usb_hcd *hcd) writel(threshold, hcd->regs + AHB2STBUS_INSREG01); ehci->caps = hcd->regs + pdata->caps_offset; - retval = ehci_setup(hcd); - if (retval) - return retval; - - return 0; + return ehci_setup(hcd); } static int st_ehci_platform_power_on(struct platform_device *dev) -- cgit v0.10.2 From aa31a0909cc44bf2f75c14e800caff2d06ff725e Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:03:20 +0000 Subject: usb: host: oxu210hp-hcd: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 6352f54..fe3bd1c 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -2670,7 +2670,6 @@ static int oxu_hcd_init(struct usb_hcd *hcd) static int oxu_reset(struct usb_hcd *hcd) { struct oxu_hcd *oxu = hcd_to_oxu(hcd); - int ret; spin_lock_init(&oxu->mem_lock); INIT_LIST_HEAD(&oxu->urb_list); @@ -2696,11 +2695,7 @@ static int oxu_reset(struct usb_hcd *hcd) oxu->hcs_params = readl(&oxu->caps->hcs_params); oxu->sbrn = 0x20; - ret = oxu_hcd_init(hcd); - if (ret) - return ret; - - return 0; + return oxu_hcd_init(hcd); } static int oxu_run(struct usb_hcd *hcd) -- cgit v0.10.2 From 8602b08ab641a6004efa553c8089180c40bc1f72 Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:03:45 +0000 Subject: usb: host: u132-hcd: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index d516877..a67bd50 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -1542,11 +1542,8 @@ static int u132_periodic_reinit(struct u132 *u132) (fit ^ FIT) | u132->hc_fminterval); if (retval) return retval; - retval = u132_write_pcimem(u132, periodicstart, - ((9 * fi) / 10) & 0x3fff); - if (retval) - return retval; - return 0; + return u132_write_pcimem(u132, periodicstart, + ((9 * fi) / 10) & 0x3fff); } static char *hcfs2string(int state) @@ -2701,28 +2698,18 @@ static int u132_roothub_setportfeature(struct u132 *u132, u16 wValue, if (wIndex == 0 || wIndex > u132->num_ports) { return -EINVAL; } else { - int retval; int port_index = wIndex - 1; struct u132_port *port = &u132->port[port_index]; port->Status &= ~(1 << wValue); switch (wValue) { case USB_PORT_FEAT_SUSPEND: - retval = u132_write_pcimem(u132, - roothub.portstatus[port_index], RH_PS_PSS); - if (retval) - return retval; - return 0; + return u132_write_pcimem(u132, + roothub.portstatus[port_index], RH_PS_PSS); case USB_PORT_FEAT_POWER: - retval = u132_write_pcimem(u132, - roothub.portstatus[port_index], RH_PS_PPS); - if (retval) - return retval; - return 0; + return u132_write_pcimem(u132, + roothub.portstatus[port_index], RH_PS_PPS); case USB_PORT_FEAT_RESET: - retval = u132_roothub_portreset(u132, port_index); - if (retval) - return retval; - return 0; + return u132_roothub_portreset(u132, port_index); default: return -EPIPE; } @@ -2737,7 +2724,6 @@ static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue, } else { int port_index = wIndex - 1; u32 temp; - int retval; struct u132_port *port = &u132->port[port_index]; port->Status &= ~(1 << wValue); switch (wValue) { @@ -2773,11 +2759,8 @@ static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue, default: return -EPIPE; } - retval = u132_write_pcimem(u132, roothub.portstatus[port_index], - temp); - if (retval) - return retval; - return 0; + return u132_write_pcimem(u132, roothub.portstatus[port_index], + temp); } } -- cgit v0.10.2 From f1cda54cfb71720058cd65b2f1be7f2a86889935 Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:04:09 +0000 Subject: usb: host: xhci: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index c3ac0a2..91fd328 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4678,7 +4678,6 @@ int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd, { struct xhci_hcd *xhci; u16 mel; - int ret; xhci = hcd_to_xhci(hcd); if (!xhci || !(xhci->quirks & XHCI_LPM_SUPPORT) || @@ -4686,10 +4685,7 @@ int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd, return 0; mel = calculate_max_exit_latency(udev, state, USB3_LPM_DISABLED); - ret = xhci_change_max_exit_latency(xhci, udev, mel); - if (ret) - return ret; - return 0; + return xhci_change_max_exit_latency(xhci, udev, mel); } #else /* CONFIG_PM */ -- cgit v0.10.2 From eb82122a665b31ff9c40f1b4b66be71f0ef21bd3 Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:04:35 +0000 Subject: usb: serial: mxuport: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c index 460a406..31a8b47 100644 --- a/drivers/usb/serial/mxuport.c +++ b/drivers/usb/serial/mxuport.c @@ -1137,13 +1137,9 @@ static int mxuport_port_probe(struct usb_serial_port *port) return err; /* Set interface (RS-232) */ - err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_INTERFACE, - MX_INT_RS232, - port->port_number); - if (err) - return err; - - return 0; + return mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_INTERFACE, + MX_INT_RS232, + port->port_number); } static int mxuport_alloc_write_urb(struct usb_serial *serial, -- cgit v0.10.2 From a53870c0ebe0b84a6e1a09785d24b0f0e6729962 Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:05:03 +0000 Subject: usb: misc: ftdi-elan: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 8ab1f8f..52c27ca 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -2568,11 +2568,7 @@ static int ftdi_elan_close_controller(struct usb_ftdi *ftdi, int fn) 0x00); if (UxxxStatus) return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - return 0; + return ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, &pcidata); } static int ftdi_elan_found_controller(struct usb_ftdi *ftdi, int fn, int quirk) @@ -2695,11 +2691,7 @@ static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi) } } if (ftdi->function > 0) { - UxxxStatus = ftdi_elan_setup_controller(ftdi, - ftdi->function - 1); - if (UxxxStatus) - return UxxxStatus; - return 0; + return ftdi_elan_setup_controller(ftdi, ftdi->function - 1); } else if (controllers > 0) { return -ENXIO; } else if (unrecognized > 0) { -- cgit v0.10.2 From 26bf956aa9952a8141a12f314df70dcd020572d6 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 6 Aug 2015 14:11:09 +0200 Subject: usb: gadget: epautoconf: rework ep_matches() function Rework ep_matches() function to make it shorter and more readable. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 52658fe..95e1275 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -32,7 +32,6 @@ ep_matches ( { u8 type; u16 max; - int num_req_streams = 0; /* endpoint already claimed? */ @@ -40,6 +39,20 @@ ep_matches ( return 0; type = usb_endpoint_type(desc); + max = 0x7ff & usb_endpoint_maxp(desc); + + if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in) + return 0; + if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out) + return 0; + + if (max > ep->maxpacket_limit) + return 0; + + /* "high bandwidth" works only at high speed */ + if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp(desc) & (3<<11)) + return 0; + switch (type) { case USB_ENDPOINT_XFER_CONTROL: /* only support ep0 for portable CONTROL traffic */ @@ -47,66 +60,36 @@ ep_matches ( case USB_ENDPOINT_XFER_ISOC: if (!ep->caps.type_iso) return 0; + /* ISO: limit 1023 bytes full speed, + * 1024 high/super speed + */ + if (!gadget_is_dualspeed(gadget) && max > 1023) + return 0; break; case USB_ENDPOINT_XFER_BULK: if (!ep->caps.type_bulk) return 0; + if (ep_comp && gadget_is_superspeed(gadget)) { + /* Get the number of required streams from the + * EP companion descriptor and see if the EP + * matches it + */ + num_req_streams = ep_comp->bmAttributes & 0x1f; + if (num_req_streams > ep->max_streams) + return 0; + } break; case USB_ENDPOINT_XFER_INT: - /* bulk endpoints handle interrupt transfers, + /* Bulk endpoints handle interrupt transfers, * except the toggle-quirky iso-synch kind */ if (!ep->caps.type_int && !ep->caps.type_bulk) return 0; - break; - } - - if (usb_endpoint_dir_in(desc)) { - if (!ep->caps.dir_in) - return 0; - } else { - if (!ep->caps.dir_out) - return 0; - } - - /* - * Get the number of required streams from the EP companion - * descriptor and see if the EP matches it - */ - if (usb_endpoint_xfer_bulk(desc)) { - if (ep_comp && gadget->max_speed >= USB_SPEED_SUPER) { - num_req_streams = ep_comp->bmAttributes & 0x1f; - if (num_req_streams > ep->max_streams) - return 0; - } - - } - - /* endpoint maxpacket size is an input parameter, except for bulk - * where it's an output parameter representing the full speed limit. - * the usb spec fixes high speed bulk maxpacket at 512 bytes. - */ - max = 0x7ff & usb_endpoint_maxp(desc); - switch (type) { - case USB_ENDPOINT_XFER_INT: - /* INT: limit 64 bytes full speed, 1024 high/super speed */ + /* INT: limit 64 bytes full speed, + * 1024 high/super speed + */ if (!gadget_is_dualspeed(gadget) && max > 64) return 0; - /* FALLTHROUGH */ - - case USB_ENDPOINT_XFER_ISOC: - /* ISO: limit 1023 bytes full speed, 1024 high/super speed */ - if (ep->maxpacket_limit < max) - return 0; - if (!gadget_is_dualspeed(gadget) && max > 1023) - return 0; - - /* BOTH: "high bandwidth" works only at high speed */ - if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) { - if (!gadget_is_dualspeed(gadget)) - return 0; - /* configure your hardware with enough buffering!! */ - } break; } -- cgit v0.10.2 From 596c154d62330ea0bb4e3c3e50afa3682e50b617 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 6 Aug 2015 14:11:10 +0200 Subject: usb: gadget: add 'ep_match' callback to usb_gadget_ops Add callback that is called by epautoconf to allow UDC driver match the best endpoint for specific descriptor. It's intended to supply mechanism which allows to get rid of chip-specific endpoint matching code from epautoconf. If gadget has set 'ep_match' callback we prefer to call it first, and if it fails to find matching endpoint, then we try to use default matching algorithm. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 95e1275..f000c73 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -165,6 +165,12 @@ struct usb_ep *usb_ep_autoconfig_ss( type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + if (gadget->ops->match_ep) { + ep = gadget->ops->match_ep(gadget, desc, ep_comp); + if (ep) + goto found_ep; + } + /* First, apply chip-specific "best usage" knowledge. * This might make a good usb_gadget_ops hook ... */ diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 82b5bcb..303214b 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -534,6 +534,9 @@ struct usb_gadget_ops { int (*udc_start)(struct usb_gadget *, struct usb_gadget_driver *); int (*udc_stop)(struct usb_gadget *); + struct usb_ep *(*match_ep)(struct usb_gadget *, + struct usb_endpoint_descriptor *, + struct usb_ss_ep_comp_descriptor *); }; /** -- cgit v0.10.2 From 4278c687f697b651ab0c771114564da5ed006f22 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 6 Aug 2015 14:11:11 +0200 Subject: usb: gadget: move ep_matches() from epautoconf to udc-core Move ep_matches() function to udc-core and rename it to usb_gadget_ep_match_desc(). This function can be used by UDC drivers in 'match_ep' callback to avoid writing lots of repetitive code. Replace all calls of ep_matches() with usb_gadget_ep_match_desc(). Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index f000c73..d49af4f 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -22,82 +22,6 @@ #include "gadget_chips.h" -static int -ep_matches ( - struct usb_gadget *gadget, - struct usb_ep *ep, - struct usb_endpoint_descriptor *desc, - struct usb_ss_ep_comp_descriptor *ep_comp -) -{ - u8 type; - u16 max; - int num_req_streams = 0; - - /* endpoint already claimed? */ - if (ep->claimed) - return 0; - - type = usb_endpoint_type(desc); - max = 0x7ff & usb_endpoint_maxp(desc); - - if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in) - return 0; - if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out) - return 0; - - if (max > ep->maxpacket_limit) - return 0; - - /* "high bandwidth" works only at high speed */ - if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp(desc) & (3<<11)) - return 0; - - switch (type) { - case USB_ENDPOINT_XFER_CONTROL: - /* only support ep0 for portable CONTROL traffic */ - return 0; - case USB_ENDPOINT_XFER_ISOC: - if (!ep->caps.type_iso) - return 0; - /* ISO: limit 1023 bytes full speed, - * 1024 high/super speed - */ - if (!gadget_is_dualspeed(gadget) && max > 1023) - return 0; - break; - case USB_ENDPOINT_XFER_BULK: - if (!ep->caps.type_bulk) - return 0; - if (ep_comp && gadget_is_superspeed(gadget)) { - /* Get the number of required streams from the - * EP companion descriptor and see if the EP - * matches it - */ - num_req_streams = ep_comp->bmAttributes & 0x1f; - if (num_req_streams > ep->max_streams) - return 0; - } - break; - case USB_ENDPOINT_XFER_INT: - /* Bulk endpoints handle interrupt transfers, - * except the toggle-quirky iso-synch kind - */ - if (!ep->caps.type_int && !ep->caps.type_bulk) - return 0; - /* INT: limit 64 bytes full speed, - * 1024 high/super speed - */ - if (!gadget_is_dualspeed(gadget) && max > 64) - return 0; - break; - } - - /* MATCH!! */ - - return 1; -} - static struct usb_ep * find_ep (struct usb_gadget *gadget, const char *name) { @@ -180,10 +104,12 @@ struct usb_ep *usb_ep_autoconfig_ss( if (type == USB_ENDPOINT_XFER_INT) { /* ep-e, ep-f are PIO with only 64 byte fifos */ ep = find_ep(gadget, "ep-e"); - if (ep && ep_matches(gadget, ep, desc, ep_comp)) + if (ep && usb_gadget_ep_match_desc(gadget, + ep, desc, ep_comp)) goto found_ep; ep = find_ep(gadget, "ep-f"); - if (ep && ep_matches(gadget, ep, desc, ep_comp)) + if (ep && usb_gadget_ep_match_desc(gadget, + ep, desc, ep_comp)) goto found_ep; } @@ -191,20 +117,21 @@ struct usb_ep *usb_ep_autoconfig_ss( snprintf(name, sizeof(name), "ep%d%s", usb_endpoint_num(desc), usb_endpoint_dir_in(desc) ? "in" : "out"); ep = find_ep(gadget, name); - if (ep && ep_matches(gadget, ep, desc, ep_comp)) + if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) goto found_ep; } else if (gadget_is_goku (gadget)) { if (USB_ENDPOINT_XFER_INT == type) { /* single buffering is enough */ ep = find_ep(gadget, "ep3-bulk"); - if (ep && ep_matches(gadget, ep, desc, ep_comp)) + if (ep && usb_gadget_ep_match_desc(gadget, + ep, desc, ep_comp)) goto found_ep; } else if (USB_ENDPOINT_XFER_BULK == type && (USB_DIR_IN & desc->bEndpointAddress)) { /* DMA may be available */ ep = find_ep(gadget, "ep2-bulk"); - if (ep && ep_matches(gadget, ep, desc, - ep_comp)) + if (ep && usb_gadget_ep_match_desc(gadget, + ep, desc, ep_comp)) goto found_ep; } @@ -223,14 +150,14 @@ struct usb_ep *usb_ep_autoconfig_ss( ep = find_ep(gadget, "ep2out"); } else ep = NULL; - if (ep && ep_matches(gadget, ep, desc, ep_comp)) + if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) goto found_ep; #endif } /* Second, look at endpoints until an unclaimed one looks usable */ list_for_each_entry (ep, &gadget->ep_list, ep_list) { - if (ep_matches(gadget, ep, desc, ep_comp)) + if (usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) goto found_ep; } diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 362ee8a..b6427d1 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -131,6 +131,75 @@ EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); /* ------------------------------------------------------------------------- */ +int usb_gadget_ep_match_desc(struct usb_gadget *gadget, + struct usb_ep *ep, struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp) +{ + u8 type; + u16 max; + int num_req_streams = 0; + + /* endpoint already claimed? */ + if (ep->claimed) + return 0; + + type = usb_endpoint_type(desc); + max = 0x7ff & usb_endpoint_maxp(desc); + + if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in) + return 0; + if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out) + return 0; + + if (max > ep->maxpacket_limit) + return 0; + + /* "high bandwidth" works only at high speed */ + if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp(desc) & (3<<11)) + return 0; + + switch (type) { + case USB_ENDPOINT_XFER_CONTROL: + /* only support ep0 for portable CONTROL traffic */ + return 0; + case USB_ENDPOINT_XFER_ISOC: + if (!ep->caps.type_iso) + return 0; + /* ISO: limit 1023 bytes full speed, 1024 high/super speed */ + if (!gadget_is_dualspeed(gadget) && max > 1023) + return 0; + break; + case USB_ENDPOINT_XFER_BULK: + if (!ep->caps.type_bulk) + return 0; + if (ep_comp && gadget_is_superspeed(gadget)) { + /* Get the number of required streams from the + * EP companion descriptor and see if the EP + * matches it + */ + num_req_streams = ep_comp->bmAttributes & 0x1f; + if (num_req_streams > ep->max_streams) + return 0; + } + break; + case USB_ENDPOINT_XFER_INT: + /* Bulk endpoints handle interrupt transfers, + * except the toggle-quirky iso-synch kind + */ + if (!ep->caps.type_int && !ep->caps.type_bulk) + return 0; + /* INT: limit 64 bytes full speed, 1024 high/super speed */ + if (!gadget_is_dualspeed(gadget) && max > 64) + return 0; + break; + } + + return 1; +} +EXPORT_SYMBOL_GPL(usb_gadget_ep_match_desc); + +/* ------------------------------------------------------------------------- */ + static void usb_gadget_state_work(struct work_struct *work) { struct usb_gadget *gadget = work_to_gadget(work); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 303214b..e04fd63 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -1204,6 +1204,14 @@ extern void usb_gadget_giveback_request(struct usb_ep *ep, /*-------------------------------------------------------------------------*/ +/* utility to check if endpoint caps match descriptor needs */ + +extern int usb_gadget_ep_match_desc(struct usb_gadget *gadget, + struct usb_ep *ep, struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp); + +/*-------------------------------------------------------------------------*/ + /* utility to update vbus status for udc core, it may be scheduled */ extern void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status); -- cgit v0.10.2 From b0aea0037c8896b8e69cad3f6e828782789c1edf Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 6 Aug 2015 14:11:12 +0200 Subject: usb: gadget: move find_ep() from epautoconf to udc-core Move find_ep() to udc-core and rename it to gadget_find_ep_by_name(). It can be used in UDC drivers, especially in 'match_ep' callback after moving chip-specific endpoint matching logic from epautoconf to UDC drivers. Replace all calls of find_ep() function with gadget_find_ep_by_name(). Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index d49af4f..a39ca03 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -22,18 +22,6 @@ #include "gadget_chips.h" -static struct usb_ep * -find_ep (struct usb_gadget *gadget, const char *name) -{ - struct usb_ep *ep; - - list_for_each_entry (ep, &gadget->ep_list, ep_list) { - if (0 == strcmp (ep->name, name)) - return ep; - } - return NULL; -} - /** * usb_ep_autoconfig_ss() - choose an endpoint matching the ep * descriptor and ep companion descriptor @@ -103,11 +91,11 @@ struct usb_ep *usb_ep_autoconfig_ss( if (type == USB_ENDPOINT_XFER_INT) { /* ep-e, ep-f are PIO with only 64 byte fifos */ - ep = find_ep(gadget, "ep-e"); + ep = gadget_find_ep_by_name(gadget, "ep-e"); if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) goto found_ep; - ep = find_ep(gadget, "ep-f"); + ep = gadget_find_ep_by_name(gadget, "ep-f"); if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) goto found_ep; @@ -116,20 +104,20 @@ struct usb_ep *usb_ep_autoconfig_ss( /* USB3380: use same address for usb and hardware endpoints */ snprintf(name, sizeof(name), "ep%d%s", usb_endpoint_num(desc), usb_endpoint_dir_in(desc) ? "in" : "out"); - ep = find_ep(gadget, name); + ep = gadget_find_ep_by_name(gadget, name); if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) goto found_ep; } else if (gadget_is_goku (gadget)) { if (USB_ENDPOINT_XFER_INT == type) { /* single buffering is enough */ - ep = find_ep(gadget, "ep3-bulk"); + ep = gadget_find_ep_by_name(gadget, "ep3-bulk"); if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) goto found_ep; } else if (USB_ENDPOINT_XFER_BULK == type && (USB_DIR_IN & desc->bEndpointAddress)) { /* DMA may be available */ - ep = find_ep(gadget, "ep2-bulk"); + ep = gadget_find_ep_by_name(gadget, "ep2-bulk"); if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) goto found_ep; @@ -140,14 +128,14 @@ struct usb_ep *usb_ep_autoconfig_ss( if ((USB_ENDPOINT_XFER_BULK == type) || (USB_ENDPOINT_XFER_ISOC == type)) { if (USB_DIR_IN & desc->bEndpointAddress) - ep = find_ep (gadget, "ep5in"); + ep = gadget_find_ep_by_name(gadget, "ep5in"); else - ep = find_ep (gadget, "ep6out"); + ep = gadget_find_ep_by_name(gadget, "ep6out"); } else if (USB_ENDPOINT_XFER_INT == type) { if (USB_DIR_IN & desc->bEndpointAddress) - ep = find_ep(gadget, "ep1in"); + ep = gadget_find_ep_by_name(gadget, "ep1in"); else - ep = find_ep(gadget, "ep2out"); + ep = gadget_find_ep_by_name(gadget, "ep2out"); } else ep = NULL; if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index b6427d1..3c954b5 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -131,6 +131,27 @@ EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); /* ------------------------------------------------------------------------- */ +/** + * gadget_find_ep_by_name - returns ep whose name is the same as sting passed + * in second parameter or NULL if searched endpoint not found + * @g: controller to check for quirk + * @name: name of searched endpoint + */ +struct usb_ep *gadget_find_ep_by_name(struct usb_gadget *g, const char *name) +{ + struct usb_ep *ep; + + gadget_for_each_ep(ep, g) { + if (!strcmp(ep->name, name)) + return ep; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(gadget_find_ep_by_name); + +/* ------------------------------------------------------------------------- */ + int usb_gadget_ep_match_desc(struct usb_gadget *gadget, struct usb_ep *ep, struct usb_endpoint_descriptor *desc, struct usb_ss_ep_comp_descriptor *ep_comp) diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index e04fd63..c14a69b 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -639,7 +639,6 @@ static inline struct usb_gadget *dev_to_usb_gadget(struct device *dev) #define gadget_for_each_ep(tmp, gadget) \ list_for_each_entry(tmp, &(gadget)->ep_list, ep_list) - /** * usb_ep_align_maybe - returns @len aligned to ep's maxpacketsize if gadget * requires quirk_ep_out_aligned_size, otherwise reguens len. @@ -1204,6 +1203,13 @@ extern void usb_gadget_giveback_request(struct usb_ep *ep, /*-------------------------------------------------------------------------*/ +/* utility to find endpoint by name */ + +extern struct usb_ep *gadget_find_ep_by_name(struct usb_gadget *g, + const char *name); + +/*-------------------------------------------------------------------------*/ + /* utility to check if endpoint caps match descriptor needs */ extern int usb_gadget_ep_match_desc(struct usb_gadget *gadget, -- cgit v0.10.2 From 3e8b231818c25a250c36f8bfb944aa1fd2b13396 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 6 Aug 2015 14:11:13 +0200 Subject: usb: gadget: net2280: add net2280_match_ep() function Add 'match_ep' callback to utilize chip-specific knowledge in endpoint matching process. Function does the same that was done by chip-specific code inside of epautoconf. Now this code can be removed from there to separate generic code from platform specific logic. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index a39ca03..0ff5134 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -86,28 +86,7 @@ struct usb_ep *usb_ep_autoconfig_ss( /* First, apply chip-specific "best usage" knowledge. * This might make a good usb_gadget_ops hook ... */ - if (gadget_is_net2280(gadget)) { - char name[8]; - - if (type == USB_ENDPOINT_XFER_INT) { - /* ep-e, ep-f are PIO with only 64 byte fifos */ - ep = gadget_find_ep_by_name(gadget, "ep-e"); - if (ep && usb_gadget_ep_match_desc(gadget, - ep, desc, ep_comp)) - goto found_ep; - ep = gadget_find_ep_by_name(gadget, "ep-f"); - if (ep && usb_gadget_ep_match_desc(gadget, - ep, desc, ep_comp)) - goto found_ep; - } - - /* USB3380: use same address for usb and hardware endpoints */ - snprintf(name, sizeof(name), "ep%d%s", usb_endpoint_num(desc), - usb_endpoint_dir_in(desc) ? "in" : "out"); - ep = gadget_find_ep_by_name(gadget, name); - if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) - goto found_ep; - } else if (gadget_is_goku (gadget)) { + if (gadget_is_goku(gadget)) { if (USB_ENDPOINT_XFER_INT == type) { /* single buffering is enough */ ep = gadget_find_ep_by_name(gadget, "ep3-bulk"); diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index 872ca25..cf0ed42 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -1550,6 +1550,33 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on) return 0; } +static struct usb_ep *net2280_match_ep(struct usb_gadget *_gadget, + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp) +{ + char name[8]; + struct usb_ep *ep; + + if (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_INT) { + /* ep-e, ep-f are PIO with only 64 byte fifos */ + ep = gadget_find_ep_by_name(_gadget, "ep-e"); + if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) + return ep; + ep = gadget_find_ep_by_name(_gadget, "ep-f"); + if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) + return ep; + } + + /* USB3380: use same address for usb and hardware endpoints */ + snprintf(name, sizeof(name), "ep%d%s", usb_endpoint_num(desc), + usb_endpoint_dir_in(desc) ? "in" : "out"); + ep = gadget_find_ep_by_name(_gadget, name); + if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) + return ep; + + return NULL; +} + static int net2280_start(struct usb_gadget *_gadget, struct usb_gadget_driver *driver); static int net2280_stop(struct usb_gadget *_gadget); @@ -1561,6 +1588,7 @@ static const struct usb_gadget_ops net2280_ops = { .pullup = net2280_pullup, .udc_start = net2280_start, .udc_stop = net2280_stop, + .match_ep = net2280_match_ep, }; /*-------------------------------------------------------------------------*/ -- cgit v0.10.2 From 8cc67b7bff2fc1adfd080233d35aacba4411cf87 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 6 Aug 2015 14:11:14 +0200 Subject: usb: gadget: goku_udc: add goku_match_ep() function Add 'match_ep' callback to utilize chip-specific knowledge in endpoint matching process. Function does the same that was done by chip-specific code inside of epautoconf. Now this code can be removed from there to separate generic code from platform specific logic. [ balbi@ti.com : fix build breakage ] Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 0ff5134..574b6a4 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -86,24 +86,8 @@ struct usb_ep *usb_ep_autoconfig_ss( /* First, apply chip-specific "best usage" knowledge. * This might make a good usb_gadget_ops hook ... */ - if (gadget_is_goku(gadget)) { - if (USB_ENDPOINT_XFER_INT == type) { - /* single buffering is enough */ - ep = gadget_find_ep_by_name(gadget, "ep3-bulk"); - if (ep && usb_gadget_ep_match_desc(gadget, - ep, desc, ep_comp)) - goto found_ep; - } else if (USB_ENDPOINT_XFER_BULK == type - && (USB_DIR_IN & desc->bEndpointAddress)) { - /* DMA may be available */ - ep = gadget_find_ep_by_name(gadget, "ep2-bulk"); - if (ep && usb_gadget_ep_match_desc(gadget, - ep, desc, ep_comp)) - goto found_ep; - } - #ifdef CONFIG_BLACKFIN - } else if (gadget_is_musbhdrc(gadget)) { + if (gadget_is_musbhdrc(gadget)) { if ((USB_ENDPOINT_XFER_BULK == type) || (USB_ENDPOINT_XFER_ISOC == type)) { if (USB_DIR_IN & desc->bEndpointAddress) @@ -119,8 +103,8 @@ struct usb_ep *usb_ep_autoconfig_ss( ep = NULL; if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) goto found_ep; -#endif } +#endif /* Second, look at endpoints until an unclaimed one looks usable */ list_for_each_entry (ep, &gadget->ep_list, ep_list) { diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c index 46b8d14..1fdfec1 100644 --- a/drivers/usb/gadget/udc/goku_udc.c +++ b/drivers/usb/gadget/udc/goku_udc.c @@ -990,6 +990,35 @@ static int goku_get_frame(struct usb_gadget *_gadget) return -EOPNOTSUPP; } +static struct usb_ep *goku_match_ep(struct usb_gadget *g, + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp) +{ + struct goku_udc *dev = to_goku_udc(g); + struct usb_ep *ep; + + switch (usb_endpoint_type(desc)) { + case USB_ENDPOINT_XFER_INT: + /* single buffering is enough */ + ep = &dev->ep[3].ep; + if (usb_gadget_ep_match_desc(g, ep, desc, ep_comp)) + return ep; + break; + case USB_ENDPOINT_XFER_BULK: + if (usb_endpoint_dir_in(desc)) { + /* DMA may be available */ + ep = &dev->ep[2].ep; + if (usb_gadget_ep_match_desc(g, ep, desc, ep_comp)) + return ep; + } + break; + default: + /* nothing */ ; + } + + return NULL; +} + static int goku_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver); static int goku_udc_stop(struct usb_gadget *g); @@ -998,6 +1027,7 @@ static const struct usb_gadget_ops goku_ops = { .get_frame = goku_get_frame, .udc_start = goku_udc_start, .udc_stop = goku_udc_stop, + .match_ep = goku_match_ep, // no remote wakeup // not selfpowered }; -- cgit v0.10.2 From 26b8aa458c7d99181ceb07f27da9bd7d94185e35 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 6 Aug 2015 14:11:15 +0200 Subject: usb: musb: gadget: add musb_match_ep() function Add 'match_ep' callback to utilize chip-specific knowledge in endpoint matching process. Function does the same that was done by chip-specific code inside of epautoconf. Now this code can be removed from there to separate generic code from platform specific logic. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 574b6a4..16c1cc9 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -83,29 +83,6 @@ struct usb_ep *usb_ep_autoconfig_ss( goto found_ep; } - /* First, apply chip-specific "best usage" knowledge. - * This might make a good usb_gadget_ops hook ... - */ -#ifdef CONFIG_BLACKFIN - if (gadget_is_musbhdrc(gadget)) { - if ((USB_ENDPOINT_XFER_BULK == type) || - (USB_ENDPOINT_XFER_ISOC == type)) { - if (USB_DIR_IN & desc->bEndpointAddress) - ep = gadget_find_ep_by_name(gadget, "ep5in"); - else - ep = gadget_find_ep_by_name(gadget, "ep6out"); - } else if (USB_ENDPOINT_XFER_INT == type) { - if (USB_DIR_IN & desc->bEndpointAddress) - ep = gadget_find_ep_by_name(gadget, "ep1in"); - else - ep = gadget_find_ep_by_name(gadget, "ep2out"); - } else - ep = NULL; - if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) - goto found_ep; - } -#endif - /* Second, look at endpoints until an unclaimed one looks usable */ list_for_each_entry (ep, &gadget->ep_list, ep_list) { if (usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 4150baf..5f52bcb 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1684,6 +1684,39 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on) return 0; } +#ifdef CONFIG_BLACKFIN +static struct usb_ep *musb_match_ep(struct usb_gadget *g, + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp) +{ + struct usb_ep *ep = NULL; + + switch (usb_endpoint_type(desc)) { + case USB_ENDPOINT_XFER_ISOC: + case USB_ENDPOINT_XFER_BULK: + if (usb_endpoint_dir_in(desc)) + ep = gadget_find_ep_by_name(g, "ep5in"); + else + ep = gadget_find_ep_by_name(g, "ep6out"); + break; + case USB_ENDPOINT_XFER_INT: + if (usb_endpoint_dir_in(desc)) + ep = gadget_find_ep_by_name(g, "ep1in"); + else + ep = gadget_find_ep_by_name(g, "ep2out"); + break; + default: + } + + if (ep && usb_gadget_ep_match_desc(g, ep, desc, ep_comp)) + return ep; + + return NULL; +} +#else +#define musb_match_ep NULL +#endif + static int musb_gadget_start(struct usb_gadget *g, struct usb_gadget_driver *driver); static int musb_gadget_stop(struct usb_gadget *g); @@ -1697,6 +1730,7 @@ static const struct usb_gadget_ops musb_gadget_operations = { .pullup = musb_gadget_pullup, .udc_start = musb_gadget_start, .udc_stop = musb_gadget_stop, + .match_ep = musb_match_ep, }; /* ----------------------------------------------------------------------- */ -- cgit v0.10.2 From adab43396ed4830c7cee29837e8cedcddb2b5315 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 6 Aug 2015 14:11:16 +0200 Subject: usb: gadget: remove gadget_chips.h This header file contains helpers for quirks based on UDC controller name. Since we have generic quirk bitfields in usb_gadget structure for all of these quirks we don't need to have this header any longer. This patch removes gadget_chips.h file and makes sure that it's no longer included anywhere in kernel sources. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 16c1cc9..978435a 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -20,8 +20,6 @@ #include #include -#include "gadget_chips.h" - /** * usb_ep_autoconfig_ss() - choose an endpoint matching the ep * descriptor and ep companion descriptor diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c index aad8165..be9df09 100644 --- a/drivers/usb/gadget/function/f_acm.c +++ b/drivers/usb/gadget/function/f_acm.c @@ -21,7 +21,6 @@ #include #include "u_serial.h" -#include "gadget_chips.h" /* diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 04c3bb6..11a7f5a 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -219,7 +219,6 @@ #include #include -#include "gadget_chips.h" #include "configfs.h" diff --git a/drivers/usb/gadget/function/f_obex.c b/drivers/usb/gadget/function/f_obex.c index 2682d59..5460426 100644 --- a/drivers/usb/gadget/function/f_obex.c +++ b/drivers/usb/gadget/function/f_obex.c @@ -20,7 +20,6 @@ #include #include "u_serial.h" -#include "gadget_chips.h" /* diff --git a/drivers/usb/gadget/function/f_serial.c b/drivers/usb/gadget/function/f_serial.c index 2e02dfa..1d162e2 100644 --- a/drivers/usb/gadget/function/f_serial.c +++ b/drivers/usb/gadget/function/f_serial.c @@ -16,7 +16,6 @@ #include #include "u_serial.h" -#include "gadget_chips.h" /* diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c index e6af171..cbfaf86 100644 --- a/drivers/usb/gadget/function/f_sourcesink.c +++ b/drivers/usb/gadget/function/f_sourcesink.c @@ -20,7 +20,6 @@ #include #include "g_zero.h" -#include "gadget_chips.h" #include "u_f.h" /* diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index 1384f00..c77145b 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -20,8 +20,6 @@ #include #include -#include "gadget_chips.h" - #define QMULT_DEFAULT 5 /* diff --git a/drivers/usb/gadget/function/u_uac1.h b/drivers/usb/gadget/function/u_uac1.h index fe386df..5c2ac8e 100644 --- a/drivers/usb/gadget/function/u_uac1.h +++ b/drivers/usb/gadget/function/u_uac1.h @@ -21,8 +21,6 @@ #include #include -#include "gadget_chips.h" - #define FILE_PCM_PLAYBACK "/dev/snd/pcmC0D0p" #define FILE_PCM_CAPTURE "/dev/snd/pcmC0D0c" #define FILE_CONTROL "/dev/snd/controlC0" diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c index 9b2c1c6..685cf3b 100644 --- a/drivers/usb/gadget/legacy/audio.c +++ b/drivers/usb/gadget/legacy/audio.c @@ -15,7 +15,6 @@ #include #include -#include "gadget_chips.h" #define DRIVER_DESC "Linux USB Audio Gadget" #define DRIVER_VERSION "Feb 2, 2012" diff --git a/drivers/usb/gadget/legacy/gmidi.c b/drivers/usb/gadget/legacy/gmidi.c index 650568d..8a18348 100644 --- a/drivers/usb/gadget/legacy/gmidi.c +++ b/drivers/usb/gadget/legacy/gmidi.c @@ -35,8 +35,6 @@ #include #include -#include "gadget_chips.h" - #include "u_midi.h" /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c index e4874d3..7e5d2c4 100644 --- a/drivers/usb/gadget/legacy/hid.c +++ b/drivers/usb/gadget/legacy/hid.c @@ -19,7 +19,6 @@ #include #include -#include "gadget_chips.h" #define DRIVER_DESC "HID Gadget" #define DRIVER_VERSION "2010/03/16" diff --git a/drivers/usb/gadget/legacy/nokia.c b/drivers/usb/gadget/legacy/nokia.c index c20f3b5..8b3f6fb 100644 --- a/drivers/usb/gadget/legacy/nokia.c +++ b/drivers/usb/gadget/legacy/nokia.c @@ -23,7 +23,6 @@ #include "u_ether.h" #include "u_phonet.h" #include "u_ecm.h" -#include "gadget_chips.h" #include "f_mass_storage.h" /* Defines */ diff --git a/drivers/usb/gadget/legacy/printer.c b/drivers/usb/gadget/legacy/printer.c index 0c1fc06..a22d30a 100644 --- a/drivers/usb/gadget/legacy/printer.c +++ b/drivers/usb/gadget/legacy/printer.c @@ -19,8 +19,6 @@ #include #include -#include "gadget_chips.h" - USB_GADGET_COMPOSITE_OPTIONS(); #define DRIVER_DESC "Printer Gadget" diff --git a/drivers/usb/gadget/legacy/serial.c b/drivers/usb/gadget/legacy/serial.c index 9836d16..c5d42e0 100644 --- a/drivers/usb/gadget/legacy/serial.c +++ b/drivers/usb/gadget/legacy/serial.c @@ -17,7 +17,6 @@ #include #include "u_serial.h" -#include "gadget_chips.h" /* Defines */ diff --git a/drivers/usb/gadget/udc/gadget_chips.h b/drivers/usb/gadget/udc/gadget_chips.h deleted file mode 100644 index bcd04bc..0000000 --- a/drivers/usb/gadget/udc/gadget_chips.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * USB device controllers have lots of quirks. Use these macros in - * gadget drivers or other code that needs to deal with them, and which - * autoconfigures instead of using early binding to the hardware. - * - * This SHOULD eventually work like the ARM mach_is_*() stuff, driven by - * some config file that gets updated as new hardware is supported. - * (And avoiding all runtime comparisons in typical one-choice configs!) - * - * NOTE: some of these controller drivers may not be available yet. - * Some are available on 2.4 kernels; several are available, but not - * yet pushed in the 2.6 mainline tree. - */ - -#ifndef __GADGET_CHIPS_H -#define __GADGET_CHIPS_H - -#include - -/* - * NOTICE: the entries below are alphabetical and should be kept - * that way. - * - * Always be sure to add new entries to the correct position or - * accept the bashing later. - * - * If you have forgotten the alphabetical order let VIM/EMACS - * do that for you. - */ -#define gadget_is_at91(g) (!strcmp("at91_udc", (g)->name)) -#define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name)) -#define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name)) -#define gadget_is_net2280(g) (!strcmp("net2280", (g)->name)) -#define gadget_is_pxa(g) (!strcmp("pxa25x_udc", (g)->name)) -#define gadget_is_pxa27x(g) (!strcmp("pxa27x_udc", (g)->name)) - -/** - * gadget_supports_altsettings - return true if altsettings work - * @gadget: the gadget in question - */ -static inline bool gadget_supports_altsettings(struct usb_gadget *gadget) -{ - /* PXA 21x/25x/26x has no altsettings at all */ - if (gadget_is_pxa(gadget)) - return false; - - /* PXA 27x and 3xx have *broken* altsetting support */ - if (gadget_is_pxa27x(gadget)) - return false; - - /* Everything else is *presumably* fine ... */ - return true; -} - -#endif /* __GADGET_CHIPS_H */ -- cgit v0.10.2 From 03840fad004ce8a56bc8b3bb60a2df10f6f9481e Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Aug 2015 10:47:16 -0500 Subject: usb: musb: gadget: remove remaining DMA ifdeferry Commit fb91cddc54e7 ("usb: musb: Remove DMA ifdef for musb_gadget.c short_packet") tried to remove DMA ifdeferry from musb_gadget.c but ended up leaving some around. Remove them so that when building kernels with all DMA engines enabled, we don't end up trying to allocte channels twice. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 5f52bcb..cc50359 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -313,8 +313,7 @@ static void txstate(struct musb *musb, struct musb_request *req) /* MUSB_TXCSR_P_ISO is still set correctly */ -#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) - { + if (musb_dma_inventra(musb) || musb_dma_ux500(musb)) { if (request_size < musb_ep->packet_sz) musb_ep->dma->desired_mode = 0; else @@ -365,7 +364,6 @@ static void txstate(struct musb *musb, struct musb_request *req) } } -#endif if (is_cppi_enabled(musb)) { /* program endpoint CSR first, then setup DMA */ csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY); @@ -641,8 +639,10 @@ static void rxstate(struct musb *musb, struct musb_request *req) use_mode_1 = 0; if (request->actual < request->length) { -#ifdef CONFIG_USB_INVENTRA_DMA - if (is_buffer_mapped(req)) { + if (!is_buffer_mapped(req)) + goto buffer_aint_mapped; + + if (musb_dma_inventra(musb)) { struct dma_controller *c; struct dma_channel *channel; int use_dma = 0; @@ -716,8 +716,8 @@ static void rxstate(struct musb *musb, struct musb_request *req) if (use_dma) return; } -#elif defined(CONFIG_USB_UX500_DMA) - if ((is_buffer_mapped(req)) && + + if ((musb_dma_ux500(musb)) && (request->actual < request->length)) { struct dma_controller *c; @@ -765,7 +765,6 @@ static void rxstate(struct musb *musb, struct musb_request *req) return; } -#endif /* Mentor's DMA */ len = request->length - request->actual; dev_dbg(musb->controller, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n", @@ -775,8 +774,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) fifo_count = min_t(unsigned, len, fifo_count); -#ifdef CONFIG_USB_TUSB_OMAP_DMA - if (tusb_dma_omap(musb) && is_buffer_mapped(req)) { + if (tusb_dma_omap(musb)) { struct dma_controller *c = musb->dma_controller; struct dma_channel *channel = musb_ep->dma; u32 dma_addr = request->dma + request->actual; @@ -790,23 +788,22 @@ static void rxstate(struct musb *musb, struct musb_request *req) if (ret) return; } -#endif + /* * Unmap the dma buffer back to cpu if dma channel * programming fails. This buffer is mapped if the * channel allocation is successful */ - if (is_buffer_mapped(req)) { - unmap_dma_buffer(req, musb); - - /* - * Clear DMAENAB and AUTOCLEAR for the - * PIO mode transfer - */ - csr &= ~(MUSB_RXCSR_DMAENAB | MUSB_RXCSR_AUTOCLEAR); - musb_writew(epio, MUSB_RXCSR, csr); - } + unmap_dma_buffer(req, musb); + + /* + * Clear DMAENAB and AUTOCLEAR for the + * PIO mode transfer + */ + csr &= ~(MUSB_RXCSR_DMAENAB | MUSB_RXCSR_AUTOCLEAR); + musb_writew(epio, MUSB_RXCSR, csr); +buffer_aint_mapped: musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *) (request->buf + request->actual)); request->actual += fifo_count; -- cgit v0.10.2 From b0a688ddcc5015eb26000c63841db7c46cfb380a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Aug 2015 10:51:29 -0500 Subject: usb: musb: cppi41: allow it to work again since commit 33c300cb90a6 ("usb: musb: dsps: don't fake of_node to musb core") we have been preventing CPPI 4.1 from probing due to NULL of_node. We can't revert said commit otherwise a different regression would show up, so the fix is to look for the parent device's (glue layer's) of_node instead, since that's the thing which is actually described in DTS. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index 4d1b44c..d07cafb 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -614,7 +614,7 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) { struct musb *musb = controller->musb; struct device *dev = musb->controller; - struct device_node *np = dev->of_node; + struct device_node *np = dev->parent->of_node; struct cppi41_dma_channel *cppi41_channel; int count; int i; @@ -664,7 +664,7 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) musb_dma->status = MUSB_DMA_STATUS_FREE; musb_dma->max_len = SZ_4M; - dc = dma_request_slave_channel(dev, str); + dc = dma_request_slave_channel(dev->parent, str); if (!dc) { dev_err(dev, "Failed to request %s.\n", str); ret = -EPROBE_DEFER; @@ -695,7 +695,7 @@ cppi41_dma_controller_create(struct musb *musb, void __iomem *base) struct cppi41_dma_controller *controller; int ret = 0; - if (!musb->controller->of_node) { + if (!musb->controller->parent->of_node) { dev_err(musb->controller, "Need DT for the DMA engine.\n"); return NULL; } -- cgit v0.10.2 From 4a1e9211809d4130fe23cad1bea222222d6e94f4 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Aug 2015 11:23:32 -0500 Subject: usb: gadget: f_mass_storage: add mising was originally being pulled indirectly through some other header, however it's not anymore, so we need to include it directly Reported-by: Jim Davis Suggested-by: Alan Stern Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 11a7f5a..a6eb537 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -214,6 +214,7 @@ #include #include #include +#include #include #include -- cgit v0.10.2 From 2e8328fb87d02569511c4808a1b3f44f67bd83fd Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Aug 2015 11:29:19 -0500 Subject: usb: gadget: legacy: nokia: add CONFIG_BLOCK dependency g_nokia now has mass_storage function, so it should depend on CONFIG_BLOCK. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig index ddef41f..4d682ad 100644 --- a/drivers/usb/gadget/legacy/Kconfig +++ b/drivers/usb/gadget/legacy/Kconfig @@ -339,6 +339,7 @@ config USB_CDC_COMPOSITE config USB_G_NOKIA tristate "Nokia composite gadget" depends on PHONET + depends on BLOCK select USB_LIBCOMPOSITE select USB_U_SERIAL select USB_U_ETHER -- cgit v0.10.2 From 2f3cc24f07b8bfe8302a46ceb1ed58cde62cbd09 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 7 Aug 2015 14:13:34 +0200 Subject: usb: musb: gadget: fix build break by adding missing 'break' Add missing break after 'default' label to fix compilation error. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index cc50359..67ad630 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1703,6 +1703,7 @@ static struct usb_ep *musb_match_ep(struct usb_gadget *g, ep = gadget_find_ep_by_name(g, "ep2out"); break; default: + break; } if (ep && usb_gadget_ep_match_desc(g, ep, desc, ep_comp)) -- cgit v0.10.2 From 6c05cb145d6716f00d452aeb27916efb6d190cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 6 Aug 2015 19:23:57 +0300 Subject: usb: xhci: make USB_XHCI_PLATFORM selectable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Right now xhci-plat-hcd can be built when using one of platform specific drivers only (mvebu/rcar). There shouldn't be such limitation as some platforms may not require any quirks and may want to just use a generic driver ("generic-xhci" / "xhci-hcd"). Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 8afc3c1..5f05679 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -32,7 +32,14 @@ config USB_XHCI_PCI default y config USB_XHCI_PLATFORM - tristate + tristate "Generic xHCI driver for a platform device" + ---help--- + Adds an xHCI host driver for a generic platform device, which + provides a memory space and an irq. + It is also a prerequisite for platform specific drivers that + implement some extra quirks. + + If unsure, say N. config USB_XHCI_MVEBU tristate "xHCI support for Marvell Armada 375/38x" -- cgit v0.10.2 From 4758dcd19a7d9ba9610b38fecb93f65f56f86346 Mon Sep 17 00:00:00 2001 From: Reyad Attiyat Date: Thu, 6 Aug 2015 19:23:58 +0300 Subject: usb: xhci: Add support for URB_ZERO_PACKET to bulk/sg transfers This commit checks for the URB_ZERO_PACKET flag and creates an extra zero-length td if the urb transfer length is a multiple of the endpoint's max packet length. Signed-off-by: Reyad Attiyat Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 6a8fc52..463562d 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3041,9 +3041,11 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct xhci_td *td; struct scatterlist *sg; int num_sgs; - int trb_buff_len, this_sg_len, running_total; + int trb_buff_len, this_sg_len, running_total, ret; unsigned int total_packet_count; + bool zero_length_needed; bool first_trb; + int last_trb_num; u64 addr; bool more_trbs_coming; @@ -3059,13 +3061,27 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, total_packet_count = DIV_ROUND_UP(urb->transfer_buffer_length, usb_endpoint_maxp(&urb->ep->desc)); - trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id], + ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, num_trbs, urb, 0, mem_flags); - if (trb_buff_len < 0) - return trb_buff_len; + if (ret < 0) + return ret; urb_priv = urb->hcpriv; + + /* Deal with URB_ZERO_PACKET - need one more td/trb */ + zero_length_needed = urb->transfer_flags & URB_ZERO_PACKET && + urb_priv->length == 2; + if (zero_length_needed) { + num_trbs++; + xhci_dbg(xhci, "Creating zero length td.\n"); + ret = prepare_transfer(xhci, xhci->devs[slot_id], + ep_index, urb->stream_id, + 1, urb, 1, mem_flags); + if (ret < 0) + return ret; + } + td = urb_priv->td[0]; /* @@ -3095,6 +3111,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, trb_buff_len = urb->transfer_buffer_length; first_trb = true; + last_trb_num = zero_length_needed ? 2 : 1; /* Queue the first TRB, even if it's zero-length */ do { u32 field = 0; @@ -3112,12 +3129,15 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* Chain all the TRBs together; clear the chain bit in the last * TRB to indicate it's the last TRB in the chain. */ - if (num_trbs > 1) { + if (num_trbs > last_trb_num) { field |= TRB_CHAIN; - } else { - /* FIXME - add check for ZERO_PACKET flag before this */ + } else if (num_trbs == last_trb_num) { td->last_trb = ep_ring->enqueue; field |= TRB_IOC; + } else if (zero_length_needed && num_trbs == 1) { + trb_buff_len = 0; + urb_priv->td[1]->last_trb = ep_ring->enqueue; + field |= TRB_IOC; } /* Only set interrupt on short packet for IN endpoints */ @@ -3179,7 +3199,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (running_total + trb_buff_len > urb->transfer_buffer_length) trb_buff_len = urb->transfer_buffer_length - running_total; - } while (running_total < urb->transfer_buffer_length); + } while (num_trbs > 0); check_trb_math(urb, num_trbs, running_total); giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, @@ -3197,7 +3217,9 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, int num_trbs; struct xhci_generic_trb *start_trb; bool first_trb; + int last_trb_num; bool more_trbs_coming; + bool zero_length_needed; int start_cycle; u32 field, length_field; @@ -3228,7 +3250,6 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, num_trbs++; running_total += TRB_MAX_BUFF_SIZE; } - /* FIXME: this doesn't deal with URB_ZERO_PACKET - need one more */ ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, @@ -3237,6 +3258,20 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, return ret; urb_priv = urb->hcpriv; + + /* Deal with URB_ZERO_PACKET - need one more td/trb */ + zero_length_needed = urb->transfer_flags & URB_ZERO_PACKET && + urb_priv->length == 2; + if (zero_length_needed) { + num_trbs++; + xhci_dbg(xhci, "Creating zero length td.\n"); + ret = prepare_transfer(xhci, xhci->devs[slot_id], + ep_index, urb->stream_id, + 1, urb, 1, mem_flags); + if (ret < 0) + return ret; + } + td = urb_priv->td[0]; /* @@ -3258,7 +3293,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, trb_buff_len = urb->transfer_buffer_length; first_trb = true; - + last_trb_num = zero_length_needed ? 2 : 1; /* Queue the first TRB, even if it's zero-length */ do { u32 remainder = 0; @@ -3275,12 +3310,15 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* Chain all the TRBs together; clear the chain bit in the last * TRB to indicate it's the last TRB in the chain. */ - if (num_trbs > 1) { + if (num_trbs > last_trb_num) { field |= TRB_CHAIN; - } else { - /* FIXME - add check for ZERO_PACKET flag before this */ + } else if (num_trbs == last_trb_num) { td->last_trb = ep_ring->enqueue; field |= TRB_IOC; + } else if (zero_length_needed && num_trbs == 1) { + trb_buff_len = 0; + urb_priv->td[1]->last_trb = ep_ring->enqueue; + field |= TRB_IOC; } /* Only set interrupt on short packet for IN endpoints */ @@ -3318,7 +3356,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, trb_buff_len = urb->transfer_buffer_length - running_total; if (trb_buff_len > TRB_MAX_BUFF_SIZE) trb_buff_len = TRB_MAX_BUFF_SIZE; - } while (running_total < urb->transfer_buffer_length); + } while (num_trbs > 0); check_trb_math(urb, num_trbs, running_total); giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 91fd328..6b0f4a4 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1340,6 +1340,11 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) if (usb_endpoint_xfer_isoc(&urb->ep->desc)) size = urb->number_of_packets; + else if (usb_endpoint_is_bulk_out(&urb->ep->desc) && + urb->transfer_buffer_length > 0 && + urb->transfer_flags & URB_ZERO_PACKET && + !(urb->transfer_buffer_length % usb_endpoint_maxp(&urb->ep->desc))) + size = 2; else size = 1; -- cgit v0.10.2 From 79b8094f60d8ce54ee76e631ab665c5e3012e6ba Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Thu, 6 Aug 2015 19:24:00 +0300 Subject: xhci: xHCI 1.1: Contiguous Frame ID Capability (CFC) If the Contiguous Frame ID Capability is supported (CFC = 1), then the xHC shall match the Frame ID in every Isoch TD with SIA = 0 against the Frame Index of the MFINDEX register. This rule ensures resynchronization of Isoch TDs even if some are dropped due to Missed Service Errors or Stopping the endpoint. This patch enables xHCI driver to support CFC by calculating and setting the Frame ID field of an Isoch TRB. [made some dbg messages checkpatch friendly -Mathias] Signed-off-by: Lu Baolu Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index 745717e..c867ecb 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -99,6 +99,8 @@ static void xhci_print_cap_regs(struct xhci_hcd *xhci) xhci_dbg(xhci, "HCC PARAMS 0x%x:\n", (unsigned int) temp); xhci_dbg(xhci, " HC generates %s bit addresses\n", HCC_64BIT_ADDR(temp) ? "64" : "32"); + xhci_dbg(xhci, " HC %s Contiguous Frame ID Capability\n", + HCC_CFC(temp) ? "has" : "hasn't"); /* FIXME */ xhci_dbg(xhci, " FIXME: more HCCPARAMS debugging\n"); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 463562d..af8c0f2 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3555,6 +3555,97 @@ static unsigned int xhci_get_last_burst_packet_count(struct xhci_hcd *xhci, } } +/* + * Calculates Frame ID field of the isochronous TRB identifies the + * target frame that the Interval associated with this Isochronous + * Transfer Descriptor will start on. Refer to 4.11.2.5 in 1.1 spec. + * + * Returns actual frame id on success, negative value on error. + */ +static int xhci_get_isoc_frame_id(struct xhci_hcd *xhci, + struct urb *urb, int index) +{ + int start_frame, ist, ret = 0; + int start_frame_id, end_frame_id, current_frame_id; + + if (urb->dev->speed == USB_SPEED_LOW || + urb->dev->speed == USB_SPEED_FULL) + start_frame = urb->start_frame + index * urb->interval; + else + start_frame = (urb->start_frame + index * urb->interval) >> 3; + + /* Isochronous Scheduling Threshold (IST, bits 0~3 in HCSPARAMS2): + * + * If bit [3] of IST is cleared to '0', software can add a TRB no + * later than IST[2:0] Microframes before that TRB is scheduled to + * be executed. + * If bit [3] of IST is set to '1', software can add a TRB no later + * than IST[2:0] Frames before that TRB is scheduled to be executed. + */ + ist = HCS_IST(xhci->hcs_params2) & 0x7; + if (HCS_IST(xhci->hcs_params2) & (1 << 3)) + ist <<= 3; + + /* Software shall not schedule an Isoch TD with a Frame ID value that + * is less than the Start Frame ID or greater than the End Frame ID, + * where: + * + * End Frame ID = (Current MFINDEX register value + 895 ms.) MOD 2048 + * Start Frame ID = (Current MFINDEX register value + IST + 1) MOD 2048 + * + * Both the End Frame ID and Start Frame ID values are calculated + * in microframes. When software determines the valid Frame ID value; + * The End Frame ID value should be rounded down to the nearest Frame + * boundary, and the Start Frame ID value should be rounded up to the + * nearest Frame boundary. + */ + current_frame_id = readl(&xhci->run_regs->microframe_index); + start_frame_id = roundup(current_frame_id + ist + 1, 8); + end_frame_id = rounddown(current_frame_id + 895 * 8, 8); + + start_frame &= 0x7ff; + start_frame_id = (start_frame_id >> 3) & 0x7ff; + end_frame_id = (end_frame_id >> 3) & 0x7ff; + + xhci_dbg(xhci, "%s: index %d, reg 0x%x start_frame_id 0x%x, end_frame_id 0x%x, start_frame 0x%x\n", + __func__, index, readl(&xhci->run_regs->microframe_index), + start_frame_id, end_frame_id, start_frame); + + if (start_frame_id < end_frame_id) { + if (start_frame > end_frame_id || + start_frame < start_frame_id) + ret = -EINVAL; + } else if (start_frame_id > end_frame_id) { + if ((start_frame > end_frame_id && + start_frame < start_frame_id)) + ret = -EINVAL; + } else { + ret = -EINVAL; + } + + if (index == 0) { + if (ret == -EINVAL || start_frame == start_frame_id) { + start_frame = start_frame_id + 1; + if (urb->dev->speed == USB_SPEED_LOW || + urb->dev->speed == USB_SPEED_FULL) + urb->start_frame = start_frame; + else + urb->start_frame = start_frame << 3; + ret = 0; + } + } + + if (ret) { + xhci_warn(xhci, "Frame ID %d (reg %d, index %d) beyond range (%d, %d)\n", + start_frame, current_frame_id, index, + start_frame_id, end_frame_id); + xhci_warn(xhci, "Ignore frame ID field, use SIA bit instead\n"); + return ret; + } + + return start_frame; +} + /* This is for isoc transfer */ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index) @@ -3571,7 +3662,9 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, u64 start_addr, addr; int i, j; bool more_trbs_coming; + struct xhci_virt_ep *xep; + xep = &xhci->devs[slot_id]->eps[ep_index]; ep_ring = xhci->devs[slot_id]->eps[ep_index].ring; num_tds = urb->number_of_packets; @@ -3619,6 +3712,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, td = urb_priv->td[i]; for (j = 0; j < trbs_per_td; j++) { + int frame_id = 0; u32 remainder = 0; field = 0; @@ -3627,8 +3721,20 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, TRB_TLBPC(residue); /* Queue the isoc TRB */ field |= TRB_TYPE(TRB_ISOC); - /* Assume URB_ISO_ASAP is set */ - field |= TRB_SIA; + + /* Calculate Frame ID and SIA fields */ + if (!(urb->transfer_flags & URB_ISO_ASAP) && + HCC_CFC(xhci->hcc_params)) { + frame_id = xhci_get_isoc_frame_id(xhci, + urb, + i); + if (frame_id >= 0) + field |= TRB_FRAME_ID(frame_id); + else + field |= TRB_SIA; + } else + field |= TRB_SIA; + if (i == 0) { if (start_cycle == 0) field |= 0x1; @@ -3704,6 +3810,10 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } } + /* store the next frame id */ + if (HCC_CFC(xhci->hcc_params)) + xep->next_frame_id = urb->start_frame + num_tds * urb->interval; + if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs == 0) { if (xhci->quirks & XHCI_AMD_PLL_FIX) usb_amd_quirk_pll_disable(); @@ -3737,12 +3847,34 @@ cleanup: return ret; } +static int ep_ring_is_processing(struct xhci_hcd *xhci, + int slot_id, unsigned int ep_index) +{ + struct xhci_virt_device *xdev; + struct xhci_ring *ep_ring; + struct xhci_ep_ctx *ep_ctx; + struct xhci_virt_ep *xep; + dma_addr_t hw_deq; + + xdev = xhci->devs[slot_id]; + xep = &xhci->devs[slot_id]->eps[ep_index]; + ep_ring = xep->ring; + ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); + + if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) != EP_STATE_RUNNING) + return 0; + + hw_deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK; + return (hw_deq != + xhci_trb_virt_to_dma(ep_ring->enq_seg, ep_ring->enqueue)); +} + /* * Check transfer ring to guarantee there is enough room for the urb. * Update ISO URB start_frame and interval. - * Update interval as xhci_queue_intr_tx does. Just use xhci frame_index to - * update the urb->start_frame by now. - * Always assume URB_ISO_ASAP set, and NEVER use urb->start_frame as input. + * Update interval as xhci_queue_intr_tx does. Use xhci frame_index to + * update urb->start_frame if URB_ISO_ASAP is set in transfer_flags or + * Contiguous Frame ID is not supported by HC. */ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index) @@ -3755,8 +3887,11 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, int ep_interval; int num_tds, num_trbs, i; int ret; + struct xhci_virt_ep *xep; + int ist; xdev = xhci->devs[slot_id]; + xep = &xhci->devs[slot_id]->eps[ep_index]; ep_ring = xdev->eps[ep_index].ring; ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); @@ -3773,14 +3908,10 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, if (ret) return ret; - start_frame = readl(&xhci->run_regs->microframe_index); - start_frame &= 0x3fff; - - urb->start_frame = start_frame; - if (urb->dev->speed == USB_SPEED_LOW || - urb->dev->speed == USB_SPEED_FULL) - urb->start_frame >>= 3; - + /* + * Check interval value. This should be done before we start to + * calculate the start frame value. + */ xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx->ep_info)); ep_interval = urb->interval; /* Convert to microframes */ @@ -3801,6 +3932,40 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, urb->dev->speed == USB_SPEED_FULL) urb->interval /= 8; } + + /* Calculate the start frame and put it in urb->start_frame. */ + if (HCC_CFC(xhci->hcc_params) && + ep_ring_is_processing(xhci, slot_id, ep_index)) { + urb->start_frame = xep->next_frame_id; + goto skip_start_over; + } + + start_frame = readl(&xhci->run_regs->microframe_index); + start_frame &= 0x3fff; + /* + * Round up to the next frame and consider the time before trb really + * gets scheduled by hardare. + */ + ist = HCS_IST(xhci->hcs_params2) & 0x7; + if (HCS_IST(xhci->hcs_params2) & (1 << 3)) + ist <<= 3; + start_frame += ist + XHCI_CFC_DELAY; + start_frame = roundup(start_frame, 8); + + /* + * Round up to the next ESIT (Endpoint Service Interval Time) if ESIT + * is greate than 8 microframes. + */ + if (urb->dev->speed == USB_SPEED_LOW || + urb->dev->speed == USB_SPEED_FULL) { + start_frame = roundup(start_frame, urb->interval << 3); + urb->start_frame = start_frame >> 3; + } else { + start_frame = roundup(start_frame, urb->interval); + urb->start_frame = start_frame; + } + +skip_start_over: ep_ring->num_trbs_free_temp = ep_ring->num_trbs_free; return xhci_queue_isoc_tx(xhci, mem_flags, urb, slot_id, ep_index); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index ed2ebf6..7368692 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -119,6 +119,8 @@ struct xhci_cap_regs { #define HCC_LTC(p) ((p) & (1 << 6)) /* true: no secondary Stream ID Support */ #define HCC_NSS(p) ((p) & (1 << 7)) +/* true: HC has Contiguous Frame ID Capability */ +#define HCC_CFC(p) ((p) & (1 << 11)) /* Max size for Primary Stream Arrays - 2^(n+1), where n is bits 12:15 */ #define HCC_MAX_PSA(p) (1 << ((((p) >> 12) & 0xf) + 1)) /* Extended Capabilities pointer from PCI base - section 5.3.6 */ @@ -891,6 +893,8 @@ struct xhci_virt_ep { /* Bandwidth checking storage */ struct xhci_bw_info bw_info; struct list_head bw_endpoint_list; + /* Isoch Frame ID checking storage */ + int next_frame_id; }; enum xhci_overhead_type { @@ -1165,6 +1169,7 @@ enum xhci_setup_dev { /* Isochronous TRB specific fields */ #define TRB_SIA (1<<31) +#define TRB_FRAME_ID(p) (((p) & 0x7ff) << 20) struct xhci_generic_trb { __le32 field[4]; @@ -1601,6 +1606,8 @@ struct xhci_driver_overrides { int (*start)(struct usb_hcd *hcd); }; +#define XHCI_CFC_DELAY 10 + /* convert between an HCD pointer and the corresponding EHCI_HCD */ static inline struct xhci_hcd *hcd_to_xhci(struct usb_hcd *hcd) { -- cgit v0.10.2 From 40a3b775f49c2784c96b19170fd2478e5e5511a1 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Thu, 6 Aug 2015 19:24:01 +0300 Subject: xhci: xHCI 1.1: Stopped - Short Packet Capability (SPC) This patch enables xhci driver to support SPC by handling Stopped - Short Packet event in transfer event path. If SPC = '1' and the stop endpoint command is executed, after a Short Packet condition has been detected, but before the end of the TD has been reached, (i.e. the TD is in progress for pipe), then a Transfer Event TRB with its Completion Code set to Stopped - Short Packet and its TRB Transfer Length set to value of the EDTLA shall be forced for the interrupted TRB, irrespective of whether its IOC or ISP flags are set. This Transfer Event TRB will precede the Command Completion Event TRB for the command, and is referred to as a Stopped Transfer Event. Signed-off-by: Lu Baolu Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index c867ecb..2d16fae 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -101,6 +101,8 @@ static void xhci_print_cap_regs(struct xhci_hcd *xhci) HCC_64BIT_ADDR(temp) ? "64" : "32"); xhci_dbg(xhci, " HC %s Contiguous Frame ID Capability\n", HCC_CFC(temp) ? "has" : "hasn't"); + xhci_dbg(xhci, " HC %s generate Stopped - Short Package event\n", + HCC_SPC(temp) ? "can" : "can't"); /* FIXME */ xhci_dbg(xhci, " FIXME: more HCCPARAMS debugging\n"); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index af8c0f2..5fbf339 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1812,7 +1812,9 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, if (skip) goto td_cleanup; - if (trb_comp_code == COMP_STOP_INVAL || trb_comp_code == COMP_STOP) { + if (trb_comp_code == COMP_STOP_INVAL || + trb_comp_code == COMP_STOP || + trb_comp_code == COMP_STOP_SHORT) { /* The Endpoint Stop Command completion will take care of any * stopped TDs. A stopped TD may be restarted, so don't update * the ring dequeue pointer or take this TD off any lists yet. @@ -1919,8 +1921,22 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, else *status = 0; break; - case COMP_STOP_INVAL: + case COMP_STOP_SHORT: + if (event_trb == ep_ring->dequeue || event_trb == td->last_trb) + xhci_warn(xhci, "WARN: Stopped Short Packet on ctrl setup or status TRB\n"); + else + td->urb->actual_length = + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); + + return finish_td(xhci, td, event_trb, event, ep, status, false); case COMP_STOP: + /* Did we stop at data stage? */ + if (event_trb != ep_ring->dequeue && event_trb != td->last_trb) + td->urb->actual_length = + td->urb->transfer_buffer_length - + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); + /* fall through */ + case COMP_STOP_INVAL: return finish_td(xhci, td, event_trb, event, ep, status, false); default: if (!xhci_requires_manual_halt_cleanup(xhci, @@ -2014,6 +2030,8 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, } if ((xhci->quirks & XHCI_TRUST_TX_LENGTH)) trb_comp_code = COMP_SHORT_TX; + /* fallthrough */ + case COMP_STOP_SHORT: case COMP_SHORT_TX: frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ? -EREMOTEIO : 0; @@ -2049,6 +2067,10 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, if (trb_comp_code == COMP_SUCCESS || skip_td) { frame->actual_length = frame->length; td->urb->actual_length += frame->length; + } else if (trb_comp_code == COMP_STOP_SHORT) { + frame->actual_length = + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); + td->urb->actual_length += frame->actual_length; } else { for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg; cur_trb != event_trb; @@ -2129,6 +2151,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, *status = 0; } break; + case COMP_STOP_SHORT: case COMP_SHORT_TX: if (td->urb->transfer_flags & URB_SHORT_NOT_OK) *status = -EREMOTEIO; @@ -2145,8 +2168,20 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, td->urb->ep->desc.bEndpointAddress, td->urb->transfer_buffer_length, EVENT_TRB_LEN(le32_to_cpu(event->transfer_len))); + /* Stopped - short packet completion */ + if (trb_comp_code == COMP_STOP_SHORT) { + td->urb->actual_length = + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); + + if (td->urb->transfer_buffer_length < + td->urb->actual_length) { + xhci_warn(xhci, "HC gave bad length of %d bytes txed\n", + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len))); + td->urb->actual_length = 0; + /* status will be set by usb core for canceled urbs */ + } /* Fast path - was this the last TRB in the TD for this URB? */ - if (event_trb == td->last_trb) { + } else if (event_trb == td->last_trb) { if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { td->urb->actual_length = td->urb->transfer_buffer_length - @@ -2300,6 +2335,9 @@ static int handle_tx_event(struct xhci_hcd *xhci, case COMP_STOP_INVAL: xhci_dbg(xhci, "Stopped on No-op or Link TRB\n"); break; + case COMP_STOP_SHORT: + xhci_dbg(xhci, "Stopped with short packet transfer detected\n"); + break; case COMP_STALL: xhci_dbg(xhci, "Stalled endpoint\n"); ep->ep_state |= EP_HALTED; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 7368692..dbda41e 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -119,6 +119,8 @@ struct xhci_cap_regs { #define HCC_LTC(p) ((p) & (1 << 6)) /* true: no secondary Stream ID Support */ #define HCC_NSS(p) ((p) & (1 << 7)) +/* true: HC supports Stopped - Short Packet */ +#define HCC_SPC(p) ((p) & (1 << 9)) /* true: HC has Contiguous Frame ID Capability */ #define HCC_CFC(p) ((p) & (1 << 11)) /* Max size for Primary Stream Arrays - 2^(n+1), where n is bits 12:15 */ @@ -1063,8 +1065,8 @@ struct xhci_transfer_event { #define COMP_STOP 26 /* Same as COMP_EP_STOPPED, but the transferred length in the event is invalid */ #define COMP_STOP_INVAL 27 -/* Control Abort Error - Debug Capability - control pipe aborted */ -#define COMP_DBG_ABORT 28 +/* Same as COMP_EP_STOPPED, but a short packet detected */ +#define COMP_STOP_SHORT 28 /* Max Exit Latency Too Large Error */ #define COMP_MEL_ERR 29 /* TRB type 30 reserved */ -- cgit v0.10.2 From f355e830a54ebe1601613d78a8d5b85eeafde358 Mon Sep 17 00:00:00 2001 From: Kris Borer Date: Fri, 7 Aug 2015 07:22:44 -0400 Subject: usb: devio: fix spacing Fix two occurrences of the checkpatch.pl error: ERROR: space prohibited before that ',' (ctx:WxW) Fix one occurrence of the checkpatch error: ERROR: space required before the open parenthesis '(' Signed-off-by: Kris Borer Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index ed6d1d5..38ae877c 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -103,7 +103,7 @@ MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic"); #define snoop(dev, format, arg...) \ do { \ if (usbfs_snoop) \ - dev_info(dev , format , ## arg); \ + dev_info(dev, format, ## arg); \ } while (0) enum snoop_when { @@ -1321,7 +1321,7 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb is_in = (uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0; u = 0; - switch(uurb->type) { + switch (uurb->type) { case USBDEVFS_URB_TYPE_CONTROL: if (!usb_endpoint_xfer_control(&ep->desc)) return -EINVAL; -- cgit v0.10.2 From 166b8639f52ebeec1bfbe966239530a83040c428 Mon Sep 17 00:00:00 2001 From: Chase Metzger Date: Sat, 8 Aug 2015 01:03:34 -0700 Subject: usb: core: hub.c: Removed some warnings generated by checkpatch.pl Removed some checkpatch.pl warnings saying there was an unwanted space between function names and their arguments. Signed-off-by: Chase Metzger Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 917c27c..a0b22be 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -50,8 +50,8 @@ DEFINE_MUTEX(usb_port_peer_mutex); /* cycle leds on hubs that aren't blinking for attention */ static bool blinkenlights = 0; -module_param (blinkenlights, bool, S_IRUGO); -MODULE_PARM_DESC (blinkenlights, "true to cycle leds on hubs"); +module_param(blinkenlights, bool, S_IRUGO); +MODULE_PARM_DESC(blinkenlights, "true to cycle leds on hubs"); /* * Device SATA8000 FW1.0 from DATAST0R Technology Corp requires about @@ -439,7 +439,7 @@ static void set_port_led(struct usb_hub *hub, int port1, int selector) #define LED_CYCLE_PERIOD ((2*HZ)/3) -static void led_work (struct work_struct *work) +static void led_work(struct work_struct *work) { struct usb_hub *hub = container_of(work, struct usb_hub, leds.work); @@ -646,7 +646,7 @@ static void hub_irq(struct urb *urb) default: /* presumably an error */ /* Cause a hub reset after 10 consecutive errors */ - dev_dbg (hub->intfdev, "transfer --> %d\n", status); + dev_dbg(hub->intfdev, "transfer --> %d\n", status); if ((++hub->nerrors < 10) || hub->error) goto resubmit; hub->error = status; @@ -671,14 +671,14 @@ resubmit: if (hub->quiescing) return; - if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0 + if ((status = usb_submit_urb(hub->urb, GFP_ATOMIC)) != 0 && status != -ENODEV && status != -EPERM) - dev_err (hub->intfdev, "resubmit --> %d\n", status); + dev_err(hub->intfdev, "resubmit --> %d\n", status); } /* USB 2.0 spec Section 11.24.2.3 */ static inline int -hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt) +hub_clear_tt_buffer(struct usb_device *hdev, u16 devinfo, u16 tt) { /* Need to clear both directions for control ep */ if (((devinfo >> 11) & USB_ENDPOINT_XFERTYPE_MASK) == @@ -706,7 +706,7 @@ static void hub_tt_work(struct work_struct *work) container_of(work, struct usb_hub, tt.clear_work); unsigned long flags; - spin_lock_irqsave (&hub->tt.lock, flags); + spin_lock_irqsave(&hub->tt.lock, flags); while (!list_empty(&hub->tt.clear_list)) { struct list_head *next; struct usb_tt_clear *clear; @@ -715,14 +715,14 @@ static void hub_tt_work(struct work_struct *work) int status; next = hub->tt.clear_list.next; - clear = list_entry (next, struct usb_tt_clear, clear_list); - list_del (&clear->clear_list); + clear = list_entry(next, struct usb_tt_clear, clear_list); + list_del(&clear->clear_list); /* drop lock so HCD can concurrently report other TT errors */ - spin_unlock_irqrestore (&hub->tt.lock, flags); - status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt); + spin_unlock_irqrestore(&hub->tt.lock, flags); + status = hub_clear_tt_buffer(hdev, clear->devinfo, clear->tt); if (status && status != -ENODEV) - dev_err (&hdev->dev, + dev_err(&hdev->dev, "clear tt %d (%04x) error %d\n", clear->tt, clear->devinfo, status); @@ -734,7 +734,7 @@ static void hub_tt_work(struct work_struct *work) kfree(clear); spin_lock_irqsave(&hub->tt.lock, flags); } - spin_unlock_irqrestore (&hub->tt.lock, flags); + spin_unlock_irqrestore(&hub->tt.lock, flags); } /** @@ -797,7 +797,7 @@ int usb_hub_clear_tt_buffer(struct urb *urb) */ clear = kmalloc(sizeof *clear, GFP_ATOMIC); if (clear == NULL) { - dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n"); + dev_err(&udev->dev, "can't save CLEAR_TT_BUFFER state\n"); /* FIXME recover somehow ... RESET_TT? */ return -ENOMEM; } @@ -806,10 +806,10 @@ int usb_hub_clear_tt_buffer(struct urb *urb) clear->tt = tt->multi ? udev->ttport : 1; clear->devinfo = usb_pipeendpoint (pipe); clear->devinfo |= udev->devnum << 4; - clear->devinfo |= usb_pipecontrol (pipe) + clear->devinfo |= usb_pipecontrol(pipe) ? (USB_ENDPOINT_XFER_CONTROL << 11) : (USB_ENDPOINT_XFER_BULK << 11); - if (usb_pipein (pipe)) + if (usb_pipein(pipe)) clear->devinfo |= 1 << 15; /* info for completion callback */ @@ -817,10 +817,10 @@ int usb_hub_clear_tt_buffer(struct urb *urb) clear->ep = urb->ep; /* tell keventd to clear state for this TT */ - spin_lock_irqsave (&tt->lock, flags); - list_add_tail (&clear->clear_list, &tt->clear_list); + spin_lock_irqsave(&tt->lock, flags); + list_add_tail(&clear->clear_list, &tt->clear_list); schedule_work(&tt->clear_work); - spin_unlock_irqrestore (&tt->lock, flags); + spin_unlock_irqrestore(&tt->lock, flags); return 0; } EXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer); -- cgit v0.10.2 From 7e34d70a7163b236f520ef4fc0d7c50093dd3746 Mon Sep 17 00:00:00 2001 From: Tal Shorer Date: Fri, 7 Aug 2015 22:35:51 +0300 Subject: usb: hcd.h: Fix the values of SetHubDepth and GetPortErrorCount to match USB 3.1 specification >From the usb 3.1 spec available at http://www.usb.org/developers/docs/ table 10-7 (Hub Class Requests) specifies the values for SetHubDepth and GetPortErrorCount as: Request bmRequestType bRequest wValue wIndex wLength Data SetHubDepth 00100000B SET_HUB_DEPTH Hub Depth Zero Zero None GetPortErrorCount 10100011B GET_PORT_ERR_COUNT Zero Port Two Number of Link Errors on this port Fix these two values to match the spec. Signed-off-by: Tal Shorer Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index c9aa779..d2784c1 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -564,9 +564,9 @@ extern void usb_ep0_reinit(struct usb_device *); /*-------------------------------------------------------------------------*/ -/* class requests from USB 3.0 hub spec, table 10-5 */ -#define SetHubDepth (0x3000 | HUB_SET_DEPTH) -#define GetPortErrorCount (0x8000 | HUB_GET_PORT_ERR_COUNT) +/* class requests from USB 3.1 hub spec, table 10-7 */ +#define SetHubDepth (0x2000 | HUB_SET_DEPTH) +#define GetPortErrorCount (0xa300 | HUB_GET_PORT_ERR_COUNT) /* * Generic bandwidth allocation constants/support -- cgit v0.10.2 From cfd093bbb5fe84ec8c7bb069fe618159a8b601f5 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Sun, 9 Aug 2015 00:02:41 +0200 Subject: phy: lpc18xx-usb-otg: fix clock order in phy init Changing the frequency of the USB clock must be done before the PLL is powered on (prepared). This matters when the USB clock is not setup by either boot ROM or boot loader. Reorder the function calls to adhere to the order noted in the user manual. Signed-off-by: Joachim Eastwood Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-lpc18xx-usb-otg.c b/drivers/phy/phy-lpc18xx-usb-otg.c index 3aa8e4d..3b7a71e 100644 --- a/drivers/phy/phy-lpc18xx-usb-otg.c +++ b/drivers/phy/phy-lpc18xx-usb-otg.c @@ -33,12 +33,12 @@ static int lpc18xx_usb_otg_phy_init(struct phy *phy) struct lpc18xx_usb_otg_phy *lpc = phy_get_drvdata(phy); int ret; - ret = clk_prepare(lpc->clk); + /* The PHY must be clocked at 480 MHz */ + ret = clk_set_rate(lpc->clk, 480000000); if (ret) return ret; - /* The PHY must be clocked at 480 MHz */ - return clk_set_rate(lpc->clk, 480000000); + return clk_prepare(lpc->clk); } static int lpc18xx_usb_otg_phy_exit(struct phy *phy) -- cgit v0.10.2 From 28362673129e7d4510a5a92a8b68ee47f282210b Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 18 Jun 2015 11:51:53 +0800 Subject: usb: chipidea: add ttctrl.ttha control interface The register of ttctrl.ttha describes like below: - Internal TT Hub Address Representation - RW - Default = 0000000b This field is used to match against the Hub Address field in QH & siTD to determine if the packet is routed to the internal TT for directly attached FS/LS devices. If the Hub Address in the QH or siTD does not match this address then the packet will be broadcast on the High Speed ports destined for a downstream High Speed hub with the address in the QH/siTD. In silicon RTL, this entry only affects QH and siTD, and the hub.addr at both QH and siTD are 0 in ehci core for chipidea (with hcd->has_tt = 1). So, for QH, if the "usage_tt" flag at RTL is 0, set CI_HDRC_SET_NON_ZERO_TTHA will not affect QH (with non-hs device); for siTD, set this flag will change remaining space requirement for the last transaction from 1023 bytes to 188 bytes, it can increase the number of transactions within one frame, ehci periodic schedule code will not queue the packet if the frame space is full, so it is safe to set this flag for siTD. With this flag, it can fix the problem Alan Stern reported below: http://www.spinics.net/lists/linux-usb/msg123125.html And may fix Michael Tessier's problem too. http://www.spinics.net/lists/linux-usb/msg118679.html CC: stern@rowland.harvard.edu CC: michael.tessier@axiontech.ca Signed-off-by: Peter Chen diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h index 3cb9bda..831a8f6 100644 --- a/drivers/usb/chipidea/bits.h +++ b/drivers/usb/chipidea/bits.h @@ -53,6 +53,11 @@ #define DEVICEADDR_USBADRA BIT(24) #define DEVICEADDR_USBADR (0x7FUL << 25) +/* TTCTRL */ +#define TTCTRL_TTHA_MASK (0x7fUL << 24) +/* Set non-zero value for internal TT Hub address representation */ +#define TTCTRL_TTHA (0x7fUL << 24) + /* PORTSC */ #define PORTSC_CCS BIT(0) #define PORTSC_CSC BIT(1) diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 6d6200e..df57e49 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -50,6 +50,7 @@ enum ci_hw_regs { OP_USBINTR, OP_DEVICEADDR, OP_ENDPTLISTADDR, + OP_TTCTRL, OP_PORTSC, OP_DEVLC, OP_OTGSC, diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 3ad48e1..b0d01f2 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -84,6 +84,7 @@ static const u8 ci_regs_nolpm[] = { [OP_USBINTR] = 0x08U, [OP_DEVICEADDR] = 0x14U, [OP_ENDPTLISTADDR] = 0x18U, + [OP_TTCTRL] = 0x1CU, [OP_PORTSC] = 0x44U, [OP_DEVLC] = 0x84U, [OP_OTGSC] = 0x64U, @@ -106,6 +107,7 @@ static const u8 ci_regs_lpm[] = { [OP_USBINTR] = 0x08U, [OP_DEVICEADDR] = 0x14U, [OP_ENDPTLISTADDR] = 0x18U, + [OP_TTCTRL] = 0x1CU, [OP_PORTSC] = 0x44U, [OP_DEVLC] = 0x84U, [OP_OTGSC] = 0xC4U, diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 7161439..b01716c 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -159,6 +159,9 @@ static int host_start(struct ci_hdrc *ci) if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC); + if (ci->platdata->flags & CI_HDRC_SET_NON_ZERO_TTHA) + hw_write(ci, OP_TTCTRL, TTCTRL_TTHA_MASK, TTCTRL_TTHA); + return ret; disable_reg: diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index ab94f78..d1e1285 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -29,6 +29,7 @@ struct ci_hdrc_platform_data { #define CI_HDRC_IMX28_WRITE_FIX BIT(5) #define CI_HDRC_FORCE_FULLSPEED BIT(6) #define CI_HDRC_TURN_VBUS_EARLY_ON BIT(7) +#define CI_HDRC_SET_NON_ZERO_TTHA BIT(8) enum usb_dr_mode dr_mode; #define CI_HDRC_CONTROLLER_RESET_EVENT 0 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 -- cgit v0.10.2 From e765bfb73ff711b1d139a4438af9ecedabb07d34 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 18 Jun 2015 11:43:34 +0800 Subject: usb: chipidea: imx: enable CI_HDRC_SET_NON_ZERO_TTHA For i.mx platform, set ttctrl.ttha with non-zero value only affects sitd, and ehci core makes sure the schedule is not full when accepts new request, so it will not occur the transaction which will acorss the SoF. Signed-off-by: Peter Chen diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 389f0e0..6d2a85a 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -126,7 +126,8 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) struct ci_hdrc_platform_data pdata = { .name = dev_name(&pdev->dev), .capoffset = DEF_CAPOFFSET, - .flags = CI_HDRC_DISABLE_STREAMING, + .flags = CI_HDRC_DISABLE_STREAMING | + CI_HDRC_SET_NON_ZERO_TTHA, }; int ret; const struct of_device_id *of_id = -- cgit v0.10.2 From 3520d462b95fff1c445faec6f54953cd8da25ca7 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Fri, 17 Jul 2015 08:44:24 +0800 Subject: usb: chipidea: udc: add USB_DEVICE_A_HNP_SUPPORT request support We can support USB OTG 1.3 USB_DEVICE_A_HNP_SUPPORT request when the driver supports OTG FSM mode. Signed-off-by: Peter Chen diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 764f668..27cbd1c 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1090,6 +1090,13 @@ __acquires(ci->lock) if (ci_otg_is_fsm_mode(ci)) err = otg_a_alt_hnp_support(ci); break; + case USB_DEVICE_A_HNP_SUPPORT: + if (ci_otg_is_fsm_mode(ci)) { + ci->gadget.a_hnp_support = 1; + err = isr_setup_status_phase( + ci); + } + break; default: goto delegate; } -- cgit v0.10.2 From 9d2effea12a3a7139daf04a2be97f18d3e6913a3 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 15 Jul 2015 13:56:26 +0800 Subject: usb: chipidea: otg_fsm: delete the duplicated reset controller operation At host_stop, it will call usb_remove_hcd, and reset controller later. Signed-off-by: Peter Chen diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index 19d655a..00ab59d 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -525,7 +525,6 @@ static int ci_otg_start_host(struct otg_fsm *fsm, int on) ci_role_start(ci, CI_ROLE_HOST); } else { ci_role_stop(ci); - hw_device_reset(ci); ci_role_start(ci, CI_ROLE_GADGET); } return 0; -- cgit v0.10.2 From bf9c85e78d0fec61360ece46dacf9ab71ba89361 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 17 Mar 2015 10:40:50 +0800 Subject: usb: chipidea: introduce ci_platform_configure It is used to configure controller parameters according to platform data, like speed, stream mode, etc, both host and device's initialization need it, most of code are the same for both roles, with this new interface, it can reduce the duplicated code and be easy to maintain in future. Signed-off-by: Peter Chen diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index df57e49..1320a4d 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -427,4 +427,6 @@ u8 hw_port_test_get(struct ci_hdrc *ci); int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask, u32 value, unsigned int timeout_ms); +void ci_platform_configure(struct ci_hdrc *ci); + #endif /* __DRIVERS_USB_CHIPIDEA_CI_H */ diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index b0d01f2..1b1dd80 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -405,6 +405,28 @@ static int ci_usb_phy_init(struct ci_hdrc *ci) return ret; } + +/** + * ci_platform_configure: do controller configure + * @ci: the controller + * + */ +void ci_platform_configure(struct ci_hdrc *ci) +{ + if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING) + hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); + + if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) { + if (ci->hw_bank.lpm) + hw_write(ci, OP_DEVLC, DEVLC_PFSC, DEVLC_PFSC); + else + hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC); + } + + if (ci->platdata->flags & CI_HDRC_SET_NON_ZERO_TTHA) + hw_write(ci, OP_TTCTRL, TTCTRL_TTHA_MASK, TTCTRL_TTHA); +} + /** * hw_controller_reset: do controller reset * @ci: the controller @@ -449,16 +471,6 @@ int hw_device_reset(struct ci_hdrc *ci) ci->platdata->notify_event(ci, CI_HDRC_CONTROLLER_RESET_EVENT); - if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING) - hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); - - if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) { - if (ci->hw_bank.lpm) - hw_write(ci, OP_DEVLC, DEVLC_PFSC, DEVLC_PFSC); - else - hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC); - } - /* USBMODE should be configured step by step */ hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE); hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_DC); @@ -471,6 +483,8 @@ int hw_device_reset(struct ci_hdrc *ci) return -ENODEV; } + ci_platform_configure(ci); + return 0; } diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index b01716c..4455431 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -153,14 +153,7 @@ static int host_start(struct ci_hdrc *ci) } } - if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING) - hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); - - if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) - hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC); - - if (ci->platdata->flags & CI_HDRC_SET_NON_ZERO_TTHA) - hw_write(ci, OP_TTCTRL, TTCTRL_TTHA_MASK, TTCTRL_TTHA); + ci_platform_configure(ci); return ret; -- cgit v0.10.2 From 1bd57127d4aaff518cf93f4809ec2f11b2baf865 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 15 Jul 2015 13:53:05 +0800 Subject: Doc: usb: ci-hdrc-usb2: add itc-setting at binding doc It is used to configure the ITC (in register USBCMD) value for kinds of applications. Signed-off-by: Peter Chen diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt index 553e2fa..4159c8c 100644 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt @@ -30,6 +30,8 @@ Optional properties: argument that indicate usb controller index - disable-over-current: (FSL only) disable over current detect - external-vbus-divider: (FSL only) enables off-chip resistor divider for Vbus +- itc-setting: interrupt threshold control register control, the setting + should be aligned with ITC bits at register USBCMD. Example: @@ -41,4 +43,5 @@ Example: phys = <&usb_phy0>; phy-names = "usb-phy"; vbus-supply = <®_usb0_vbus>; + gadget-itc-setting = <0x4>; /* 4 micro-frames */ }; -- cgit v0.10.2 From df96ed8dced21426c54c7f69cf7513e75280957a Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Mon, 22 Sep 2014 16:45:39 +0800 Subject: usb: chipidea: introduce ITC tuning interface ITC (Interrupt Threshold Control) is used to set the maximum rate at which the host/device controller will issue interrupts. The default value is 8 (1ms) for it. EHCI core will modify it to 1, but device mode keeps it as default value. In some use cases like Android ADB, it only has one usb request for each direction, and maximum payload data is only 4KB, so the speed is 4MB/s at most, it needs controller to trigger interrupt as fast as possible to increase the speed. The USB performance will be better if the interrupt can be triggered faster. Reduce ITC value is benefit for USB performance, but the interrupt number is increased at the same time, it may increase cpu utilization too. Most of use case cares about performance, but some may care about cpu utilization, so, we leave a platform interface for user. We set ITC as 1 (1 micro-frame) as default value which is aligned with ehci core default value. Signed-off-by: Peter Chen diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 1b1dd80..845d0d7 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -425,6 +425,9 @@ void ci_platform_configure(struct ci_hdrc *ci) if (ci->platdata->flags & CI_HDRC_SET_NON_ZERO_TTHA) hw_write(ci, OP_TTCTRL, TTCTRL_TTHA_MASK, TTCTRL_TTHA); + + hw_write(ci, OP_USBCMD, 0xff0000, ci->platdata->itc_setting << 16); + } /** @@ -576,6 +579,8 @@ static irqreturn_t ci_irq(int irq, void *data) static int ci_get_platdata(struct device *dev, struct ci_hdrc_platform_data *platdata) { + int ret; + if (!platdata->phy_mode) platdata->phy_mode = of_usb_get_phy_mode(dev->of_node); @@ -607,6 +612,17 @@ static int ci_get_platdata(struct device *dev, if (of_usb_get_maximum_speed(dev->of_node) == USB_SPEED_FULL) platdata->flags |= CI_HDRC_FORCE_FULLSPEED; + platdata->itc_setting = 1; + if (of_find_property(dev->of_node, "itc-setting", NULL)) { + ret = of_property_read_u32(dev->of_node, "itc-setting", + &platdata->itc_setting); + if (ret) { + dev_err(dev, + "failed to get itc-setting\n"); + return ret; + } + } + return 0; } diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index d1e1285..1c5d776 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -36,6 +36,8 @@ struct ci_hdrc_platform_data { void (*notify_event) (struct ci_hdrc *ci, unsigned event); struct regulator *reg_vbus; bool tpl_support; + /* interrupt threshold setting */ + u32 itc_setting; }; /* Default offset of capability registers */ -- cgit v0.10.2 From 1311d6e3ea3316e9d2383219a36353ad335f6932 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 14 Jul 2015 15:43:02 +0800 Subject: usb: chipidea: host: delete the redundancy ci_hdrc struct The struct ci_hdrc is the drvdata for hcd device, so we don't need to introduce extra ci_hdrc structure for ehci. Signed-off-by: Peter Chen diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 4455431..ee38c5d 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -37,15 +37,14 @@ static int (*orig_bus_suspend)(struct usb_hcd *hcd); struct ehci_ci_priv { struct regulator *reg_vbus; - struct ci_hdrc *ci; }; static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct ehci_ci_priv *priv = (struct ehci_ci_priv *)ehci->priv; - struct ci_hdrc *ci = priv->ci; struct device *dev = hcd->self.controller; + struct ci_hdrc *ci = dev_get_drvdata(dev); int ret = 0; int port = HCS_N_PORTS(ehci->hcs_params); @@ -123,7 +122,6 @@ static int host_start(struct ci_hdrc *ci) priv = (struct ehci_ci_priv *)ehci->priv; priv->reg_vbus = NULL; - priv->ci = ci; if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) { if (ci->platdata->flags & CI_HDRC_TURN_VBUS_EARLY_ON) { -- cgit v0.10.2 From 158ec071fb5243e5c49259d2dbc4c8dbaed24c47 Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Sat, 27 Jun 2015 00:34:48 -0400 Subject: usb:chipidea:Make the function hw_alloc_repmap have a return type of void This makes the function hw_alloc_repmap be declared to have a return type of void now due to this particular function never returning a error code to its caller due to this function always running successfully to completion nor it's caller putting the return value into a variable in order to check if a error code is passed from the function hw_alloc_repmap when calling this function. Signed-off-by: Nicholas Krause diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 845d0d7..f620e35 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -120,7 +120,7 @@ static const u8 ci_regs_lpm[] = { [OP_ENDPTCTRL] = 0xECU, }; -static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm) +static void hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm) { int i; @@ -136,7 +136,6 @@ static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm) ? ci_regs_lpm[OP_ENDPTCTRL] : ci_regs_nolpm[OP_ENDPTCTRL]); - return 0; } static enum ci_revision ci_get_revision(struct ci_hdrc *ci) -- cgit v0.10.2 From bc24937943d9f71a1e32b5dc4e2f0ef8fcc07b64 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Wed, 29 Jul 2015 13:11:11 +0800 Subject: usb: chipidea: debug: add runtime pm for register access Add runtime pm operations for registers access to avoid system hang. Signed-off-by: Li Jun diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index 5b7061a..64b6a47 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -66,9 +66,11 @@ static int ci_port_test_show(struct seq_file *s, void *data) unsigned long flags; unsigned mode; + pm_runtime_get_sync(ci->dev); spin_lock_irqsave(&ci->lock, flags); mode = hw_port_test_get(ci); spin_unlock_irqrestore(&ci->lock, flags); + pm_runtime_put_sync(ci->dev); seq_printf(s, "mode = %u\n", mode); @@ -98,9 +100,11 @@ static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf, if (sscanf(buf, "%u", &mode) != 1) return -EINVAL; + pm_runtime_get_sync(ci->dev); spin_lock_irqsave(&ci->lock, flags); ret = hw_port_test_set(ci, mode); spin_unlock_irqrestore(&ci->lock, flags); + pm_runtime_put_sync(ci->dev); return ret ? ret : count; } @@ -316,8 +320,10 @@ static ssize_t ci_role_write(struct file *file, const char __user *ubuf, if (role == CI_ROLE_END || role == ci->role) return -EINVAL; + pm_runtime_get_sync(ci->dev); ci_role_stop(ci); ret = ci_role_start(ci, role); + pm_runtime_put_sync(ci->dev); return ret ? ret : count; } -- cgit v0.10.2 From ef12da914ed696745b495bea22aea137e88cffb6 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Thu, 6 Aug 2015 15:09:54 +0200 Subject: usb: chipidea: imx: properly check for usbmisc If usbmisc hasn't probed yet, defer the probe. It's not enough to check if the platform device for the OF node of the usbmisc has been registered, but it also needs to have been probed already before we can call imx_usbmisc_init(). This can happen if the order in which devices are probed change due to async probing or on-demand probing of dependencies. Signed-off-by: Tomeu Vizoso diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 6d2a85a..9ccae5a 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -104,7 +104,7 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) misc_pdev = of_find_device_by_node(args.np); of_node_put(args.np); - if (!misc_pdev) + if (!misc_pdev || !platform_get_drvdata(misc_pdev)) return ERR_PTR(-EPROBE_DEFER); data->dev = &misc_pdev->dev; -- cgit v0.10.2 From 11a27098e884b8eb797f1579ebc51cb0e0510cc3 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 5 Aug 2015 10:16:19 +0800 Subject: usb: chipidea: host: override hcd reset API The system configuration API should be called before the controller run, otherwise, undefined results may occur. So, we override hcd reset API, and add system configuration API after controller reset. Cc: Li Jun Cc: Alan Stern Acked-by: Alan Stern Signed-off-by: Peter Chen diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index ee38c5d..3d24304 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -77,9 +77,25 @@ static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable) return 0; }; +static int ehci_ci_reset(struct usb_hcd *hcd) +{ + struct device *dev = hcd->self.controller; + struct ci_hdrc *ci = dev_get_drvdata(dev); + int ret; + + ret = ehci_setup(hcd); + if (ret) + return ret; + + ci_platform_configure(ci); + + return ret; +} + static const struct ehci_driver_overrides ehci_ci_overrides = { .extra_priv_size = sizeof(struct ehci_ci_priv), .port_power = ehci_ci_portpower, + .reset = ehci_ci_reset, }; static irqreturn_t host_irq(struct ci_hdrc *ci) @@ -151,8 +167,6 @@ static int host_start(struct ci_hdrc *ci) } } - ci_platform_configure(ci); - return ret; disable_reg: -- cgit v0.10.2 From a4da4f12b4a7e7072753ebae9b2ccd72b89c3392 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 28 Jul 2015 10:08:32 +0800 Subject: usb: chipidea: udc: zero-length packet is only needed for TX The zero-length packet is the sendor tells the receiver that there is no more data, so it is only needed at the TX side. Signed-off-by: Peter Chen diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 27cbd1c..aca7a97 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -445,7 +445,7 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq) rest -= count; } - if (hwreq->req.zero && hwreq->req.length + if (hwreq->req.zero && hwreq->req.length && hwep->dir == TX && (hwreq->req.length % hwep->ep.maxpacket == 0)) add_td_to_list(hwep, hwreq, 0); -- cgit v0.10.2 From 8022d3d51c6fb14736e26fd13caca91a38e07580 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 30 Oct 2014 09:15:15 +0800 Subject: usb: chipidea: define stream mode disable for both roles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The system bus and chipidea IP have different limitations for both host and device mode. For example, with below errata, we need to enable SDIS(Stream Disable Mode) at host mode. But we don't want it for device mode at the same system. TAR 9000378958 Title: Non-Double Word Aligned Buffer Address Sometimes Causes Host to Hang on OUT Retry Impacted Configuration: Host mode, all transfer types Description: The host core operating in streaming mode may under run while sending the data packet of an OUT transaction. This under run can occur if there are unexpected system delays in fetching the remaining packet data from memory. The host forces a bad CRC on the packet, the device detects the error and discards the packet. The host then retries a Bulk, Interrupt, or Control transfer if an under run occurs according to the USB specification. During simulations, it was found that the host does not issue the retry of the failed bulk OUT. It does not issue any other transactions except SOF packets that have incorrect frame numbers. The second failure mode occurs if the under run occurs on an ISO OUT transaction and the next ISO transaction is a zero byte packet. The host does not issue any transactions (including SOFs). The device detects a Suspend condition, reverts to full speed, and waits for resume signaling. A third failure mode occurs when the host under runs on an ISO OUT and the next ISO in the schedule is an ISO OUT with two max packets of 1024 bytes each. The host should issue MDATA for the first OUT followed by DATA1 for the second. However, it drops the MDATA transaction, and issues the DATA1 transaction. The system impact of this bug is the same regardless of the failure mode observed. The host core hangs, the ehci_ctrl state machine waits for the protocol engine to send the completion status for the corrupted transaction, which never occurs. No indication is sent to the host controller driver, no register bits change and no interrupts occur. Eventually the requesting application times out. Detailed internal behavior: The EHCI control state machine (ehci_ctrl) in the DMA block is responsible for parsing the schedules and initiating all transactions. The ehci_ctrl state machine passes the transaction details to the protocol block by writing the transaction information in to the TxFIFO. It then asserts the pe_hst_run_pkt signal to inform the host protocol state machine (pe_hst_state) that there is a packet in the TxFIFO. A tag of 0x0 indicates a start of packet with the data providing the following information: 35:32 Tag 31:30 Reserved 29:23 Endpoint (lowest 4 bits) 22:16 Address 15:10 Reserved 9:8 Endpoint speed 7:6 Endpoint type 5:6 Data Toggle 3:0 PID The pe_hst_state reads the packet information and constructs the packet and issues it to the PHY interface. The ehci_ctrl state machine writes the start transaction information in to the TxFIFO as 0x03002910c for the OUT packet that had the under run error. However, it writes 0xC3002910C for the retry of the Out transaction, which is incorrect. The pe_hst_state enters a bus timeout state after sending the bad CRC for the packet that under ran. It then purges any data that was back filled in to the TxFIFO for the packet that under ran. The pe_hst_state machine stops purging the TxFIFO when it is empty or if it reads a location that has a tag of 0x0, indicating a start of packet command. The pe_hst_state reads 0xC3002910C and discards it as it does not decode to a start of packet command. It continues to purge the OUT data that has been pre-buffered for the OUT retry . The pe_hst_state detects the hst_packet_run signal and attempts to read the PID and address information from the TxFIFO. This location has packet data and so does not decode to a valid PID and so falls through to the PE_HST_SOF_LOAD state where the frame_num_counter is updated. The frame_num_counter is updated with the data in the TxFIFO. In this case, the data is incorrect as the ehci_ctrl state machine did not initiate the load. The hst_pe_state machine detects the SOF request signal and sends an SOF with the bad frame number. Meanwhile, the ehci_ctrl state machine waits indefinitely in the run_pkt state waiting for the completion status from pe_hst_state machine, which will never happen. The ISO failure case is similar except that there is no retry for ISO. The ehci_ctrl state machine moves to the next transfer in the periodic schedule. If the under run occurs on the last entry of the periodic list then it moves to the Async schedule. In the case of ISO OUT simulations, the next ISO is a zero byte OUT and again the start of packet command gets corrupted. The TxFIFO is empty when the hst_pe_state attempts to read the Address and PID information as the transaction is a zero byte packet. This results in the hst_pe_state machine staying in the GET_PID state, which means that it does not issue any transactions (including SOFs). The device detects a Suspend condition and reverts to full speed mode and waits for a Resume or Reset signal. The EHCI specification allows a Non-DoubleWord (32 bits) offset to be used as a current offset for Buffer Pointer Page 0 of the qTD. In Non-DoubleWord aligned cases, the core reads the packet data from the AHB memory, performs the alignment operation before writing it in to the TxFIFO as a 32 bit data word. An End Of Packet tag (EOP) is written to the TxFIFO after all the packet data has been written in to the TxFIFO. The alignment function is reset to Idle by the EOP tag. The corruption of the start of packet command arises because the packet buffer for the OUT transaction that under ran is not aligned to a DoubleWord, and hence no EOP tag is written to the TxFIFO. The alignment function is still active when the start packet information is written in to the TxFIFO for the retry of the bulk packet or for the next transaction in the case of an under run on an ISO. This results in the corruption of the start tag and the transaction information. Click for waveform showing the command 0x 0000300291 being written in to the TX FIFO for the Out that under ran. Click for waveform showing the command 0xC3002910C written to the TxFIFO instead of 0x 0000300291 Versions affected: Versions 2.10a and previous versions How discovered: Customer simulation Workaround: 1- The EHCI specification allows a non-DoubleWord offset to be used as a current offset for Buffer Pointer Page 0 of the qTD. However, if a DoubleWord offset is used then this issue does not arise. 2- Use non streaming mode to eliminate under runs. Resolution: The fix involves changes to the traffic state machine in the vusb_hs_dma_traf block. The ehci_ctrl state machine updates the context information by encoding the transaction results on the hst_op_context_update signals at the end of a transaction. The signal hst_op_context_update is added to the traffic state machine, and the tx_fifo_under_ran_r signal is generated if the transaction results in an under run error. Click for waveform The traffic state machine then traverses to the do_eop states if the tx_fifo_under_ran error is asserted. Thus an EOP tag is written in to the TxFIFO as shown in this waveform . The EOP tag resets the align state machine to the Idle state ensuring that the next command written by the echi_ctrl state machine does not get corrupted. File(s) modified: RTL code fixed: ….. Method of reproducing: This failure cannot be reproduced in the current test bench. Date Found: March 2010 Date Fixed: June 2010 Update information: Added the RTL code fix Signed-off-by: Peter Chen diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index f620e35..7a2c217 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -64,6 +64,7 @@ #include #include #include +#include #include "ci.h" #include "udc.h" @@ -412,7 +413,17 @@ static int ci_usb_phy_init(struct ci_hdrc *ci) */ void ci_platform_configure(struct ci_hdrc *ci) { - if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING) + bool is_device_mode, is_host_mode; + + is_device_mode = hw_read(ci, OP_USBMODE, USBMODE_CM) == USBMODE_CM_DC; + is_host_mode = hw_read(ci, OP_USBMODE, USBMODE_CM) == USBMODE_CM_HC; + + if (is_device_mode && + (ci->platdata->flags & CI_HDRC_DISABLE_DEVICE_STREAMING)) + hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); + + if (is_host_mode && + (ci->platdata->flags & CI_HDRC_DISABLE_HOST_STREAMING)) hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) { diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 1c5d776..4d34a86 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -19,8 +19,11 @@ struct ci_hdrc_platform_data { enum usb_phy_interface phy_mode; unsigned long flags; #define CI_HDRC_REGS_SHARED BIT(0) +#define CI_HDRC_DISABLE_DEVICE_STREAMING BIT(1) #define CI_HDRC_SUPPORTS_RUNTIME_PM BIT(2) -#define CI_HDRC_DISABLE_STREAMING BIT(3) +#define CI_HDRC_DISABLE_HOST_STREAMING BIT(3) +#define CI_HDRC_DISABLE_STREAMING (CI_HDRC_DISABLE_DEVICE_STREAMING | \ + CI_HDRC_DISABLE_HOST_STREAMING) /* * Only set it when DCCPARAMS.DC==1 and DCCPARAMS.HC==1, * but otg is not supported (no register otgsc). -- cgit v0.10.2 From 0ef877a408ebaa4d65ab1f886100dab198bf673e Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 30 Oct 2014 11:10:04 +0800 Subject: usb: chipidea: imx: add stream mode enable for device mode at imx6sl/imx6sx Stream mode enable is known for better performance, this stream mode enable patch has been passed with stress tests at device mode for imx6sl and imx6sx, and no issue is found. Signed-off-by: Peter Chen diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 9ccae5a..867e9f3 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -29,26 +29,31 @@ struct ci_hdrc_imx_platform_flag { }; static const struct ci_hdrc_imx_platform_flag imx27_usb_data = { + CI_HDRC_DISABLE_STREAMING, }; static const struct ci_hdrc_imx_platform_flag imx28_usb_data = { .flags = CI_HDRC_IMX28_WRITE_FIX | - CI_HDRC_TURN_VBUS_EARLY_ON, + CI_HDRC_TURN_VBUS_EARLY_ON | + CI_HDRC_DISABLE_STREAMING, }; static const struct ci_hdrc_imx_platform_flag imx6q_usb_data = { .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | - CI_HDRC_TURN_VBUS_EARLY_ON, + CI_HDRC_TURN_VBUS_EARLY_ON | + CI_HDRC_DISABLE_STREAMING, }; static const struct ci_hdrc_imx_platform_flag imx6sl_usb_data = { .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | - CI_HDRC_TURN_VBUS_EARLY_ON, + CI_HDRC_TURN_VBUS_EARLY_ON | + CI_HDRC_DISABLE_HOST_STREAMING, }; static const struct ci_hdrc_imx_platform_flag imx6sx_usb_data = { .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | - CI_HDRC_TURN_VBUS_EARLY_ON, + CI_HDRC_TURN_VBUS_EARLY_ON | + CI_HDRC_DISABLE_HOST_STREAMING, }; static const struct of_device_id ci_hdrc_imx_dt_ids[] = { @@ -126,8 +131,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) struct ci_hdrc_platform_data pdata = { .name = dev_name(&pdev->dev), .capoffset = DEF_CAPOFFSET, - .flags = CI_HDRC_DISABLE_STREAMING | - CI_HDRC_SET_NON_ZERO_TTHA, + .flags = CI_HDRC_SET_NON_ZERO_TTHA, }; int ret; const struct of_device_id *of_id = -- cgit v0.10.2 From c6fba7b750efe64a69dd83e0ff7249abd0e783aa Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 28 Jul 2015 13:33:15 +0800 Subject: Doc: usb: ci-hdrc-usb2: add ahb-burst-config for binding doc It is used to change ahb burst configuration for platforms, it is vendor specific. Signed-off-by: Peter Chen diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt index 4159c8c..d52a747 100644 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt @@ -32,6 +32,11 @@ Optional properties: - external-vbus-divider: (FSL only) enables off-chip resistor divider for Vbus - itc-setting: interrupt threshold control register control, the setting should be aligned with ITC bits at register USBCMD. +- ahb-burst-config: it is vendor dependent, the required value should be + aligned with AHBBRST at SBUSCFG, the range is from 0x0 to 0x7. This + property is used to change AHB burst configuration, check the chipidea + spec for meaning of each value. If this property is not existed, it + will use the reset value. Example: @@ -44,4 +49,6 @@ Example: phy-names = "usb-phy"; vbus-supply = <®_usb0_vbus>; gadget-itc-setting = <0x4>; /* 4 micro-frames */ + /* Incremental burst of unspecified length */ + ahb-burst-config = <0x0>; }; -- cgit v0.10.2 From 65668718f2c5b76d5f4513564a3c56672bb07892 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 17 Mar 2015 14:21:00 +0800 Subject: usb: chipidea: add ahb burst configuration interface The users can change it through dts or platform data if they want to change the default value. Signed-off-by: Peter Chen diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h index 831a8f6..462ad02 100644 --- a/drivers/usb/chipidea/bits.h +++ b/drivers/usb/chipidea/bits.h @@ -25,6 +25,9 @@ #define VERSION (0xF << 25) #define CIVERSION (0x7 << 29) +/* SBUSCFG */ +#define AHBBRST_MASK 0x7 + /* HCCPARAMS */ #define HCCPARAMS_LEN BIT(17) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 7a2c217..ce04897 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -438,6 +438,9 @@ void ci_platform_configure(struct ci_hdrc *ci) hw_write(ci, OP_USBCMD, 0xff0000, ci->platdata->itc_setting << 16); + if (ci->platdata->flags & CI_HDRC_OVERRIDE_AHB_BURST) + hw_write_id_reg(ci, ID_SBUSCFG, AHBBRST_MASK, + ci->platdata->ahb_burst_config); } /** @@ -633,6 +636,17 @@ static int ci_get_platdata(struct device *dev, } } + if (of_find_property(dev->of_node, "ahb-burst-config", NULL)) { + ret = of_property_read_u32(dev->of_node, "ahb-burst-config", + &platdata->ahb_burst_config); + if (ret) { + dev_err(dev, + "failed to get ahb-burst-config\n"); + return ret; + } + platdata->flags |= CI_HDRC_OVERRIDE_AHB_BURST; + } + return 0; } diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 4d34a86..cd7fcad 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -33,6 +33,7 @@ struct ci_hdrc_platform_data { #define CI_HDRC_FORCE_FULLSPEED BIT(6) #define CI_HDRC_TURN_VBUS_EARLY_ON BIT(7) #define CI_HDRC_SET_NON_ZERO_TTHA BIT(8) +#define CI_HDRC_OVERRIDE_AHB_BURST BIT(9) enum usb_dr_mode dr_mode; #define CI_HDRC_CONTROLLER_RESET_EVENT 0 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 @@ -41,6 +42,7 @@ struct ci_hdrc_platform_data { bool tpl_support; /* interrupt threshold setting */ u32 itc_setting; + u32 ahb_burst_config; }; /* Default offset of capability registers */ -- cgit v0.10.2 From ed6e5eb50f7f07561d6a40f18bc11484736098db Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 5 Nov 2014 14:58:32 +0800 Subject: usb: chipidea: usbmisc_imx: add non-burst setting for imx6 With this setting and AHBBRST at SBUSCFG as "Incremental burst of unspecified length", each non-burst size can be taken as single transfer. It is benefit for non-burst size transfer. Signed-off-by: Peter Chen diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index 3cefd49..5ddab30 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -54,6 +54,7 @@ #define MX53_USB_PHYCTRL1_PLLDIV_MASK 0x3 #define MX53_USB_PLL_DIV_24_MHZ 0x01 +#define MX6_BM_NON_BURST_SETTING BIT(1) #define MX6_BM_OVER_CUR_DIS BIT(7) #define MX6_BM_WAKEUP_ENABLE BIT(10) #define MX6_BM_ID_WAKEUP BIT(16) @@ -255,14 +256,21 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) if (data->index > 3) return -EINVAL; + spin_lock_irqsave(&usbmisc->lock, flags); + if (data->disable_oc) { - spin_lock_irqsave(&usbmisc->lock, flags); reg = readl(usbmisc->base + data->index * 4); writel(reg | MX6_BM_OVER_CUR_DIS, usbmisc->base + data->index * 4); - spin_unlock_irqrestore(&usbmisc->lock, flags); } + /* SoC non-burst setting */ + reg = readl(usbmisc->base + data->index * 4); + writel(reg | MX6_BM_NON_BURST_SETTING, + usbmisc->base + data->index * 4); + + spin_unlock_irqrestore(&usbmisc->lock, flags); + usbmisc_imx6q_set_wakeup(data, false); return 0; -- cgit v0.10.2 From bd6e9d115df7fc6f11f3021c6fc05e3eaeb04a32 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Fri, 7 Aug 2015 15:08:02 +0800 Subject: Doc: usb: ci-hdrc-usb2: add tx(rx)-burst-config-dword for binding doc It is used to override the default setting for burst size, changing burst size takes effect only when the SBUSCFG.AHBBRST = 0. Signed-off-by: Peter Chen diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt index d52a747..d71ef07 100644 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt @@ -37,6 +37,14 @@ Optional properties: property is used to change AHB burst configuration, check the chipidea spec for meaning of each value. If this property is not existed, it will use the reset value. +- tx-burst-size-dword: it is vendor dependent, the tx burst size in dword + (4 bytes), This register represents the maximum length of a the burst + in 32-bit words while moving data from system memory to the USB + bus, changing this value takes effect only the SBUSCFG.AHBBRST is 0. +- rx-burst-size-dword: it is vendor dependent, the rx burst size in dword + (4 bytes), This register represents the maximum length of a the burst + in 32-bit words while moving data from the USB bus to system memory, + changing this value takes effect only the SBUSCFG.AHBBRST is 0. Example: @@ -51,4 +59,6 @@ Example: gadget-itc-setting = <0x4>; /* 4 micro-frames */ /* Incremental burst of unspecified length */ ahb-burst-config = <0x0>; + tx-burst-size-dword = <0x10>; /* 64 bytes */ + rx-burst-size-dword = <0x10>; }; -- cgit v0.10.2 From 96625eadca1bb8832fb502f0899a543695f1ba35 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 17 Mar 2015 17:32:45 +0800 Subject: usb: chipidea: add tx/rx burst size configuration interface The user can adjust it through dts or platform data Signed-off-by: Peter Chen diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h index 462ad02..e462f55 100644 --- a/drivers/usb/chipidea/bits.h +++ b/drivers/usb/chipidea/bits.h @@ -61,6 +61,10 @@ /* Set non-zero value for internal TT Hub address representation */ #define TTCTRL_TTHA (0x7fUL << 24) +/* BURSTSIZE */ +#define RX_BURST_MASK 0xff +#define TX_BURST_MASK 0xff00 + /* PORTSC */ #define PORTSC_CCS BIT(0) #define PORTSC_CSC BIT(1) diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 1320a4d..62f2a7b 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -51,6 +51,7 @@ enum ci_hw_regs { OP_DEVICEADDR, OP_ENDPTLISTADDR, OP_TTCTRL, + OP_BURSTSIZE, OP_PORTSC, OP_DEVLC, OP_OTGSC, diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index ce04897..50cd23b 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -86,6 +86,7 @@ static const u8 ci_regs_nolpm[] = { [OP_DEVICEADDR] = 0x14U, [OP_ENDPTLISTADDR] = 0x18U, [OP_TTCTRL] = 0x1CU, + [OP_BURSTSIZE] = 0x20U, [OP_PORTSC] = 0x44U, [OP_DEVLC] = 0x84U, [OP_OTGSC] = 0x64U, @@ -109,6 +110,7 @@ static const u8 ci_regs_lpm[] = { [OP_DEVICEADDR] = 0x14U, [OP_ENDPTLISTADDR] = 0x18U, [OP_TTCTRL] = 0x1CU, + [OP_BURSTSIZE] = 0x20U, [OP_PORTSC] = 0x44U, [OP_DEVLC] = 0x84U, [OP_OTGSC] = 0xC4U, @@ -441,6 +443,17 @@ void ci_platform_configure(struct ci_hdrc *ci) if (ci->platdata->flags & CI_HDRC_OVERRIDE_AHB_BURST) hw_write_id_reg(ci, ID_SBUSCFG, AHBBRST_MASK, ci->platdata->ahb_burst_config); + + /* override burst size, take effect only when ahb_burst_config is 0 */ + if (!hw_read_id_reg(ci, ID_SBUSCFG, AHBBRST_MASK)) { + if (ci->platdata->flags & CI_HDRC_OVERRIDE_TX_BURST) + hw_write(ci, OP_BURSTSIZE, TX_BURST_MASK, + ci->platdata->tx_burst_size << __ffs(TX_BURST_MASK)); + + if (ci->platdata->flags & CI_HDRC_OVERRIDE_RX_BURST) + hw_write(ci, OP_BURSTSIZE, RX_BURST_MASK, + ci->platdata->rx_burst_size); + } } /** @@ -647,6 +660,28 @@ static int ci_get_platdata(struct device *dev, platdata->flags |= CI_HDRC_OVERRIDE_AHB_BURST; } + if (of_find_property(dev->of_node, "tx-burst-size-dword", NULL)) { + ret = of_property_read_u32(dev->of_node, "tx-burst-size-dword", + &platdata->tx_burst_size); + if (ret) { + dev_err(dev, + "failed to get tx-burst-size-dword\n"); + return ret; + } + platdata->flags |= CI_HDRC_OVERRIDE_TX_BURST; + } + + if (of_find_property(dev->of_node, "rx-burst-size-dword", NULL)) { + ret = of_property_read_u32(dev->of_node, "rx-burst-size-dword", + &platdata->rx_burst_size); + if (ret) { + dev_err(dev, + "failed to get rx-burst-size-dword\n"); + return ret; + } + platdata->flags |= CI_HDRC_OVERRIDE_RX_BURST; + } + return 0; } diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index cd7fcad..575eaf0 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -34,6 +34,8 @@ struct ci_hdrc_platform_data { #define CI_HDRC_TURN_VBUS_EARLY_ON BIT(7) #define CI_HDRC_SET_NON_ZERO_TTHA BIT(8) #define CI_HDRC_OVERRIDE_AHB_BURST BIT(9) +#define CI_HDRC_OVERRIDE_TX_BURST BIT(10) +#define CI_HDRC_OVERRIDE_RX_BURST BIT(11) enum usb_dr_mode dr_mode; #define CI_HDRC_CONTROLLER_RESET_EVENT 0 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 @@ -43,6 +45,8 @@ struct ci_hdrc_platform_data { /* interrupt threshold setting */ u32 itc_setting; u32 ahb_burst_config; + u32 tx_burst_size; + u32 rx_burst_size; }; /* Default offset of capability registers */ -- cgit v0.10.2 From f8786a91548df6930643a052e40e5c0b7a8403a5 Mon Sep 17 00:00:00 2001 From: Nikhil Badola Date: Thu, 6 Aug 2015 14:51:27 +0530 Subject: drivers: usb: fsl: Workaround for USB erratum-A005275 Incoming packets in high speed are randomly corrupted by h/w resulting in multiple errors. This workaround makes FS as default mode in all affected socs by disabling HS chirp signalling.This errata does not affect FS and LS mode. Forces all HS devices to connect in FS mode for all socs affected by this erratum: P3041 and P2041 rev 1.0 and 1.1 P5020 and P5010 rev 1.0 and 2.0 P5040, P1010 and T4240 rev 1.0 Signed-off-by: Ramneek Mehresh Signed-off-by: Nikhil Badola Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 202dafb..3b6eb21 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -278,6 +278,10 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci) out_be32(non_ehci + FSL_SOC_USB_SNOOP2, 0x80000000 | SNOOP_SIZE_2GB); } + /* Deal with USB erratum A-005275 */ + if (pdata->has_fsl_erratum_a005275 == 1) + ehci->has_fsl_hs_errata = 1; + if ((pdata->operating_mode == FSL_USB2_DR_HOST) || (pdata->operating_mode == FSL_USB2_DR_OTG)) if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0)) diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 22abb68..086a711 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -1221,6 +1221,13 @@ int ehci_hub_control( */ ehci->reset_done [wIndex] = jiffies + msecs_to_jiffies (50); + + /* + * Force full-speed connect for FSL high-speed + * erratum; disable HS Chirp by setting PFSC bit + */ + if (ehci_has_fsl_hs_errata(ehci)) + temp |= (1 << PORTSC_FSL_PFSC); } ehci_writel(ehci, temp, status_reg); break; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index f700157..46f62e4 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -215,6 +215,7 @@ struct ehci_hcd { /* one per controller */ /* SILICON QUIRKS */ unsigned no_selective_suspend:1; unsigned has_fsl_port_bug:1; /* FreeScale */ + unsigned has_fsl_hs_errata:1; /* Freescale HS quirk */ unsigned big_endian_mmio:1; unsigned big_endian_desc:1; unsigned big_endian_capbase:1; @@ -686,6 +687,17 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) #define ehci_has_fsl_portno_bug(e) (0) #endif +#define PORTSC_FSL_PFSC 24 /* Port Force Full-Speed Connect */ + +#if defined(CONFIG_PPC_85xx) +/* Some Freescale processors have an erratum (USB A-005275) in which + * incoming packets get corrupted in HS mode + */ +#define ehci_has_fsl_hs_errata(e) ((e)->has_fsl_hs_errata) +#else +#define ehci_has_fsl_hs_errata(e) (0) +#endif + /* * While most USB host controllers implement their registers in * little-endian format, a minority (celleb companion chip) implement diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 9f73141..534c4c5 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -221,6 +221,10 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) pdata->has_fsl_erratum_a007792 = 1; else pdata->has_fsl_erratum_a007792 = 0; + if (of_get_property(np, "fsl,usb-erratum-a005275", NULL)) + pdata->has_fsl_erratum_a005275 = 1; + else + pdata->has_fsl_erratum_a005275 = 0; /* * Determine whether phy_clk_valid needs to be checked diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index cebdbbb..f291291 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -99,6 +99,7 @@ struct fsl_usb2_platform_data { unsigned suspended:1; unsigned already_suspended:1; unsigned has_fsl_erratum_a007792:1; + unsigned has_fsl_erratum_a005275:1; unsigned check_phy_clk_valid:1; /* register save area for suspend/resume */ -- cgit v0.10.2 From 31b92d81e5d4574eb3d038642c7ba6ec66ea7db1 Mon Sep 17 00:00:00 2001 From: Kris Borer Date: Sun, 9 Aug 2015 21:48:18 -0400 Subject: usb: otg_whitelist: remove whitespace Fix one occurrence of the checkpatch error: ERROR: space prohibited before open square bracket '[' Signed-off-by: Kris Borer Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h index a6315ab..a95b0c9 100644 --- a/drivers/usb/core/otg_whitelist.h +++ b/drivers/usb/core/otg_whitelist.h @@ -16,7 +16,7 @@ * YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING! */ -static struct usb_device_id whitelist_table [] = { +static struct usb_device_id whitelist_table[] = { /* hubs are optional in OTG, but very handy ... */ { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), }, -- cgit v0.10.2 From 3290b1b818934a517a593159f39a3651dcf34518 Mon Sep 17 00:00:00 2001 From: Kris Borer Date: Mon, 10 Aug 2015 09:13:15 -0400 Subject: usb: endpoint: convert spaces to tabs Fix one occurrence of the checkpatch error: ERROR: code indent should use tabs where possible Signed-off-by: Kris Borer Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index 39a2402..101983b 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -51,7 +51,7 @@ static ssize_t wMaxPacketSize_show(struct device *dev, { struct ep_device *ep = to_ep_device(dev); return sprintf(buf, "%04x\n", - usb_endpoint_maxp(ep->desc) & 0x07ff); + usb_endpoint_maxp(ep->desc) & 0x07ff); } static DEVICE_ATTR_RO(wMaxPacketSize); -- cgit v0.10.2 From e3ec4fda072c72c8ed014b58a3a4dd54b2b454bd Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Aug 2015 16:29:33 +0200 Subject: usb: gadget: atmel: remove useless include Definitions from linux/platform_data/atmel.h are not used, remove the include. Signed-off-by: Alexandre Belloni Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 267d84f..3dfada8 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include -- cgit v0.10.2 From 088a3daeadf6f4123f54d5208b0ec7cbbfc8853f Mon Sep 17 00:00:00 2001 From: Kris Borer Date: Tue, 11 Aug 2015 11:12:45 -0400 Subject: usb: hub: remove assignment from if condition Fix one occurrence of the checkpatch.pl error: ERROR: do not use assignment in if condition The semantic patch that makes this change is: // @@ identifier i; expression E, E2, E3; statement S1, S2; binary operator b; @@ + i = E; if ( - (i = E) + i b ... && E2 && E3 ) S1 else S2 // Signed-off-by: Kris Borer Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index a0b22be..78bd0d6 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -671,8 +671,8 @@ resubmit: if (hub->quiescing) return; - if ((status = usb_submit_urb(hub->urb, GFP_ATOMIC)) != 0 - && status != -ENODEV && status != -EPERM) + status = usb_submit_urb(hub->urb, GFP_ATOMIC); + if (status != 0 && status != -ENODEV && status != -EPERM) dev_err(hub->intfdev, "resubmit --> %d\n", status); } -- cgit v0.10.2 From 484ebaedecc5ddf778a30ee1efab367cbee27030 Mon Sep 17 00:00:00 2001 From: Stefan Koch Date: Sat, 8 Aug 2015 11:32:50 +0200 Subject: usb: interface authorization: Declare authorized attribute The attribute authorized shows the authorization state for an interface. Signed-off-by: Stefan Koch Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/usb.h b/include/linux/usb.h index 447fe29..3deccab 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -178,6 +178,7 @@ struct usb_interface { unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */ unsigned needs_binding:1; /* needs delayed unbind/rebind */ unsigned resetting_device:1; /* true: bandwidth alloc after reset */ + unsigned authorized:1; /* used for interface authorization */ struct device dev; /* interface specific device info */ struct device *usb_dev; -- cgit v0.10.2 From 1d958bef45030acfc5578263e9de3bb07032b8da Mon Sep 17 00:00:00 2001 From: Stefan Koch Date: Sat, 8 Aug 2015 11:32:51 +0200 Subject: usb: interface authorization: Introduces the default interface authorization Interfaces are allowed per default. This can disabled or enabled (again) by writing 0 or 1 to /sys/bus/usb/devices/usbX/interface_authorized_default Signed-off-by: Stefan Koch Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 4d64e5c4..83df1dd 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -882,9 +882,53 @@ static ssize_t authorized_default_store(struct device *dev, } static DEVICE_ATTR_RW(authorized_default); +/* + * interface_authorized_default_show - show default authorization status + * for USB interfaces + * + * note: interface_authorized_default is the default value + * for initializing the authorized attribute of interfaces + */ +static ssize_t interface_authorized_default_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_device *usb_dev = to_usb_device(dev); + struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus); + + return sprintf(buf, "%u\n", !!HCD_INTF_AUTHORIZED(hcd)); +} + +/* + * interface_authorized_default_store - store default authorization status + * for USB interfaces + * + * note: interface_authorized_default is the default value + * for initializing the authorized attribute of interfaces + */ +static ssize_t interface_authorized_default_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_device *usb_dev = to_usb_device(dev); + struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus); + int rc = count; + bool val; + + if (strtobool(buf, &val) != 0) + return -EINVAL; + + if (val) + set_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags); + else + clear_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags); + + return rc; +} +static DEVICE_ATTR_RW(interface_authorized_default); + /* Group all the USB bus attributes */ static struct attribute *usb_bus_attrs[] = { &dev_attr_authorized_default.attr, + &dev_attr_interface_authorized_default.attr, NULL, }; @@ -2682,6 +2726,9 @@ int usb_add_hcd(struct usb_hcd *hcd, hcd->authorized_default = authorized_default; set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + /* per default all interfaces are authorized */ + set_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags); + /* HC is in reset state, but accessible. Now do the one-time init, * bottom up so that hcds can customize the root hubs before hub_wq * starts talking to them. (Note, bus id is assigned early too.) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index f368d20..3d25d89 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1807,6 +1807,7 @@ free_interfaces: intfc = cp->intf_cache[i]; intf->altsetting = intfc->altsetting; intf->num_altsetting = intfc->num_altsetting; + intf->authorized = !!HCD_INTF_AUTHORIZED(hcd); kref_get(&intfc->ref); alt = usb_altnum_to_altsetting(intf, 0); diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index d2784c1..36ce3d2 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -120,6 +120,7 @@ struct usb_hcd { #define HCD_FLAG_WAKEUP_PENDING 4 /* root hub is resuming? */ #define HCD_FLAG_RH_RUNNING 5 /* root hub is running? */ #define HCD_FLAG_DEAD 6 /* controller has died? */ +#define HCD_FLAG_INTF_AUTHORIZED 7 /* authorize interfaces? */ /* The flags can be tested using these macros; they are likely to * be slightly faster than test_bit(). @@ -131,6 +132,14 @@ struct usb_hcd { #define HCD_RH_RUNNING(hcd) ((hcd)->flags & (1U << HCD_FLAG_RH_RUNNING)) #define HCD_DEAD(hcd) ((hcd)->flags & (1U << HCD_FLAG_DEAD)) + /* + * Specifies if interfaces are authorized by default + * or they require explicit user space authorization; this bit is + * settable through /sys/class/usb_host/X/interface_authorized_default + */ +#define HCD_INTF_AUTHORIZED(hcd) \ + ((hcd)->flags & (1U << HCD_FLAG_INTF_AUTHORIZED)) + /* Flags that get set only during HCD registration or removal. */ unsigned rh_registered:1;/* is root hub registered? */ unsigned rh_pollable:1; /* may we poll the root hub? */ -- cgit v0.10.2 From de7718bd9c4d3db96991a98c2a0cb38258a04e47 Mon Sep 17 00:00:00 2001 From: Stefan Koch Date: Sat, 8 Aug 2015 11:32:52 +0200 Subject: usb: interface authorization: Control interface probing and claiming Driver probings and interface claims get rejected if an interface is not authorized. Signed-off-by: Stefan Koch Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 6b5063e..9416254 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -296,6 +296,10 @@ static int usb_probe_interface(struct device *dev) if (udev->authorized == 0) { dev_err(&intf->dev, "Device is not authorized for usage\n"); return error; + } else if (intf->authorized == 0) { + dev_err(&intf->dev, "Interface %d is not authorized for usage\n", + intf->altsetting->desc.bInterfaceNumber); + return error; } id = usb_match_dynamic_id(intf, driver); @@ -508,6 +512,10 @@ int usb_driver_claim_interface(struct usb_driver *driver, if (dev->driver) return -EBUSY; + /* reject claim if not iterface is not authorized */ + if (!iface->authorized) + return -ENODEV; + udev = interface_to_usbdev(iface); dev->driver = &driver->drvwrap.driver; -- cgit v0.10.2 From ef0909c50fe63be3f9aa09bdf4db7efaa5919be9 Mon Sep 17 00:00:00 2001 From: Stefan Koch Date: Sat, 8 Aug 2015 11:32:53 +0200 Subject: usb: interface authorization: Introduces the USB interface authorization The kernel supports the device authorization because of wireless USB. These is usable for wired USB devices, too. These new interface authorization allows to enable or disable individual interfaces instead a whole device. If a deauthorized interface will be authorized so the driver probing must be triggered manually by writing INTERFACE to /sys/bus/usb/drivers_probe Signed-off-by: Stefan Koch Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 3d25d89..c090f50 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1555,6 +1555,44 @@ static void usb_release_interface(struct device *dev) kfree(intf); } +/* + * usb_deauthorize_interface - deauthorize an USB interface + * + * @intf: USB interface structure + */ +void usb_deauthorize_interface(struct usb_interface *intf) +{ + struct device *dev = &intf->dev; + + device_lock(dev->parent); + + if (intf->authorized) { + device_lock(dev); + intf->authorized = 0; + device_unlock(dev); + + usb_forced_unbind_intf(intf); + } + + device_unlock(dev->parent); +} + +/* + * usb_authorize_interface - authorize an USB interface + * + * @intf: USB interface structure + */ +void usb_authorize_interface(struct usb_interface *intf) +{ + struct device *dev = &intf->dev; + + if (!intf->authorized) { + device_lock(dev); + intf->authorized = 1; /* authorize interface */ + device_unlock(dev); + } +} + static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) { struct usb_device *usb_dev; diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 457255a..05b5e17 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -27,6 +27,8 @@ extern void usb_release_interface_cache(struct kref *ref); extern void usb_disable_device(struct usb_device *dev, int skip_ep0); extern int usb_deauthorize_device(struct usb_device *); extern int usb_authorize_device(struct usb_device *); +extern void usb_deauthorize_interface(struct usb_interface *); +extern void usb_authorize_interface(struct usb_interface *); extern void usb_detect_quirks(struct usb_device *udev); extern void usb_detect_interface_quirks(struct usb_device *udev); extern int usb_remove_device(struct usb_device *udev); -- cgit v0.10.2 From 187b3d75bbfba45a38b5d1d3656c0f11f6f6f2d0 Mon Sep 17 00:00:00 2001 From: Stefan Koch Date: Sat, 8 Aug 2015 11:32:54 +0200 Subject: usb: interface authorization: SysFS part of USB interface authorization This introduces an attribute for each interface to authorize (1) or deauthorize (0) it: /sys/bus/usb/devices/INTERFACE/authorized Signed-off-by: Stefan Koch Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index cfc68c1..d9ec2de 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -957,6 +957,41 @@ static ssize_t supports_autosuspend_show(struct device *dev, } static DEVICE_ATTR_RO(supports_autosuspend); +/* + * interface_authorized_show - show authorization status of an USB interface + * 1 is authorized, 0 is deauthorized + */ +static ssize_t interface_authorized_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_interface *intf = to_usb_interface(dev); + + return sprintf(buf, "%u\n", intf->authorized); +} + +/* + * interface_authorized_store - authorize or deauthorize an USB interface + */ +static ssize_t interface_authorized_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + bool val; + + if (strtobool(buf, &val) != 0) + return -EINVAL; + + if (val) + usb_authorize_interface(intf); + else + usb_deauthorize_interface(intf); + + return count; +} +static struct device_attribute dev_attr_interface_authorized = + __ATTR(authorized, S_IRUGO | S_IWUSR, + interface_authorized_show, interface_authorized_store); + static struct attribute *intf_attrs[] = { &dev_attr_bInterfaceNumber.attr, &dev_attr_bAlternateSetting.attr, @@ -966,6 +1001,7 @@ static struct attribute *intf_attrs[] = { &dev_attr_bInterfaceProtocol.attr, &dev_attr_modalias.attr, &dev_attr_supports_autosuspend.attr, + &dev_attr_interface_authorized.attr, NULL, }; static struct attribute_group intf_attr_grp = { -- cgit v0.10.2 From 6ef2bf71764708f7c58ee9300acd8df05dbaa06f Mon Sep 17 00:00:00 2001 From: Stefan Koch Date: Sat, 8 Aug 2015 11:32:55 +0200 Subject: usb: interface authorization: Documentation part This part adds the documentation for the interface authorization. Signed-off-by: Stefan Koch Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index 864637f..5c6c264 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -1,3 +1,25 @@ +What: /sys/bus/usb/devices/INTERFACE/authorized +Date: June 2015 +KernelVersion: 4.2 +Description: + This allows to authorize (1) or deauthorize (0) + individual interfaces instead a whole device + in contrast to the device authorization. + If a deauthorized interface will be authorized + so the driver probing must be triggered manually + by writing INTERFACE to /sys/bus/usb/drivers_probe + This allows to avoid side-effects with drivers + that need multiple interfaces. + A deauthorized interface cannot be probed or claimed. + +What: /sys/bus/usb/devices/usbX/interface_authorized_default +Date: June 2015 +KernelVersion: 4.2 +Description: + This is used as default value that determines + if interfaces would authorized per default. + The value can be 1 or 0. It is per default 1. + What: /sys/bus/usb/device/.../authorized Date: July 2008 KernelVersion: 2.6.26 diff --git a/Documentation/usb/authorization.txt b/Documentation/usb/authorization.txt index c069b68..020cec5 100644 --- a/Documentation/usb/authorization.txt +++ b/Documentation/usb/authorization.txt @@ -3,6 +3,9 @@ Authorizing (or not) your USB devices to connect to the system (C) 2007 Inaky Perez-Gonzalez Intel Corporation +Interface authorization part: + (C) 2015 Stefan Koch SUSE LLC + This feature allows you to control if a USB device can be used (or not) in a system. This feature will allow you to implement a lock-down of USB devices, fully controlled by user space. @@ -90,3 +93,34 @@ etc, but you get the idea. Anybody with access to a device gadget kit can fake descriptors and device info. Don't trust that. You are welcome. + +Interface authorization +----------------------- +There is a similar approach to allow or deny specific USB interfaces. +That allows to block only a subset of an USB device. + +Authorize an interface: +$ echo 1 > /sys/bus/usb/devices/INTERFACE/authorized + +Deauthorize an interface: +$ echo 0 > /sys/bus/usb/devices/INTERFACE/authorized + +The default value for new interfaces +on a particular USB bus can be changed, too. + +Allow interfaces per default: +$ echo 1 > /sys/bus/usb/devices/usbX/interface_authorized_default + +Deny interfaces per default: +$ echo 0 > /sys/bus/usb/devices/usbX/interface_authorized_default + +Per default the interface_authorized_default bit is 1. +So all interfaces would authorized per default. + +Note: +If a deauthorized interface will be authorized so the driver probing must +be triggered manually by writing INTERFACE to /sys/bus/usb/drivers_probe + +For drivers that need multiple interfaces all needed interfaces should be +authroized first. After that the drivers should be probed. +This avoids side effects. -- cgit v0.10.2 From 3cf1fc80655d3af7083ea4b3615e5f8532543be7 Mon Sep 17 00:00:00 2001 From: Stefan Koch Date: Sat, 8 Aug 2015 11:32:56 +0200 Subject: usb: interface authorization: Use a flag for the default device authorization With this patch a flag instead of a variable is used for the default device authorization. Signed-off-by: Stefan Koch Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 83df1dd..86b3d11 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -854,10 +854,10 @@ static ssize_t authorized_default_show(struct device *dev, { struct usb_device *rh_usb_dev = to_usb_device(dev); struct usb_bus *usb_bus = rh_usb_dev->bus; - struct usb_hcd *usb_hcd; + struct usb_hcd *hcd; - usb_hcd = bus_to_hcd(usb_bus); - return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default); + hcd = bus_to_hcd(usb_bus); + return snprintf(buf, PAGE_SIZE, "%u\n", !!HCD_DEV_AUTHORIZED(hcd)); } static ssize_t authorized_default_store(struct device *dev, @@ -868,12 +868,16 @@ static ssize_t authorized_default_store(struct device *dev, unsigned val; struct usb_device *rh_usb_dev = to_usb_device(dev); struct usb_bus *usb_bus = rh_usb_dev->bus; - struct usb_hcd *usb_hcd; + struct usb_hcd *hcd; - usb_hcd = bus_to_hcd(usb_bus); + hcd = bus_to_hcd(usb_bus); result = sscanf(buf, "%u\n", &val); if (result == 1) { - usb_hcd->authorized_default = val ? 1 : 0; + if (val) + set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); + else + clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); + result = size; } else { result = -EINVAL; @@ -2720,10 +2724,17 @@ int usb_add_hcd(struct usb_hcd *hcd, dev_info(hcd->self.controller, "%s\n", hcd->product_desc); /* Keep old behaviour if authorized_default is not in [0, 1]. */ - if (authorized_default < 0 || authorized_default > 1) - hcd->authorized_default = hcd->wireless ? 0 : 1; - else - hcd->authorized_default = authorized_default; + if (authorized_default < 0 || authorized_default > 1) { + if (hcd->wireless) + clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); + else + set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); + } else { + if (authorized_default) + set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); + else + clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); + } set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); /* per default all interfaces are authorized */ diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 8d5b2f4..f8bbd0b 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -510,7 +510,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, if (root_hub) /* Root hub always ok [and always wired] */ dev->authorized = 1; else { - dev->authorized = usb_hcd->authorized_default; + dev->authorized = !!HCD_DEV_AUTHORIZED(usb_hcd); dev->wusb = usb_bus_is_wusb(bus) ? 1 : 0; } return dev; diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 36ce3d2..4d14727 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -58,12 +58,6 @@ * * Since "struct usb_bus" is so thin, you can't share much code in it. * This framework is a layer over that, and should be more sharable. - * - * @authorized_default: Specifies if new devices are authorized to - * connect by default or they require explicit - * user space authorization; this bit is settable - * through /sys/class/usb_host/X/authorized_default. - * For the rest is RO, so we don't lock to r/w it. */ /*-------------------------------------------------------------------------*/ @@ -121,6 +115,7 @@ struct usb_hcd { #define HCD_FLAG_RH_RUNNING 5 /* root hub is running? */ #define HCD_FLAG_DEAD 6 /* controller has died? */ #define HCD_FLAG_INTF_AUTHORIZED 7 /* authorize interfaces? */ +#define HCD_FLAG_DEV_AUTHORIZED 8 /* authorize devices? */ /* The flags can be tested using these macros; they are likely to * be slightly faster than test_bit(). @@ -140,6 +135,14 @@ struct usb_hcd { #define HCD_INTF_AUTHORIZED(hcd) \ ((hcd)->flags & (1U << HCD_FLAG_INTF_AUTHORIZED)) + /* + * Specifies if devices are authorized by default + * or they require explicit user space authorization; this bit is + * settable through /sys/class/usb_host/X/authorized_default + */ +#define HCD_DEV_AUTHORIZED(hcd) \ + ((hcd)->flags & (1U << HCD_FLAG_DEV_AUTHORIZED)) + /* Flags that get set only during HCD registration or removal. */ unsigned rh_registered:1;/* is root hub registered? */ unsigned rh_pollable:1; /* may we poll the root hub? */ @@ -150,7 +153,6 @@ struct usb_hcd { * support the new root-hub polling mechanism. */ unsigned uses_new_polling:1; unsigned wireless:1; /* Wireless USB HCD */ - unsigned authorized_default:1; unsigned has_tt:1; /* Integrated TT in root hub */ unsigned amd_resume_bug:1; /* AMD remote wakeup quirk */ unsigned can_do_streams:1; /* HC supports streams */ -- cgit v0.10.2 From b4f194706dd98d6de21c97eeb888a75abbf75174 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Aug 2015 16:23:09 +0200 Subject: USB: host: ohci-at91: move at91_usbh_data definition in c file Move struct at91_usbh_data back in ohci-at91.c as this is the only user left after switching all at91 platforms to DT only. Signed-off-by: Alexandre Belloni Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 15df00c..72dc4f9 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -36,6 +36,17 @@ #define hcd_to_ohci_at91_priv(h) \ ((struct ohci_at91_priv *)hcd_to_ohci(h)->priv) +#define AT91_MAX_USBH_PORTS 3 +struct at91_usbh_data { + int vbus_pin[AT91_MAX_USBH_PORTS]; /* port power-control pin */ + int overcurrent_pin[AT91_MAX_USBH_PORTS]; + u8 ports; /* number of ports on root hub */ + u8 overcurrent_supported; + u8 vbus_pin_active_low[AT91_MAX_USBH_PORTS]; + u8 overcurrent_status[AT91_MAX_USBH_PORTS]; + u8 overcurrent_changed[AT91_MAX_USBH_PORTS]; +}; + struct ohci_at91_priv { struct clk *iclk; struct clk *fclk; diff --git a/include/linux/platform_data/atmel.h b/include/linux/platform_data/atmel.h index 4b452c6..527a85c 100644 --- a/include/linux/platform_data/atmel.h +++ b/include/linux/platform_data/atmel.h @@ -46,18 +46,6 @@ struct at91_cf_data { #define AT91_IDE_SWAP_A0_A2 0x02 }; - /* USB Host */ -#define AT91_MAX_USBH_PORTS 3 -struct at91_usbh_data { - int vbus_pin[AT91_MAX_USBH_PORTS]; /* port power-control pin */ - int overcurrent_pin[AT91_MAX_USBH_PORTS]; - u8 ports; /* number of ports on root hub */ - u8 overcurrent_supported; - u8 vbus_pin_active_low[AT91_MAX_USBH_PORTS]; - u8 overcurrent_status[AT91_MAX_USBH_PORTS]; - u8 overcurrent_changed[AT91_MAX_USBH_PORTS]; -}; - /* NAND / SmartMedia */ struct atmel_nand_data { int enable_pin; /* chip enable */ -- cgit v0.10.2 From be12be546baa26a1eeb59b78e2a616cd946e850a Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Aug 2015 16:23:10 +0200 Subject: USB: host: ohci-at91: depend on OF Make the driver depend on CONFIG_OF and remove the now useless #ifdef Also, fix the Kconfig indentation. Signed-off-by: Alexandre Belloni Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 5f05679..079991e 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -448,10 +448,10 @@ config USB_OHCI_HCD_PXA27X PXA27x/PXA3xx chips. config USB_OHCI_HCD_AT91 - tristate "Support for Atmel on-chip OHCI USB controller" - depends on USB_OHCI_HCD && ARCH_AT91 - default y - ---help--- + tristate "Support for Atmel on-chip OHCI USB controller" + depends on USB_OHCI_HCD && ARCH_AT91 && OF + default y + ---help--- Enables support for the on-chip OHCI controller on Atmel chips. diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 72dc4f9..8e17d5b 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -442,7 +442,6 @@ static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) return IRQ_HANDLED; } -#ifdef CONFIG_OF static const struct of_device_id at91_ohci_dt_ids[] = { { .compatible = "atmel,at91rm9200-ohci" }, { /* sentinel */ } @@ -492,12 +491,6 @@ static int ohci_at91_of_init(struct platform_device *pdev) return 0; } -#else -static int ohci_at91_of_init(struct platform_device *pdev) -{ - return 0; -} -#endif /*-------------------------------------------------------------------------*/ @@ -684,7 +677,7 @@ static struct platform_driver ohci_hcd_at91_driver = { .driver = { .name = "at91_ohci", .pm = &ohci_hcd_at91_pm_ops, - .of_match_table = of_match_ptr(at91_ohci_dt_ids), + .of_match_table = at91_ohci_dt_ids, }, }; -- cgit v0.10.2 From bd73bfcd44c0bdcf6efa238e5b21bdbf0778d6ce Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Aug 2015 16:23:11 +0200 Subject: USB: host: ohci-at91: merge ohci_at91_of_init in ohci_hcd_at91_drv_probe As device tree support is now mandatory, merge ohci_at91_of_init() in ohci_hcd_at91_drv_probe(). Signed-off-by: Alexandre Belloni Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 8e17d5b..cdd91c5 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -449,16 +449,17 @@ static const struct of_device_id at91_ohci_dt_ids[] = { MODULE_DEVICE_TABLE(of, at91_ohci_dt_ids); -static int ohci_at91_of_init(struct platform_device *pdev) +/*-------------------------------------------------------------------------*/ + +static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - int i, gpio, ret; - enum of_gpio_flags flags; struct at91_usbh_data *pdata; - u32 ports; - - if (!np) - return 0; + int i; + int gpio; + int ret; + enum of_gpio_flags flags; + u32 ports; /* Right now device-tree probed devices don't get dma_mask set. * Since shared usb code relies on it, set it here for now. @@ -489,89 +490,69 @@ static int ohci_at91_of_init(struct platform_device *pdev) pdev->dev.platform_data = pdata; - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) -{ - struct at91_usbh_data *pdata; - int i; - int gpio; - int ret; - - ret = ohci_at91_of_init(pdev); - if (ret) - return ret; + at91_for_each_port(i) { + /* + * do not configure PIO if not in relation with + * real USB port on board + */ + if (i >= pdata->ports) { + pdata->vbus_pin[i] = -EINVAL; + pdata->overcurrent_pin[i] = -EINVAL; + break; + } - pdata = dev_get_platdata(&pdev->dev); + if (!gpio_is_valid(pdata->vbus_pin[i])) + continue; + gpio = pdata->vbus_pin[i]; - if (pdata) { - at91_for_each_port(i) { - /* - * do not configure PIO if not in relation with - * real USB port on board - */ - if (i >= pdata->ports) { - pdata->vbus_pin[i] = -EINVAL; - pdata->overcurrent_pin[i] = -EINVAL; - break; - } + ret = gpio_request(gpio, "ohci_vbus"); + if (ret) { + dev_err(&pdev->dev, + "can't request vbus gpio %d\n", gpio); + continue; + } + ret = gpio_direction_output(gpio, + !pdata->vbus_pin_active_low[i]); + if (ret) { + dev_err(&pdev->dev, + "can't put vbus gpio %d as output %d\n", + gpio, !pdata->vbus_pin_active_low[i]); + gpio_free(gpio); + continue; + } - if (!gpio_is_valid(pdata->vbus_pin[i])) - continue; - gpio = pdata->vbus_pin[i]; + ohci_at91_usb_set_power(pdata, i, 1); + } - ret = gpio_request(gpio, "ohci_vbus"); - if (ret) { - dev_err(&pdev->dev, - "can't request vbus gpio %d\n", gpio); - continue; - } - ret = gpio_direction_output(gpio, - !pdata->vbus_pin_active_low[i]); - if (ret) { - dev_err(&pdev->dev, - "can't put vbus gpio %d as output %d\n", - gpio, !pdata->vbus_pin_active_low[i]); - gpio_free(gpio); - continue; - } + at91_for_each_port(i) { + if (!gpio_is_valid(pdata->overcurrent_pin[i])) + continue; + gpio = pdata->overcurrent_pin[i]; - ohci_at91_usb_set_power(pdata, i, 1); + ret = gpio_request(gpio, "ohci_overcurrent"); + if (ret) { + dev_err(&pdev->dev, + "can't request overcurrent gpio %d\n", + gpio); + continue; } - at91_for_each_port(i) { - if (!gpio_is_valid(pdata->overcurrent_pin[i])) - continue; - gpio = pdata->overcurrent_pin[i]; - - ret = gpio_request(gpio, "ohci_overcurrent"); - if (ret) { - dev_err(&pdev->dev, - "can't request overcurrent gpio %d\n", - gpio); - continue; - } - - ret = gpio_direction_input(gpio); - if (ret) { - dev_err(&pdev->dev, - "can't configure overcurrent gpio %d as input\n", - gpio); - gpio_free(gpio); - continue; - } + ret = gpio_direction_input(gpio); + if (ret) { + dev_err(&pdev->dev, + "can't configure overcurrent gpio %d as input\n", + gpio); + gpio_free(gpio); + continue; + } - ret = request_irq(gpio_to_irq(gpio), - ohci_hcd_at91_overcurrent_irq, - IRQF_SHARED, "ohci_overcurrent", pdev); - if (ret) { - gpio_free(gpio); - dev_err(&pdev->dev, - "can't get gpio IRQ for overcurrent\n"); - } + ret = request_irq(gpio_to_irq(gpio), + ohci_hcd_at91_overcurrent_irq, + IRQF_SHARED, "ohci_overcurrent", pdev); + if (ret) { + gpio_free(gpio); + dev_err(&pdev->dev, + "can't get gpio IRQ for overcurrent\n"); } } -- cgit v0.10.2 From e4df92279fd9e01532f65e5ba397877799ed6252 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Aug 2015 16:23:12 +0200 Subject: USB: host: ohci-at91: merge loops in ohci_hcd_at91_drv_probe ohci_hcd_at91_drv_probe() has four at91_for_each_port. They can be merged into two loops without changing the driver behaviour. Signed-off-by: Alexandre Belloni Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index cdd91c5..342ffd1 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -477,33 +477,21 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) pdata->ports = ports; at91_for_each_port(i) { - gpio = of_get_named_gpio_flags(np, "atmel,vbus-gpio", i, &flags); - pdata->vbus_pin[i] = gpio; - if (!gpio_is_valid(gpio)) - continue; - pdata->vbus_pin_active_low[i] = flags & OF_GPIO_ACTIVE_LOW; - } - - at91_for_each_port(i) - pdata->overcurrent_pin[i] = - of_get_named_gpio_flags(np, "atmel,oc-gpio", i, &flags); - - pdev->dev.platform_data = pdata; - - at91_for_each_port(i) { /* * do not configure PIO if not in relation with * real USB port on board */ if (i >= pdata->ports) { pdata->vbus_pin[i] = -EINVAL; - pdata->overcurrent_pin[i] = -EINVAL; - break; + continue; } - if (!gpio_is_valid(pdata->vbus_pin[i])) + gpio = of_get_named_gpio_flags(np, "atmel,vbus-gpio", i, + &flags); + pdata->vbus_pin[i] = gpio; + if (!gpio_is_valid(gpio)) continue; - gpio = pdata->vbus_pin[i]; + pdata->vbus_pin_active_low[i] = flags & OF_GPIO_ACTIVE_LOW; ret = gpio_request(gpio, "ohci_vbus"); if (ret) { @@ -525,6 +513,14 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) } at91_for_each_port(i) { + if (i >= pdata->ports) { + pdata->overcurrent_pin[i] = -EINVAL; + continue; + } + + pdata->overcurrent_pin[i] = + of_get_named_gpio_flags(np, "atmel,oc-gpio", i, &flags); + if (!gpio_is_valid(pdata->overcurrent_pin[i])) continue; gpio = pdata->overcurrent_pin[i]; @@ -556,6 +552,8 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) } } + pdev->dev.platform_data = pdata; + device_init_wakeup(&pdev->dev, 1); return usb_hcd_at91_probe(&ohci_at91_hc_driver, pdev); } -- cgit v0.10.2 From 17248569499eae54b314fb05c4ff19fd47c9e99b Mon Sep 17 00:00:00 2001 From: Chase Metzger Date: Tue, 11 Aug 2015 21:34:37 -0700 Subject: usb: core: hub: Removed some warnings generated by checkpatch.pl Removed some checkpatch.pl warnings saying there was an unwanted space between function names and their arguments. Signed-off-by: Chase Metzger Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 78bd0d6..431839b 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1442,8 +1442,8 @@ static int hub_configure(struct usb_hub *hub, break; } - spin_lock_init (&hub->tt.lock); - INIT_LIST_HEAD (&hub->tt.clear_list); + spin_lock_init(&hub->tt.lock); + INIT_LIST_HEAD(&hub->tt.clear_list); INIT_WORK(&hub->tt.clear_work, hub_tt_work); switch (hdev->descriptor.bDeviceProtocol) { case USB_HUB_PR_FS: @@ -1632,7 +1632,7 @@ static int hub_configure(struct usb_hub *hub, return 0; fail: - dev_err (hub_dev, "config failed, %s (err %d)\n", + dev_err(hub_dev, "config failed, %s (err %d)\n", message, ret); /* hub_disconnect() frees urb and descriptor */ return ret; @@ -1775,7 +1775,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) if ((desc->desc.bInterfaceSubClass != 0) && (desc->desc.bInterfaceSubClass != 1)) { descriptor_error: - dev_err (&intf->dev, "bad descriptor, ignoring hub\n"); + dev_err(&intf->dev, "bad descriptor, ignoring hub\n"); return -EIO; } @@ -1790,11 +1790,11 @@ descriptor_error: goto descriptor_error; /* We found a hub */ - dev_info (&intf->dev, "USB hub found\n"); + dev_info(&intf->dev, "USB hub found\n"); hub = kzalloc(sizeof(*hub), GFP_KERNEL); if (!hub) { - dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n"); + dev_dbg(&intf->dev, "couldn't kmalloc hub struct\n"); return -ENOMEM; } @@ -1807,7 +1807,7 @@ descriptor_error: usb_get_intf(intf); usb_get_dev(hdev); - usb_set_intfdata (intf, hub); + usb_set_intfdata(intf, hub); intf->needs_remote_wakeup = 1; pm_suspend_ignore_children(&intf->dev, true); @@ -1820,14 +1820,14 @@ descriptor_error: if (hub_configure(hub, endpoint) >= 0) return 0; - hub_disconnect (intf); + hub_disconnect(intf); return -ENODEV; } static int hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data) { - struct usb_device *hdev = interface_to_usbdev (intf); + struct usb_device *hdev = interface_to_usbdev(intf); struct usb_hub *hub = usb_hub_to_struct_hub(hdev); /* assert ifno == 0 (part of hub spec) */ @@ -2143,7 +2143,7 @@ void usb_disconnect(struct usb_device **pdev) * cleaning up all state associated with the current configuration * so that the hardware is now fully quiesced. */ - dev_dbg (&udev->dev, "unregistering device\n"); + dev_dbg(&udev->dev, "unregistering device\n"); usb_disable_device(udev, 0); usb_hcd_synchronize_unlinks(udev); @@ -2242,7 +2242,7 @@ static int usb_enumerate_device_otg(struct usb_device *udev) struct usb_bus *bus = udev->bus; /* descriptor may appear anywhere in config */ - if (__usb_get_extra_descriptor (udev->rawdescriptors[0], + if (__usb_get_extra_descriptor(udev->rawdescriptors[0], le16_to_cpu(udev->config[0].desc.wTotalLength), USB_DT_OTG, (void **) &desc) == 0) { if (desc->bmAttributes & USB_OTG_HNP) { @@ -3526,7 +3526,7 @@ static int check_ports_changed(struct usb_hub *hub) static int hub_suspend(struct usb_interface *intf, pm_message_t msg) { - struct usb_hub *hub = usb_get_intfdata (intf); + struct usb_hub *hub = usb_get_intfdata(intf); struct usb_device *hdev = hub->hdev; unsigned port1; int status; -- cgit v0.10.2 From a1b93ab71587b8b44d45d114937cb4e75f9a5f27 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 18 Aug 2015 09:56:04 -0700 Subject: Revert "usb: interface authorization: Use a flag for the default device authorization" This reverts commit 3cf1fc80655d3af7083ea4b3615e5f8532543be7 as the signed-off-by address is invalid. Cc: Stefan Koch Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 86b3d11..83df1dd 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -854,10 +854,10 @@ static ssize_t authorized_default_show(struct device *dev, { struct usb_device *rh_usb_dev = to_usb_device(dev); struct usb_bus *usb_bus = rh_usb_dev->bus; - struct usb_hcd *hcd; + struct usb_hcd *usb_hcd; - hcd = bus_to_hcd(usb_bus); - return snprintf(buf, PAGE_SIZE, "%u\n", !!HCD_DEV_AUTHORIZED(hcd)); + usb_hcd = bus_to_hcd(usb_bus); + return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default); } static ssize_t authorized_default_store(struct device *dev, @@ -868,16 +868,12 @@ static ssize_t authorized_default_store(struct device *dev, unsigned val; struct usb_device *rh_usb_dev = to_usb_device(dev); struct usb_bus *usb_bus = rh_usb_dev->bus; - struct usb_hcd *hcd; + struct usb_hcd *usb_hcd; - hcd = bus_to_hcd(usb_bus); + usb_hcd = bus_to_hcd(usb_bus); result = sscanf(buf, "%u\n", &val); if (result == 1) { - if (val) - set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); - else - clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); - + usb_hcd->authorized_default = val ? 1 : 0; result = size; } else { result = -EINVAL; @@ -2724,17 +2720,10 @@ int usb_add_hcd(struct usb_hcd *hcd, dev_info(hcd->self.controller, "%s\n", hcd->product_desc); /* Keep old behaviour if authorized_default is not in [0, 1]. */ - if (authorized_default < 0 || authorized_default > 1) { - if (hcd->wireless) - clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); - else - set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); - } else { - if (authorized_default) - set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); - else - clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); - } + if (authorized_default < 0 || authorized_default > 1) + hcd->authorized_default = hcd->wireless ? 0 : 1; + else + hcd->authorized_default = authorized_default; set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); /* per default all interfaces are authorized */ diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index f8bbd0b..8d5b2f4 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -510,7 +510,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, if (root_hub) /* Root hub always ok [and always wired] */ dev->authorized = 1; else { - dev->authorized = !!HCD_DEV_AUTHORIZED(usb_hcd); + dev->authorized = usb_hcd->authorized_default; dev->wusb = usb_bus_is_wusb(bus) ? 1 : 0; } return dev; diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 4d14727..36ce3d2 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -58,6 +58,12 @@ * * Since "struct usb_bus" is so thin, you can't share much code in it. * This framework is a layer over that, and should be more sharable. + * + * @authorized_default: Specifies if new devices are authorized to + * connect by default or they require explicit + * user space authorization; this bit is settable + * through /sys/class/usb_host/X/authorized_default. + * For the rest is RO, so we don't lock to r/w it. */ /*-------------------------------------------------------------------------*/ @@ -115,7 +121,6 @@ struct usb_hcd { #define HCD_FLAG_RH_RUNNING 5 /* root hub is running? */ #define HCD_FLAG_DEAD 6 /* controller has died? */ #define HCD_FLAG_INTF_AUTHORIZED 7 /* authorize interfaces? */ -#define HCD_FLAG_DEV_AUTHORIZED 8 /* authorize devices? */ /* The flags can be tested using these macros; they are likely to * be slightly faster than test_bit(). @@ -135,14 +140,6 @@ struct usb_hcd { #define HCD_INTF_AUTHORIZED(hcd) \ ((hcd)->flags & (1U << HCD_FLAG_INTF_AUTHORIZED)) - /* - * Specifies if devices are authorized by default - * or they require explicit user space authorization; this bit is - * settable through /sys/class/usb_host/X/authorized_default - */ -#define HCD_DEV_AUTHORIZED(hcd) \ - ((hcd)->flags & (1U << HCD_FLAG_DEV_AUTHORIZED)) - /* Flags that get set only during HCD registration or removal. */ unsigned rh_registered:1;/* is root hub registered? */ unsigned rh_pollable:1; /* may we poll the root hub? */ @@ -153,6 +150,7 @@ struct usb_hcd { * support the new root-hub polling mechanism. */ unsigned uses_new_polling:1; unsigned wireless:1; /* Wireless USB HCD */ + unsigned authorized_default:1; unsigned has_tt:1; /* Integrated TT in root hub */ unsigned amd_resume_bug:1; /* AMD remote wakeup quirk */ unsigned can_do_streams:1; /* HC supports streams */ -- cgit v0.10.2 From dba3398381dd1175c74721c97d1daf8fc5939276 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 18 Aug 2015 09:57:15 -0700 Subject: Revert "usb: interface authorization: Documentation part" This reverts commit 6ef2bf71764708f7c58ee9300acd8df05dbaa06f as the signed-off-by address is invalid. Cc: Stefan Koch Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index 5c6c264..864637f 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -1,25 +1,3 @@ -What: /sys/bus/usb/devices/INTERFACE/authorized -Date: June 2015 -KernelVersion: 4.2 -Description: - This allows to authorize (1) or deauthorize (0) - individual interfaces instead a whole device - in contrast to the device authorization. - If a deauthorized interface will be authorized - so the driver probing must be triggered manually - by writing INTERFACE to /sys/bus/usb/drivers_probe - This allows to avoid side-effects with drivers - that need multiple interfaces. - A deauthorized interface cannot be probed or claimed. - -What: /sys/bus/usb/devices/usbX/interface_authorized_default -Date: June 2015 -KernelVersion: 4.2 -Description: - This is used as default value that determines - if interfaces would authorized per default. - The value can be 1 or 0. It is per default 1. - What: /sys/bus/usb/device/.../authorized Date: July 2008 KernelVersion: 2.6.26 diff --git a/Documentation/usb/authorization.txt b/Documentation/usb/authorization.txt index 020cec5..c069b68 100644 --- a/Documentation/usb/authorization.txt +++ b/Documentation/usb/authorization.txt @@ -3,9 +3,6 @@ Authorizing (or not) your USB devices to connect to the system (C) 2007 Inaky Perez-Gonzalez Intel Corporation -Interface authorization part: - (C) 2015 Stefan Koch SUSE LLC - This feature allows you to control if a USB device can be used (or not) in a system. This feature will allow you to implement a lock-down of USB devices, fully controlled by user space. @@ -93,34 +90,3 @@ etc, but you get the idea. Anybody with access to a device gadget kit can fake descriptors and device info. Don't trust that. You are welcome. - -Interface authorization ------------------------ -There is a similar approach to allow or deny specific USB interfaces. -That allows to block only a subset of an USB device. - -Authorize an interface: -$ echo 1 > /sys/bus/usb/devices/INTERFACE/authorized - -Deauthorize an interface: -$ echo 0 > /sys/bus/usb/devices/INTERFACE/authorized - -The default value for new interfaces -on a particular USB bus can be changed, too. - -Allow interfaces per default: -$ echo 1 > /sys/bus/usb/devices/usbX/interface_authorized_default - -Deny interfaces per default: -$ echo 0 > /sys/bus/usb/devices/usbX/interface_authorized_default - -Per default the interface_authorized_default bit is 1. -So all interfaces would authorized per default. - -Note: -If a deauthorized interface will be authorized so the driver probing must -be triggered manually by writing INTERFACE to /sys/bus/usb/drivers_probe - -For drivers that need multiple interfaces all needed interfaces should be -authroized first. After that the drivers should be probed. -This avoids side effects. -- cgit v0.10.2 From 4d924d7a81627663720223b5c4330c18d8063fb6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 18 Aug 2015 09:57:43 -0700 Subject: Revert "usb: interface authorization: SysFS part of USB interface authorization" This reverts commit 187b3d75bbfba45a38b5d1d3656c0f11f6f6f2d0 as the signed-off-by address is invalid. Cc: Stefan Koch Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index d9ec2de..cfc68c1 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -957,41 +957,6 @@ static ssize_t supports_autosuspend_show(struct device *dev, } static DEVICE_ATTR_RO(supports_autosuspend); -/* - * interface_authorized_show - show authorization status of an USB interface - * 1 is authorized, 0 is deauthorized - */ -static ssize_t interface_authorized_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - - return sprintf(buf, "%u\n", intf->authorized); -} - -/* - * interface_authorized_store - authorize or deauthorize an USB interface - */ -static ssize_t interface_authorized_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct usb_interface *intf = to_usb_interface(dev); - bool val; - - if (strtobool(buf, &val) != 0) - return -EINVAL; - - if (val) - usb_authorize_interface(intf); - else - usb_deauthorize_interface(intf); - - return count; -} -static struct device_attribute dev_attr_interface_authorized = - __ATTR(authorized, S_IRUGO | S_IWUSR, - interface_authorized_show, interface_authorized_store); - static struct attribute *intf_attrs[] = { &dev_attr_bInterfaceNumber.attr, &dev_attr_bAlternateSetting.attr, @@ -1001,7 +966,6 @@ static struct attribute *intf_attrs[] = { &dev_attr_bInterfaceProtocol.attr, &dev_attr_modalias.attr, &dev_attr_supports_autosuspend.attr, - &dev_attr_interface_authorized.attr, NULL, }; static struct attribute_group intf_attr_grp = { -- cgit v0.10.2 From 5651440e453910f3a1f795e66db5d16291c3ba44 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 18 Aug 2015 09:58:04 -0700 Subject: Revert "usb: interface authorization: Introduces the USB interface authorization" This reverts commit ef0909c50fe63be3f9aa09bdf4db7efaa5919be9 as the signed-off-by address is invalid. Cc: Stefan Koch Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index c090f50..3d25d89 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1555,44 +1555,6 @@ static void usb_release_interface(struct device *dev) kfree(intf); } -/* - * usb_deauthorize_interface - deauthorize an USB interface - * - * @intf: USB interface structure - */ -void usb_deauthorize_interface(struct usb_interface *intf) -{ - struct device *dev = &intf->dev; - - device_lock(dev->parent); - - if (intf->authorized) { - device_lock(dev); - intf->authorized = 0; - device_unlock(dev); - - usb_forced_unbind_intf(intf); - } - - device_unlock(dev->parent); -} - -/* - * usb_authorize_interface - authorize an USB interface - * - * @intf: USB interface structure - */ -void usb_authorize_interface(struct usb_interface *intf) -{ - struct device *dev = &intf->dev; - - if (!intf->authorized) { - device_lock(dev); - intf->authorized = 1; /* authorize interface */ - device_unlock(dev); - } -} - static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) { struct usb_device *usb_dev; diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 05b5e17..457255a 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -27,8 +27,6 @@ extern void usb_release_interface_cache(struct kref *ref); extern void usb_disable_device(struct usb_device *dev, int skip_ep0); extern int usb_deauthorize_device(struct usb_device *); extern int usb_authorize_device(struct usb_device *); -extern void usb_deauthorize_interface(struct usb_interface *); -extern void usb_authorize_interface(struct usb_interface *); extern void usb_detect_quirks(struct usb_device *udev); extern void usb_detect_interface_quirks(struct usb_device *udev); extern int usb_remove_device(struct usb_device *udev); -- cgit v0.10.2 From 8c2ea97a3a4124628de2ed9a1f891c706788468a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 18 Aug 2015 09:58:26 -0700 Subject: Revert "usb: interface authorization: Control interface probing and claiming" This reverts commit de7718bd9c4d3db96991a98c2a0cb38258a04e47 as the signed-off-by address is invalid. Cc: Stefan Koch Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 9416254..6b5063e 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -296,10 +296,6 @@ static int usb_probe_interface(struct device *dev) if (udev->authorized == 0) { dev_err(&intf->dev, "Device is not authorized for usage\n"); return error; - } else if (intf->authorized == 0) { - dev_err(&intf->dev, "Interface %d is not authorized for usage\n", - intf->altsetting->desc.bInterfaceNumber); - return error; } id = usb_match_dynamic_id(intf, driver); @@ -512,10 +508,6 @@ int usb_driver_claim_interface(struct usb_driver *driver, if (dev->driver) return -EBUSY; - /* reject claim if not iterface is not authorized */ - if (!iface->authorized) - return -ENODEV; - udev = interface_to_usbdev(iface); dev->driver = &driver->drvwrap.driver; -- cgit v0.10.2 From 12e1a6a0f16168346cb8f33aff135ed523a9f097 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 18 Aug 2015 09:58:45 -0700 Subject: Revert "usb: interface authorization: Introduces the default interface authorization" This reverts commit 1d958bef45030acfc5578263e9de3bb07032b8da as the signed-off-by address is invalid. Cc: Stefan Koch Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 83df1dd..4d64e5c4 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -882,53 +882,9 @@ static ssize_t authorized_default_store(struct device *dev, } static DEVICE_ATTR_RW(authorized_default); -/* - * interface_authorized_default_show - show default authorization status - * for USB interfaces - * - * note: interface_authorized_default is the default value - * for initializing the authorized attribute of interfaces - */ -static ssize_t interface_authorized_default_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_device *usb_dev = to_usb_device(dev); - struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus); - - return sprintf(buf, "%u\n", !!HCD_INTF_AUTHORIZED(hcd)); -} - -/* - * interface_authorized_default_store - store default authorization status - * for USB interfaces - * - * note: interface_authorized_default is the default value - * for initializing the authorized attribute of interfaces - */ -static ssize_t interface_authorized_default_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct usb_device *usb_dev = to_usb_device(dev); - struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus); - int rc = count; - bool val; - - if (strtobool(buf, &val) != 0) - return -EINVAL; - - if (val) - set_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags); - else - clear_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags); - - return rc; -} -static DEVICE_ATTR_RW(interface_authorized_default); - /* Group all the USB bus attributes */ static struct attribute *usb_bus_attrs[] = { &dev_attr_authorized_default.attr, - &dev_attr_interface_authorized_default.attr, NULL, }; @@ -2726,9 +2682,6 @@ int usb_add_hcd(struct usb_hcd *hcd, hcd->authorized_default = authorized_default; set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - /* per default all interfaces are authorized */ - set_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags); - /* HC is in reset state, but accessible. Now do the one-time init, * bottom up so that hcds can customize the root hubs before hub_wq * starts talking to them. (Note, bus id is assigned early too.) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 3d25d89..f368d20 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1807,7 +1807,6 @@ free_interfaces: intfc = cp->intf_cache[i]; intf->altsetting = intfc->altsetting; intf->num_altsetting = intfc->num_altsetting; - intf->authorized = !!HCD_INTF_AUTHORIZED(hcd); kref_get(&intfc->ref); alt = usb_altnum_to_altsetting(intf, 0); diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 36ce3d2..d2784c1 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -120,7 +120,6 @@ struct usb_hcd { #define HCD_FLAG_WAKEUP_PENDING 4 /* root hub is resuming? */ #define HCD_FLAG_RH_RUNNING 5 /* root hub is running? */ #define HCD_FLAG_DEAD 6 /* controller has died? */ -#define HCD_FLAG_INTF_AUTHORIZED 7 /* authorize interfaces? */ /* The flags can be tested using these macros; they are likely to * be slightly faster than test_bit(). @@ -132,14 +131,6 @@ struct usb_hcd { #define HCD_RH_RUNNING(hcd) ((hcd)->flags & (1U << HCD_FLAG_RH_RUNNING)) #define HCD_DEAD(hcd) ((hcd)->flags & (1U << HCD_FLAG_DEAD)) - /* - * Specifies if interfaces are authorized by default - * or they require explicit user space authorization; this bit is - * settable through /sys/class/usb_host/X/interface_authorized_default - */ -#define HCD_INTF_AUTHORIZED(hcd) \ - ((hcd)->flags & (1U << HCD_FLAG_INTF_AUTHORIZED)) - /* Flags that get set only during HCD registration or removal. */ unsigned rh_registered:1;/* is root hub registered? */ unsigned rh_pollable:1; /* may we poll the root hub? */ -- cgit v0.10.2 From 475908bc4d29b95b24c03206f673f46b41e7124d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 18 Aug 2015 09:59:12 -0700 Subject: Revert "usb: interface authorization: Declare authorized attribute" This reverts commit 484ebaedecc5ddf778a30ee1efab367cbee27030 as the signed-off-by address is invalid. Cc: Stefan Koch Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/usb.h b/include/linux/usb.h index 3deccab..447fe29 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -178,7 +178,6 @@ struct usb_interface { unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */ unsigned needs_binding:1; /* needs delayed unbind/rebind */ unsigned resetting_device:1; /* true: bandwidth alloc after reset */ - unsigned authorized:1; /* used for interface authorization */ struct device dev; /* interface specific device info */ struct device *usb_dev; -- cgit v0.10.2 From 0521cfd06e1ebcd575e7ae36aab068b38df23850 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Mon, 17 Aug 2015 10:23:03 +0800 Subject: usb: host: ehci-sys: delete useless bus_to_hcd conversion The ehci platform device's drvdata is the pointer of struct usb_hcd already, so we doesn't need to call bus_to_hcd conversion again. Cc: Signed-off-by: Peter Chen Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-sysfs.c b/drivers/usb/host/ehci-sysfs.c index 5e44407..5216f2b 100644 --- a/drivers/usb/host/ehci-sysfs.c +++ b/drivers/usb/host/ehci-sysfs.c @@ -29,7 +29,7 @@ static ssize_t show_companion(struct device *dev, int count = PAGE_SIZE; char *ptr = buf; - ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); + ehci = hcd_to_ehci(dev_get_drvdata(dev)); nports = HCS_N_PORTS(ehci->hcs_params); for (index = 0; index < nports; ++index) { @@ -54,7 +54,7 @@ static ssize_t store_companion(struct device *dev, struct ehci_hcd *ehci; int portnum, new_owner; - ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); + ehci = hcd_to_ehci(dev_get_drvdata(dev)); new_owner = PORT_OWNER; /* Owned by companion */ if (sscanf(buf, "%d", &portnum) != 1) return -EINVAL; @@ -85,7 +85,7 @@ static ssize_t show_uframe_periodic_max(struct device *dev, struct ehci_hcd *ehci; int n; - ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); + ehci = hcd_to_ehci(dev_get_drvdata(dev)); n = scnprintf(buf, PAGE_SIZE, "%d\n", ehci->uframe_periodic_max); return n; } @@ -101,7 +101,7 @@ static ssize_t store_uframe_periodic_max(struct device *dev, unsigned long flags; ssize_t ret; - ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); + ehci = hcd_to_ehci(dev_get_drvdata(dev)); if (kstrtouint(buf, 0, &uframe_periodic_max) < 0) return -EINVAL; -- cgit v0.10.2 From a0c9d0defcdadd31ab111b1616f60cf919c6a020 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Mon, 17 Aug 2015 16:36:53 +0800 Subject: usb: misc: usbtest: format max packet size for iso transfer The current code prints all wMaxPacketSize content at endpoint descriptor, if there is a high speed, high bandwidth endpoint, it may confuse the users, eg, if there are 3 transactions during microframe, it will print "wMaxPacket 1400" for packet content. This commit splits wMaxpacketSize and transaction numbers for output messages. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 0bbafe7..9517812 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -1925,10 +1925,11 @@ test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param, memset(urbs, 0, sizeof(urbs)); udev = testdev_to_usbdev(dev); dev_info(&dev->intf->dev, - "... iso period %d %sframes, wMaxPacket %04x\n", + "iso period %d %sframes, wMaxPacket %d, transactions: %d\n", 1 << (desc->bInterval - 1), (udev->speed == USB_SPEED_HIGH) ? "micro" : "", - usb_endpoint_maxp(desc)); + usb_endpoint_maxp(desc) & 0x7ff, + 1 + (0x3 & (usb_endpoint_maxp(desc) >> 11))); for (i = 0; i < param->sglen; i++) { urbs[i] = iso_alloc_urb(udev, pipe, desc, @@ -1942,7 +1943,7 @@ test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param, } packets *= param->iterations; dev_info(&dev->intf->dev, - "... total %lu msec (%lu packets)\n", + "total %lu msec (%lu packets)\n", (packets * (1 << (desc->bInterval - 1))) / ((udev->speed == USB_SPEED_HIGH) ? 8 : 1), packets); -- cgit v0.10.2 From 951d3793bbfc0a441d791d820183aa3085c83ea9 Mon Sep 17 00:00:00 2001 From: Philipp Hachtmann Date: Mon, 17 Aug 2015 17:31:46 +0200 Subject: USB: symbolserial: Use usb_get_serial_port_data The driver used usb_get_serial_data(port->serial) which compiled but resulted in a NULL pointer being returned (and subsequently used). I did not go deeper into this but I guess this is a regression. Signed-off-by: Philipp Hachtmann Fixes: a85796ee5149 ("USB: symbolserial: move private-data allocation to port_probe") Cc: stable # v3.10 Acked-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c index 8fceec7..6ed8044 100644 --- a/drivers/usb/serial/symbolserial.c +++ b/drivers/usb/serial/symbolserial.c @@ -94,7 +94,7 @@ exit: static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port) { - struct symbol_private *priv = usb_get_serial_data(port->serial); + struct symbol_private *priv = usb_get_serial_port_data(port); unsigned long flags; int result = 0; @@ -120,7 +120,7 @@ static void symbol_close(struct usb_serial_port *port) static void symbol_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - struct symbol_private *priv = usb_get_serial_data(port->serial); + struct symbol_private *priv = usb_get_serial_port_data(port); spin_lock_irq(&priv->lock); priv->throttled = true; @@ -130,7 +130,7 @@ static void symbol_throttle(struct tty_struct *tty) static void symbol_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - struct symbol_private *priv = usb_get_serial_data(port->serial); + struct symbol_private *priv = usb_get_serial_port_data(port); int result; bool was_throttled; -- cgit v0.10.2 From 8ae25a355b5969e12f3185e8cb8eb08b871c9084 Mon Sep 17 00:00:00 2001 From: Philipp Hachtmann Date: Mon, 17 Aug 2015 17:31:47 +0200 Subject: USB: symbolserial: Correct transferred data size The scanner (here DS3508) always returns 64 bytes per urb buffer. The first byte indicates the data length used in the current buffer. There even was a comment describing this. But the comment also said that we'll send everything in the buffer to the tty layer. That means sending the actual barcode data and lots of trailing zeroes. This patch lets the driver only send the real data. Signed-off-by: Philipp Hachtmann Acked-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c index 6ed8044..37f3ad1 100644 --- a/drivers/usb/serial/symbolserial.c +++ b/drivers/usb/serial/symbolserial.c @@ -60,17 +60,15 @@ static void symbol_int_callback(struct urb *urb) usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); + /* + * Data from the device comes with a 1 byte header: + * + * ... + */ if (urb->actual_length > 1) { - data_length = urb->actual_length - 1; - - /* - * Data from the device comes with a 1 byte header: - * - * data... - * This is real data to be sent to the tty layer - * we pretty much just ignore the size and send everything - * else to the tty layer. - */ + data_length = data[0]; + if (data_length > (urb->actual_length - 1)) + data_length = urb->actual_length - 1; tty_insert_flip_string(&port->port, &data[1], data_length); tty_flip_buffer_push(&port->port); } else { -- cgit v0.10.2 From 9257f1daa8befd5c0a343031dd870236550e00c5 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Aug 2015 17:35:23 +0200 Subject: USB: option: silence interrupt errors Avoid spamming the logs (e.g. with -EPROTO errors) when attempting to resubmit the interrupt urb while a disconnect of an in-use device is being processed. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 876423b..6d1941a 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1941,7 +1941,7 @@ static void option_instat_callback(struct urb *urb) } else if (status == -ENOENT || status == -ESHUTDOWN) { dev_dbg(dev, "%s: urb stopped: %d\n", __func__, status); } else - dev_err(dev, "%s: error %d\n", __func__, status); + dev_dbg(dev, "%s: error %d\n", __func__, status); /* Resubmit urb so we continue receiving IRQ data */ if (status != -ESHUTDOWN && status != -ENOENT) { -- cgit v0.10.2 From d2958d1b8fb0cffa362b187c0375a5aff4fe3825 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Aug 2015 17:35:24 +0200 Subject: USB: usb_wwan: silence read errors on disconnect Silence read-urb resubmission errors when the device is going away. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 2f805cb..825305c 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -282,7 +282,7 @@ static void usb_wwan_indat_callback(struct urb *urb) /* Resubmit urb so we continue receiving */ err = usb_submit_urb(urb, GFP_ATOMIC); if (err) { - if (err != -EPERM) { + if (err != -EPERM && err != -ENODEV) { dev_err(dev, "%s: resubmit read urb failed. (%d)\n", __func__, err); /* busy also in error unless we are killed */ -- cgit v0.10.2 From 1fb8dc36384ae1140ee6ccc470de74397606a9d5 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 18 Aug 2015 10:33:56 +0200 Subject: USB: ftdi_sio: Added custom PID for CustomWare products CustomWare uses the FTDI VID with custom PIDs for their ShipModul MiniPlex products. Signed-off-by: Matthijs Kooijman Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 4c8b3b8..a5a0376 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -605,6 +605,10 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLXM_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, FTDI_SYNAPSE_SS200_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CUSTOMWARE_MINIPLEX_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CUSTOMWARE_MINIPLEX2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CUSTOMWARE_MINIPLEX2WI_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CUSTOMWARE_MINIPLEX3_PID) }, /* * ELV devices: */ diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index cb12b31..67c6d44 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -568,6 +568,14 @@ */ #define FTDI_SYNAPSE_SS200_PID 0x9090 /* SS200 - SNAP Stick 200 */ +/* + * CustomWare / ShipModul NMEA multiplexers product ids (FTDI_VID) + */ +#define FTDI_CUSTOMWARE_MINIPLEX_PID 0xfd48 /* MiniPlex first generation NMEA Multiplexer */ +#define FTDI_CUSTOMWARE_MINIPLEX2_PID 0xfd49 /* MiniPlex-USB and MiniPlex-2 series */ +#define FTDI_CUSTOMWARE_MINIPLEX2WI_PID 0xfd4a /* MiniPlex-2Wi */ +#define FTDI_CUSTOMWARE_MINIPLEX3_PID 0xfd4b /* MiniPlex-3 series */ + /********************************/ /** third-party VID/PID combos **/ -- cgit v0.10.2 From 44840dec6127e4d7c5074f75d2dd96bc4ab85fe3 Mon Sep 17 00:00:00 2001 From: David Ward Date: Tue, 18 Aug 2015 10:36:23 +0200 Subject: USB: qcserial: add HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module This is an HP-branded Sierra Wireless EM7355: https://bugzilla.redhat.com/show_bug.cgi?id=1223646#c2 Signed-off-by: David Ward Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index d156545..ebcec8c 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -139,6 +139,7 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(0x0AF0, 0x8120)}, /* Option GTM681W */ /* non-Gobi Sierra Wireless devices */ + {DEVICE_SWI(0x03f0, 0x4e1d)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */ {DEVICE_SWI(0x0f3d, 0x68a2)}, /* Sierra Wireless MC7700 */ {DEVICE_SWI(0x114f, 0x68a2)}, /* Sierra Wireless MC7750 */ {DEVICE_SWI(0x1199, 0x68a2)}, /* Sierra Wireless MC7710 */ -- cgit v0.10.2