dwc3: gadget: add VBUS session handling
authorRobert Baldyga <r.baldyga@samsung.com>
Mon, 9 Mar 2015 10:20:15 +0000 (11:20 +0100)
committerMarek Szyprowski <m.szyprowski@samsung.com>
Mon, 13 Apr 2015 10:44:41 +0000 (12:44 +0200)
Add software VBUS session handling code.
It's necessary for OTG role switching.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
drivers/usb/dwc3/core.h
drivers/usb/dwc3/gadget.c

index 30abb5f..6d3a695 100644 (file)
@@ -845,6 +845,7 @@ struct dwc3 {
 
        unsigned                tx_de_emphasis_quirk:1;
        unsigned                tx_de_emphasis:2;
+       unsigned                vbus_session:1;
 
        unsigned                needs_reinit:1;
 };
index a03a485..c16ec55 100644 (file)
@@ -1475,12 +1475,53 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
        return 0;
 }
 
+static int dwc3_gadget_vbus_session(struct usb_gadget *g, int is_active)
+{
+       struct dwc3 *dwc = gadget_to_dwc(g);
+       unsigned long flags;
+
+       if (!dwc->dotg)
+               return -EPERM;
+
+       is_active = !!is_active;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+
+       /* Mark that the vbus was powered */
+       dwc->vbus_session = is_active;
+
+       /*
+        * Check if upper level usb_gadget_driver was already registerd with
+        * this udc controller driver (if dwc3_gadget_start was called)
+        */
+       if (dwc->gadget_driver) {
+               if (dwc->vbus_session) {
+                       /*
+                        * Both vbus was activated by otg and pullup was
+                        * signaled by the gadget driver.
+                        */
+                       dwc3_gadget_run_stop(dwc, 1, false);
+               } else {
+                       dwc3_gadget_run_stop(dwc, 0, false);
+               }
+       }
+
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return 0;
+}
+
+
 static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 {
        struct dwc3             *dwc = gadget_to_dwc(g);
        unsigned long           flags;
        int                     ret;
 
+       /* Need to wait for vbus_session(on) from otg driver */
+       if (dwc->dotg && !dwc->vbus_session)
+               return 0;
+
        is_on = !!is_on;
 
        spin_lock_irqsave(&dwc->lock, flags);
@@ -1657,6 +1698,7 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {
        .get_frame              = dwc3_gadget_get_frame,
        .wakeup                 = dwc3_gadget_wakeup,
        .set_selfpowered        = dwc3_gadget_set_selfpowered,
+       .vbus_session           = dwc3_gadget_vbus_session,
        .pullup                 = dwc3_gadget_pullup,
        .udc_start              = dwc3_gadget_start,
        .udc_stop               = dwc3_gadget_stop,