summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2011-06-23 14:26:15 +0200
committerGreg Kroah-Hartman <gregkh@suse.de>2011-07-01 14:31:13 -0700
commit352c2dc8b07491bbab77ddf86c20c16a97326ee7 (patch)
treea1aaa9ab0b95701e4f8aba194bfbbb42df81b572 /drivers/usb/gadget
parentb5738413c96126e8191bc506b403cd55950b8f9a (diff)
usb: gadget: udc-core: add "new-style" registration interface
udc_start() should only trigger the internal state machine and make minimal house keeping. Before that call udc-core calls the bind() callback and after the callback the pullup(). udc_stop() is simillar, udc-core calls pullup(), unbind() and finally udc_stop(). Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Felipe Balbi <balbi@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/udc-core.c75
1 files changed, 71 insertions, 4 deletions
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index 83e9e5f99b4a..2ddb7c8b5b3d 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/drivers/usb/gadget/udc-core.c
@@ -73,6 +73,26 @@ static inline int usb_gadget_start(struct usb_gadget *gadget,
}
/**
+ * usb_gadget_udc_start - tells usb device controller to start up
+ * @gadget: The gadget we want to get started
+ * @driver: The driver we want to bind to @gadget
+ *
+ * This call is issued by the UDC Class driver when it's about
+ * to register a gadget driver to the device controller, before
+ * calling gadget driver's bind() method.
+ *
+ * It allows the controller to be powered off until strictly
+ * necessary to have it powered on.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int usb_gadget_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ return gadget->ops->udc_start(gadget, driver);
+}
+
+/**
* usb_gadget_stop - tells usb device controller we don't need it anymore
* @gadget: The device we want to stop activity
* @driver: The driver to unbind from @gadget
@@ -91,6 +111,24 @@ static inline void usb_gadget_stop(struct usb_gadget *gadget,
}
/**
+ * usb_gadget_udc_stop - tells usb device controller we don't need it anymore
+ * @gadget: The device we want to stop activity
+ * @driver: The driver to unbind from @gadget
+ *
+ * This call is issued by the UDC Class driver after calling
+ * gadget driver's unbind() method.
+ *
+ * The details are implementation specific, but it can go as
+ * far as powering off UDC completely and disable its data
+ * line pullups.
+ */
+static inline void usb_gadget_udc_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ gadget->ops->udc_stop(gadget, driver);
+}
+
+/**
* usb_udc_release - release the usb_udc struct
* @dev: the dev member within usb_udc
*
@@ -155,6 +193,14 @@ err1:
}
EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
+static int udc_is_newstyle(struct usb_udc *udc)
+{
+ if (udc->gadget->ops->udc_start && udc->gadget->ops->udc_stop)
+ return 1;
+ return 0;
+}
+
+
static void usb_gadget_remove_driver(struct usb_udc *udc)
{
dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
@@ -162,7 +208,14 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
- usb_gadget_stop(udc->gadget, udc->driver);
+ if (udc_is_newstyle(udc)) {
+ usb_gadget_disconnect(udc->gadget);
+ udc->driver->unbind(udc->gadget);
+ usb_gadget_udc_stop(udc->gadget, udc->driver);
+
+ } else {
+ usb_gadget_stop(udc->gadget, udc->driver);
+ }
udc->driver = NULL;
udc->dev.driver = NULL;
@@ -232,9 +285,23 @@ found:
udc->driver = driver;
udc->dev.driver = &driver->driver;
- ret = usb_gadget_start(udc->gadget, driver, bind);
- if (ret)
- goto err1;
+ if (udc_is_newstyle(udc)) {
+ ret = bind(udc->gadget);
+ if (ret)
+ goto err1;
+ ret = usb_gadget_udc_start(udc->gadget, driver);
+ if (ret) {
+ driver->unbind(udc->gadget);
+ goto err1;
+ }
+ usb_gadget_connect(udc->gadget);
+ } else {
+
+ ret = usb_gadget_start(udc->gadget, driver, bind);
+ if (ret)
+ goto err1;
+
+ }
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
mutex_unlock(&udc_lock);