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;
......
......@@ -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;
}
......
......@@ -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