Commit fc30c4bb authored by John Stultz's avatar John Stultz Committed by Felipe Balbi

usb: dwc2: Workaround case where GOTGCTL state is wrong

When removing a USB-A to USB-otg adapter cable, we get a change status
irq, and then in dwc2_conn_id_status_change, we erroneously see the
GOTGCTL_CONID_B flag set. This causes us to get stuck in the
"while (!dwc2_is_device_mode(hsotg))" loop, spitting out "Waiting for
Peripheral Mode, Mode=Host" warnings until it fails out many seconds
later.

This patch works around the issue by re-reading the GOTGCTL state to
check if the GOTGCTL_CONID_B is still set and if not restarting the
change status logic.

Cc: Wei Xu <xuwei5@hisilicon.com>
Cc: Guodong Xu <guodong.xu@linaro.org>
Cc: Amit Pundir <amit.pundir@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: John Youn <johnyoun@synopsys.com>
Cc: Douglas Anderson <dianders@chromium.org>
Cc: Chen Yu <chenyu56@huawei.com>
Cc: Vardan Mikayelyan <mvardan@synopsys.com>
Cc: Kishon Vijay Abraham I <kishon@ti.com>
Cc: Felipe Balbi <felipe.balbi@linux.intel.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-usb@vger.kernel.org
Reviewed-by: default avatarVardan Mikayelyan <mvardan@synopsys.com>
Signed-off-by: default avatarJohn Stultz <john.stultz@linaro.org>
Signed-off-by: default avatarJohn Youn <johnyoun@synopsys.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent 6e6360b6
...@@ -3237,6 +3237,14 @@ static void dwc2_conn_id_status_change(struct work_struct *work) ...@@ -3237,6 +3237,14 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
dwc2_is_host_mode(hsotg) ? "Host" : dwc2_is_host_mode(hsotg) ? "Host" :
"Peripheral"); "Peripheral");
msleep(20); msleep(20);
/*
* Sometimes the initial GOTGCTRL read is wrong, so
* check it again and jump to host mode if that was
* the case.
*/
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
if (!(gotgctl & GOTGCTL_CONID_B))
goto host;
if (++count > 250) if (++count > 250)
break; break;
} }
...@@ -3251,6 +3259,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work) ...@@ -3251,6 +3259,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
spin_unlock_irqrestore(&hsotg->lock, flags); spin_unlock_irqrestore(&hsotg->lock, flags);
dwc2_hsotg_core_connect(hsotg); dwc2_hsotg_core_connect(hsotg);
} else { } else {
host:
/* A-Device connector (Host Mode) */ /* A-Device connector (Host Mode) */
dev_dbg(hsotg->dev, "connId A\n"); dev_dbg(hsotg->dev, "connId A\n");
while (!dwc2_is_host_mode(hsotg)) { while (!dwc2_is_host_mode(hsotg)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment