All of lore.kernel.org
 help / color / mirror / Atom feed
From: Roger Quadros <rogerq@ti.com>
To: <peter.chen@freescale.com>
Cc: <balbi@kernel.org>, <tony@atomide.com>,
	<gregkh@linuxfoundation.org>, <dan.j.williams@intel.com>,
	<mathias.nyman@linux.intel.com>, <Joao.Pinto@synopsys.com>,
	<sergei.shtylyov@cogentembedded.com>, <jun.li@freescale.com>,
	<grygorii.strashko@ti.com>, <yoshihiro.shimoda.uh@renesas.com>,
	<robh@kernel.org>, <nsekhar@ti.com>, <b-liu@ti.com>,
	<joe@perches.com>, <linux-usb@vger.kernel.org>,
	<linux-omap@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<devicetree@vger.kernel.org>, <rogerq@ti.com>
Subject: [PATCH v11 13/14] usb: gadget: udc: adapt to OTG core
Date: Mon, 13 Jun 2016 10:55:12 +0300	[thread overview]
Message-ID: <575E66E0.1060503@ti.com> (raw)
In-Reply-To: <1465564043-27163-14-git-send-email-rogerq@ti.com>

The OTG state machine needs a mechanism to start and
stop the gadget controller as well as connect/disconnect
from the bus. Add usb_gadget_start(), usb_gadget_stop()
and usb_gadget_connect_control().

Introduce usb_otg_add_gadget_udc() to allow controller drivers
to register a gadget controller that is part of an OTG instance.

Register with OTG core when UDC is added in usb_add_gadget_udc_release()
and unregister on usb_del_gadget_udc().

Notify the OTG core when gadget function driver is available on
udc_bind_to_driver() and when it is removed in usb_gadget_remove_driver().

We need to unlock the usb_lock mutex before calling
usb_otg_register_gadget() else it will cause a circular
locking dependency.

Ignore softconnect sysfs control when we're in OTG
mode as OTG FSM should care of gadget softconnect using
the b_bus_req mechanism.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
v11:
- removed left over -EPROBE_DEFER in udc_bind_to_driver().

 drivers/usb/gadget/udc/core.c | 202 +++++++++++++++++++++++++++++++++++++++---
 include/linux/usb/gadget.h    |   4 +
 2 files changed, 196 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 42756d7..1290f03 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -28,6 +28,11 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/of.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
 #include "trace.h"
 
@@ -1060,6 +1065,113 @@ static inline void usb_gadget_udc_stop(struct usb_udc *udc)
 }
 
 /**
+ * usb_gadget_to_udc - get the UDC owning the gadget
+ *
+ * udc_lock must be held.
+ * Returs NULL if UDC is not found.
+ */
+static struct usb_udc *usb_gadget_to_udc(struct usb_gadget *gadget)
+{
+	struct usb_udc *udc;
+
+	list_for_each_entry(udc, &udc_list, list)
+		if (udc->gadget == gadget)
+			return udc;
+
+	return NULL;
+}
+
+/**
+ * usb_gadget_start - start the usb gadget controller
+ * @gadget: the gadget device to start
+ *
+ * This is external API for use by OTG core.
+ *
+ * Start the usb device controller. Does not connect to the bus.
+ */
+static int usb_gadget_start(struct usb_gadget *gadget)
+{
+	int ret;
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	ret = usb_gadget_udc_start(udc);
+	if (ret)
+		dev_err(&udc->dev, "USB Device Controller didn't start: %d\n",
+			ret);
+
+	mutex_unlock(&udc_lock);
+
+	return ret;
+}
+
+/**
+ * usb_gadget_stop - stop the usb gadget controller
+ * @gadget: the gadget device we want to stop
+ *
+ * This is external API for use by OTG core.
+ *
+ * Stop the gadget controller. Does not disconnect from the bus.
+ * Caller must ensure that gadget has disconnected from the bus
+ * before calling usb_gadget_stop().
+ */
+static int usb_gadget_stop(struct usb_gadget *gadget)
+{
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	if (gadget->connected)
+		dev_dbg(gadget->dev.parent,
+			"%s: called while still connected\n", __func__);
+
+	usb_gadget_udc_stop(udc);
+	mutex_unlock(&udc_lock);
+
+	return 0;
+}
+
+static int usb_gadget_connect_control(struct usb_gadget *gadget, bool connect)
+{
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	if (connect) {
+		usb_gadget_connect(udc->gadget);
+	} else {
+		usb_gadget_disconnect(udc->gadget);
+		udc->driver->disconnect(udc->gadget);
+	}
+
+	mutex_unlock(&udc_lock);
+
+	return 0;
+}
+
+/**
  * usb_udc_release - release the usb_udc struct
  * @dev: the dev member within usb_udc
  *
@@ -1082,6 +1194,12 @@ static void usb_udc_nop_release(struct device *dev)
 	dev_vdbg(dev, "%s\n", __func__);
 }
 
+struct otg_gadget_ops otg_gadget_intf = {
+	.start = usb_gadget_start,
+	.stop = usb_gadget_stop,
+	.connect_control = usb_gadget_connect_control,
+};
+
 /**
  * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
  * @parent: the parent device to this udc. Usually the controller driver's
@@ -1137,6 +1255,14 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
 	usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
 	udc->vbus = true;
 
+	if (gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		ret = usb_otg_register_gadget(gadget, &otg_gadget_intf);
+		mutex_lock(&udc_lock);
+		if (ret)
+			goto err5;
+	}
+
 	/* pick up one of pending gadget drivers */
 	list_for_each_entry(driver, &gadget_driver_pending_list, pending) {
 		if (!driver->udc_name || strcmp(driver->udc_name,
@@ -1145,7 +1271,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
 			if (ret != -EPROBE_DEFER)
 				list_del(&driver->pending);
 			if (ret)
-				goto err4;
+				goto err5;
 			break;
 		}
 	}
@@ -1154,6 +1280,8 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
 
 	return 0;
 
+err5:
+	device_del(&udc->dev);
 err4:
 	list_del(&udc->list);
 	mutex_unlock(&udc_lock);
@@ -1215,6 +1343,33 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
 }
 EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
 
