diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index fc192ad9cc6a..1a377cac4d4c 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -477,6 +477,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, musb->port1_status |= (USB_PORT_STAT_C_SUSPEND << 16) | MUSB_PORT_STAT_RESUME; + musb->rh_timer = jiffies + + msecs_to_jiffies(20); schedule_delayed_work( &musb->finish_resume_work, 20); diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index eb634433ef09..32f49e1efa9c 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -158,7 +158,6 @@ void musb_port_reset(struct musb *musb, bool do_reset) */ power = musb_readb(mbase, MUSB_POWER); if (do_reset) { - /* * If RESUME is set, we must make sure it stays minimum 20 ms. * Then we must clear RESUME and wait a bit to let musb start @@ -167,11 +166,22 @@ void musb_port_reset(struct musb *musb, bool do_reset) * detected". */ if (power & MUSB_POWER_RESUME) { - while (time_before(jiffies, musb->rh_timer)) - msleep(1); + long remain = (unsigned long) musb->rh_timer - jiffies; + + if (musb->rh_timer > 0 && remain > 0) { + /* take into account the minimum delay after resume */ + schedule_delayed_work( + &musb->deassert_reset_work, + jiffies_to_msecs(remain)); + return; + } + musb_writeb(mbase, MUSB_POWER, - power & ~MUSB_POWER_RESUME); - msleep(1); + power & ~MUSB_POWER_RESUME); + + /* Give the core 1 ms to clear MUSB_POWER_RESUME */ + schedule_delayed_work(&musb->deassert_reset_work, 1); + return; } power &= 0xf0;