diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 18882924d9d53b7cc6aafa5c56c71b6b39c076f2..138d1dd862354fdd29d43e66c3e4f6c36579479b 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -329,9 +329,21 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set. * Also, DRVVBUS pulses for SRP (but not at 5V) ... */ - if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE) + if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE) { pr_info("CAUTION: musb: Babble Interrupt Occurred\n"); + /* + * When a babble condition occurs, the musb controller removes + * the session and is no longer in host mode. Hence, all + * devices connected to its root hub get disconnected. + * + * Hand this error down to the musb core isr, so it can + * recover. + */ + musb->int_usb = MUSB_INTR_BABBLE | MUSB_INTR_DISCONNECT; + musb->int_tx = musb->int_rx = 0; + } + if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) { int drvvbus = dsps_readl(reg_base, wrp->status); void __iomem *mregs = musb->mregs; @@ -523,6 +535,16 @@ static int dsps_musb_set_mode(struct musb *musb, u8 mode) return 0; } +static void dsps_musb_reset(struct musb *musb) +{ + struct device *dev = musb->controller; + struct dsps_glue *glue = dev_get_drvdata(dev->parent); + const struct dsps_musb_wrapper *wrp = glue->wrp; + + dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset)); + udelay(100); +} + static struct musb_platform_ops dsps_ops = { .init = dsps_musb_init, .exit = dsps_musb_exit, @@ -532,6 +554,7 @@ static struct musb_platform_ops dsps_ops = { .try_idle = dsps_musb_try_idle, .set_mode = dsps_musb_set_mode, + .reset = dsps_musb_reset, }; static u64 musb_dmamask = DMA_BIT_MASK(32);