diff options
Diffstat (limited to 'drivers/usb/gadget/udc')
-rw-r--r-- | drivers/usb/gadget/udc/aspeed-vhub/dev.c | 19 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/aspeed-vhub/ep0.c | 7 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/aspeed-vhub/hub.c | 47 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/aspeed-vhub/vhub.h | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/at91_udc.c | 67 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/at91_udc.h | 8 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/bcm63xx_udc.c | 8 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/bdc/bdc_core.c | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/mv_udc_core.c | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/pxa25x_udc.c | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/udc-xilinx.c | 56 |
11 files changed, 156 insertions, 64 deletions
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c index d918e8b2af3c..b0dfca43fbdc 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c @@ -110,15 +110,26 @@ static int ast_vhub_dev_feature(struct ast_vhub_dev *d, u16 wIndex, u16 wValue, bool is_set) { + u32 val; + DDBG(d, "%s_FEATURE(dev val=%02x)\n", is_set ? "SET" : "CLEAR", wValue); - if (wValue != USB_DEVICE_REMOTE_WAKEUP) - return std_req_driver; + if (wValue == USB_DEVICE_REMOTE_WAKEUP) { + d->wakeup_en = is_set; + return std_req_complete; + } - d->wakeup_en = is_set; + if (wValue == USB_DEVICE_TEST_MODE) { + val = readl(d->vhub->regs + AST_VHUB_CTRL); + val &= ~GENMASK(10, 8); + val |= VHUB_CTRL_SET_TEST_MODE((wIndex >> 8) & 0x7); + writel(val, d->vhub->regs + AST_VHUB_CTRL); - return std_req_complete; + return std_req_complete; + } + + return std_req_driver; } static int ast_vhub_ep_feature(struct ast_vhub_dev *d, diff --git a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c index 74ea36c19b1e..b4cf46249fea 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c @@ -251,6 +251,13 @@ static void ast_vhub_ep0_do_receive(struct ast_vhub_ep *ep, struct ast_vhub_req len = remain; rc = -EOVERFLOW; } + + /* Hardware return wrong data len */ + if (len < ep->ep.maxpacket && len != remain) { + EPDBG(ep, "using expected data len instead\n"); + len = remain; + } + if (len && req->req.buf) memcpy(req->req.buf + req->req.actual, ep->buf, len); req->req.actual += len; diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/aspeed-vhub/hub.c index b9960fdd8a51..65cd4e46f031 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c @@ -68,6 +68,18 @@ static const struct usb_device_descriptor ast_vhub_dev_desc = { .bNumConfigurations = 1, }; +static const struct usb_qualifier_descriptor ast_vhub_qual_desc = { + .bLength = 0xA, + .bDescriptorType = USB_DT_DEVICE_QUALIFIER, + .bcdUSB = cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_HUB, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .bNumConfigurations = 1, + .bRESERVED = 0, +}; + /* * Configuration descriptor: same comments as above * regarding handling USB1 mode. @@ -200,17 +212,28 @@ static int ast_vhub_hub_dev_feature(struct ast_vhub_ep *ep, u16 wIndex, u16 wValue, bool is_set) { + u32 val; + EPDBG(ep, "%s_FEATURE(dev val=%02x)\n", is_set ? "SET" : "CLEAR", wValue); - if (wValue != USB_DEVICE_REMOTE_WAKEUP) - return std_req_stall; + if (wValue == USB_DEVICE_REMOTE_WAKEUP) { + ep->vhub->wakeup_en = is_set; + EPDBG(ep, "Hub remote wakeup %s\n", + is_set ? "enabled" : "disabled"); + return std_req_complete; + } - ep->vhub->wakeup_en = is_set; - EPDBG(ep, "Hub remote wakeup %s\n", - is_set ? "enabled" : "disabled"); + if (wValue == USB_DEVICE_TEST_MODE) { + val = readl(ep->vhub->regs + AST_VHUB_CTRL); + val &= ~GENMASK(10, 8); + val |= VHUB_CTRL_SET_TEST_MODE((wIndex >> 8) & 0x7); + writel(val, ep->vhub->regs + AST_VHUB_CTRL); - return std_req_complete; + return std_req_complete; + } + + return std_req_stall; } static int ast_vhub_hub_ep_feature(struct ast_vhub_ep *ep, @@ -271,9 +294,11 @@ static int ast_vhub_rep_desc(struct ast_vhub_ep *ep, BUILD_BUG_ON(dsize > sizeof(vhub->vhub_dev_desc)); BUILD_BUG_ON(USB_DT_DEVICE_SIZE >= AST_VHUB_EP0_MAX_PACKET); break; + case USB_DT_OTHER_SPEED_CONFIG: case USB_DT_CONFIG: dsize = AST_VHUB_CONF_DESC_SIZE; memcpy(ep->buf, &vhub->vhub_conf_desc, dsize); + ((u8 *)ep->buf)[1] = desc_type; BUILD_BUG_ON(dsize > sizeof(vhub->vhub_conf_desc)); BUILD_BUG_ON(AST_VHUB_CONF_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET); break; @@ -283,6 +308,10 @@ static int ast_vhub_rep_desc(struct ast_vhub_ep *ep, BUILD_BUG_ON(dsize > sizeof(vhub->vhub_hub_desc)); BUILD_BUG_ON(AST_VHUB_HUB_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET); break; + case USB_DT_DEVICE_QUALIFIER: + dsize = sizeof(vhub->vhub_qual_desc); + memcpy(ep->buf, &vhub->vhub_qual_desc, dsize); + break; default: return std_req_stall; } @@ -428,6 +457,8 @@ enum std_req_rc ast_vhub_std_hub_request(struct ast_vhub_ep *ep, switch (wValue >> 8) { case USB_DT_DEVICE: case USB_DT_CONFIG: + case USB_DT_DEVICE_QUALIFIER: + case USB_DT_OTHER_SPEED_CONFIG: return ast_vhub_rep_desc(ep, wValue >> 8, wLength); case USB_DT_STRING: @@ -1033,6 +1064,10 @@ static int ast_vhub_init_desc(struct ast_vhub *vhub) else ret = ast_vhub_str_alloc_add(vhub, &ast_vhub_strings); + /* Initialize vhub Qualifier Descriptor. */ + memcpy(&vhub->vhub_qual_desc, &ast_vhub_qual_desc, + sizeof(vhub->vhub_qual_desc)); + return ret; } diff --git a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h index 87a5dea12d3c..6b9dfa6e10eb 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h +++ b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h @@ -425,6 +425,7 @@ struct ast_vhub { struct ast_vhub_full_cdesc vhub_conf_desc; struct usb_hub_descriptor vhub_hub_desc; struct list_head vhub_str_desc; + struct usb_qualifier_descriptor vhub_qual_desc; }; /* Standard request handlers result codes */ diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index d9ad9adf7348..dd0819df096e 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -25,7 +25,7 @@ #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> #include <linux/of.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> #include <linux/platform_data/atmel.h> #include <linux/regmap.h> #include <linux/mfd/syscon.h> @@ -1510,7 +1510,6 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc) static void at91_vbus_update(struct at91_udc *udc, unsigned value) { - value ^= udc->board.vbus_active_low; if (value != udc->vbus) at91_vbus_session(&udc->gadget, value); } @@ -1521,7 +1520,7 @@ static irqreturn_t at91_vbus_irq(int irq, void *_udc) /* vbus needs at least brief debouncing */ udelay(10); - at91_vbus_update(udc, gpio_get_value(udc->board.vbus_pin)); + at91_vbus_update(udc, gpiod_get_value(udc->board.vbus_pin)); return IRQ_HANDLED; } @@ -1531,7 +1530,7 @@ static void at91_vbus_timer_work(struct work_struct *work) struct at91_udc *udc = container_of(work, struct at91_udc, vbus_timer_work); - at91_vbus_update(udc, gpio_get_value_cansleep(udc->board.vbus_pin)); + at91_vbus_update(udc, gpiod_get_value_cansleep(udc->board.vbus_pin)); if (!timer_pending(&udc->vbus_timer)) mod_timer(&udc->vbus_timer, jiffies + VBUS_POLL_TIMEOUT); @@ -1595,7 +1594,6 @@ static void at91udc_shutdown(struct platform_device *dev) static int at91rm9200_udc_init(struct at91_udc *udc) { struct at91_ep *ep; - int ret; int i; for (i = 0; i < NUM_ENDPOINTS; i++) { @@ -1615,32 +1613,23 @@ static int at91rm9200_udc_init(struct at91_udc *udc) } } - if (!gpio_is_valid(udc->board.pullup_pin)) { + if (!udc->board.pullup_pin) { DBG("no D+ pullup?\n"); return -ENODEV; } - ret = devm_gpio_request(&udc->pdev->dev, udc->board.pullup_pin, - "udc_pullup"); - if (ret) { - DBG("D+ pullup is busy\n"); - return ret; - } - - gpio_direction_output(udc->board.pullup_pin, - udc->board.pullup_active_low); + gpiod_direction_output(udc->board.pullup_pin, + gpiod_is_active_low(udc->board.pullup_pin)); return 0; } static void at91rm9200_udc_pullup(struct at91_udc *udc, int is_on) { - int active = !udc->board.pullup_active_low; - if (is_on) - gpio_set_value(udc->board.pullup_pin, active); + gpiod_set_value(udc->board.pullup_pin, 1); else - gpio_set_value(udc->board.pullup_pin, !active); + gpiod_set_value(udc->board.pullup_pin, 0); } static const struct at91_udc_caps at91rm9200_udc_caps = { @@ -1783,20 +1772,20 @@ static void at91udc_of_init(struct at91_udc *udc, struct device_node *np) { struct at91_udc_data *board = &udc->board; const struct of_device_id *match; - enum of_gpio_flags flags; u32 val; if (of_property_read_u32(np, "atmel,vbus-polled", &val) == 0) board->vbus_polled = 1; - board->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0, - &flags); - board->vbus_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0; + board->vbus_pin = gpiod_get_from_of_node(np, "atmel,vbus-gpio", 0, + GPIOD_IN, "udc_vbus"); + if (IS_ERR(board->vbus_pin)) + board->vbus_pin = NULL; - board->pullup_pin = of_get_named_gpio_flags(np, "atmel,pullup-gpio", 0, - &flags); - - board->pullup_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0; + board->pullup_pin = gpiod_get_from_of_node(np, "atmel,pullup-gpio", 0, + GPIOD_ASIS, "udc_pullup"); + if (IS_ERR(board->pullup_pin)) + board->pullup_pin = NULL; match = of_match_node(at91_udc_dt_ids, np); if (match) @@ -1886,22 +1875,14 @@ static int at91udc_probe(struct platform_device *pdev) goto err_unprepare_iclk; } - if (gpio_is_valid(udc->board.vbus_pin)) { - retval = devm_gpio_request(dev, udc->board.vbus_pin, - "udc_vbus"); - if (retval) { - DBG("request vbus pin failed\n"); - goto err_unprepare_iclk; - } - - gpio_direction_input(udc->board.vbus_pin); + if (udc->board.vbus_pin) { + gpiod_direction_input(udc->board.vbus_pin); /* * Get the initial state of VBUS - we cannot expect * a pending interrupt. */ - udc->vbus = gpio_get_value_cansleep(udc->board.vbus_pin) ^ - udc->board.vbus_active_low; + udc->vbus = gpiod_get_value_cansleep(udc->board.vbus_pin); if (udc->board.vbus_polled) { INIT_WORK(&udc->vbus_timer_work, at91_vbus_timer_work); @@ -1910,7 +1891,7 @@ static int at91udc_probe(struct platform_device *pdev) jiffies + VBUS_POLL_TIMEOUT); } else { retval = devm_request_irq(dev, - gpio_to_irq(udc->board.vbus_pin), + gpiod_to_irq(udc->board.vbus_pin), at91_vbus_irq, 0, driver_name, udc); if (retval) { DBG("request vbus irq %d failed\n", @@ -1988,8 +1969,8 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg) enable_irq_wake(udc->udp_irq); udc->active_suspend = wake; - if (gpio_is_valid(udc->board.vbus_pin) && !udc->board.vbus_polled && wake) - enable_irq_wake(udc->board.vbus_pin); + if (udc->board.vbus_pin && !udc->board.vbus_polled && wake) + enable_irq_wake(gpiod_to_irq(udc->board.vbus_pin)); return 0; } @@ -1998,9 +1979,9 @@ static int at91udc_resume(struct platform_device *pdev) struct at91_udc *udc = platform_get_drvdata(pdev); unsigned long flags; - if (gpio_is_valid(udc->board.vbus_pin) && !udc->board.vbus_polled && + if (udc->board.vbus_pin && !udc->board.vbus_polled && udc->active_suspend) - disable_irq_wake(udc->board.vbus_pin); + disable_irq_wake(gpiod_to_irq(udc->board.vbus_pin)); /* maybe reconnect to host; if so, clocks on */ if (udc->active_suspend) diff --git a/drivers/usb/gadget/udc/at91_udc.h b/drivers/usb/gadget/udc/at91_udc.h index fd58c5b81826..28c1042f8623 100644 --- a/drivers/usb/gadget/udc/at91_udc.h +++ b/drivers/usb/gadget/udc/at91_udc.h @@ -109,11 +109,9 @@ struct at91_udc_caps { }; struct at91_udc_data { - int vbus_pin; /* high == host powering us */ - u8 vbus_active_low; /* vbus polarity */ - u8 vbus_polled; /* Use polling, not interrupt */ - int pullup_pin; /* active == D+ pulled up */ - u8 pullup_active_low; /* true == pullup_pin is active low */ + struct gpio_desc *vbus_pin; /* high == host powering us */ + u8 vbus_polled; /* Use polling, not interrupt */ + struct gpio_desc *pullup_pin; /* active == D+ pulled up */ }; /* diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c index a9f07c59fc37..2cdb07905bde 100644 --- a/drivers/usb/gadget/udc/bcm63xx_udc.c +++ b/drivers/usb/gadget/udc/bcm63xx_udc.c @@ -2321,8 +2321,10 @@ static int bcm63xx_udc_probe(struct platform_device *pdev) /* IRQ resource #0: control interrupt (VBUS, speed, etc.) */ irq = platform_get_irq(pdev, 0); - if (irq < 0) + if (irq < 0) { + rc = irq; goto out_uninit; + } if (devm_request_irq(dev, irq, &bcm63xx_udc_ctrl_isr, 0, dev_name(dev), udc) < 0) goto report_request_failure; @@ -2330,8 +2332,10 @@ static int bcm63xx_udc_probe(struct platform_device *pdev) /* IRQ resources #1-6: data interrupts for IUDMA channels 0-5 */ for (i = 0; i < BCM63XX_NUM_IUDMA; i++) { irq = platform_get_irq(pdev, i + 1); - if (irq < 0) + if (irq < 0) { + rc = irq; goto out_uninit; + } if (devm_request_irq(dev, irq, &bcm63xx_udc_data_isr, 0, dev_name(dev), &udc->iudma[i]) < 0) goto report_request_failure; diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c index fa1a3908ec3b..9849e0c86e23 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_core.c +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c @@ -623,6 +623,7 @@ static int bdc_resume(struct device *dev) ret = bdc_reinit(bdc); if (ret) { dev_err(bdc->dev, "err in bdc reinit\n"); + clk_disable_unprepare(bdc->clk); return ret; } diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index 7f24ce400b59..b6d34dda028b 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -2084,10 +2084,8 @@ static int mv_udc_remove(struct platform_device *pdev) usb_del_gadget_udc(&udc->gadget); - if (udc->qwork) { - flush_workqueue(udc->qwork); + if (udc->qwork) destroy_workqueue(udc->qwork); - } /* free memory allocated in probe */ dma_pool_destroy(udc->dtd_pool); diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index 52cdfd8212d6..b38747fd3bb0 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -2364,7 +2364,7 @@ static int pxa25x_udc_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) - return -ENODEV; + return irq; dev->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dev->regs)) diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index 857159dd5ae0..6ce886fb7bfe 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -2179,6 +2179,61 @@ static int xudc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int xudc_suspend(struct device *dev) +{ + struct xusb_udc *udc; + u32 crtlreg; + unsigned long flags; + + udc = dev_get_drvdata(dev); + + spin_lock_irqsave(&udc->lock, flags); + + crtlreg = udc->read_fn(udc->addr + XUSB_CONTROL_OFFSET); + crtlreg &= ~XUSB_CONTROL_USB_READY_MASK; + + udc->write_fn(udc->addr, XUSB_CONTROL_OFFSET, crtlreg); + + spin_unlock_irqrestore(&udc->lock, flags); + if (udc->driver && udc->driver->suspend) + udc->driver->suspend(&udc->gadget); + + clk_disable(udc->clk); + + return 0; +} + +static int xudc_resume(struct device *dev) +{ + struct xusb_udc *udc; + u32 crtlreg; + unsigned long flags; + int ret; + + udc = dev_get_drvdata(dev); + + ret = clk_enable(udc->clk); + if (ret < 0) + return ret; + + spin_lock_irqsave(&udc->lock, flags); + + crtlreg = udc->read_fn(udc->addr + XUSB_CONTROL_OFFSET); + crtlreg |= XUSB_CONTROL_USB_READY_MASK; + + udc->write_fn(udc->addr, XUSB_CONTROL_OFFSET, crtlreg); + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops xudc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(xudc_suspend, xudc_resume) +}; + /* Match table for of_platform binding */ static const struct of_device_id usb_of_match[] = { { .compatible = "xlnx,usb2-device-4.00.a", }, @@ -2190,6 +2245,7 @@ static struct platform_driver xudc_driver = { .driver = { .name = driver_name, .of_match_table = usb_of_match, + .pm = &xudc_pm_ops, }, .probe = xudc_probe, .remove = xudc_remove, |