In device mode use cases, the following sequence of actions are observed: 1. Cable disconnect happens and clears qscratch HS_PHY_CTRL_REG properly 2. Disconnect event is generated and "connected" flag turns false. 3. Then the setmode notification from core goes to glue 4. Glue will set back the qscratch HS_PHY_CTRL_REG bits again. At this point, since the cable is removed, setting qscratch bits shouldn't affect anything. But it is observed that after setting this bits, the controller generated Event-0x101 and Event-0x30601 (bus reset and suspend) in order. In bus reset, we set back the "connected" flag and this blocks suspend again. So send set_mode call only if the cable is connected, else skip it. Signed-off-by: Krishna Kurapati <quic_kriskura@xxxxxxxxxxx> --- drivers/usb/dwc3/core.c | 3 ++- drivers/usb/dwc3/core.h | 2 ++ drivers/usb/dwc3/drd.c | 6 +++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index b4d1d1c98dd5..6ef1e3558384 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -137,7 +137,8 @@ static void __dwc3_set_mode(struct work_struct *work) if (!desired_dr_role) goto out; - dwc3_notify_set_mode(dwc, desired_dr_role); + if (dwc->cable_disconnected == false) + dwc3_notify_set_mode(dwc, desired_dr_role); if (desired_dr_role == dwc->current_dr_role) goto out; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 5ed7fd5eb776..1b79c407a798 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1365,6 +1365,8 @@ struct dwc3 { void *glue_data; const struct dwc3_glue_ops *glue_ops; + + bool cable_disconnected; }; #define INCRX_BURST_MODE 0 diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c index 947faeef0e4d..b3a87c40c4f1 100644 --- a/drivers/usb/dwc3/drd.c +++ b/drivers/usb/dwc3/drd.c @@ -446,6 +446,8 @@ static int dwc3_usb_role_switch_set(struct usb_role_switch *sw, struct dwc3 *dwc = usb_role_switch_get_drvdata(sw); u32 mode; + dwc->cable_disconnected = false; + switch (role) { case USB_ROLE_HOST: mode = DWC3_GCTL_PRTCAP_HOST; @@ -467,8 +469,10 @@ static int dwc3_usb_role_switch_set(struct usb_role_switch *sw, * glue needs to know that we are disconnected. It must not notify * the change of mode to default mode. */ - if (role == USB_ROLE_NONE) + if (role == USB_ROLE_NONE) { + dwc->cable_disconnected = true; dwc3_notify_cable_disconnect(dwc); + } dwc3_set_mode(dwc, mode); return 0; -- 2.42.0