static int musb_gadget_wakeup(struct usb_gadget *gadget)
{
struct musb *musb = gadget_to_musb(gadget);
+ void __iomem *mregs = musb->pRegs;
unsigned long flags;
int status = -EINVAL;
- u8 power;
+ u8 power, devctl;
spin_lock_irqsave(&musb->Lock, flags);
- /* fail if we're not suspended */
- power = musb_readb(musb->pRegs, MGC_O_HDRC_POWER);
- if (!(power & MGC_M_POWER_SUSPENDM))
- goto done;
-
switch (musb->xceiv.state) {
case OTG_STATE_B_PERIPHERAL:
/* NOTE: OTG state machine doesn't include B_SUSPENDED;
* that's part of the standard usb 1.1 state machine, and
* doesn't affect OTG transitions.
*/
- if (musb->may_wakeup)
+ if (musb->may_wakeup && musb->is_suspended)
break;
goto done;
case OTG_STATE_B_IDLE:
- /* REVISIT we might be able to do SRP even without OTG,
- * though Linux doesn't yet expose that capability. SRP
- * starts by setting DEVCTL.SESSION (not POWER.RESUME);
- * though DaVinci can't do it.
- */
- if (is_otg_enabled(musb)) {
- musb->xceiv.state = OTG_STATE_B_SRP_INIT;
- break;
- }
- /* FALLTHROUGH */
+ /* Start SRP ... OTG not required. */
+ devctl = musb_readb(mregs, MGC_O_HDRC_DEVCTL);
+ devctl |= MGC_M_DEVCTL_SESSION;
+ musb_writeb(mregs, MGC_O_HDRC_DEVCTL, devctl);
+ DBG(2, "SRP\n");
+ status = 0;
+ goto done;
default:
goto done;
}
status = 0;
+
+ power = musb_readb(mregs, MGC_O_HDRC_POWER);
power |= MGC_M_POWER_RESUME;
- musb_writeb(musb->pRegs, MGC_O_HDRC_POWER, power);
+ musb_writeb(mregs, MGC_O_HDRC_POWER, power);
+ DBG(2, "issue wakeup\n");
/* FIXME do this next chunk in a timer callback, no udelay */
mdelay(2);
- power = musb_readb(musb->pRegs, MGC_O_HDRC_POWER);
+ power = musb_readb(mregs, MGC_O_HDRC_POWER);
power &= ~MGC_M_POWER_RESUME;
- musb_writeb(musb->pRegs, MGC_O_HDRC_POWER, power);
-
- if (musb->xceiv.state == OTG_STATE_B_SRP_INIT)
- musb->xceiv.state = OTG_STATE_B_IDLE;
+ musb_writeb(mregs, MGC_O_HDRC_POWER, power);
done:
spin_unlock_irqrestore(&musb->Lock, flags);
return status;
void musb_g_resume(struct musb *musb)
{
+ musb->is_suspended = 0;
switch (musb->xceiv.state) {
case OTG_STATE_B_IDLE:
break;
musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
break;
case OTG_STATE_B_PERIPHERAL:
+ musb->is_suspended = 1;
if (musb->pGadgetDriver && musb->pGadgetDriver->suspend) {
spin_unlock(&musb->Lock);
musb->pGadgetDriver->suspend(&musb->g);
/* start in USB_STATE_DEFAULT */
musb->is_active = 1;
+ musb->is_suspended = 0;
MUSB_DEV_MODE(musb);
musb->bAddress = 0;
musb->ep0_state = MGC_END0_STAGE_SETUP;
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
case OTG_STATE_B_WAIT_ACON:
case OTG_STATE_B_PERIPHERAL:
+ /* disconnect while suspended? we may
+ * not get a disconnect irq...
+ */
+ if ((devctl & MGC_M_DEVCTL_VBUS)
+ != (3 << MGC_S_DEVCTL_VBUS)) {
+ pThis->int_usb |= MGC_M_INTR_DISCONNECT;
+ pThis->int_usb &= ~MGC_M_INTR_SUSPEND;
+ break;
+ }
musb_g_resume(pThis);
break;
case OTG_STATE_B_IDLE:
}
if (bIntrUSB & MGC_M_INTR_SUSPEND) {
- DBG(1, "SUSPEND (%s) devctl %02x\n",
- otg_state_string(pThis), devctl);
+ DBG(1, "SUSPEND (%s) devctl %02x power %02x\n",
+ otg_state_string(pThis), devctl, power);
handled = IRQ_HANDLED;
switch (pThis->xceiv.state) {
/* 0 = refclk (clkin, XI)
* 1 = PHY 60 MHz (internal PLL)
* 2 = not supported
- * 3 = NOR clock (huh?)
+ * 3 = what?
*/
if (mode > 0)
reg |= TUSB_PRCM_CONF_SYS_CLKSEL(mode & 0x3);
reg |= TUSB_PRCM_MNGMT_PM_IDLE | TUSB_PRCM_MNGMT_DEV_IDLE;
musb_writel(base, TUSB_PRCM_MNGMT, reg);
- DBG(2, "idle, wake on %02x\n", wakeup_enables);
+ DBG(6, "idle, wake on %02x\n", wakeup_enables);
}
/*
reg = musb_readl(base, TUSB_SCRATCH_PAD);
if (reg == i)
break;
- DBG(1, "TUSB NOR not ready\n");
+ DBG(6, "TUSB NOR not ready\n");
}
/* work around issue 13 (2nd half) */