+/**
+ * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
+ * @parent: the parent device to the UDC. Usually the Gadget controller
+ * driver's device.
+ * @gadget: the gadget to be added to the list
+ * @otg_dev: the OTG controller device
+ *
+ * If otg_dev is NULL then device tree node is checked
+ * for OTG controller via the otg-controller property.
+ * Returns zero on success, negative errno otherwise.
+ */
+int usb_otg_add_gadget_udc(struct device *parent, struct usb_gadget *gadget,
+			   struct device *otg_dev)
+{
+	if (!otg_dev) {
+		gadget->otg_dev = of_usb_get_otg(parent->of_node);
+		if (!gadget->otg_dev)
+			return -ENODEV;
+	} else {
+		gadget->otg_dev = otg_dev;
+	}
+
+	return usb_add_gadget_udc_release(parent, gadget, NULL);
+}
+EXPORT_SYMBOL_GPL(usb_otg_add_gadget_udc);
+
+/* udc_lock must be held */
 static void usb_gadget_remove_driver(struct usb_udc *udc)
 {
 	dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
@@ -1222,10 +1377,18 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
 
 	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
 
-	usb_gadget_disconnect(udc->gadget);
-	udc->driver->disconnect(udc->gadget);
+	/* If OTG/dual-role, the otg core manages UDC start/stop */
+	if (udc->gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		usb_otg_gadget_ready(udc->gadget, false);
+		mutex_lock(&udc_lock);
+	} else {
+		usb_gadget_disconnect(udc->gadget);
+		udc->driver->disconnect(udc->gadget);
+		usb_gadget_udc_stop(udc);
+	}
+
 	udc->driver->unbind(udc->gadget);
-	usb_gadget_udc_stop(udc);
 
 	udc->driver = NULL;
 	udc->dev.driver = NULL;
@@ -1259,6 +1422,9 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
 	}
 	mutex_unlock(&udc_lock);
 
+	if (gadget->otg_dev)
+		usb_otg_unregister_gadget(gadget);
+
 	kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
 	flush_work(&gadget->work);
 	device_unregister(&udc->dev);
@@ -1268,6 +1434,7 @@ EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
 
 /* ------------------------------------------------------------------------- */
 
