]> pilppa.com Git - linux-2.6-omap-h63xx.git/commitdiff
musb_hdrc: Update peripheral side suspend support
authorDavid Brownell <dbrownell@users.sourceforge.net>
Fri, 23 Mar 2007 14:00:21 +0000 (10:00 -0400)
committerTony Lindgren <tony@atomide.com>
Fri, 23 Mar 2007 14:00:21 +0000 (10:00 -0400)
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 <dbrownell@users.sourceforge.net>
drivers/usb/musb/g_ep0.c
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_host.c
drivers/usb/musb/musb_procfs.c
drivers/usb/musb/musbdefs.h
drivers/usb/musb/plat_uds.c
drivers/usb/musb/tusb6010.c

index 1c4ab2b24b132077d843462452cbeb866407f862..aad53fdd2a3041967b2e249c77368c06a663a455 100644 (file)
@@ -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);
                                        }
index 7e8dfbe82b888cd05cb5e296595a7d7ab0536bae..0626aa5148197e6ada1f346e52d5b697854bf7bf 100644 (file)
@@ -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;
index d5b53d937cfe9680e6fde33ced3b7bcda1a91923..ef473e9c9fd1d5ee9989ba674f721350141f9441 100644 (file)
@@ -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)
index 1f7d8e8735d777c313d0129ca8f7df8e465be5c3..5bddf30a3fd6bed14de60892ab30ff346831ed6a 100644 (file)
@@ -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);
index 74cad7b2ecd7a0c6c390cafc65b4d79311e2b33a..d059be34ff0a6d5bca9ea8f5add3414f18e3c5a4 100644 (file)
@@ -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;
 
index 891512353fb6c7c68bf43fec0694e87e6761675f..e29e825d7d3f7de719f5cdcf2b64dc56d7a067ef 100644 (file)
@@ -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) {
index 0e058a1e2cf448cf6e0c01a39f22a363059c6ff0..e5ec6e6e15d38f918afe3093925bb1ddb4a404c2 100644 (file)
@@ -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) */