]> rtime.felk.cvut.cz Git - zynq/linux.git/commitdiff
usb: xilinxps_udc: Added s/w workaround for USB disconnect detection
authorNaveen Mamindlapalli <naveen.mamindlapalli@xilinx.com>
Wed, 20 Mar 2013 07:36:44 +0000 (13:06 +0530)
committerMichal Simek <michal.simek@xilinx.com>
Wed, 20 Mar 2013 07:50:36 +0000 (08:50 +0100)
Added s/w workaround for USB disconnect detection as mentioned in
AR# 47538. See http://www.xilinx.com/support/answers/47538.htm for
more details. This fix is not applicable for OTG mode as there is
no callback registered for B session end event.

Signed-off-by: Naveen Mamindlapalli <naveenm@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
drivers/usb/gadget/xilinx_usbps_udc.c

index de9d7ae4f6b039a6b313bd3024e8a09b47dfdd6b..0a5b3b450e132814bc78556c9e019afa6c71749e 100644 (file)
@@ -47,9 +47,7 @@
 #include <asm/unaligned.h>
 #include <asm/dma.h>
 
-#ifdef CONFIG_USB_XUSBPS_OTG
 #include <linux/usb/xilinx_usbps_otg.h>
-#endif
 
 #define        DRIVER_DESC     "Xilinx PS USB Device Controller driver"
 #define        DRIVER_AUTHOR   "Xilinx, Inc."
@@ -648,6 +646,17 @@ static void dr_controller_run(struct xusbps_udc *udc)
 
        xusbps_writel(temp, &dr_regs->usbintr);
 
+       /*
+        * Enable disconnect notification using B session end interrupt.
+        * This is a SW workaround for USB disconnect detection as mentioned
+        * in AR# 47538
+        */
+       if (!gadget_is_otg(&udc->gadget)) {
+               temp = xusbps_readl(&dr_regs->otgsc);
+               temp |= OTGSC_BSEIE;
+               xusbps_writel(temp, &dr_regs->otgsc);
+       }
+
        /* Clear stopped bit */
        udc->stopped = 0;
 
@@ -2339,7 +2348,7 @@ static void reset_irq(struct xusbps_udc *udc)
 static irqreturn_t xusbps_udc_irq(int irq, void *_udc)
 {
        struct xusbps_udc *udc = _udc;
-       u32 irq_src;
+       u32 irq_src, otg_sts;
        irqreturn_t status = IRQ_NONE;
        unsigned long flags;
 #ifdef CONFIG_USB_XUSBPS_OTG
@@ -2368,6 +2377,20 @@ static irqreturn_t xusbps_udc_irq(int irq, void *_udc)
        /* Clear notification bits */
        xusbps_writel(irq_src, &dr_regs->usbsts);
 
+       /*
+        * Check disconnect event from B session end interrupt.
+        * This is a SW workaround for USB disconnect detection as mentioned
+        * in AR# 47538
+        */
+       if (!gadget_is_otg(&udc->gadget)) {
+               otg_sts = xusbps_readl(&dr_regs->otgsc);
+               if (otg_sts & OTGSC_BSEIS) {
+                       xusbps_writel(otg_sts, &dr_regs->otgsc);
+                       reset_queues(udc);
+                       status = IRQ_HANDLED;
+               }
+       }
+
        /* VDBG("irq_src [0x%8x]", irq_src); */
 
        /* Need to resume? */