+/* udc_lock must be held */
 static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
 {
 	int ret;
@@ -1282,17 +1449,26 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
 	ret = driver->bind(udc->gadget, driver);
 	if (ret)
 		goto err1;
-	ret = usb_gadget_udc_start(udc);
-	if (ret) {
-		driver->unbind(udc->gadget);
-		goto err1;
+
+	/* If OTG/dual-role, the otg core manages UDC start/stop */
+	if (udc->gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		usb_otg_gadget_ready(udc->gadget, true);
+		mutex_lock(&udc_lock);
+	} else {
+		ret = usb_gadget_udc_start(udc);
+		if (ret) {
+			mutex_unlock(&udc_lock);
+			driver->unbind(udc->gadget);
+			goto err1;
+		}
+		usb_udc_connect_control(udc);
 	}
-	usb_udc_connect_control(udc);
 
 	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
 	return 0;
 err1:
-	if (ret != -EISNAM)
+	if ((ret != -EISNAM))
 		dev_err(&udc->dev, "failed to start %s: %d\n",
 			udc->driver->function, ret);
 	udc->driver = NULL;
@@ -1389,6 +1565,12 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
 		return -EOPNOTSUPP;
 	}
 
+	/* In OTG/dual-role mode, soft-connect should be handled by OTG core */
+	if (udc->gadget->otg_dev) {
+		dev_err(dev, "soft-connect not supported in OTG mode\n");
+		return -EOPNOTSUPP;
+	}
+
 	if (sysfs_streq(buf, "connect")) {
 		usb_gadget_udc_start(udc);
 		usb_gadget_connect(udc->gadget);
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 1d74fb8..8c6880d 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -701,6 +701,10 @@ extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);
 extern void usb_del_gadget_udc(struct usb_gadget *gadget);
 extern char *usb_get_gadget_udc_name(void);
 
+extern int usb_otg_add_gadget_udc(struct device *parent,
+				  struct usb_gadget *gadget,
+				  struct device *otg_dev);
+
 /*-------------------------------------------------------------------------*/
 
 /* utility to simplify dealing with string descriptors */
-- 
2.7.4

WARNING: multiple messages have this Message-ID (diff)
From: Roger Quadros <rogerq@ti.com>
To: peter.chen@freescale.com
Cc: balbi@kernel.org, tony@atomide.com, gregkh@linuxfoundation.org,
	dan.j.williams@intel.com, mathias.nyman@linux.intel.com,
	Joao.Pinto@synopsys.com, sergei.shtylyov@cogentembedded.com,
	jun.li@freescale.com, grygorii.strashko@ti.com,
	yoshihiro.shimoda.uh@renesas.com, robh@kernel.org,
	nsekhar@ti.com, b-liu@ti.com, joe@perches.com,
	linux-usb@vger.kernel.org, linux-omap@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	rogerq@ti.com
Subject: [PATCH v11 13/14] usb: gadget: udc: adapt to OTG core
Date: Mon, 13 Jun 2016 10:55:12 +0300	[thread overview]
Message-ID: <575E66E0.1060503@ti.com> (raw)
In-Reply-To: <1465564043-27163-14-git-send-email-rogerq@ti.com>

The OTG state machine needs a mechanism to start and
stop the gadget controller as well as connect/disconnect
from the bus. Add usb_gadget_start(), usb_gadget_stop()
and usb_gadget_connect_control().

Introduce usb_otg_add_gadget_udc() to allow controller drivers
to register a gadget controller that is part of an OTG instance.

Register with OTG core when UDC is added in usb_add_gadget_udc_release()
and unregister on usb_del_gadget_udc().

Notify the OTG core when gadget function driver is available on
udc_bind_to_driver() and when it is removed in usb_gadget_remove_driver().

We need to unlock the usb_lock mutex before calling
usb_otg_register_gadget() else it will cause a circular
locking dependency.

Ignore softconnect sysfs control when we're in OTG
mode as OTG FSM should care of gadget softconnect using
the b_bus_req mechanism.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
v11:
- removed left over -EPROBE_DEFER in udc_bind_to_driver().

 drivers/usb/gadget/udc/core.c | 202 +++++++++++++++++++++++++++++++++++++++---
 include/linux/usb/gadget.h    |   4 +
 2 files changed, 196 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 42756d7..1290f03 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -28,6 +28,11 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/of.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
 #include "trace.h"
 
@@ -1060,6 +1065,113 @@ static inline void usb_gadget_udc_stop(struct usb_udc *udc)
 }
 
 /**
+ * usb_gadget_to_udc - get the UDC owning the gadget
+ *
+ * udc_lock must be held.
+ * Returs NULL if UDC is not found.
+ */
+static struct usb_udc *usb_gadget_to_udc(struct usb_gadget *gadget)
+{
+	struct usb_udc *udc;
+
+	list_for_each_entry(udc, &udc_list, list)
+		if (udc->gadget == gadget)
+			return udc;
+
+	return NULL;
+}
+
+/**
+ * usb_gadget_start - start the usb gadget controller
+ * @gadget: the gadget device to start
+ *
+ * This is external API for use by OTG core.
+ *
+ * Start the usb device controller. Does not connect to the bus.
+ */
+static int usb_gadget_start(struct usb_gadget *gadget)
+{
+	int ret;
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	ret = usb_gadget_udc_start(udc);
+	if (ret)
+		dev_err(&udc->dev, "USB Device Controller didn't start: %d\n",
+			ret);
+
+	mutex_unlock(&udc_lock);
+
+	return ret;
+}
+
+/**
+ * usb_gadget_stop - stop the usb gadget controller
+ * @gadget: the gadget device we want to stop
+ *
+ * This is external API for use by OTG core.
+ *
+ * Stop the gadget controller. Does not disconnect from the bus.
+ * Caller must ensure that gadget has disconnected from the bus
+ * before calling usb_gadget_stop().
+ */
+static int usb_gadget_stop(struct usb_gadget *gadget)
+{
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	if (gadget->connected)
+		dev_dbg(gadget->dev.parent,
+			"%s: called while still connected\n", __func__);
+
+	usb_gadget_udc_stop(udc);
+	mutex_unlock(&udc_lock);
+
+	return 0;
+}
+
+static int usb_gadget_connect_control(struct usb_gadget *gadget, bool connect)
+{
+	struct usb_udc *udc;
+
+	mutex_lock(&udc_lock);
+	udc = usb_gadget_to_udc(gadget);
+	if (!udc) {
+		dev_err(gadget->dev.parent, "%s: gadget not registered.\n",
+			__func__);
+		mutex_unlock(&udc_lock);
+		return -EINVAL;
+	}
+
+	if (connect) {
+		usb_gadget_connect(udc->gadget);
+	} else {
+		usb_gadget_disconnect(udc->gadget);
+		udc->driver->disconnect(udc->gadget);
+	}
+
+	mutex_unlock(&udc_lock);
+
+	return 0;
+}
+
+/**
  * usb_udc_release - release the usb_udc struct
  * @dev: the dev member within usb_udc
  *
@@ -1082,6 +1194,12 @@ static void usb_udc_nop_release(struct device *dev)
 	dev_vdbg(dev, "%s\n", __func__);
 }
 
+struct otg_gadget_ops otg_gadget_intf = {
+	.start = usb_gadget_start,
+	.stop = usb_gadget_stop,
+	.connect_control = usb_gadget_connect_control,
+};
+
 /**
  * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
  * @parent: the parent device to this udc. Usually the controller driver's
@@ -1137,6 +1255,14 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
 	usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
 	udc->vbus = true;
 
+	if (gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		ret = usb_otg_register_gadget(gadget, &otg_gadget_intf);
+		mutex_lock(&udc_lock);
+		if (ret)
+			goto err5;
+	}
+
 	/* pick up one of pending gadget drivers */
 	list_for_each_entry(driver, &gadget_driver_pending_list, pending) {
 		if (!driver->udc_name || strcmp(driver->udc_name,
@@ -1145,7 +1271,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
 			if (ret != -EPROBE_DEFER)
 				list_del(&driver->pending);
 			if (ret)
-				goto err4;
+				goto err5;
 			break;
 		}
 	}
@@ -1154,6 +1280,8 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
 
 	return 0;
 
+err5:
+	device_del(&udc->dev);
 err4:
 	list_del(&udc->list);
 	mutex_unlock(&udc_lock);
@@ -1215,6 +1343,33 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
 }
 EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
 
