| From 7ddde96b24d8b8488a3e1023fdf3658446122b7f Mon Sep 17 00:00:00 2001 |
| From: Tony Lindgren <tony@atomide.com> |
| Date: Tue, 7 Jan 2020 09:26:24 -0600 |
| Subject: [PATCH] usb: musb: fix idling for suspend after disconnect interrupt |
| |
| 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: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c |
| index 9f5a4819a744..8956a88e9600 100644 |
| --- a/drivers/usb/musb/musb_core.c |
| +++ b/drivers/usb/musb/musb_core.c |
| @@ -1843,6 +1843,9 @@ static const struct attribute_group musb_attr_group = { |
| #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) |
| |
| @@ -1865,6 +1868,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, |
| -- |
| 2.7.4 |
| |