]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
musb_hdrc: host side suspend/resume mostly behaves
authorDavid Brownell <dbrownell@users.sourceforge.net>
Wed, 1 Nov 2006 21:12:17 +0000 (23:12 +0200)
committerTony Lindgren <tony@atomide.com>
Wed, 1 Nov 2006 21:12:17 +0000 (23:12 +0200)
Host side suspend/resume updates:

 - Add the missing "bus-wide" suspend/resume calls, which in this case
   leave everything up to the root port suspend code.

 - Scrub out state more completely on disconnect

 - Remote wakeup IRQ handling (untested because of enumeration issues)

Also:

 - Handle a host side oops if DMA is disabled as a module parameter

 - Minor cleanups of unused symbols

 - Update version string

And some very minor, related, peripheral side fixes.

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_host.h
drivers/usb/musb/musbdefs.h
drivers/usb/musb/plat_uds.c
drivers/usb/musb/virthub.c

index b38a86830376afa5ab166484c11a107e5edf825c..c4cb54434f3da41fc40b012ae2e2c72ca13fa479 100644 (file)
@@ -330,9 +330,6 @@ __acquires(pThis->Lock)
                                        pThis->g.b_hnp_enable = 1;
                                        devctl = musb_readb(pBase,
                                                        MGC_O_HDRC_DEVCTL);
-                                       /* REVISIT after roleswitch, HR will
-                                        * have been cleared ... reset it
-                                        */
                                        musb_writeb(pBase, MGC_O_HDRC_DEVCTL,
                                                devctl | MGC_M_DEVCTL_HR);
                                        }
index 8158169481456f103ff16f05b864627e670e773d..0bdcf19a4c9d9ec2aab5c76e89f1340bc88e0213 100644 (file)
@@ -1449,6 +1449,10 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
 
        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->bMayWakeup)
                        break;
                goto done;
@@ -1470,12 +1474,14 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
        musb_writeb(musb->pRegs, MGC_O_HDRC_POWER, power);
 
        /* FIXME do this next chunk in a timer callback, no udelay */
-       mdelay(10);
+       mdelay(2);
 
        power = musb_readb(musb->pRegs, 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;
 done:
        spin_unlock_irqrestore(&musb->Lock, flags);
        return status;
@@ -1929,7 +1935,8 @@ void musb_g_suspend(struct musb *pThis)
                /* REVISIT if B_HOST, clear DEVCTL.HOSTREQ;
                 * A_PERIPHERAL may need care too
                 */
-               WARN("unhandled SUSPEND transition (%d)\n", pThis->xceiv.state);
+               WARN("unhandled SUSPEND transition (%s)\n",
+                               otg_state_string(pThis));
        }
 }
 
index 125199c6dbb9c56e9d0671ce5b03b92e61a16920..599351c25a569b62abff29609deee99f5029a3fe 100644 (file)
@@ -1929,10 +1929,14 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in)
                struct dma_channel      *dma;
 
                dma = is_in ? ep->rx_channel : ep->tx_channel;
-               status = ep->musb->pDmaController->channel_abort(dma);
-               DBG(status ? 1 : 3, "abort %cX%d DMA for urb %p --> %d\n",
-                       is_in ? 'R' : 'T', ep->bLocalEnd, urb, status);
-               urb->actual_length += dma->dwActualLength;
+               if (dma) {
+                       status = ep->musb->pDmaController->channel_abort(dma);
+                       DBG(status ? 1 : 3,
+                               "abort %cX%d DMA for urb %p --> %d\n",
+                               is_in ? 'R' : 'T', ep->bLocalEnd,
+                               urb, status);
+                       urb->actual_length += dma->dwActualLength;
+               }
        }
 
        /* turn off DMA requests, discard state, stop polling ... */
@@ -2130,6 +2134,19 @@ static void musb_h_stop(struct usb_hcd *hcd)
        hcd->state = HC_STATE_HALT;
 }
 