+/**
+ * usb_otg_add_gadget_udc - adds a new gadget to the udc class driver list
+ * @parent: the parent device to the UDC. Usually the Gadget controller
+ * driver's device.
+ * @gadget: the gadget to be added to the list
+ * @otg_dev: the OTG controller device
+ *
+ * If otg_dev is NULL then device tree node is checked
+ * for OTG controller via the otg-controller property.
+ * Returns zero on success, negative errno otherwise.
+ */
+int usb_otg_add_gadget_udc(struct device *parent, struct usb_gadget *gadget,
+			   struct device *otg_dev)
+{
+	if (!otg_dev) {
+		gadget->otg_dev = of_usb_get_otg(parent->of_node);
+		if (!gadget->otg_dev)
+			return -ENODEV;
+	} else {
+		gadget->otg_dev = otg_dev;
+	}
+
+	return usb_add_gadget_udc_release(parent, gadget, NULL);
+}
+EXPORT_SYMBOL_GPL(usb_otg_add_gadget_udc);
+
+/* udc_lock must be held */
 static void usb_gadget_remove_driver(struct usb_udc *udc)
 {
 	dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
@@ -1222,10 +1377,18 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
 
 	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
 
-	usb_gadget_disconnect(udc->gadget);
-	udc->driver->disconnect(udc->gadget);
+	/* If OTG/dual-role, the otg core manages UDC start/stop */
+	if (udc->gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		usb_otg_gadget_ready(udc->gadget, false);
+		mutex_lock(&udc_lock);
+	} else {
+		usb_gadget_disconnect(udc->gadget);
+		udc->driver->disconnect(udc->gadget);
+		usb_gadget_udc_stop(udc);
+	}
+
 	udc->driver->unbind(udc->gadget);
-	usb_gadget_udc_stop(udc);
 
 	udc->driver = NULL;
 	udc->dev.driver = NULL;
@@ -1259,6 +1422,9 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
 	}
 	mutex_unlock(&udc_lock);
 
