Loading drivers/usb/dwc3/core.h +8 −0 Original line number Diff line number Diff line Loading @@ -825,6 +825,13 @@ enum dwc3_link_state { DWC3_LINK_STATE_MASK = 0x0f, }; enum gadget_state { DWC3_GADGET_INACTIVE, DWC3_GADGET_SOFT_CONN, DWC3_GADGET_CABLE_CONN, DWC3_GADGET_ACTIVE, }; /* TRB Length, PCM and Status */ #define DWC3_TRB_SIZE_MASK (0x00ffffff) #define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK) Loading Loading @@ -1343,6 +1350,7 @@ struct dwc3 { unsigned int irq_event_count[MAX_INTR_STATS]; unsigned int irq_dbg_index; enum gadget_state gadget_state; /* Indicate if the gadget was powered by the otg driver */ unsigned int vbus_active:1; /* Indicate if software connect was issued by the usb_gadget_driver */ Loading drivers/usb/dwc3/gadget.c +70 −15 Original line number Diff line number Diff line Loading @@ -2226,6 +2226,71 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) return 0; } static int dwc3_gadget_run_stop_util(struct dwc3 *dwc) { int ret = 0; dev_dbg(dwc->dev, "%s: enter: %d\n", __func__, dwc->gadget_state); switch (dwc->gadget_state) { case DWC3_GADGET_INACTIVE: if (dwc->vbus_active && dwc->softconnect) { ret = dwc3_gadget_run_stop(dwc, true, false); dwc->gadget_state = DWC3_GADGET_ACTIVE; break; } if (dwc->vbus_active) { dwc->gadget_state = DWC3_GADGET_CABLE_CONN; break; } if (dwc->softconnect) { dwc->gadget_state = DWC3_GADGET_SOFT_CONN; break; } case DWC3_GADGET_SOFT_CONN: if (!dwc->softconnect) { dwc->gadget_state = DWC3_GADGET_INACTIVE; break; } if (dwc->vbus_active) { ret = dwc3_gadget_run_stop(dwc, true, false); dwc->gadget_state = DWC3_GADGET_ACTIVE; } break; case DWC3_GADGET_CABLE_CONN: if (!dwc->vbus_active) { dwc->gadget_state = DWC3_GADGET_INACTIVE; break; } if (dwc->softconnect) { ret = dwc3_gadget_run_stop(dwc, true, false); dwc->gadget_state = DWC3_GADGET_ACTIVE; } break; case DWC3_GADGET_ACTIVE: if (!dwc->vbus_active) { dwc->gadget_state = DWC3_GADGET_SOFT_CONN; ret = dwc3_gadget_run_stop(dwc, false, false); break; } if (!dwc->softconnect) { dwc->gadget_state = DWC3_GADGET_CABLE_CONN; ret = dwc3_gadget_run_stop(dwc, false, false); break; } break; default: dev_err(dwc->dev, "Invalid state\n"); } dev_dbg(dwc->dev, "%s: exit: %d\n", __func__, dwc->gadget_state); return ret; } static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA) { struct dwc3 *dwc = gadget_to_dwc(g); Loading @@ -2245,6 +2310,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) ktime_t diff; is_on = !!is_on; spin_lock_irqsave(&dwc->lock, flags); dwc->softconnect = is_on; if ((dwc3_is_otg_or_drd(dwc) && !dwc->vbus_active) Loading @@ -2253,9 +2319,11 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) * Need to wait for vbus_session(on) from otg driver or to * the udc_start. */ spin_unlock_irqrestore(&dwc->lock, flags); dbg_event(0xFF, "WaitPullup", 0); return 0; } spin_unlock_irqrestore(&dwc->lock, flags); pm_runtime_get_sync(dwc->dev); dbg_event(0xFF, "Pullup gsync", Loading Loading @@ -2307,7 +2375,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) dwc->b_suspend = false; dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0); ret = dwc3_gadget_run_stop(dwc, is_on, false); ret = dwc3_gadget_run_stop_util(dwc); spin_unlock_irqrestore(&dwc->lock, flags); if (!is_on && ret == -ETIMEDOUT) { dev_err(dwc->dev, "%s: Core soft reset...\n", __func__); Loading Loading @@ -2421,26 +2489,13 @@ static int dwc3_gadget_vbus_session(struct usb_gadget *_gadget, int is_active) /* Mark that the vbus was powered */ dwc->vbus_active = is_active; /* * Check if upper level usb_gadget_driver was already registered with * this udc controller driver (if dwc3_gadget_start was called) */ if (dwc->gadget_driver && dwc->softconnect) { if (dwc->vbus_active) { /* * Both vbus was activated by otg and pullup was * signaled by the gadget driver. */ ret = dwc3_gadget_run_stop(dwc, 1, false); } } ret = dwc3_gadget_run_stop_util(dwc); /* * Clearing run/stop bit might occur before disconnect event is seen. * Make sure to let gadget driver know in that case. */ if (!dwc->vbus_active) { ret = dwc3_gadget_run_stop(dwc, 0, false); dev_dbg(dwc->dev, "calling disconnect from %s\n", __func__); dwc3_gadget_disconnect_interrupt(dwc); } Loading Loading
drivers/usb/dwc3/core.h +8 −0 Original line number Diff line number Diff line Loading @@ -825,6 +825,13 @@ enum dwc3_link_state { DWC3_LINK_STATE_MASK = 0x0f, }; enum gadget_state { DWC3_GADGET_INACTIVE, DWC3_GADGET_SOFT_CONN, DWC3_GADGET_CABLE_CONN, DWC3_GADGET_ACTIVE, }; /* TRB Length, PCM and Status */ #define DWC3_TRB_SIZE_MASK (0x00ffffff) #define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK) Loading Loading @@ -1343,6 +1350,7 @@ struct dwc3 { unsigned int irq_event_count[MAX_INTR_STATS]; unsigned int irq_dbg_index; enum gadget_state gadget_state; /* Indicate if the gadget was powered by the otg driver */ unsigned int vbus_active:1; /* Indicate if software connect was issued by the usb_gadget_driver */ Loading
drivers/usb/dwc3/gadget.c +70 −15 Original line number Diff line number Diff line Loading @@ -2226,6 +2226,71 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) return 0; } static int dwc3_gadget_run_stop_util(struct dwc3 *dwc) { int ret = 0; dev_dbg(dwc->dev, "%s: enter: %d\n", __func__, dwc->gadget_state); switch (dwc->gadget_state) { case DWC3_GADGET_INACTIVE: if (dwc->vbus_active && dwc->softconnect) { ret = dwc3_gadget_run_stop(dwc, true, false); dwc->gadget_state = DWC3_GADGET_ACTIVE; break; } if (dwc->vbus_active) { dwc->gadget_state = DWC3_GADGET_CABLE_CONN; break; } if (dwc->softconnect) { dwc->gadget_state = DWC3_GADGET_SOFT_CONN; break; } case DWC3_GADGET_SOFT_CONN: if (!dwc->softconnect) { dwc->gadget_state = DWC3_GADGET_INACTIVE; break; } if (dwc->vbus_active) { ret = dwc3_gadget_run_stop(dwc, true, false); dwc->gadget_state = DWC3_GADGET_ACTIVE; } break; case DWC3_GADGET_CABLE_CONN: if (!dwc->vbus_active) { dwc->gadget_state = DWC3_GADGET_INACTIVE; break; } if (dwc->softconnect) { ret = dwc3_gadget_run_stop(dwc, true, false); dwc->gadget_state = DWC3_GADGET_ACTIVE; } break; case DWC3_GADGET_ACTIVE: if (!dwc->vbus_active) { dwc->gadget_state = DWC3_GADGET_SOFT_CONN; ret = dwc3_gadget_run_stop(dwc, false, false); break; } if (!dwc->softconnect) { dwc->gadget_state = DWC3_GADGET_CABLE_CONN; ret = dwc3_gadget_run_stop(dwc, false, false); break; } break; default: dev_err(dwc->dev, "Invalid state\n"); } dev_dbg(dwc->dev, "%s: exit: %d\n", __func__, dwc->gadget_state); return ret; } static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA) { struct dwc3 *dwc = gadget_to_dwc(g); Loading @@ -2245,6 +2310,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) ktime_t diff; is_on = !!is_on; spin_lock_irqsave(&dwc->lock, flags); dwc->softconnect = is_on; if ((dwc3_is_otg_or_drd(dwc) && !dwc->vbus_active) Loading @@ -2253,9 +2319,11 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) * Need to wait for vbus_session(on) from otg driver or to * the udc_start. */ spin_unlock_irqrestore(&dwc->lock, flags); dbg_event(0xFF, "WaitPullup", 0); return 0; } spin_unlock_irqrestore(&dwc->lock, flags); pm_runtime_get_sync(dwc->dev); dbg_event(0xFF, "Pullup gsync", Loading Loading @@ -2307,7 +2375,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) dwc->b_suspend = false; dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0); ret = dwc3_gadget_run_stop(dwc, is_on, false); ret = dwc3_gadget_run_stop_util(dwc); spin_unlock_irqrestore(&dwc->lock, flags); if (!is_on && ret == -ETIMEDOUT) { dev_err(dwc->dev, "%s: Core soft reset...\n", __func__); Loading Loading @@ -2421,26 +2489,13 @@ static int dwc3_gadget_vbus_session(struct usb_gadget *_gadget, int is_active) /* Mark that the vbus was powered */ dwc->vbus_active = is_active; /* * Check if upper level usb_gadget_driver was already registered with * this udc controller driver (if dwc3_gadget_start was called) */ if (dwc->gadget_driver && dwc->softconnect) { if (dwc->vbus_active) { /* * Both vbus was activated by otg and pullup was * signaled by the gadget driver. */ ret = dwc3_gadget_run_stop(dwc, 1, false); } } ret = dwc3_gadget_run_stop_util(dwc); /* * Clearing run/stop bit might occur before disconnect event is seen. * Make sure to let gadget driver know in that case. */ if (!dwc->vbus_active) { ret = dwc3_gadget_run_stop(dwc, 0, false); dev_dbg(dwc->dev, "calling disconnect from %s\n", __func__); dwc3_gadget_disconnect_interrupt(dwc); } Loading