From fc30c4bb44a3665edcc76bd7af93f009bc9dc672 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 23 Jan 2017 14:59:35 -0800 Subject: 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 Cc: Guodong Xu Cc: Amit Pundir Cc: Rob Herring Cc: John Youn Cc: Douglas Anderson Cc: Chen Yu Cc: Vardan Mikayelyan Cc: Kishon Vijay Abraham I Cc: Felipe Balbi Cc: Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org Reviewed-by: Vardan Mikayelyan Signed-off-by: John Stultz Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/hcd.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/usb/dwc2') diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 8b688b041696..e0d152f2c81b 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -3237,6 +3237,14 @@ static void dwc2_conn_id_status_change(struct work_struct *work) dwc2_is_host_mode(hsotg) ? "Host" : "Peripheral"); 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) break; } @@ -3251,6 +3259,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work) spin_unlock_irqrestore(&hsotg->lock, flags); dwc2_hsotg_core_connect(hsotg); } else { +host: /* A-Device connector (Host Mode) */ dev_dbg(hsotg->dev, "connId A\n"); while (!dwc2_is_host_mode(hsotg)) { -- cgit v1.2.3-55-g7522