From: David Brownell Date: Fri, 23 Mar 2007 14:00:21 +0000 (-0400) Subject: musb_hdrc: Update peripheral side suspend support X-Git-Tag: v2.6.21-omap1~70 X-Git-Url: http://pilppa.com/gitweb/?a=commitdiff_plain;h=68a37991fe438a5ec061e49278917e9f75e36931;p=linux-2.6-omap-h63xx.git musb_hdrc: Update peripheral side suspend support Update peripheral side suspend support: - Work around some IRQ strangeness (disconnect not detected reliably while suspended). - Swaps out clearly-broken SRP logic (from Mentor?) with code which at least matches the documentation. - Track whether peripheral is suspended; this helps detect invalid remote wakeup requests, and will also help work around a tusb6010 peripheral side issue (separate patch). - For tusb6010, don't be so noisy with tps65030 idle/suspend messaging; among other things, it interferes with debugging. - In OTG mode, host side can now autosuspend when peripheral side is active (connected or otherwise). USBCV remote wakeup tests now pass. Signed-off-by: David Brownell --- diff --git a/drivers/usb/musb/g_ep0.c b/drivers/usb/musb/g_ep0.c index 1c4ab2b24b1..aad53fdd2a3 100644 --- a/drivers/usb/musb/g_ep0.c +++ b/drivers/usb/musb/g_ep0.c @@ -330,6 +330,10 @@ __acquires(musb->Lock) musb->g.b_hnp_enable = 1; devctl = musb_readb(pBase, MGC_O_HDRC_DEVCTL); + /* NOTE: at least DaVinci doesn't + * like to set HR ... + */ + DBG(1, "set HR\n"); musb_writeb(pBase, MGC_O_HDRC_DEVCTL, devctl | MGC_M_DEVCTL_HR); } diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 7e8dfbe82b8..0626aa51481 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1426,54 +1426,47 @@ static int musb_gadget_get_frame(struct usb_gadget *gadget) 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; @@ -1898,6 +1891,7 @@ EXPORT_SYMBOL(usb_gadget_unregister_driver); void musb_g_resume(struct musb *musb) { + musb->is_suspended = 0; switch (musb->xceiv.state) { case OTG_STATE_B_IDLE: break; @@ -1930,6 +1924,7 @@ void musb_g_suspend(struct musb *musb) 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); @@ -2017,6 +2012,7 @@ __acquires(musb->Lock) /* 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; diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index d5b53d937cf..ef473e9c9fd 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -2141,7 +2141,10 @@ static int musb_bus_suspend(struct usb_hcd *hcd) { struct musb *musb = hcd_to_musb(hcd); - return musb->is_active ? -EBUSY : 0; + if (is_host_active(musb) && musb->is_active) + return -EBUSY; + else + return 0; } static int musb_bus_resume(struct usb_hcd *hcd) diff --git a/drivers/usb/musb/musb_procfs.c b/drivers/usb/musb/musb_procfs.c index 1f7d8e8735d..5bddf30a3fd 100644 --- a/drivers/usb/musb/musb_procfs.c +++ b/drivers/usb/musb/musb_procfs.c @@ -534,6 +534,15 @@ static int dump_header_stats(struct musb *pThis, char *buffer) count += code; buffer += code; +#ifdef CONFIG_USB_GADGET_MUSB_HDRC + code = sprintf(buffer, "Peripheral address: %02x\n", + musb_readb(pThis, MGC_O_HDRC_FADDR)); + if (code <= 0) + goto done; + buffer += code; + count += code; +#endif + #ifdef CONFIG_USB_MUSB_HDRC_HCD code = sprintf(buffer, "Root port status: %08x\n", pThis->port1_status); diff --git a/drivers/usb/musb/musbdefs.h b/drivers/usb/musb/musbdefs.h index 74cad7b2ecd..d059be34ff0 100644 --- a/drivers/usb/musb/musbdefs.h +++ b/drivers/usb/musb/musbdefs.h @@ -433,6 +433,9 @@ struct musb { #endif #ifdef CONFIG_USB_GADGET_MUSB_HDRC + /* is_suspended means USB B_PERIPHERAL suspend */ + unsigned is_suspended:1; + /* may_wakeup means remote wakeup is enabled */ unsigned may_wakeup:1; diff --git a/drivers/usb/musb/plat_uds.c b/drivers/usb/musb/plat_uds.c index 891512353fb..e29e825d7d3 100644 --- a/drivers/usb/musb/plat_uds.c +++ b/drivers/usb/musb/plat_uds.c @@ -368,6 +368,15 @@ static irqreturn_t musb_stage0_irq(struct musb * pThis, u8 bIntrUSB, #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: @@ -646,8 +655,8 @@ static irqreturn_t musb_stage2_irq(struct musb * pThis, u8 bIntrUSB, } 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) { diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 0e058a1e2cf..e5ec6e6e15d 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -199,7 +199,7 @@ static void tusb_set_clock_source(struct musb *musb, unsigned mode) /* 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); @@ -242,7 +242,7 @@ static void tusb_allow_idle(struct musb *musb, u32 wakeup_enables) 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); } /* @@ -545,7 +545,7 @@ static irqreturn_t tusb_interrupt(int irq, void *__hci) 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) */