]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
MUSB: TUSB PM cleanup
authorDavid Brownell <dbrownell@users.sourceforge.net>
Wed, 6 Sep 2006 13:48:15 +0000 (16:48 +0300)
committerTony Lindgren <tony@atomide.com>
Wed, 6 Sep 2006 13:48:15 +0000 (16:48 +0300)
Start updating the TUSB power related code ... first pass, use the chip's
idle mode whenever the USB link is inactive (disconnected or suspended).
That rule applies to both host and peripheral roles, and saves a fair
amount of power (50mA at 3.3V, etc).

Plus some cleanups.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_procfs.c
drivers/usb/musb/musbdefs.h
drivers/usb/musb/otg.c
drivers/usb/musb/plat_uds.c
drivers/usb/musb/tusb6010.c
drivers/usb/musb/tusb6010.h
drivers/usb/musb/virthub.c

index 24a07ccb5ade7a5886596f2510633e796a40f2df..5dbeb418876ff2f9d2792de9339639a2a1cded82 100644 (file)
@@ -508,7 +508,6 @@ void musb_g_tx(struct musb *pThis, u8 bEnd)
                                if (!pRequest) {
                                        DBG(4, "%s idle now\n",
                                                        pEnd->end_point.name);
-                                       musb_platform_try_idle(pThis);
                                        break;
                                }
                        }
@@ -1664,6 +1663,9 @@ int __devinit musb_gadget_setup(struct musb *pThis)
 
        musb_g_init_endpoints(pThis);
 
+       pThis->is_active = 0;
+       musb_platform_try_idle(pThis);
+
        status = device_register(&pThis->g.dev);
        if (status != 0)
                the_gadget = NULL;
@@ -1746,6 +1748,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
                 */
                pThis->xceiv.gadget = &pThis->g;
                pThis->xceiv.state = OTG_STATE_B_IDLE;
+               pThis->is_active = 1;
 
                /* FIXME this ignores the softconnect flag.  Drivers are
                 * allowed hold the peripheral inactive until for example
@@ -1857,6 +1860,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
                musb->pGadgetDriver = NULL;
                musb->g.dev.driver = NULL;
 
+               musb->is_active = 0;
                musb_platform_try_idle(musb);
        } else
                retval = -EINVAL;
@@ -1944,6 +1948,8 @@ void musb_g_disconnect(struct musb *pThis)
        case OTG_STATE_B_SRP_INIT:
                break;
        }
+
+       pThis->is_active = 0;
 }
 
 void musb_g_reset(struct musb *pThis)
@@ -1977,6 +1983,7 @@ __acquires(pThis->Lock)
                        ? USB_SPEED_HIGH : USB_SPEED_FULL;
 
        /* start in USB_STATE_DEFAULT */
+       pThis->is_active = 1;
        MUSB_DEV_MODE(pThis);
        pThis->bAddress = 0;
        pThis->ep0_state = MGC_END0_STAGE_SETUP;
index 674b115b96a3fb1594782a99134746f7b9469b3a..eae8c5b9b7026e5c546b570f37032329d41b26ae 100644 (file)
@@ -754,11 +754,11 @@ static int musb_proc_read(char *page, char **start,
                }
        }
 
+       musb_platform_try_idle(pThis);
+
        spin_unlock_irqrestore(&pThis->Lock, flags);
        *eof = 1;
 
-       musb_platform_try_idle(pThis);
-
        return (buffer - page) - off;
 }
 
index f27aea7fb4b8d0ba68cdb535c39d85f243448981..0d6e0efdfffa4c04581838c216b49e902e809e74 100644 (file)
@@ -454,6 +454,9 @@ struct musb {
 
        s8 bFailCode;           /* one of MUSB_ERR_* failure code */
 
+       /* active means connected and not suspended */
+       unsigned is_active:1;
+
        unsigned bIsMultipoint:1;
        unsigned bIsDevice:1;
        unsigned bIsHost:1;
index 7d35c273c194f17d0d78c266c147d7a67b68bc29..1be6259d6ca1a9af8d19c3814c1c0807242f38d4 100644 (file)
@@ -212,6 +212,7 @@ static void otg_timeout(unsigned long ptr)
        default:
                WARN("timeout in state %d, now what?\n", pMachine->bState);
        }