+	if (gadget->otg_dev)
+		usb_otg_unregister_gadget(gadget);
+
 	kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
 	flush_work(&gadget->work);
 	device_unregister(&udc->dev);
@@ -1268,6 +1434,7 @@ EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
 
 /* ------------------------------------------------------------------------- */
 
+/* udc_lock must be held */
 static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
 {
 	int ret;
@@ -1282,17 +1449,26 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
 	ret = driver->bind(udc->gadget, driver);
 	if (ret)
 		goto err1;
-	ret = usb_gadget_udc_start(udc);
-	if (ret) {
-		driver->unbind(udc->gadget);
-		goto err1;
+
+	/* If OTG/dual-role, the otg core manages UDC start/stop */
+	if (udc->gadget->otg_dev) {
+		mutex_unlock(&udc_lock);
+		usb_otg_gadget_ready(udc->gadget, true);
+		mutex_lock(&udc_lock);
+	} else {
+		ret = usb_gadget_udc_start(udc);
+		if (ret) {
+			mutex_unlock(&udc_lock);
+			driver->unbind(udc->gadget);
+			goto err1;
+		}
+		usb_udc_connect_control(udc);
 	}
-	usb_udc_connect_control(udc);
 
 	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
 	return 0;
 err1:
-	if (ret != -EISNAM)
+	if ((ret != -EISNAM))
 		dev_err(&udc->dev, "failed to start %s: %d\n",
 			udc->driver->function, ret);
 	udc->driver = NULL;
@@ -1389,6 +1565,12 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
 		return -EOPNOTSUPP;
 	}
 
+	/* In OTG/dual-role mode, soft-connect should be handled by OTG core */
+	if (udc->gadget->otg_dev) {
+		dev_err(dev, "soft-connect not supported in OTG mode\n");
+		return -EOPNOTSUPP;
+	}
+
 	if (sysfs_streq(buf, "connect")) {
 		usb_gadget_udc_start(udc);
 		usb_gadget_connect(udc->gadget);
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 1d74fb8..8c6880d 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -701,6 +701,10 @@ extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);
 extern void usb_del_gadget_udc(struct usb_gadget *gadget);
 extern char *usb_get_gadget_udc_name(void);
 
+extern int usb_otg_add_gadget_udc(struct device *parent,
+				  struct usb_gadget *gadget,
+				  struct device *otg_dev);
+
 /*-------------------------------------------------------------------------*/
 
 /* utility to simplify dealing with string descriptors */
-- 
2.7.4

  parent reply	other threads:[~2016-06-13  7:55 UTC|newest]

Thread overview: 159+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-06-10 13:07 [PATCH v10 00/14] USB OTG/dual-role framework Roger Quadros
2016-06-10 13:07 ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 01/14] usb: hcd: Initialize hcd->flags to 0 Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-14  8:16   ` Roger Quadros
2016-06-14  8:16     ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 02/14] usb: otg-fsm: Prevent build warning "VDBG" redefined Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 03/14] usb: hcd.h: Add OTG to HCD interface Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-14  8:17   ` Roger Quadros
2016-06-14  8:17     ` Roger Quadros
2016-06-14 14:21     ` Alan Stern
2016-06-14 14:21       ` Alan Stern
2016-06-15  7:14       ` Roger Quadros
2016-06-15  7:14         ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 04/14] usb: otg-fsm: use usb_otg wherever possible Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 05/14] usb: otg-fsm: move host controller operations into usb_otg->hcd_ops Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 06/14] usb: gadget.h: Add OTG to gadget interface Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-12  9:13   ` Peter Chen
2016-06-20  7:21   ` Felipe Balbi
2016-06-20  7:21     ` Felipe Balbi
2016-06-20  7:28     ` Roger Quadros
2016-06-20  7:28       ` Roger Quadros
2016-06-20  8:13       ` Felipe Balbi
2016-06-20  8:13         ` Felipe Balbi
2016-06-20  8:25         ` Roger Quadros
2016-06-20  8:25           ` Roger Quadros
2016-06-20  9:24           ` Felipe Balbi
2016-06-20  9:24             ` Felipe Balbi
2016-06-20  9:43             ` Roger Quadros
2016-06-20  9:43               ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 07/14] usb: otg: get rid of CONFIG_USB_OTG_FSM in favour of CONFIG_USB_OTG Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 08/14] usb: otg: add OTG/dual-role core Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-12 11:21   ` Peter Chen
2016-06-12 11:21     ` Peter Chen
2016-06-13  7:42     ` Roger Quadros
2016-06-13  7:42       ` Roger Quadros
2016-06-13  7:56   ` [PATCH v11 " Roger Quadros
2016-06-13  7:56     ` Roger Quadros
2016-06-13  7:58     ` Peter Chen
2016-06-20  7:45     ` Felipe Balbi
2016-06-20  7:45       ` Felipe Balbi
2016-06-20 10:13       ` Roger Quadros
2016-06-20 10:13         ` Roger Quadros
2016-06-20 12:03         ` Felipe Balbi
2016-06-20 12:26           ` Roger Quadros
2016-06-20 12:26             ` Roger Quadros
2016-06-20 12:46             ` Felipe Balbi
2016-06-21  6:39           ` Peter Chen
2016-06-21  7:19             ` Felipe Balbi
2016-06-21  7:19               ` Felipe Balbi
2016-06-21  8:02               ` Peter Chen
2016-06-21  8:18                 ` Felipe Balbi
2016-06-21  8:18                   ` Felipe Balbi
2016-06-21  9:14                   ` Peter Chen
2016-06-21  9:14                     ` Peter Chen
2016-06-21 12:35                     ` Felipe Balbi
2016-06-21 12:35                       ` Felipe Balbi
2016-06-21 13:12                       ` Peter Chen
2016-06-21 14:47                         ` Felipe Balbi
2016-06-22  3:33                           ` Peter Chen
2016-06-22  3:33                             ` Peter Chen
2016-06-22  6:51                             ` Felipe Balbi
2016-06-22  6:51                               ` Felipe Balbi
2016-06-22  7:30                               ` Peter Chen
2016-06-22  7:30                                 ` Peter Chen
2016-06-22  8:00                                 ` Felipe Balbi
2016-06-22  8:00                                   ` Felipe Balbi
2016-06-23  7:41                             ` Yoshihiro Shimoda
2016-06-23  7:41                               ` Yoshihiro Shimoda
2016-06-21  2:30         ` Yoshihiro Shimoda
2016-06-21  2:30           ` Yoshihiro Shimoda
2016-06-21  7:21           ` Felipe Balbi
2016-06-21  7:21             ` Felipe Balbi
2016-06-20 11:49       ` Peter Chen
2016-06-20 11:49         ` Peter Chen
2016-06-20 12:08         ` Felipe Balbi
2016-06-20 12:08           ` Felipe Balbi
2016-06-21  6:05           ` Peter Chen
2016-06-21  7:26             ` Felipe Balbi
2016-06-21  7:26               ` Felipe Balbi
2016-06-21  9:07               ` Peter Chen
2016-06-21  9:07                 ` Peter Chen
2016-06-21 10:02                 ` Felipe Balbi
2016-06-21 10:43                   ` Tony Lindgren
2016-06-21 10:43                     ` Tony Lindgren
2016-06-21 10:56                     ` Felipe Balbi
2016-06-21 13:05                   ` Peter Chen
2016-06-21 13:05                     ` Peter Chen
2016-06-22  6:56                     ` Felipe Balbi
2016-06-22  6:56                       ` Felipe Balbi
2016-06-22  7:33                       ` Peter Chen
2016-06-22  8:03                         ` Felipe Balbi
2016-06-22  7:49                       ` Roger Quadros
2016-06-22  7:49                         ` Roger Quadros
2016-06-22  8:14                         ` Felipe Balbi
2016-06-22  8:30                           ` Roger Quadros
2016-06-22  8:30                             ` Roger Quadros
2017-01-19 11:56                             ` Vivek Gautam
2017-01-19 12:15                               ` Roger Quadros
2017-01-19 12:15                                 ` Roger Quadros
2017-01-19 15:15                                 ` vivek.gautam
2017-01-20  8:30                                   ` Roger Quadros
2017-01-20  8:30                                     ` Roger Quadros
2017-01-20 11:39                                     ` Vivek Gautam
2016-06-23  7:42                         ` Yoshihiro Shimoda
2016-06-23  7:42                           ` Yoshihiro Shimoda
2016-06-10 13:07 ` [PATCH v10 09/14] usb: of: add an API to get OTG device from USB controller node Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-13  8:13   ` Jun Li
2016-06-13  8:13     ` Jun Li
2016-06-13  8:16     ` Roger Quadros
2016-06-13  8:16       ` Roger Quadros
2016-06-13  8:23   ` [PATCH v11 " Roger Quadros
2016-06-13  8:23     ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 10/14] usb: otg: add hcd companion support Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 11/14] usb: otg: use dev_vdbg() instead of VDBG() Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 12/14] usb: hcd: Adapt to OTG core Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-14  8:17   ` Roger Quadros
2016-06-14  8:17     ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 13/14] usb: gadget: udc: adapt " Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-12 11:36   ` Peter Chen
2016-06-12 11:36     ` Peter Chen
2016-06-13  7:14     ` Roger Quadros
2016-06-13  7:14       ` Roger Quadros
2016-06-13  7:20       ` Peter Chen
2016-06-13  7:20         ` Peter Chen
2016-06-13  7:37         ` Roger Quadros
2016-06-13  7:37           ` Roger Quadros
2016-06-13  7:40           ` Peter Chen
2016-06-13  7:40             ` Peter Chen
2016-06-13  7:55   ` Roger Quadros [this message]
2016-06-13  7:55     ` [PATCH v11 " Roger Quadros
2016-06-13  7:56     ` Peter Chen
2016-06-13  8:06       ` Roger Quadros
2016-06-13  8:06         ` Roger Quadros
2016-06-10 13:07 ` [PATCH v10 14/14] usb: host: xhci-plat: Add otg device to platform data Roger Quadros
2016-06-10 13:07   ` Roger Quadros
2016-06-14  8:18   ` Roger Quadros
2016-06-14  8:18     ` Roger Quadros
2016-06-14  2:17 ` [PATCH v10 00/14] USB OTG/dual-role framework Peter Chen
2016-06-14  8:12   ` Roger Quadros
2016-06-14  8:12     ` Roger Quadros
2016-06-16 11:07 ` Roger Quadros
2016-06-16 11:07   ` Roger Quadros
2016-06-17  7:17   ` Felipe Balbi
2016-06-17  7:17     ` Felipe Balbi
2016-06-17  7:31     ` Roger Quadros
2016-06-17  7:31       ` Roger Quadros

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=575E66E0.1060503@ti.com \
    --to=rogerq@ti.com \
    --cc=Joao.Pinto@synopsys.com \
    --cc=b-liu@ti.com \
    --cc=balbi@kernel.org \
    --cc=dan.j.williams@intel.com \
    --cc=devicetree@vger.kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=grygorii.strashko@ti.com \
    --cc=joe@perches.com \
    --cc=jun.li@freescale.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-omap@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=mathias.nyman@linux.intel.com \
    --cc=nsekhar@ti.com \
    --cc=peter.chen@freescale.com \
    --cc=robh@kernel.org \
    --cc=sergei.shtylyov@cogentembedded.com \
    --cc=tony@atomide.com \
    --cc=yoshihiro.shimoda.uh@renesas.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.