Przeglądaj źródła

usb: musb: dsps: handle babble interrupts

When the dsps isr sees a babble error, pass it down to the core for
fixup. Also, provide a .reset hook so the core can call us back.

A babble interrupt error occured when a USB mass storage device
("CHIPSBNK v3.3.9.1", 1e3d:2093) was disconnected from a AM33xx host.

Signed-off-by: Daniel Mack <zonque@gmail.com>
Reported-by: Thomas Mellenthin <mellenthin@teufel.de>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Daniel Mack 11 lat temu
rodzic
commit
1d57de306e
1 zmienionych plików z 24 dodań i 1 usunięć
  1. 24 1
      drivers/usb/musb/musb_dsps.c

+ 24 - 1
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.
 	 * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
 	 * Also, DRVVBUS pulses for SRP (but not at 5V) ...
 	 * 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");
 		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)) {
 	if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {
 		int drvvbus = dsps_readl(reg_base, wrp->status);
 		int drvvbus = dsps_readl(reg_base, wrp->status);
 		void __iomem *mregs = musb->mregs;
 		void __iomem *mregs = musb->mregs;
@@ -523,6 +535,16 @@ static int dsps_musb_set_mode(struct musb *musb, u8 mode)
 	return 0;
 	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 = {
 static struct musb_platform_ops dsps_ops = {
 	.init		= dsps_musb_init,
 	.init		= dsps_musb_init,
 	.exit		= dsps_musb_exit,
 	.exit		= dsps_musb_exit,
@@ -532,6 +554,7 @@ static struct musb_platform_ops dsps_ops = {
 
 
 	.try_idle	= dsps_musb_try_idle,
 	.try_idle	= dsps_musb_try_idle,
 	.set_mode	= dsps_musb_set_mode,
 	.set_mode	= dsps_musb_set_mode,
+	.reset		= dsps_musb_reset,
 };
 };
 
 
 static u64 musb_dmamask = DMA_BIT_MASK(32);
 static u64 musb_dmamask = DMA_BIT_MASK(32);