On Thu, Aug 18, 2016 at 03:46:47PM -0700, Tony Lindgren wrote: > We want to keep musb enabled always when the session bit is > set. This simplifies the PM runtime and allows making it more > generic across the various glue layers. > > So far the only exception to just following the session bit is > host mode disconnect where the session bit stays set. > > In that case, just allow PM and let the PM runtime autoidle > timeout deal with it. > > Signed-off-by: Tony Lindgren <tony@xxxxxxxxxxx> > --- > drivers/usb/musb/musb_core.c | 70 ++++++++++++++++++++++++++++++++++++++++++++ > drivers/usb/musb/musb_core.h | 1 + > 2 files changed, 71 insertions(+) > > diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c > index 74fc306..9c4e1a5 100644 > --- a/drivers/usb/musb/musb_core.c > +++ b/drivers/usb/musb/musb_core.c > @@ -1831,11 +1831,81 @@ static const struct attribute_group musb_attr_group = { > .attrs = musb_attributes, > }; > > +#define MUSB_QUIRK_B_INVALID_VBUS_91 (MUSB_DEVCTL_BDEVICE | \ > + (2 << MUSB_DEVCTL_VBUS_SHIFT) | \ > + MUSB_DEVCTL_SESSION) > +#define MUSB_QUIRK_A_DISCONNECT_19 ((3 << MUSB_DEVCTL_VBUS_SHIFT) | \ > + MUSB_DEVCTL_SESSION) > + > +/* > + * 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 > + * active when the session bit is set except after host disconnect. > + * > + * Only called from musb_irq_work. If this ever needs to get called > + * elsewhere, proper locking must be implemented for musb->session. > + */ > +static void musb_pm_runtime_check_session(struct musb *musb) > +{ > + u8 devctl, s; > + int error; > + > + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); > + > + /* Handle session status quirks first */ > + s = MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV | > + MUSB_DEVCTL_HR; > + switch (devctl & ~s) { > + case MUSB_QUIRK_B_INVALID_VBUS_91: > + if (musb->session) > + break; > + dev_dbg(musb->controller, > + "Allow PM as device with invalid vbus: %02x\n", > + devctl); > + return; > + case MUSB_QUIRK_A_DISCONNECT_19: > + if (!musb->session) > + break; > + dev_dbg(musb->controller, > + "Allow PM on possible host mode disconnect\n"); > + pm_runtime_mark_last_busy(musb->controller); > + pm_runtime_put_autosuspend(musb->controller); > + musb->session = false; > + return; > + default: > + break; > + } > + > + /* No need to do anything if session has not changed */ > + s = devctl & MUSB_DEVCTL_SESSION; > + if (s == musb->session) > + return; > + > + /* Block PM or allow PM? */ > + if (s) { > + dev_dbg(musb->controller, "Block PM on active session: %02x\n", > + devctl); > + error = pm_runtime_get_sync(musb->controller); > + if (error < 0) > + dev_err(musb->controller, "Could not enable: %i\n", > + error); > + } else { > + dev_dbg(musb->controller, "Allow PM with no session: %02x\n", > + devctl); I changed dev_dbg() to musb_dbg(). musb core already moves to tracepoints for debug. > + pm_runtime_mark_last_busy(musb->controller); > + pm_runtime_put_autosuspend(musb->controller); > + } > + > + musb->session = s; > +} > + > /* Only used to provide driver mode change events */ > static void musb_irq_work(struct work_struct *data) > { > struct musb *musb = container_of(data, struct musb, irq_work); > > + musb_pm_runtime_check_session(musb); > + > if (musb->xceiv->otg->state != musb->xceiv_old_state) { > musb->xceiv_old_state = musb->xceiv->otg->state; > sysfs_notify(&musb->controller->kobj, NULL, "mode"); > diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h > index b55a776..65288a5 100644 > --- a/drivers/usb/musb/musb_core.h > +++ b/drivers/usb/musb/musb_core.h > @@ -378,6 +378,7 @@ struct musb { > u8 min_power; /* vbus for periph, in mA/2 */ > > int port_mode; /* MUSB_PORT_MODE_* */ > + bool session; > bool is_host; > > int a_wait_bcon; /* VBUS timeout in msecs */ > -- > 2.8.1 > -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html