diff options
Diffstat (limited to 'drivers/usb')
| -rw-r--r-- | drivers/usb/chipidea/otg.h | 3 | ||||
| -rw-r--r-- | drivers/usb/class/cdc-acm.c | 3 | ||||
| -rw-r--r-- | drivers/usb/core/hub.c | 4 | ||||
| -rw-r--r-- | drivers/usb/core/quirks.c | 8 | ||||
| -rw-r--r-- | drivers/usb/dwc3/dwc3-msm.c | 62 | ||||
| -rw-r--r-- | drivers/usb/gadget/function/f_gsi.c | 11 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-hub.c | 68 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-ring.c | 2 | ||||
| -rw-r--r-- | drivers/usb/host/xhci.h | 2 | ||||
| -rw-r--r-- | drivers/usb/misc/appledisplay.c | 1 | ||||
| -rw-r--r-- | drivers/usb/misc/diag_ipc_bridge.c | 2 | ||||
| -rw-r--r-- | drivers/usb/misc/ks_bridge.c | 1 |
12 files changed, 125 insertions, 42 deletions
diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h index 9ecb598e48f0..a5557c70034a 100644 --- a/drivers/usb/chipidea/otg.h +++ b/drivers/usb/chipidea/otg.h @@ -20,7 +20,8 @@ void ci_handle_vbus_change(struct ci_hdrc *ci); static inline void ci_otg_queue_work(struct ci_hdrc *ci) { disable_irq_nosync(ci->irq); - queue_work(ci->wq, &ci->work); + if (queue_work(ci->wq, &ci->work) == false) + enable_irq(ci->irq); } #endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */ diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 3cbf6aa10f2c..0a8e5ac891d4 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1716,6 +1716,9 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, + { USB_DEVICE(0x0572, 0x1349), /* Hiro (Conexant) USB MODEM H50228 */ + .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ + }, { USB_DEVICE(0x20df, 0x0001), /* Simtec Electronics Entropy Key */ .driver_info = QUIRK_CONTROL_LINE_STATE, }, { USB_DEVICE(0x2184, 0x001c) }, /* GW Instek AFG-2225 */ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 1e25aa251c05..ebae7460a60e 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2768,7 +2768,9 @@ static int hub_port_reset(struct usb_hub *hub, int port1, USB_PORT_FEAT_C_BH_PORT_RESET); usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_PORT_LINK_STATE); - usb_clear_port_feature(hub->hdev, port1, + + if (udev) + usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_CONNECTION); /* diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 37a5e07b3488..1e8f68960014 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -243,6 +243,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT | USB_QUIRK_DELAY_CTRL_MSG }, + /* Corsair K70 LUX RGB */ + { USB_DEVICE(0x1b1c, 0x1b33), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Corsair K70 LUX */ { USB_DEVICE(0x1b1c, 0x1b36), .driver_info = USB_QUIRK_DELAY_INIT }, @@ -263,6 +266,11 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x2040, 0x7200), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, + /* Raydium Touchscreen */ + { USB_DEVICE(0x2386, 0x3114), .driver_info = USB_QUIRK_NO_LPM }, + + { USB_DEVICE(0x2386, 0x3119), .driver_info = USB_QUIRK_NO_LPM }, + /* DJI CineSSD */ { USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM }, diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 5f547793eb9f..1c7d7af6787a 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -202,6 +202,7 @@ struct dwc3_msm { struct power_supply *usb_psy; struct work_struct vbus_draw_work; bool in_host_mode; + bool in_device_mode; enum usb_device_speed max_rh_port_speed; unsigned int tx_fifo_size; bool vbus_active; @@ -239,6 +240,8 @@ struct dwc3_msm { struct delayed_work sdp_check; bool usb_compliance_mode; struct mutex suspend_resume_mutex; + + enum usb_device_speed override_usb_speed; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ @@ -1574,8 +1577,17 @@ static void dwc3_restart_usb_work(struct work_struct *w) mdwc->in_restart = false; /* Force reconnect only if cable is still connected */ - if (mdwc->vbus_active) + if (mdwc->vbus_active) { + if (mdwc->override_usb_speed) { + dwc->maximum_speed = mdwc->override_usb_speed; + dwc->gadget.max_speed = dwc->maximum_speed; + dbg_event(0xFF, "override_usb_speed", + mdwc->override_usb_speed); + mdwc->override_usb_speed = 0; + } + dwc3_resume_work(&mdwc->resume_work); + } dwc->err_evt_seen = false; flush_delayed_work(&mdwc->sm_work); @@ -1934,7 +1946,7 @@ static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc) unsigned long timeout; u32 reg = 0; - if ((mdwc->in_host_mode || mdwc->vbus_active) + if ((mdwc->in_host_mode || mdwc->in_device_mode) && dwc3_msm_is_superspeed(mdwc) && !mdwc->in_restart) { if (!atomic_read(&mdwc->in_p3)) { dev_err(mdwc->dev, "Not in P3,aborting LPM sequence\n"); @@ -2017,8 +2029,6 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool hibernation) int ret, i; struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); - dbg_event(0xFF, "Ctl Sus", atomic_read(&dwc->in_lpm)); - mutex_lock(&mdwc->suspend_resume_mutex); if (atomic_read(&dwc->in_lpm)) { dev_dbg(mdwc->dev, "%s: Already suspended\n", __func__); @@ -2134,8 +2144,8 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool hibernation) clk_disable_unprepare(mdwc->xo_clk); /* Perform controller power collapse */ - if ((!mdwc->in_host_mode && (!mdwc->vbus_active || mdwc->in_restart)) || - hibernation) { + if ((!mdwc->in_host_mode && (!mdwc->in_device_mode || mdwc->in_restart)) + || hibernation) { mdwc->lpm_flags |= MDWC3_POWER_COLLAPSE; dev_dbg(mdwc->dev, "%s: power collapse\n", __func__); dwc3_msm_config_gdsc(mdwc, 0); @@ -2168,7 +2178,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool hibernation) * using HS_PHY_IRQ or SS_PHY_IRQ. Hence enable wakeup only in * case of host bus suspend and device bus suspend. */ - if (mdwc->vbus_active || mdwc->in_host_mode) { + if (mdwc->in_device_mode || mdwc->in_host_mode) { if (!mdwc->no_wakeup_src_in_hostmode) enable_irq_wake(mdwc->hs_phy_irq); enable_irq(mdwc->hs_phy_irq); @@ -2181,6 +2191,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool hibernation) } dev_info(mdwc->dev, "DWC3 in low power mode\n"); + dbg_event(0xFF, "Ctl Sus", atomic_read(&dwc->in_lpm)); mutex_unlock(&mdwc->suspend_resume_mutex); return 0; } @@ -2649,6 +2660,13 @@ static int dwc3_msm_id_notifier(struct notifier_block *nb, if (dwc->maximum_speed > dwc->max_hw_supp_speed) dwc->maximum_speed = dwc->max_hw_supp_speed; + if (!id && mdwc->override_usb_speed) { + dwc->maximum_speed = mdwc->override_usb_speed; + dbg_event(0xFF, "override_usb_speed", + mdwc->override_usb_speed); + mdwc->override_usb_speed = 0; + } + if (mdwc->id_state != id) { mdwc->id_state = id; dbg_event(0xFF, "id_state", mdwc->id_state); @@ -2833,14 +2851,19 @@ static ssize_t mode_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RW(mode); +/* This node only shows max speed supported dwc3 and it should be + * same as what is reported in udc/core.c max_speed node. For current + * operating gadget speed, query current_speed node which is implemented + * by udc/core.c + */ static ssize_t speed_show(struct device *dev, struct device_attribute *attr, char *buf) { struct dwc3_msm *mdwc = dev_get_drvdata(dev); struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); - return snprintf(buf, PAGE_SIZE, "%s", - usb_speed_string(dwc->max_hw_supp_speed)); + return snprintf(buf, PAGE_SIZE, "%s\n", + usb_speed_string(dwc->maximum_speed)); } static ssize_t speed_store(struct device *dev, struct device_attribute *attr, @@ -2850,14 +2873,25 @@ static ssize_t speed_store(struct device *dev, struct device_attribute *attr, struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); enum usb_device_speed req_speed = USB_SPEED_UNKNOWN; - if (sysfs_streq(buf, "high")) + /* DEVSPD can only have values SS(0x4), HS(0x0) and FS(0x1). + * per 3.20a data book. Allow only these settings. Note that, + * xhci does not support full-speed only mode. + */ + if (sysfs_streq(buf, "full")) + req_speed = USB_SPEED_FULL; + else if (sysfs_streq(buf, "high")) req_speed = USB_SPEED_HIGH; else if (sysfs_streq(buf, "super")) req_speed = USB_SPEED_SUPER; + else + return -EINVAL; - if (req_speed != USB_SPEED_UNKNOWN && - req_speed != dwc->max_hw_supp_speed) { - dwc->maximum_speed = dwc->max_hw_supp_speed = req_speed; + /* restart usb only works for device mode. Perform manual cable + * plug in/out for host mode restart. + */ + if (req_speed != dwc->maximum_speed && + req_speed <= dwc->max_hw_supp_speed) { + mdwc->override_usb_speed = req_speed; schedule_work(&mdwc->restart_usb_work); } @@ -3725,6 +3759,7 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on) dwc3_msm_block_reset(mdwc, false); dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); + mdwc->in_device_mode = true; usb_gadget_vbus_connect(&dwc->gadget); #ifdef CONFIG_SMP mdwc->pm_qos_req_dma.type = PM_QOS_REQ_AFFINE_IRQ; @@ -3743,6 +3778,7 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on) msm_dwc3_perf_vote_update(mdwc, false); pm_qos_remove_request(&mdwc->pm_qos_req_dma); + mdwc->in_device_mode = false; usb_gadget_vbus_disconnect(&dwc->gadget); usb_phy_notify_disconnect(mdwc->hs_phy, USB_SPEED_HIGH); usb_phy_notify_disconnect(mdwc->ss_phy, USB_SPEED_SUPER); diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index ff61879767b3..266d19049986 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -2843,16 +2843,13 @@ static void gsi_unbind(struct usb_configuration *c, struct usb_function *f) if (gsi->prot_id == IPA_USB_MBIM) mbim_gsi_ext_config_desc.function.subCompatibleID[0] = 0; - if (gadget_is_superspeed(c->cdev->gadget)) { + if (gadget_is_superspeed(c->cdev->gadget)) usb_free_descriptors(f->ss_descriptors); - f->ss_descriptors = NULL; - } - if (gadget_is_dualspeed(c->cdev->gadget)) { + + if (gadget_is_dualspeed(c->cdev->gadget)) usb_free_descriptors(f->hs_descriptors); - f->hs_descriptors = NULL; - } + usb_free_descriptors(f->fs_descriptors); - f->fs_descriptors = NULL; if (gsi->c_port.notify) { kfree(gsi->c_port.notify_req->buf); diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 744157e73acb..61da1a22b98a 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -348,7 +348,7 @@ int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci, slot_id = 0; for (i = 0; i < MAX_HC_SLOTS; i++) { - if (!xhci->devs[i]) + if (!xhci->devs[i] || !xhci->devs[i]->udev) continue; speed = xhci->devs[i]->udev->speed; if (((speed >= USB_SPEED_SUPER) == (hcd->speed >= HCD_USB3)) @@ -747,7 +747,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, status |= USB_PORT_STAT_SUSPEND; } if ((raw_port_status & PORT_PLS_MASK) == XDEV_RESUME && - !DEV_SUPERSPEED_ANY(raw_port_status)) { + !DEV_SUPERSPEED_ANY(raw_port_status) && hcd->speed < HCD_USB3) { if ((raw_port_status & PORT_RESET) || !(raw_port_status & PORT_PE)) return 0xffffffff; @@ -793,7 +793,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, time_left = wait_for_completion_timeout( &bus_state->rexit_done[wIndex], msecs_to_jiffies( - XHCI_MAX_REXIT_TIMEOUT)); + XHCI_MAX_REXIT_TIMEOUT_MS)); spin_lock_irqsave(&xhci->lock, flags); if (time_left) { @@ -807,7 +807,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, } else { int port_status = readl(port_array[wIndex]); xhci_warn(xhci, "Port resume took longer than %i msec, port status = 0x%x\n", - XHCI_MAX_REXIT_TIMEOUT, + XHCI_MAX_REXIT_TIMEOUT_MS, port_status); status |= USB_PORT_STAT_SUSPEND; clear_bit(wIndex, &bus_state->rexit_ports); @@ -1473,13 +1473,16 @@ int xhci_bus_suspend(struct usb_hcd *hcd) __le32 __iomem **port_array; struct xhci_bus_state *bus_state; unsigned long flags; + u32 portsc_buf[USB_MAXCHILDREN]; + bool wake_enabled; max_ports = xhci_get_ports(hcd, &port_array); bus_state = &xhci->bus_state[hcd_index(hcd)]; + wake_enabled = hcd->self.root_hub->do_remote_wakeup; spin_lock_irqsave(&xhci->lock, flags); - if (hcd->self.root_hub->do_remote_wakeup) { + if (wake_enabled) { if (bus_state->resuming_ports || /* USB2 */ bus_state->port_remote_wakeup) { /* USB3 */ spin_unlock_irqrestore(&xhci->lock, flags); @@ -1487,26 +1490,36 @@ int xhci_bus_suspend(struct usb_hcd *hcd) return -EBUSY; } } - - port_index = max_ports; + /* + * Prepare ports for suspend, but don't write anything before all ports + * are checked and we know bus suspend can proceed + */ bus_state->bus_suspended = 0; + port_index = max_ports; while (port_index--) { - /* suspend the port if the port is not suspended */ u32 t1, t2; - int slot_id; t1 = readl(port_array[port_index]); t2 = xhci_port_state_to_neutral(t1); + portsc_buf[port_index] = 0; - if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) { - xhci_dbg(xhci, "port %d not suspended\n", port_index); - slot_id = xhci_find_slot_id_by_port(hcd, xhci, - port_index + 1); - if (slot_id) { + /* Bail out if a USB3 port has a new device in link training */ + if ((t1 & PORT_PLS_MASK) == XDEV_POLLING) { + bus_state->bus_suspended = 0; + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_dbg(xhci, "Bus suspend bailout, port in polling\n"); + return -EBUSY; + } + + /* suspend ports in U0, or bail out for new connect changes */ + if ((t1 & PORT_PE) && (t1 & PORT_PLS_MASK) == XDEV_U0) { + if ((t1 & PORT_CSC) && wake_enabled) { + bus_state->bus_suspended = 0; spin_unlock_irqrestore(&xhci->lock, flags); - xhci_stop_device(xhci, slot_id, 1); - spin_lock_irqsave(&xhci->lock, flags); + xhci_dbg(xhci, "Bus suspend bailout, port connect change\n"); + return -EBUSY; } + xhci_dbg(xhci, "port %d not suspended\n", port_index); t2 &= ~PORT_PLS_MASK; t2 |= PORT_LINK_STROBE | XDEV_U3; set_bit(port_index, &bus_state->bus_suspended); @@ -1515,7 +1528,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd) * including the USB 3.0 roothub, but only if CONFIG_PM * is enabled, so also enable remote wake here. */ - if (hcd->self.root_hub->do_remote_wakeup) { + if (wake_enabled) { if (t1 & PORT_CONNECT) { t2 |= PORT_WKOC_E | PORT_WKDISC_E; t2 &= ~PORT_WKCONN_E; @@ -1528,7 +1541,26 @@ int xhci_bus_suspend(struct usb_hcd *hcd) t1 = xhci_port_state_to_neutral(t1); if (t1 != t2) - writel(t2, port_array[port_index]); + portsc_buf[port_index] = t2; + } + + /* write port settings, stopping and suspending ports if needed */ + port_index = max_ports; + while (port_index--) { + if (!portsc_buf[port_index]) + continue; + if (test_bit(port_index, &bus_state->bus_suspended)) { + int slot_id; + + slot_id = xhci_find_slot_id_by_port(hcd, xhci, + port_index + 1); + if (slot_id) { + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_stop_device(xhci, slot_id, 1); + spin_lock_irqsave(&xhci->lock, flags); + } + } + writel(portsc_buf[port_index], port_array[port_index]); } hcd->state = HC_STATE_SUSPENDED; bus_state->next_statechange = jiffies + msecs_to_jiffies(10); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 5bfe47816ac3..e6d366d4e80b 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1673,7 +1673,7 @@ static void handle_port_status(struct xhci_hcd *xhci, * RExit to a disconnect state). If so, let the the driver know it's * out of the RExit state. */ - if (!DEV_SUPERSPEED_ANY(temp) && + if (!DEV_SUPERSPEED_ANY(temp) && hcd->speed < HCD_USB3 && test_and_clear_bit(faked_port_index, &bus_state->rexit_ports)) { complete(&bus_state->rexit_done[faked_port_index]); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 72beaa47c15b..b3454c06bb0c 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1490,7 +1490,7 @@ struct xhci_bus_state { * It can take up to 20 ms to transition from RExit to U0 on the * Intel Lynx Point LP xHCI host. */ -#define XHCI_MAX_REXIT_TIMEOUT (20 * 1000) +#define XHCI_MAX_REXIT_TIMEOUT_MS 20 static inline unsigned int hcd_index(struct usb_hcd *hcd) { diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index a0a3827b4aff..b15842c6f916 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -63,6 +63,7 @@ static const struct usb_device_id appledisplay_table[] = { { APPLEDISPLAY_DEVICE(0x9219) }, { APPLEDISPLAY_DEVICE(0x921c) }, { APPLEDISPLAY_DEVICE(0x921d) }, + { APPLEDISPLAY_DEVICE(0x9222) }, { APPLEDISPLAY_DEVICE(0x9236) }, /* Terminating entry */ diff --git a/drivers/usb/misc/diag_ipc_bridge.c b/drivers/usb/misc/diag_ipc_bridge.c index 2ff3aa021bf8..cb3aa9375ca3 100644 --- a/drivers/usb/misc/diag_ipc_bridge.c +++ b/drivers/usb/misc/diag_ipc_bridge.c @@ -732,6 +732,8 @@ static const struct usb_device_id diag_bridge_ids[] = { .driver_info = DEV_ID(0), }, { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x901D, 0), .driver_info = DEV_ID(0), }, + { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x901F, 0), + .driver_info = DEV_ID(0), }, { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9034, 0), .driver_info = DEV_ID(0), }, { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9048, 0), diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c index 4004ba0437d5..3497880dea09 100644 --- a/drivers/usb/misc/ks_bridge.c +++ b/drivers/usb/misc/ks_bridge.c @@ -462,6 +462,7 @@ static const struct usb_device_id ksb_usb_ids[] = { { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9025, 0), }, { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9091, 0), }, { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x901D, 0), }, + { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x901F, 0), }, { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x900E, 0), }, { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9900, 0), }, { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9901, 0), }, |