+       musb_platform_try_idle(musb);
        spin_unlock_irqrestore(&musb->Lock, flags);
 }
 
index 77fd3a31b1703860102344592d76390d052ee295..ac8d9625bb12ec868e18aabad05291720bd6c119 100644 (file)
@@ -384,6 +384,7 @@ static irqreturn_t musb_stage0_irq(struct musb * pThis, u8 bIntrUSB,
        if (bIntrUSB & MGC_M_INTR_RESUME) {
                handled = IRQ_HANDLED;
                DBG(3, "RESUME\n");
+               pThis->is_active = 1;
 
                if (devctl & MGC_M_DEVCTL_HM) {
 #ifdef CONFIG_USB_MUSB_HDRC_HCD
@@ -458,6 +459,7 @@ static irqreturn_t musb_stage0_irq(struct musb * pThis, u8 bIntrUSB,
 
        if (bIntrUSB & MGC_M_INTR_CONNECT) {
                handled = IRQ_HANDLED;
+               pThis->is_active = 1;
 
                pThis->bEnd0Stage = MGC_END0_START;
 
@@ -598,6 +600,7 @@ static irqreturn_t musb_stage2_irq(struct musb * pThis, u8 bIntrUSB,
                DBG(1, "DISCONNECT as %s, devctl %02x\n",
                                MUSB_MODE(pThis), devctl);
                handled = IRQ_HANDLED;
+               pThis->is_active = 0;
 
                /* need to check it against pThis, because devctl is going
                 * to report ID low as soon as the device gets disconnected
@@ -618,9 +621,15 @@ static irqreturn_t musb_stage2_irq(struct musb * pThis, u8 bIntrUSB,
                /* peripheral suspend, may trigger HNP */
                if (!(devctl & MGC_M_DEVCTL_HM)) {
                        musb_g_suspend(pThis);
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+                       pThis->is_active = is_otg_enabled(pThis)
+                                       && pThis->xceiv.gadget->b_hnp_enable;
+#else
+                       pThis->is_active = 0;
+#endif
                        otg_input_changed(pThis, devctl, FALSE, FALSE, TRUE);
-                       musb_platform_try_idle(pThis);
-               }
+               } else
+                       pThis->is_active = 0;
        }
 
        return handled;
@@ -1416,7 +1425,6 @@ musb_cable_show(struct device *dev, struct device_attribute *attr, char *buf)
                v2 = "connected";
        else
                v2 = "disconnected";
-       musb_platform_try_idle(musb);
 #else
        /* NOTE: board-specific issues, like too-big capacitors keeping
         * VBUS high for a long time after power has been removed, can
@@ -1440,6 +1448,7 @@ musb_cable_show(struct device *dev, struct device_attribute *attr, char *buf)
        } else  /* VBUS level below A-Valid */
                v2 = "disconnected";
 #endif
+       musb_platform_try_idle(musb);
        spin_unlock_irqrestore(&musb->Lock, flags);
 
        return sprintf(buf, "%s%s\n", v1, v2);
@@ -1458,7 +1467,6 @@ static void musb_irq_work(void *data)
                musb->status &= ~MUSB_VBUS_STATUS_CHG;
                event = 1;
        }
-       musb_platform_try_idle(musb);
        spin_unlock_irqrestore(&musb->Lock, flags);
 
 #ifdef CONFIG_SYSFS
@@ -1654,6 +1662,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
                goto fail2;
        }
        pThis->nIrq = nIrq;
+       device_init_wakeup(dev, 1);
 
        pr_info("%s: USB %s mode controller at %p using %s, IRQ %d\n",
                        musb_driver_name,
@@ -1668,11 +1677,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
                                ? "DMA" : "PIO",
                        pThis->nIrq);
 
-// FIXME:
-//  - convert to the HCD framework
-//  - if (board_mode == MUSB_OTG) do startup with peripheral
-//  - ... involves refcounting updates
-
 #ifdef CONFIG_USB_MUSB_HDRC_HCD
        /* host side needs more setup, except for no-host modes */
        if (pThis->board_mode != MUSB_PERIPHERAL) {
@@ -1737,7 +1741,9 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
                musb_debug_create("driver/musb_hdrc", pThis);
        else {
 fail:
+               device_init_wakeup(dev, 0);
                musb_free(pThis);
+               return status;
        }
 
        INIT_WORK(&pThis->irq_work, musb_irq_work, pThis);
@@ -1796,15 +1802,12 @@ static int __devexit musb_remove(struct platform_device *pdev)
                usb_remove_hcd(musb_to_hcd(musb));
 #endif
        musb_free(musb);
+       device_init_wakeup(&pdev->dev, 0);
        return 0;
 }
 
 #ifdef CONFIG_PM
 
-/* REVISIT when power savings matter on DaVinci, look at turning
- * off its phy clock during system suspend iff wakeup is disabled
- */
-
 static int musb_suspend(struct platform_device *pdev, pm_message_t message)
 {
        unsigned long   flags;
@@ -1821,11 +1824,10 @@ static int musb_suspend(struct platform_device *pdev, pm_message_t message)
                 */
        } else if (is_host_active(musb)) {
                /* we know all the children are suspended; sometimes
-                * they will even be wakeup-enabled
+                * they will even be wakeup-enabled.
                 */
        }
 
-       musb_platform_try_idle(musb);
        clk_disable(musb->clock);
        spin_unlock_irqrestore(&musb->Lock, flags);
        return 0;
index 65091a10941c34b062adcb663a75bcff6124d5c7..7d9e09bbb3c65b72510b5904df76fdb60ae7c6ee 100644 (file)
@@ -145,6 +145,10 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
 
 /*
  * Enables TUSB6010 to use VBUS as power source in peripheral mode.
+ * In host mode, a local battery must power the TUSB chip as well as
+ * (through the charge pump) VBUS.  For OTG peripherals, the battery
+ * must power the chip until it enters a confguration that's allowed
+ * to draw enough current (call it 100mA).
  */
 static inline void tusb_enable_vbus_charge(struct musb *musb)
 {
@@ -159,21 +163,29 @@ static inline void tusb_enable_vbus_charge(struct musb *musb)
 }
 
 /*
- * Idles TUSB6010 until next wake-up event interrupt. Use all wake-up
- * events for now. Note that TUSB will not respond if NOR chip select
- * wake-up event is masked. Also note that any access to TUSB will wake
- * it up from idle.
+ * Idle TUSB6010 until next wake-up event; NOR access always wakes.
+ * Other code ensures that we idle unless we're connected _and_ the
+ * USB link is not suspended ... and tells us the relevant wakeup
+ * events.
  */
-static inline void tusb_allow_idle(struct musb *musb, int wakeup_mask)
+static inline void tusb_allow_idle(struct musb *musb, u32 wakeup_enables)
 {
        void __iomem    *base = musb->ctrl_base;
        u32             reg;
 
-       musb_writel(base, TUSB_PRCM_WAKEUP_MASK, wakeup_mask);
+       wakeup_enables |= TUSB_PRCM_WNORCS;
+       musb_writel(base, TUSB_PRCM_WAKEUP_MASK, ~wakeup_enables);
+
        reg = musb_readl(base, TUSB_PRCM_MNGMT);
-       reg &= ~TUSB_PRCM_MNGMT_CPEN_MASK;
-       reg |= TUSB_PRCM_MNGMT_SUSPEND_MASK;
+       reg &= ~( TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN
+                       | TUSB_PRCM_MNGMT_15_SW_EN
+                       | TUSB_PRCM_MNGMT_33_SW_EN );
+       reg |= TUSB_PRCM_MNGMT_OTG_SESS_END_EN
+                       | 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);
 }
 
 /*
@@ -206,36 +218,117 @@ int musb_platform_get_vbus_status(struct musb *musb)
        return ret;
 }
 
+static struct timer_list musb_idle_timer;
+
+static void musb_do_idle(unsigned long _musb)
+{
+       struct musb     *musb = (void *)_musb;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&musb->Lock, flags);
+       if (!musb->is_active) {
+               u32     wakeups;
+
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+               if (is_peripheral_enabled(musb) && !musb->pGadgetDriver)
+                       wakeups = 0;
+               else {
+                       wakeups = TUSB_PRCM_WHOSTDISCON
+                                       | TUSB_PRCM_WBUS
+                                       | TUSB_PRCM_WVBUS;
+                       if (is_otg_enabled(musb))
+                               wakeups |= TUSB_PRCM_WLD;
+               }
+#else
+               wakeups = TUSB_PRCM_WHOSTDISCON | TUSB_PRCM_WBUS;
+#endif
+               tusb_allow_idle(musb, wakeups);
+       }
+       spin_unlock_irqrestore(&musb->Lock, flags);
+}
+
 /*
- * Sets the TUSB6010 idles mode in peripheral mode depending on the
- * gadget driver state and cable VBUS status. Needs to be called as
- * the last function everywhere where there is register access to
- * TUSB6010 because of the NOR flash wake-up capability.
- * Caller must take care of locking.
+ * Maybe put TUSB6010 into idle mode mode depending on USB link status,
+ * like "disconnected" or "suspended".  We'll be woken out of it by
+ * connect, resume, or disconnect.
+ *
+ * Needs to be called as the last function everywhere where there is
+ * register access to TUSB6010 because of NOR flash wake-up.
+ * Caller should own controller spinlock.
+ *
+ * Delay because peripheral enables D+ pullup 3msec after SE0, and
+ * we don't want to treat that full speed J as a wakeup event.
+ * ... peripherals must draw only suspend current after 10 msec.
  */
 void musb_platform_try_idle(struct musb *musb)
 {
-       u32             wakeup_mask = 0;
+       if (musb->is_active)
+               del_timer(&musb_idle_timer);
+       else
+               mod_timer(&musb_idle_timer, jiffies +
+                       (is_host_active(musb) ? msecs_to_jiffies(3) : 0));
+}
+
+static inline void
+tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *base)
+{
+       u32     otg_stat = musb_readl(base, TUSB_DEV_OTG_STAT);
+
+       /* ID pin */
+       if ((int_src & TUSB_INT_SRC_ID_STATUS_CHNG)) {
+               int     default_a;
+
+               default_a = is_host_enabled(musb)
+                       && (otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS);
+               if (default_a != musb->xceiv.default_a) {
+                       musb->xceiv.default_a = default_a;
+                       if (musb->xceiv.default_a) {
+                               musb->xceiv.state = OTG_STATE_A_IDLE;
+                               /* REVISIT start the session? */
+                       } else
+                               musb->xceiv.state = OTG_STATE_B_IDLE;
+                       DBG(1, "Default-%c\n", musb->xceiv.default_a
+                                       ? 'A' : 'B');
+                       musb->is_active = 1;
+               }
+       }
 
-       /* Suspend with only NOR flash wake-up event enabled if no
-        * gadget driver is active.
-        */
-       if (musb->xceiv.state == OTG_STATE_UNDEFINED) {
-               wakeup_mask = 0xffff & ~TUSB_PRCM_WNORCS;
-               tusb_allow_idle(musb, wakeup_mask);
-               return;
+       /* VBUS state change */
+       if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) {
+               /* no vbus ~= disconnect */
+               if (!is_host_enabled(musb) || !musb->xceiv.default_a) {
+
+                       /* REVISIT in B-Default state machine, use VBUS power
+                        * for the USB link when (a) non-OTG, since 100 mA is
+                        * always available; or (b) OTG after SET_CONFIGURATION
+                        * enabling 100+ (?) mA draw.
+                        */
+
+                       /* REVISIT use the b_sess_valid comparator, not
+                        * lowpower one; TUSB_DEV_OTG_STAT_SESS_VALID ?
+                        */
+
+                       if (otg_stat & TUSB_DEV_OTG_STAT_VBUS_SENSE) {
+                               musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+                               musb->is_active = 1;
+                               /* REVISIT start the session? */
+                       } else {
+                               musb->xceiv.state = OTG_STATE_B_IDLE;
+                               musb->is_active = 0;
+                       }
+                       DBG(1, "%s\n", musb->is_active
+                                       ? "b_peripheral" : "b_idle");
+                       musb->status |= MUSB_VBUS_STATUS_CHG;
+                       schedule_work(&musb->irq_work);
+               }
        }
 
-       /* Use VBUS as power source if available, otherwise suspend
-        * with all wake-up events enabled.
-        *
-        * FIXME only B-device state machine ever _consumes_ VBUS.
-        */
-       if (musb_platform_get_vbus_status(musb))
-               tusb_enable_vbus_charge(musb);
-       else {
-               wakeup_mask = TUSB_PRCM_WLD;
-               tusb_allow_idle(musb, wakeup_mask);
+       /* OTG timer expiration */
+       if (int_src & TUSB_INT_SRC_OTG_TIMEOUT) {
+               DBG(3, "tusb: OTG timer expired\n");
+               musb_writel(base, TUSB_DEV_OTG_TIMER,
+                       musb_readl(base, TUSB_DEV_OTG_TIMER)
+                       | TUSB_DEV_OTG_TIMER_ENABLE);
        }
 }
 
@@ -244,88 +337,43 @@ irqreturn_t tusb_interrupt(int irq, void *__hci, struct pt_regs *r)
        struct musb     *musb = __hci;
        void __iomem    *base = musb->ctrl_base;
        unsigned long   flags;
-       u32             dma_src, int_src, otg_stat, musb_src = 0;
+       u32             dma_src = 0, int_src;
 
        spin_lock_irqsave(&musb->Lock, flags);
 
-       dma_src = musb_readl(base, TUSB_DMA_INT_SRC);
        int_src = musb_readl(base, TUSB_INT_SRC) & ~TUSB_INT_SRC_RESERVED_BITS;
-       otg_stat = musb_readl(base, TUSB_DEV_OTG_STAT);
+       if (int_src & TUSB_INT_SRC_TXRX_DMA_DONE)
+               dma_src = musb_readl(base, TUSB_DMA_INT_SRC);
 
-       DBG(3, "TUSB interrupt dma: %08x int: %08x otg: %08x\n",
-               dma_src, int_src, otg_stat);
+       DBG(3, "TUSB interrupt dma: %08x int: %08x\n", dma_src, int_src);
 
-       musb->int_usb = 0;
-       musb->int_rx = 0;
-       musb->int_tx = 0;
        musb->int_regs = r;
 
-       if (otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS) {
-               /* ID pin is up. Either A-plug was removed or TUSB6010
-                * is in peripheral mode */
-
-               /* Still in pheripheral mode? */
-               if ((int_src & TUSB_INT_SRC_ID_STATUS_CHNG)) {
-                       DBG(3, "tusb: Status change\n");
-                       //goto out;
-               }
-       }
-
-       /* Peripheral suspend. Cable may be disconnected, try to idle */
-       if (int_src & TUSB_INT_SRC_USB_IP_SUSPEND) {
-               musb->status |= MUSB_VBUS_STATUS_CHG;
-               schedule_work(&musb->irq_work);
-       }
-
-       /* Connect and disconnect for host mode */
-       if (int_src & TUSB_INT_SRC_USB_IP_CONN) {
-               DBG(3, "tusb: Connected\n");
-       }
-       else if (int_src & TUSB_INT_SRC_USB_IP_DISCON) {
-               DBG(3, "tusb: Disconnected\n");
-       }
-
-       /* VBUS state change */
-       if ((int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG)
-                       || (int_src & TUSB_INT_SRC_USB_IP_VBUS_ERR)) {
-               musb->status |= MUSB_VBUS_STATUS_CHG;
-               schedule_work(&musb->irq_work);
+       /* Acknowledge wake-up source interrupts */
+       if (int_src & TUSB_INT_SRC_DEV_WAKEUP) {
+               u32     reg = musb_readl(base, TUSB_PRCM_WAKEUP_SOURCE);
 
-#if 0
-               DBG(3, "tusb: VBUS changed. VBUS state %d\n",
-                       (otg_stat & TUSB_DEV_OTG_STAT_VBUS_SENSE) ? 1 : 0);
-               if (!(otg_stat & TUSB_DEV_OTG_STAT_VBUS_SENSE)
-                               && !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS)) {
-                       /* VBUS went off and ID pin is down */
-                       DBG(3, "tusb: No VBUS, starting session\n");
-                       /* Start session again, VBUS will be enabled */
-                       musb_writeb(musb_base, MGC_O_HDRC_DEVCTL,
-                               MGC_M_DEVCTL_SESSION);
+               musb_writel(base, TUSB_PRCM_WAKEUP_CLEAR, reg);
+               if (reg & ~TUSB_PRCM_WNORCS) {
+                       schedule_work(&musb->irq_work);
+                       musb->is_active = 1;
                }
-#endif
-       }
-
-       /* ID pin change */
-       if (int_src & TUSB_INT_SRC_ID_STATUS_CHNG) {
-               DBG(3, "tusb: ID pin changed. State is %d\n",
-                       (musb_readl(base, TUSB_DEV_OTG_STAT)
-                               & TUSB_DEV_OTG_STAT_ID_STATUS)
-                       ? 1 : 0);
+               DBG(3, "wake %sactive %02x\n",
+                               musb->is_active ? "" : "in", reg);
        }
 
-       /* OTG timer expiration */
-       if (int_src & TUSB_INT_SRC_OTG_TIMEOUT) {
-               DBG(3, "tusb: OTG timer expired\n");
-               musb_writel(base, TUSB_DEV_OTG_TIMER,
-                       musb_readl(base, TUSB_DEV_OTG_TIMER) |
-                       TUSB_DEV_OTG_TIMER_ENABLE);
-       }
+       /* OTG state change reports (annoyingly) not issued by Mentor core */
+       if (int_src & (TUSB_INT_SRC_VBUS_SENSE_CHNG
+                               | TUSB_INT_SRC_OTG_TIMEOUT
+                               | TUSB_INT_SRC_ID_STATUS_CHNG))
+               tusb_otg_ints(musb, int_src, base);
 
        /* TX dma callback must be handled here, RX dma callback is
         * handled in tusb_omap_dma_cb.
         */
        if ((int_src & TUSB_INT_SRC_TXRX_DMA_DONE) && dma_src) {
                u32 real_dma_src = musb_readl(base, TUSB_DMA_INT_MASK);
+
                real_dma_src = ~real_dma_src & dma_src;
                if (tusb_dma_omap()) {
                        int     tx_source = (real_dma_src & 0xffff);
@@ -343,27 +391,25 @@ irqreturn_t tusb_interrupt(int irq, void *__hci, struct pt_regs *r)
 
        /* EP interrupts. In OCP mode tusb6010 mirrors the MUSB * interrupts */
        if (int_src & (TUSB_INT_SRC_USB_IP_TX | TUSB_INT_SRC_USB_IP_RX)) {
-               musb_src = musb_readl(base, TUSB_USBIP_INT_SRC);
+               u32     musb_src = musb_readl(base, TUSB_USBIP_INT_SRC);
+
                musb_writel(base, TUSB_USBIP_INT_CLEAR, musb_src);
                musb->int_rx = (((musb_src >> 16) & 0xffff) << 1);
                musb->int_tx = (musb_src & 0xffff);
-       }
-       musb->int_usb = (int_src & 0xff);
-       if (musb->int_usb || musb->int_rx || musb->int_tx)
-               musb_interrupt(musb);
+       } else
+               musb->int_rx = musb->int_tx = 0;
 
-       /* Acknowledge wake-up source interrupts */
-       if (int_src & TUSB_INT_SRC_DEV_WAKEUP) {
-               u32 reg = musb_readl(base, TUSB_PRCM_WAKEUP_SOURCE);
-               musb_writel(base, TUSB_PRCM_WAKEUP_CLEAR, reg);
-               schedule_work(&musb->irq_work);
+       if (int_src & (TUSB_INT_SRC_USB_IP_TX | TUSB_INT_SRC_USB_IP_RX | 0xff)) {
+               musb->int_usb = (u8) int_src;
+               musb_interrupt(musb);
        }
 
        /* Acknowledge TUSB interrupts. Clear only non-reserved bits */
-       if (int_src)
-               musb_writel(base, TUSB_INT_SRC_CLEAR,
-                       int_src & ~TUSB_INT_MASK_RESERVED_BITS);
+       musb_writel(base, TUSB_INT_SRC_CLEAR,
+               int_src & ~TUSB_INT_MASK_RESERVED_BITS);
 
+       musb->int_regs = NULL;
+       musb_platform_try_idle(musb);
        spin_unlock_irqrestore(&musb->Lock, flags);
 
        return IRQ_HANDLED;
@@ -589,7 +635,7 @@ int __devinit musb_platform_init(struct musb *musb)
        }
        musb->isr = tusb_interrupt;
 
-       musb_platform_try_idle(musb);
+       setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
 
        return ret;
 }
index c8c05e2f638aa8133fcb9740fe01ec38a5b7d918..e878ae6b3c5ddd53919d230107f2ed1f04027adc 100644 (file)
 #define                TUSB_PRCM_MNGMT_5V_CPEN                 (1 << 2)
 #define                TUSB_PRCM_MNGMT_PM_IDLE                 (1 << 1)
 #define                TUSB_PRCM_MNGMT_DEV_IDLE                (1 << 0)
-#define                TUSB_PRCM_MNGMT_PM_CLEAR_MASK   ((0x3 << 3) | (0x3 << 0))
-#define                TUSB_PRCM_MNGMT_CPEN_MASK       ((1 << 9) | (0x3 << 3))
-#define                TUSB_PRCM_MNGMT_SUSPEND_MASK    ((1 << 10) | (0x3 << 0))
+
+#define                TUSB_PRCM_MNGMT_PM_CLEAR_MASK   \
+                       ( TUSB_PRCM_MNGMT_15_SW_EN \
+                       | TUSB_PRCM_MNGMT_33_SW_EN \
+                       | TUSB_PRCM_MNGMT_PM_IDLE \
+                       | TUSB_PRCM_MNGMT_DEV_IDLE )
+#define                TUSB_PRCM_MNGMT_CPEN_MASK       \
+                       ( TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN \
+                       | TUSB_PRCM_MNGMT_15_SW_EN \
+                       | TUSB_PRCM_MNGMT_33_SW_EN )
+#define                TUSB_PRCM_MNGMT_SUSPEND_MASK    \
+                       ( TUSB_PRCM_MNGMT_OTG_SESS_END_EN \
+                       | TUSB_PRCM_MNGMT_PM_IDLE \
+                       | TUSB_PRCM_MNGMT_DEV_IDLE )
 
 /* Wake-up source clear and mask registers */
 #define TUSB_PRCM_WAKEUP_SOURCE                (TUSB_SYS_REG_BASE + 0x020)
index b3300705dc7f79daab300f7c3a1d9400d3dcaf60..0d0b02cd0f35878b38ab621cd3935f1c42989bd7 100644 (file)
@@ -58,11 +58,15 @@ static void musb_port_suspend(struct musb *musb, u8 bSuspend)
                musb_writeb(pBase, MGC_O_HDRC_POWER,
                                power | MGC_M_POWER_SUSPENDM);
                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);
        } 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;
                musb_writeb(pBase, MGC_O_HDRC_POWER, power);
                musb->port1_status &= ~USB_PORT_STAT_SUSPEND;
                musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
@@ -134,6 +138,7 @@ void musb_root_disconnect(struct musb *musb)
                );
        musb->port1_status |= USB_PORT_STAT_C_CONNECTION << 16;
        usb_hcd_poll_rh_status(musb_to_hcd(musb));
+       musb->is_active = 0;
 
        switch (musb->xceiv.state) {
        case OTG_STATE_A_HOST: