From: Tony Lindgren tony@atomide.com
commit 5fbf7a2534703fd71159d3d71504b0ad01b43394 upstream.
When disconnected as USB B-device, suspend interrupt should come before diconnect interrupt, because the DP/DM pins are shorter than the VBUS/GND pins on the USB connectors. But we sometimes get a suspend interrupt after disconnect interrupt. In that case we have devctl set to 99 with VBUS still valid and musb_pm_runtime_check_session() wrongly thinks we have an active session. We have no other interrupts after disconnect coming in this case at least with the omap2430 glue.
Let's fix the issue by checking the interrupt status again with delayed work for the devctl 99 case. In the suspend after disconnect case the devctl session bit has cleared by then and musb can idle. For a typical USB B-device connect case we just continue with normal interrupts.
Fixes: 467d5c980709 ("usb: musb: Implement session bit based runtime PM for musb-core")
Cc: Merlijn Wajer merlijn@wizzup.org Cc: Pavel Machek pavel@ucw.cz Cc: Sebastian Reichel sre@kernel.org Cc: stable@vger.kernel.org Signed-off-by: Tony Lindgren tony@atomide.com Signed-off-by: Bin Liu b-liu@ti.com Link: https://lore.kernel.org/r/20200107152625.857-2-b-liu@ti.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/usb/musb/musb_core.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index b7d5627..05068a2 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1842,6 +1842,9 @@ static ssize_t srp_store(struct device *dev, struct device_attribute *attr, #define MUSB_QUIRK_B_INVALID_VBUS_91 (MUSB_DEVCTL_BDEVICE | \ (2 << MUSB_DEVCTL_VBUS_SHIFT) | \ MUSB_DEVCTL_SESSION) +#define MUSB_QUIRK_B_DISCONNECT_99 (MUSB_DEVCTL_BDEVICE | \ + (3 << MUSB_DEVCTL_VBUS_SHIFT) | \ + MUSB_DEVCTL_SESSION) #define MUSB_QUIRK_A_DISCONNECT_19 ((3 << MUSB_DEVCTL_VBUS_SHIFT) | \ MUSB_DEVCTL_SESSION)
@@ -1864,6 +1867,11 @@ static void musb_pm_runtime_check_session(struct musb *musb) s = MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV | MUSB_DEVCTL_HR; switch (devctl & ~s) { + case MUSB_QUIRK_B_DISCONNECT_99: + musb_dbg(musb, "Poll devctl in case of suspend after disconnect\n"); + schedule_delayed_work(&musb->irq_work, + msecs_to_jiffies(1000)); + break; case MUSB_QUIRK_B_INVALID_VBUS_91: if (musb->quirk_retries && !musb->flush_irq_work) { musb_dbg(musb,