summaryrefslogtreecommitdiffstats
path: root/drivers/usb/musb/musb_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/musb/musb_core.c')
-rw-r--r--drivers/usb/musb/musb_core.c71
1 files changed, 41 insertions, 30 deletions
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 4c8f0112481f..f7b1d5993f8c 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -480,9 +480,7 @@ int musb_set_host(struct musb *musb)
devctl = musb_read_devctl(musb);
if (!(devctl & MUSB_DEVCTL_BDEVICE)) {
- dev_info(musb->controller,
- "%s: already in host mode: %02x\n",
- __func__, devctl);
+ trace_musb_state(musb, devctl, "Already in host mode");
goto init_data;
}
@@ -499,6 +497,9 @@ int musb_set_host(struct musb *musb)
return error;
}
+ devctl = musb_read_devctl(musb);
+ trace_musb_state(musb, devctl, "Host mode set");
+
init_data:
musb->is_active = 1;
musb->xceiv->otg->state = OTG_STATE_A_IDLE;
@@ -526,10 +527,7 @@ int musb_set_peripheral(struct musb *musb)
devctl = musb_read_devctl(musb);
if (devctl & MUSB_DEVCTL_BDEVICE) {
- dev_info(musb->controller,
- "%s: already in peripheral mode: %02x\n",
- __func__, devctl);
-
+ trace_musb_state(musb, devctl, "Already in peripheral mode");
goto init_data;
}
@@ -546,6 +544,9 @@ int musb_set_peripheral(struct musb *musb)
return error;
}
+ devctl = musb_read_devctl(musb);
+ trace_musb_state(musb, devctl, "Peripheral mode set");
+
init_data:
musb->is_active = 0;
musb->xceiv->otg->state = OTG_STATE_B_IDLE;
@@ -1984,6 +1985,21 @@ ATTRIBUTE_GROUPS(musb);
#define MUSB_QUIRK_A_DISCONNECT_19 ((3 << MUSB_DEVCTL_VBUS_SHIFT) | \
MUSB_DEVCTL_SESSION)
+static bool musb_state_needs_recheck(struct musb *musb, u8 devctl,
+ const char *desc)
+{
+ if (musb->quirk_retries && !musb->flush_irq_work) {
+ trace_musb_state(musb, devctl, desc);
+ schedule_delayed_work(&musb->irq_work,
+ msecs_to_jiffies(1000));
+ musb->quirk_retries--;
+
+ return true;
+ }
+
+ return false;
+}
+
/*
* Check the musb devctl session bit to determine if we want to
* allow PM runtime for the device. In general, we want to keep things
@@ -2004,35 +2020,21 @@ static void musb_pm_runtime_check_session(struct musb *musb)
MUSB_DEVCTL_HR;
switch (devctl & ~s) {
case MUSB_QUIRK_B_DISCONNECT_99:
- if (musb->quirk_retries && !musb->flush_irq_work) {
- musb_dbg(musb, "Poll devctl in case of suspend after disconnect\n");
- schedule_delayed_work(&musb->irq_work,
- msecs_to_jiffies(1000));
- musb->quirk_retries--;
- }
+ musb_state_needs_recheck(musb, devctl,
+ "Poll devctl in case of suspend after disconnect");
break;
case MUSB_QUIRK_B_INVALID_VBUS_91:
- if (musb->quirk_retries && !musb->flush_irq_work) {
- musb_dbg(musb,
- "Poll devctl on invalid vbus, assume no session");
- schedule_delayed_work(&musb->irq_work,
- msecs_to_jiffies(1000));
- musb->quirk_retries--;
+ if (musb_state_needs_recheck(musb, devctl,
+ "Poll devctl on invalid vbus, assume no session"))
return;
- }
fallthrough;
case MUSB_QUIRK_A_DISCONNECT_19:
- if (musb->quirk_retries && !musb->flush_irq_work) {
- musb_dbg(musb,
- "Poll devctl on possible host mode disconnect");
- schedule_delayed_work(&musb->irq_work,
- msecs_to_jiffies(1000));
- musb->quirk_retries--;
+ if (musb_state_needs_recheck(musb, devctl,
+ "Poll devctl on possible host mode disconnect"))
return;
- }
if (!musb->session)
break;
- musb_dbg(musb, "Allow PM on possible host mode disconnect");
+ trace_musb_state(musb, devctl, "Allow PM on possible host mode disconnect");
pm_runtime_mark_last_busy(musb->controller);
pm_runtime_put_autosuspend(musb->controller);
musb->session = false;
@@ -2048,14 +2050,23 @@ static void musb_pm_runtime_check_session(struct musb *musb)
/* Block PM or allow PM? */
if (s) {
- musb_dbg(musb, "Block PM on active session: %02x", devctl);
+ trace_musb_state(musb, devctl, "Block PM on active session");
error = pm_runtime_get_sync(musb->controller);
if (error < 0)
dev_err(musb->controller, "Could not enable: %i\n",
error);
musb->quirk_retries = 3;
+
+ /*
+ * We can get a spurious MUSB_INTR_SESSREQ interrupt on start-up
+ * in B-peripheral mode with nothing connected and the session
+ * bit clears silently. Check status again in 3 seconds.
+ */
+ if (devctl & MUSB_DEVCTL_BDEVICE)
+ schedule_delayed_work(&musb->irq_work,
+ msecs_to_jiffies(3000));
} else {
- musb_dbg(musb, "Allow PM with no session: %02x", devctl);
+ trace_musb_state(musb, devctl, "Allow PM with no session");
pm_runtime_mark_last_busy(musb->controller);
pm_runtime_put_autosuspend(musb->controller);
}