+static int musb_bus_suspend(struct usb_hcd *hcd)
+{
+       struct musb     *musb = hcd_to_musb(hcd);
+
+       return musb->is_active ? -EBUSY : 0;
+}
+
+static int musb_bus_resume(struct usb_hcd *hcd)
+{
+       /* resuming child port does the work */
+       return 0;
+}
+
 const struct hc_driver musb_hc_driver = {
        .description            = "musb-hcd",
        .product_desc           = "MUSB HDRC host driver",
@@ -2151,8 +2168,8 @@ const struct hc_driver musb_hc_driver = {
 
        .hub_status_data        = musb_hub_status_data,
        .hub_control            = musb_hub_control,
-//     .bus_suspend            = musb_bus_suspend,
-//     .bus_resume             = musb_bus_resume,
+       .bus_suspend            = musb_bus_suspend,
+       .bus_resume             = musb_bus_resume,
 //     .start_port_reset       = NULL,
 //     .hub_irq_enable         = NULL,
 };
index 44ff996cc7789c4411e2ba894df50fb5dac74175..556db7427eb97578acbdc02ec889bcdbaaea6084 100644 (file)
@@ -89,8 +89,6 @@ extern int musb_hub_status_data(struct usb_hcd *hcd, char *buf);
 extern int musb_hub_control(struct usb_hcd *hcd,
                        u16 typeReq, u16 wValue, u16 wIndex,
                        char *buf, u16 wLength);
-extern int musb_bus_suspend(struct usb_hcd *);
-extern int musb_bus_resume(struct usb_hcd *);
 
 extern const struct hc_driver musb_hc_driver;
 
index e31c3390fe17f6ee7e48cfa87c92766459130ba8..dbc3b2062c3e12a98b990aa28349cd04eabebb48 100644 (file)
@@ -376,6 +376,9 @@ struct musb {
 
 #ifdef CONFIG_USB_MUSB_HDRC_HCD
 
+/* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
+#define MUSB_PORT_STAT_RESUME  (1 << 31)
+
        u32                     port1_status;
        unsigned long           rh_timer;
 
index e02f672113b1c95fc9ad5b133c7f58f946ecefb5..b500ae173f97e3c9d542c985140d97aed629a93d 100644 (file)
@@ -131,10 +131,10 @@ MODULE_PARM_DESC(debug, "initial debug message level");
 #define MUSB_VERSION_SUFFIX    "/dbg"
 #endif
 
-#define DRIVER_AUTHOR "Mentor Graphics Corp. and Texas Instruments"
+#define DRIVER_AUTHOR "Mentor Graphics, Texas Instruments, Nokia"
 #define DRIVER_DESC "Inventra Dual-Role USB Controller Driver"
 
-#define MUSB_VERSION_BASE "2.2a/db-0.5.1"
+#define MUSB_VERSION_BASE "2.2a/db-0.5.2"
 
 #ifndef MUSB_VERSION_SUFFIX
 #define MUSB_VERSION_SUFFIX    ""
@@ -149,12 +149,6 @@ MODULE_DESCRIPTION(DRIVER_INFO);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_LICENSE("GPL");
 
-/* time (millseconds) to wait before a restart */
-#define MUSB_RESTART_TIME        5000
-
-/* how many babbles to allow before giving up */
-#define MUSB_MAX_BABBLE_COUNT    10
-
 
 /*-------------------------------------------------------------------------*/
 
@@ -382,17 +376,28 @@ static irqreturn_t musb_stage0_irq(struct musb * pThis, u8 bIntrUSB,
 
                if (devctl & MGC_M_DEVCTL_HM) {
 #ifdef CONFIG_USB_MUSB_HDRC_HCD
-                       /* REVISIT:  this is where SRP kicks in, yes?
-                        * host responsibility should be to CLEAR the
-                        * resume signaling after 50 msec ...
-                        */
-                       MUSB_HST_MODE(pThis);   /* unnecessary */
                        power &= ~MGC_M_POWER_SUSPENDM;
                        musb_writeb(pBase, MGC_O_HDRC_POWER,
                                power | MGC_M_POWER_RESUME);
 
+                       /* later, GetPortStatus will stop RESUME signaling */
+                       pThis->port1_status |= MUSB_PORT_STAT_RESUME;
+                       pThis->rh_timer = jiffies + msecs_to_jiffies(20);
+
                        /* should now be A_SUSPEND */
-                       pThis->xceiv.state = OTG_STATE_A_HOST;
+                       switch (pThis->xceiv.state) {
+                       case OTG_STATE_A_SUSPEND:
+                               pThis->xceiv.state = OTG_STATE_A_HOST;
+                               usb_hcd_resume_root_hub(musb_to_hcd(pThis));
+                               break;
+                       case OTG_STATE_B_WAIT_ACON:
+                               pThis->xceiv.state = OTG_STATE_B_PERIPHERAL;
+                               MUSB_DEV_MODE(pThis);
+                               break;
+                       default:
+                               WARN("bogus RESUME, from  %s\n",
+                                       otg_state_string(pThis));
+                       }
 #endif
                } else {
 #ifdef CONFIG_USB_GADGET_MUSB_HDRC
@@ -506,10 +511,8 @@ static irqreturn_t musb_stage0_irq(struct musb * pThis, u8 bIntrUSB,
        }
 #endif /* CONFIG_USB_MUSB_HDRC_HCD */
 
-       /* saved one bit: bus reset and babble share the same bit;
-        * If I am host is a babble! i must be the only one allowed
-        * to reset the bus; when in otg mode it means that I have
-        * to switch to device
+       /* mentor saves a bit: bus reset and babble share the same irq.
+        * only host sees babble; only peripheral sees bus reset.
         */
        if (bIntrUSB & MGC_M_INTR_RESET) {
                if (devctl & MGC_M_DEVCTL_HM) {
@@ -1006,6 +1009,10 @@ static int __devinit ep_config_from_table(struct musb *musb)
        offset = fifo_setup(musb, hw_ep, &ep0_cfg, 0);
        // assert(offset > 0)
 
+       /* NOTE:  for RTL versions >= 1.400 EPINFO and RAMINFO would
+        * be better than static MUSB_C_NUM_EPS and DYN_FIFO_SIZE...
+        */
+
        for (i = 0; i < n; i++) {
                u8      epn = cfg->hw_ep_num;
 
index 7fb86df003de8be9ec0b22df953dfcb1664d4b39..cdee1b9888c82e40314786314e1be4ea7f5ccc8a 100644 (file)
@@ -44,7 +44,6 @@
 #include "musbdefs.h"
 
 
-
 static void musb_port_suspend(struct musb *musb, u8 bSuspend)
 {
        u8              power;
@@ -53,26 +52,46 @@ static void musb_port_suspend(struct musb *musb, u8 bSuspend)
        if (!is_host_active(musb))
                return;
 
+       /* NOTE:  this doesn't necessarily put PHY into low power mode,
+        * turning off its clock; that's a function of PHY integration and
+        * MGC_M_POWER_ENSUSPEND.  PHY may need a clock (sigh) to detect
+        * SE0 changing to connect (J) or wakeup (K) states.
+        */
        power = musb_readb(pBase, MGC_O_HDRC_POWER);
-
        if (bSuspend) {
-               DBG(3, "Root port suspended\n");
-               musb_writeb(pBase, MGC_O_HDRC_POWER,
-                               power | MGC_M_POWER_SUSPENDM);
+               power &= ~MGC_M_POWER_RESUME;
+               power |= MGC_M_POWER_SUSPENDM;
+               musb_writeb(pBase, MGC_O_HDRC_POWER, power);
+
+               DBG(3, "Root port suspended, power %02x\n", power);
+
                musb->port1_status |= USB_PORT_STAT_SUSPEND;
-               musb->is_active = is_otg_enabled(musb)
-                               && musb->xceiv.host->b_hnp_enable;
-               musb_platform_try_idle(musb);
+               switch (musb->xceiv.state) {
+               case OTG_STATE_A_HOST:
+                       musb->xceiv.state = OTG_STATE_A_SUSPEND;
+                       musb->is_active = is_otg_enabled(musb)
+                                       && musb->xceiv.host->b_hnp_enable;
+                       musb_platform_try_idle(musb);
+                       break;
+               case OTG_STATE_B_HOST:
+                       musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+                       MUSB_DEV_MODE(musb);
+                       /* REVISIT restore setting of MGC_M_DEVCTL_HR */
+                       break;
+               default:
+                       DBG(1, "bogus rh suspend? %s\n",
+                               otg_state_string(musb));
+               }
        } else if (power & MGC_M_POWER_SUSPENDM) {
-               DBG(3, "Root port resumed\n");
-               musb_writeb(pBase, MGC_O_HDRC_POWER,
-                               power | MGC_M_POWER_RESUME);
-
-               musb->is_active = 1;
+               power &= ~MGC_M_POWER_SUSPENDM;
+               power |= MGC_M_POWER_RESUME;
                musb_writeb(pBase, MGC_O_HDRC_POWER, power);
-               musb->port1_status &= ~USB_PORT_STAT_SUSPEND;
-               musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
-               usb_hcd_poll_rh_status(musb_to_hcd(musb));
+
+               DBG(3, "Root port resuming, power %02x\n", power);
+
+               /* later, GetPortStatus will stop RESUME signaling */
+               musb->port1_status |= MUSB_PORT_STAT_RESUME;
+               musb->rh_timer = jiffies + msecs_to_jiffies(20);
        }
 }
 
@@ -131,14 +150,9 @@ static void musb_port_reset(struct musb *musb, u8 bReset)
 
 void musb_root_disconnect(struct musb *musb)
 {
-       musb->port1_status &=
-               ~(USB_PORT_STAT_CONNECTION
-               | USB_PORT_STAT_ENABLE
-               | USB_PORT_STAT_LOW_SPEED
-               | USB_PORT_STAT_HIGH_SPEED
-               | USB_PORT_STAT_TEST
-               );
-       musb->port1_status |= USB_PORT_STAT_C_CONNECTION << 16;
+       musb->port1_status = (1 << USB_PORT_FEAT_POWER)
+                       | (1 << USB_PORT_FEAT_C_CONNECTION);
+
        usb_hcd_poll_rh_status(musb_to_hcd(musb));
        musb->is_active = 0;
 
@@ -255,11 +269,39 @@ int musb_hub_control(
                if (wIndex != 1)
                        goto error;
 
+               /* finish RESET signaling? */
                if ((musb->port1_status & USB_PORT_STAT_RESET)
                                && time_after(jiffies, musb->rh_timer))
                        musb_port_reset(musb, FALSE);
 
-               *(__le32 *) buf = cpu_to_le32 (musb->port1_status);
+               /* finish RESUME signaling? */
+               if ((musb->port1_status & MUSB_PORT_STAT_RESUME)
+                               && time_after(jiffies, musb->rh_timer)) {
+                       u8              power;
+
+                       power = musb_readb(musb->pRegs, MGC_O_HDRC_POWER);
+                       power &= ~MGC_M_POWER_RESUME;
+                       DBG(4, "root port resume stopped, power %02x\n",
+                                       power);
+                       musb_writeb(musb->pRegs, MGC_O_HDRC_POWER, power);
+
+                       /* ISSUE:  DaVinci (RTL 1.300) disconnects after
+                        * resume of high speed peripherals (but not full
+                        * speed ones).
+                        */
+
+                       musb->is_active = 1;
+                       musb->port1_status &= ~(USB_PORT_STAT_SUSPEND
+                                       | MUSB_PORT_STAT_RESUME);
+                       musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
+                       usb_hcd_poll_rh_status(musb_to_hcd(musb));
+                       /* NOTE: it might really be A_WAIT_BCON ... */
+                       musb->xceiv.state = OTG_STATE_A_HOST;
+               }
+
+               *(__le32 *) buf = cpu_to_le32(musb->port1_status
+                               & ~MUSB_PORT_STAT_RESUME);
+
                /* port change status is more interesting */
                DBG((*(u16*)(buf+2)) ? 2 : 5, "port status %08x\n",
                                musb->port1_status);