usb: udc: add usb_udc_vbus_handler
authorPeter Chen <peter.chen@freescale.com>
Fri, 6 Mar 2015 02:36:03 +0000 (10:36 +0800)
committerFelipe Balbi <balbi@ti.com>
Thu, 19 Mar 2015 16:26:03 +0000 (11:26 -0500)
This commit updates udc core vbus status, and try to connect
or disconnect gadget.

Signed-off-by: Peter Chen <peter.chen@freescale.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/gadget/udc/udc-core.c
include/linux/usb/gadget.h

index bf7ed777a87d604d4b54df4ffef847894a73f802..d69c35558f6852beecd1bfc85acee35c26781ec8 100644 (file)
@@ -35,6 +35,8 @@
  * @dev - the child device to the actual controller
  * @gadget - the gadget. For use by the class code
  * @list - for use by the udc class driver
+ * @vbus - for udcs who care about vbus status, this value is real vbus status;
+ * for udcs who do not care about vbus status, this value is always true
  *
  * This represents the internal data structure which is used by the UDC-class
  * to hold information about udc driver and gadget together.
@@ -44,6 +46,7 @@ struct usb_udc {
        struct usb_gadget               *gadget;
        struct device                   dev;
        struct list_head                list;
+       bool                            vbus;
 };
 
 static struct class *udc_class;
@@ -145,6 +148,34 @@ EXPORT_SYMBOL_GPL(usb_gadget_set_state);
 
 /* ------------------------------------------------------------------------- */
 
+static void usb_udc_connect_control(struct usb_udc *udc)
+{
+       if (udc->vbus)
+               usb_gadget_connect(udc->gadget);
+       else
+               usb_gadget_disconnect(udc->gadget);
+}
+
+/**
+ * usb_udc_vbus_handler - updates the udc core vbus status, and try to
+ * connect or disconnect gadget
+ * @gadget: The gadget which vbus change occurs
+ * @status: The vbus status
+ *
+ * The udc driver calls it when it wants to connect or disconnect gadget
+ * according to vbus status.
+ */
+void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status)
+{
+       struct usb_udc *udc = gadget->udc;
+
+       if (udc) {
+               udc->vbus = status;
+               usb_udc_connect_control(udc);
+       }
+}
+EXPORT_SYMBOL_GPL(usb_udc_vbus_handler);
+
 /**
  * usb_gadget_udc_reset - notifies the udc core that bus reset occurs
  * @gadget: The gadget which bus reset occurs
@@ -278,6 +309,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
                goto err4;
 
        usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
+       udc->vbus = true;
 
        mutex_unlock(&udc_lock);
 
@@ -381,7 +413,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
                driver->unbind(udc->gadget);
                goto err1;
        }
-       usb_gadget_connect(udc->gadget);
+       usb_udc_connect_control(udc);
 
        kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
        return 0;
index 242c694a5b856a67fe63af2edde49198dd34b336..4f3dfb7d065420d012eeade7154575100473602c 100644 (file)
@@ -1032,6 +1032,10 @@ extern void usb_gadget_udc_reset(struct usb_gadget *gadget,
 extern void usb_gadget_giveback_request(struct usb_ep *ep,
                struct usb_request *req);
 
+/*-------------------------------------------------------------------------*/
+
+/* utility to update vbus status for udc core, it may be scheduled */
+extern void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status);
 
 /*-------------------------------------------------------------------------*/