Commit e362bdfb authored by David Brownell's avatar David Brownell Committed by Tony Lindgren

MUSB: TUSB PM cleanup

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: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
parent 76947000
......@@ -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;
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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);
}
......
......@@ -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;
......
This diff is collapsed.
......@@ -103,9 +103,20 @@
#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)
......
......@@ -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:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment