linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/19] Add Support for USB DRD in AM437x
@ 2014-11-25 13:11 George Cherian
  2014-11-25 13:11 ` [PATCH 01/19] usb: common: drd-lib: Add DRD lib for USB George Cherian
                   ` (18 more replies)
  0 siblings, 19 replies; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

The series add DRD suport for AM437x.

The serires adds 
	- USB DRD Library
		This Library facilitates in switching roles between HOST 	
		and Device. 
	- DWC3 OTG driver.
		This driver currently suports only the ID based switching


Felipe Balbi (2):
  usb: dwc3: core: Adapt to named interrupts
  arm: dts: am4372: Add named interrupt property for dwc3

George Cherian (17):
  usb: common: drd-lib: Add DRD lib for USB.
  usb: host xhci: fix up deallocation code
  usb: host: xhci-plat: Add support to pass XHCI_DRD_SUPPORT quirk
  usb: host xhci: Add XHCI_NEEDS_LHC_RESET quirk
  usb: host: xhci-plat: Add support to pass XHCI_NEEDS_LHC_RESET quirk
  usb: dwc3: host: Pass the XHCI_DRD_SUPPORT and XHCI_NEEDS_LHC_RESET
    quirk
  usb: host: xhci: Adapt xhci to use usb drd library
  usb: dwc3: core: Add dwc3_drd_helper function
  usb: dwc3: dwc3-omap: Make the wrapper interrupt shared
  usb: dwc3: Add seperate dwc3_gadget object to support gadget release
  usb: dwc3: gadget: Adapt gadget to drd library
  usb: dwc3: core: Add DWC3 OTG specific register defines
  usb: dwc3: otg: Add the initial otg driver for dwc3.
  arm: dts: omap5: Add named interrupt property for dwc3
  arm: dts: dra7: Add named interrupt property for dwc3
  arm: dts: exynos5250: Add named interrupt property for dwc3
  arm: dts: am43x evms: Make usb1 as OTG

 arch/arm/boot/dts/am4372.dtsi        |  18 +-
 arch/arm/boot/dts/am437x-gp-evm.dts  |   2 +-
 arch/arm/boot/dts/am437x-sk-evm.dts  |   2 +-
 arch/arm/boot/dts/am43x-epos-evm.dts |   2 +-
 arch/arm/boot/dts/dra7.dtsi          |  28 ++-
 arch/arm/boot/dts/exynos5250.dtsi    |   7 +-
 arch/arm/boot/dts/omap5.dtsi         |   7 +-
 drivers/usb/Kconfig                  |  15 ++
 drivers/usb/common/Makefile          |   1 +
 drivers/usb/common/drd-lib.c         | 346 +++++++++++++++++++++++++++++++++++
 drivers/usb/dwc3/Makefile            |   4 +
 drivers/usb/dwc3/core.c              |  27 ++-
 drivers/usb/dwc3/core.h              |  93 +++++++++-
 drivers/usb/dwc3/dwc3-omap.c         |   4 +-
 drivers/usb/dwc3/ep0.c               |  35 ++--
 drivers/usb/dwc3/gadget.c            | 211 +++++++++++++++------
 drivers/usb/dwc3/gadget.h            |   1 +
 drivers/usb/dwc3/host.c              |   2 +
 drivers/usb/dwc3/otg.c               | 126 +++++++++++++
 drivers/usb/host/xhci-plat.c         |  22 +++
 drivers/usb/host/xhci.c              |  27 ++-
 drivers/usb/host/xhci.h              |   2 +
 include/linux/usb/drd.h              |  77 ++++++++
 include/linux/usb/xhci_pdriver.h     |   2 +
 24 files changed, 962 insertions(+), 99 deletions(-)
 create mode 100644 drivers/usb/common/drd-lib.c
 create mode 100644 drivers/usb/dwc3/otg.c
 create mode 100644 include/linux/usb/drd.h

-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH 01/19] usb: common: drd-lib: Add DRD lib for USB.
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
@ 2014-11-25 13:11 ` George Cherian
  2014-11-26  5:14   ` Peter Chen
  2014-11-25 13:11 ` [PATCH 02/19] usb: host xhci: fix up deallocation code George Cherian
                   ` (17 subsequent siblings)
  18 siblings, 1 reply; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

Add USB DRD library. This Library facilitates to
switch roles between HOST and Device modes.

A DRD should be added to the library using usb_drd_add().
Register the HOST and UDC using usb_drd_register_hcd/udc().
Un-Register the HOST and UDC using usb_drd_unregister_hcd/udc().

Depending on the state of IP -
Call the following to start/stop HOST controller
usb_drd_start/stop_hcd().
This internally calls usb_add/remove_hcd() or IP specific low level start/stop
defined in ll_start/stop

Call the following to start/stop UDC
usb_drd_start/stop_udc().
This internally calls udc_start/udc_stop() or IP specific low level start/stop
defined in ll_start/stop

Signed-off-by: George Cherian <george.cherian@ti.com>
---
 drivers/usb/Kconfig          |  15 ++
 drivers/usb/common/Makefile  |   1 +
 drivers/usb/common/drd-lib.c | 346 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/usb/drd.h      |  77 ++++++++++
 4 files changed, 439 insertions(+)
 create mode 100644 drivers/usb/common/drd-lib.c
 create mode 100644 include/linux/usb/drd.h

diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index ae481c3..ea0d944 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -34,6 +34,21 @@ config USB_COMMON
 	default y
 	depends on USB || USB_GADGET
 
+config DRD_LIB
+	tristate  "DRD Library support"
+	default y
+	depends on USB && USB_GADGET
+	---help---
+	  This option adds DRD Library support for Universal Serial Bus (USB).
+	  DRD Library faciliatets the Role switching by HOST and DEVICE roles,
+	  If your hardware has a Dual Role Device.
+
+	  The DRD Library uses USB core API's to start/stop HOST controllers,
+	  UDC API's to start/stop DEVICE controllers, ther by enabling to
+	  switch roles between HOST and Device modes.
+
+	  Say N if unsure.
+
 config USB_ARCH_HAS_HCD
 	def_bool y
 
diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile
index ca2f8bd..e2c1593 100644
--- a/drivers/usb/common/Makefile
+++ b/drivers/usb/common/Makefile
@@ -7,3 +7,4 @@ usb-common-y			  += common.o
 usb-common-$(CONFIG_USB_LED_TRIG) += led.o
 
 obj-$(CONFIG_USB_OTG_FSM) += usb-otg-fsm.o
+obj-$(CONFIG_DRD_LIB)       += drd-lib.o
diff --git a/drivers/usb/common/drd-lib.c b/drivers/usb/common/drd-lib.c
new file mode 100644
index 0000000..6159436
--- /dev/null
+++ b/drivers/usb/common/drd-lib.c
@@ -0,0 +1,346 @@
+/**
+ * drd-lib.c - USB DRD library functions
+ *
+ * Copyright (C) 2014 Texas Instruments
+ * Author: George Cherian <george.cherian@ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include <linux/usb/hcd.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/drd.h>
+
+/**
+ * struct usb_drd - describes one dual role device
+ * @host - the HOST controller device of this drd
+ * @gadget - the gadget of drd
+ * @parent - the device to the actual controller
+ * @list - for use by the drd lib
+ * @state - specifies the current state
+ *
+ * This represents the internal data structure which is used by the UDC-class
+ * to hold information about udc driver and gadget together.
+ */
+struct usb_drd {
+	struct usb_drd_host	*host;
+	struct usb_drd_gadget	*gadget;
+	struct device		*parent;
+	struct list_head	list;
+	unsigned int		state;
+};
+
+static LIST_HEAD(drd_list);
+static DEFINE_SPINLOCK(drd_lock);
+
+static struct usb_drd *usb_drd_get_dev(struct device *parent)
+{
+	struct usb_drd *drd;
+
+	spin_lock(&drd_lock);
+	list_for_each_entry(drd, &drd_list, list)
+		if (drd->parent == parent)
+			goto out;
+	drd = NULL;
+out:
+	spin_unlock(&drd_lock);
+
+	return drd;
+}
+
+int usb_drd_get_state(struct device *parent)
+{
+	struct usb_drd	*drd;
+
+	drd = usb_drd_get_dev(parent);
+	if (!drd)
+		return -ENODEV;
+
+	return drd->state;
+}
+EXPORT_SYMBOL_GPL(usb_drd_get_state);
+
+int usb_drd_release(struct device *parent)
+{
+	struct usb_drd	*drd;
+	int ret;
+
+	spin_lock(&drd_lock);
+	list_for_each_entry(drd, &drd_list, list) {
+		if (drd->parent == parent) {
+			kfree(drd);
+			ret = 0;
+			goto out;
+		}
+	}
+	ret = -ENODEV;
+out:
+	spin_unlock(&drd_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(usb_drd_release);
+
+int usb_drd_add(struct device *parent)
+{
+	struct usb_drd	*drd;
+
+	drd = kzalloc(sizeof(*drd), GFP_KERNEL);
+	if (!drd)
+		return -ENOMEM;
+
+	spin_lock(&drd_lock);
+	drd->parent = parent;
+	list_add_tail(&drd->list, &drd_list);
+	drd->state = DRD_UNREGISTERED;
+
+	spin_unlock(&drd_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_drd_add);
+
+int usb_drd_register_hcd(struct device *parent, struct usb_drd_host *host)
+{
+	struct usb_drd	*drd;
+
+	drd = usb_drd_get_dev(parent);
+	if (!drd)
+		return -ENODEV;
+
+	spin_lock(&drd_lock);
+	drd->host = host;
+	drd->state |= DRD_HOST_REGISTERED | DRD_HOST_ACTIVE;
+	spin_unlock(&drd_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_drd_register_hcd);
+
+int usb_drd_unregister_hcd(struct device *parent)
+{
+	struct usb_drd	*drd;
+
+	drd = usb_drd_get_dev(parent);
+	if (!drd)
+		return -ENODEV;
+
+	spin_lock(&drd_lock);
+	drd->state &= ~(DRD_HOST_REGISTERED | DRD_HOST_ACTIVE);
+	spin_unlock(&drd_lock);
+	kfree(drd->host);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_drd_unregister_hcd);
+
+int usb_drd_start_hcd(struct device *parent)
+{
+	struct usb_drd	*drd;
+	struct usb_drd_setup *setup;
+
+	drd = usb_drd_get_dev(parent);
+	if (!drd)
+		return -ENODEV;
+
+	if (WARN_ON(!(drd->state & DRD_HOST_REGISTERED)))
+		return -EINVAL;
+
+	setup = drd->host->host_setup;
+	if (setup && setup->ll_start)
+		setup->ll_start(setup->data);
+
+	usb_add_hcd(drd->host->main_hcd,
+		    drd->host->hcd_irq, IRQF_SHARED);
+	if (drd->host->shared_hcd)
+		usb_add_hcd(drd->host->shared_hcd,
+			    drd->host->hcd_irq, IRQF_SHARED);
+
+	spin_lock(&drd_lock);
+	drd->state |= DRD_HOST_ACTIVE;
+	spin_unlock(&drd_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_drd_start_hcd);
+
+int usb_drd_stop_hcd(struct device *parent)
+{
+	struct usb_drd	*drd;
+	struct usb_drd_setup *setup;
+
+	drd = usb_drd_get_dev(parent);
+	if (!drd)
+		return -ENODEV;
+
+	if (WARN_ON(!(drd->state & DRD_HOST_ACTIVE)))
+		return -EINVAL;
+
+	setup = drd->host->host_setup;
+	if (setup && setup->ll_stop)
+		setup->ll_stop(setup->data);
+	if (drd->host->shared_hcd)
+		usb_remove_hcd(drd->host->shared_hcd);
+
+	usb_remove_hcd(drd->host->main_hcd);
+
+	spin_lock(&drd_lock);
+	drd->state = drd->state & ~DRD_HOST_ACTIVE;
+	spin_unlock(&drd_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_drd_stop_hcd);
+
+int usb_drd_register_udc(struct device *parent, struct usb_drd_gadget *gadget)
+{
+	struct usb_drd	*drd;
+
+	drd = usb_drd_get_dev(parent);
+	if (!drd)
+		return -ENODEV;
+
+	spin_lock(&drd_lock);
+	drd->gadget = gadget;
+	drd->state |= DRD_DEVICE_REGISTERED;
+	if (drd->gadget->g_driver)
+		drd->state |= DRD_DEVICE_ACTIVE;
+
+	spin_unlock(&drd_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_drd_register_udc);
+
+int usb_drd_register_udc_driver(struct device *parent,
+				struct usb_gadget_driver *driver)
+{
+	struct usb_drd	*drd;
+
+	drd = usb_drd_get_dev(parent);
+	if (!drd)
+		return -ENODEV;
+
+	spin_lock(&drd_lock);
+	drd->gadget->g_driver = driver;
+	drd->state |= DRD_DEVICE_ACTIVE;
+	spin_unlock(&drd_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_drd_register_udc_driver);
+
+int usb_drd_unregister_udc(struct device *parent)
+{
+	struct usb_drd	*drd;
+
+	drd = usb_drd_get_dev(parent);
+	if (!drd)
+		return -ENODEV;
+
+	spin_lock(&drd_lock);
+	drd->state &= ~(DRD_DEVICE_REGISTERED | DRD_DEVICE_ACTIVE);
+	spin_unlock(&drd_lock);
+	kfree(drd->gadget->gadget_setup);
+	kfree(drd->gadget);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_drd_unregister_udc);
+
+int usb_drd_unregister_udc_driver(struct device *parent)
+{
+	struct usb_drd	*drd;
+	struct usb_drd_gadget *drd_gadget;
+
+	drd = usb_drd_get_dev(parent);
+	if (!drd)
+		return -ENODEV;
+	drd_gadget = drd->gadget;
+
+	spin_lock(&drd_lock);
+	drd->state &= ~DRD_DEVICE_ACTIVE;
+	drd_gadget->g_driver = NULL;
+	spin_unlock(&drd_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_drd_unregister_udc_driver);
+
+int usb_drd_start_udc(struct device *parent)
+{
+	struct usb_drd	*drd;
+	struct usb_drd_gadget *drd_gadget;
+	struct usb_drd_setup *setup;
+
+	drd = usb_drd_get_dev(parent);
+	if (!drd)
+		return -ENODEV;
+
+	if (WARN_ON(!(drd->state & DRD_DEVICE_REGISTERED)))
+		return -EINVAL;
+
+	drd_gadget = drd->gadget;
+	setup = drd_gadget->gadget_setup;
+
+	if (setup && setup->ll_start)
+		setup->ll_start(setup->data);
+
+	usb_add_gadget_udc_release(parent, drd_gadget->gadget,
+				   setup->ll_release);
+	spin_lock(&drd_lock);
+	drd->state |= DRD_DEVICE_ACTIVE;
+	spin_unlock(&drd_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_drd_start_udc);
+
+int usb_drd_stop_udc(struct device *parent)
+{
+	struct usb_drd	*drd;
+	struct usb_drd_gadget *drd_gadget;
+	struct usb_drd_setup *setup;
+
+	drd = usb_drd_get_dev(parent);
+	if (!drd)
+		return -ENODEV;
+
+	if (WARN_ON(!(drd->state & DRD_DEVICE_REGISTERED)))
+		return -EINVAL;
+
+	drd_gadget = drd->gadget;
+	setup = drd_gadget->gadget_setup;
+	if (setup && setup->ll_stop)
+		setup->ll_stop(setup->data);
+
+	usb_del_gadget_udc(drd_gadget->gadget);
+
+	spin_lock(&drd_lock);
+	drd->state = drd->state & ~DRD_DEVICE_ACTIVE;
+	spin_unlock(&drd_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_drd_stop_udc);
+
+MODULE_DESCRIPTION("USB-DRD Library");
+MODULE_AUTHOR("George Cherian <george.cherian@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/usb/drd.h b/include/linux/usb/drd.h
new file mode 100644
index 0000000..71c64dc
--- /dev/null
+++ b/include/linux/usb/drd.h
@@ -0,0 +1,77 @@
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/hcd.h>
+
+struct usb_drd_setup {
+	int	(*ll_start)(void *);
+	int	(*ll_stop)(void *);
+	void	(*ll_release)(struct device *);
+	void	*data;
+};
+
+struct usb_drd_host {
+	struct usb_hcd		*main_hcd;
+	struct usb_hcd		*shared_hcd;
+	int			hcd_irq;
+	struct usb_drd_setup *host_setup;
+};
+
+struct usb_drd_gadget {
+	struct usb_gadget_driver *g_driver;
+	struct usb_gadget *gadget;
+	struct usb_drd_setup *gadget_setup;
+};
+
+#define DRD_UNREGISTERED	0x0
+#define DRD_DEVICE_REGISTERED	0x1
+#define DRD_HOST_REGISTERED	0x2
+#define DRD_HOST_ACTIVE		0x4
+#define DRD_DEVICE_ACTIVE	0x8
+
+#if IS_ENABLED(CONFIG_DRD_LIB)
+int usb_drd_release(struct device *parent);
+int usb_drd_add(struct device *parent);
+int usb_drd_register_udc(struct device *parent,
+			 struct usb_drd_gadget *gadget);
+int usb_drd_register_udc_driver(struct device *parent,
+				struct usb_gadget_driver *driver);
+int usb_drd_unregister_udc(struct device *parent);
+int usb_drd_unregister_udc_driver(struct device *parent);
+int usb_drd_register_hcd(struct device *parent,
+			 struct usb_drd_host *host);
+int usb_drd_unregister_hcd(struct device *parent);
+int usb_drd_start_hcd(struct device *parent);
+int usb_drd_stop_hcd(struct device *parent);
+int usb_drd_start_udc(struct device *parent);
+int usb_drd_stop_udc(struct device *parent);
+int usb_drd_get_state(struct device *parent);
+#else
+static inline int usb_drd_release(struct device *parent)
+{ return 0; }
+static inline int usb_drd_add(struct device *parent)
+{ return 0; }
+static inline int usb_drd_register_udc(struct device *parent,
+				       struct usb_drd_gadget *gadget)
+{ return 0; }
+static inline int usb_drd_register_udc_driver(struct device *parent,
+					      struct usb_gadget_driver *driver)
+{ return 0; }
+static inline int usb_drd_unregister_udc(struct device *parent,
+					 struct usb_drd_gadget *gadget)
+{ return 0; }
+static inline int usb_drd_unregister_udc_driver(struct device *parent)
+{ return 0; }
+static inline int usb_drd_register_hcd(struct device *parent,
+				       struct usb_drd_host *host)
+{ return 0; }
+static inline int usb_drd_unregister_hcd(struct device *parent)
+{ return 0; }
+static inline int usb_drd_stop_hcd(struct device *parent)
+{ return 0; }
+static inline int usb_drd_start_udc(struct device *parent)
+{ return 0; }
+static inline int usb_drd_stop_udc(struct device *parent)
+{ return 0; }
+static inline int usb_drd_get_state(struct device *parent)
+{ return 0; }
+#endif
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 02/19] usb: host xhci: fix up deallocation code
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
  2014-11-25 13:11 ` [PATCH 01/19] usb: common: drd-lib: Add DRD lib for USB George Cherian
@ 2014-11-25 13:11 ` George Cherian
  2014-11-25 13:11 ` [PATCH 03/19] usb: host: xhci-plat: Add support to pass XHCI_DRD_SUPPORT quirk George Cherian
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

This fixes up the deallocation code in the xhci driver, so that
usb_add_hcd()/usb_remove_hcd() can be called repeatedly without
crashing.

In case of DRD mode, the DRD library calls /usb_remove_hcd() while
switching from HOST mode to Device mode, but it doesnot call usb_put_hcd().
We need to preserve the already allocated xhci struct for the subsequent
call of usb_add_hcd() from the DRD library.

A new quirk flag XHCI_DRD_SUPPORT is added to differentiate between
normal usb_remove_hcd and drd specific call.

Signed-off-by: George Cherian <george.cherian@ti.com>
---
 drivers/usb/host/xhci.c | 22 ++++++++++++++++------
 drivers/usb/host/xhci.h |  1 +
 2 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 2a5d45b..d4196f8 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -666,7 +666,8 @@ static void xhci_only_stop_hcd(struct usb_hcd *hcd)
 	 * calls this function when allocation fails in usb_add_hcd(), or
 	 * usb_remove_hcd() is called).  So we need to unset xHCI's pointer.
 	 */
-	xhci->shared_hcd = NULL;
+	if (!(xhci->quirks & XHCI_DRD_SUPPORT))
+		xhci->shared_hcd = NULL;
 	spin_unlock_irq(&xhci->lock);
 }
 
@@ -4815,6 +4816,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 	struct xhci_hcd		*xhci;
 	struct device		*dev = hcd->self.controller;
 	int			retval;
+	bool			allocated = false;
 
 	/* Accept arbitrarily long scatter-gather lists */
 	hcd->self.sg_tablesize = ~0;
@@ -4826,10 +4828,15 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 	hcd->self.no_stop_on_short = 1;
 
 	if (usb_hcd_is_primary_hcd(hcd)) {
-		xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL);
-		if (!xhci)
-			return -ENOMEM;
-		*((struct xhci_hcd **) hcd->hcd_priv) = xhci;
+		if (*((struct xhci_hcd **)hcd->hcd_priv) == NULL) {
+			xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL);
+			if (!xhci)
+				return -ENOMEM;
+			*((struct xhci_hcd **)hcd->hcd_priv) = xhci;
+			allocated = true;
+		} else {
+			xhci = *((struct xhci_hcd **)hcd->hcd_priv);
+		}
 		xhci->main_hcd = hcd;
 		/* Mark the first roothub as being USB 2.0.
 		 * The xHCI driver will register the USB 3.0 roothub.
@@ -4902,7 +4909,10 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 	xhci_dbg(xhci, "Called HCD init\n");
 	return 0;
 error:
-	kfree(xhci);
+	if (allocated) {
+		*((struct xhci_hcd **)hcd->hcd_priv) = NULL;
+		kfree(xhci);
+	}
 	return retval;
 }
 EXPORT_SYMBOL_GPL(xhci_gen_setup);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index df76d64..2248058 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1560,6 +1560,7 @@ struct xhci_hcd {
 #define XHCI_SPURIOUS_WAKEUP	(1 << 18)
 /* For controllers with a broken beyond repair streams implementation */
 #define XHCI_BROKEN_STREAMS	(1 << 19)
+#define XHCI_DRD_SUPPORT	(1 << 20)
 	unsigned int		num_active_eps;
 	unsigned int		limit_active_eps;
 	/* There are two roothubs to keep track of bus suspend info for */
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 03/19] usb: host: xhci-plat: Add support to pass XHCI_DRD_SUPPORT quirk
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
  2014-11-25 13:11 ` [PATCH 01/19] usb: common: drd-lib: Add DRD lib for USB George Cherian
  2014-11-25 13:11 ` [PATCH 02/19] usb: host xhci: fix up deallocation code George Cherian
@ 2014-11-25 13:11 ` George Cherian
  2014-11-25 13:11 ` [PATCH 04/19] usb: host xhci: Add XHCI_NEEDS_LHC_RESET quirk George Cherian
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

Extend the platform data to pass XHCI_DRD_SUPPORT quirk to the xhci driver.

Signed-off-by: George Cherian <george.cherian@ti.com>
---
 drivers/usb/host/xhci-plat.c     | 4 ++++
 include/linux/usb/xhci_pdriver.h | 1 +
 2 files changed, 5 insertions(+)

diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 3d78b0c..2c42273 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -27,6 +27,10 @@ static struct hc_driver __read_mostly xhci_plat_hc_driver;
 
 static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
 {
+	struct usb_xhci_pdata   *pdata = dev_get_platdata(dev);
+
+	if (pdata->usb_drd_support)
+		xhci->quirks |= XHCI_DRD_SUPPORT;
 	/*
 	 * As of now platform drivers don't provide MSI support so we ensure
 	 * here that the generic code does not try to make a pci_dev from our
diff --git a/include/linux/usb/xhci_pdriver.h b/include/linux/usb/xhci_pdriver.h
index 376654b..539c2d8 100644
--- a/include/linux/usb/xhci_pdriver.h
+++ b/include/linux/usb/xhci_pdriver.h
@@ -22,6 +22,7 @@
  */
 struct usb_xhci_pdata {
 	unsigned	usb3_lpm_capable:1;
+	unsigned	usb_drd_support:1;
 };
 
 #endif /* __USB_CORE_XHCI_PDRIVER_H */
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 04/19] usb: host xhci: Add XHCI_NEEDS_LHC_RESET quirk
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
                   ` (2 preceding siblings ...)
  2014-11-25 13:11 ` [PATCH 03/19] usb: host: xhci-plat: Add support to pass XHCI_DRD_SUPPORT quirk George Cherian
@ 2014-11-25 13:11 ` George Cherian
  2014-11-25 13:11 ` [PATCH 05/19] usb: host: xhci-plat: Add support to pass " George Cherian
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

This adds XHCI_NEEDS_LHC_RESET quirk, to make sure only Light Host Reset
is done during xhci_reset(). This is mainly useful when we switch roles
HOST to Device mode and viceversa.

The DWC3 IP shares internal RAM for both HOST and Device specific registers.
So while switching roles between HOST and Device modes, it's advbised to do
a LIGHT HC reset else the already configured global registers of the DWC3 IP
gets re-initialized.

Signed-off-by: George Cherian <george.cherian@ti.com>
---
 drivers/usb/host/xhci.c | 5 +++--
 drivers/usb/host/xhci.h | 1 +
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index d4196f8..5dabf9a 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -170,11 +170,12 @@ int xhci_reset(struct xhci_hcd *xhci)
 
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Reset the HC");
 	command = readl(&xhci->op_regs->command);
-	command |= CMD_RESET;
+	command |= (xhci->quirks & XHCI_NEEDS_LHC_RESET) ? CMD_LRESET : CMD_RESET;
 	writel(command, &xhci->op_regs->command);
 
 	ret = xhci_handshake(xhci, &xhci->op_regs->command,
-			CMD_RESET, 0, 10 * 1000 * 1000);
+			(xhci->quirks & XHCI_NEEDS_LHC_RESET) ? CMD_LRESET : CMD_RESET,
+			0, 10 * 1000 * 1000);
 	if (ret)
 		return ret;
 
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 2248058..1b14b09 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1561,6 +1561,7 @@ struct xhci_hcd {
 /* For controllers with a broken beyond repair streams implementation */
 #define XHCI_BROKEN_STREAMS	(1 << 19)
 #define XHCI_DRD_SUPPORT	(1 << 20)
+#define XHCI_NEEDS_LHC_RESET	(1 << 21)
 	unsigned int		num_active_eps;
 	unsigned int		limit_active_eps;
 	/* There are two roothubs to keep track of bus suspend info for */
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 05/19] usb: host: xhci-plat: Add support to pass XHCI_NEEDS_LHC_RESET quirk
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
                   ` (3 preceding siblings ...)
  2014-11-25 13:11 ` [PATCH 04/19] usb: host xhci: Add XHCI_NEEDS_LHC_RESET quirk George Cherian
@ 2014-11-25 13:11 ` George Cherian
  2014-11-25 13:11 ` [PATCH 06/19] usb: dwc3: host: Pass the XHCI_DRD_SUPPORT and " George Cherian
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

Extend the platform data to pass XHCI_NEEDS_LHC_RESET quirk to
the xhci driver.

Signed-off-by: George Cherian <george.cherian@ti.com>
---
 drivers/usb/host/xhci-plat.c     | 3 +++
 include/linux/usb/xhci_pdriver.h | 1 +
 2 files changed, 4 insertions(+)

diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 2c42273..d8d024d 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -31,6 +31,9 @@ static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
 
 	if (pdata->usb_drd_support)
 		xhci->quirks |= XHCI_DRD_SUPPORT;
+
+	if (pdata->usb_needs_lhc_reset)
+		xhci->quirks |= XHCI_NEEDS_LHC_RESET;
 	/*
 	 * As of now platform drivers don't provide MSI support so we ensure
 	 * here that the generic code does not try to make a pci_dev from our
diff --git a/include/linux/usb/xhci_pdriver.h b/include/linux/usb/xhci_pdriver.h
index 539c2d8..8ef7321 100644
--- a/include/linux/usb/xhci_pdriver.h
+++ b/include/linux/usb/xhci_pdriver.h
@@ -23,6 +23,7 @@
 struct usb_xhci_pdata {
 	unsigned	usb3_lpm_capable:1;
 	unsigned	usb_drd_support:1;
+	unsigned	usb_needs_lhc_reset:1;
 };
 
 #endif /* __USB_CORE_XHCI_PDRIVER_H */
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 06/19] usb: dwc3: host: Pass the XHCI_DRD_SUPPORT and XHCI_NEEDS_LHC_RESET quirk
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
                   ` (4 preceding siblings ...)
  2014-11-25 13:11 ` [PATCH 05/19] usb: host: xhci-plat: Add support to pass " George Cherian
@ 2014-11-25 13:11 ` George Cherian
  2014-11-27  2:00   ` Lu, Baolu
  2014-11-25 13:11 ` [PATCH 07/19] usb: host: xhci: Adapt xhci to use usb drd library George Cherian
                   ` (12 subsequent siblings)
  18 siblings, 1 reply; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

Pass the quir flag XHCI_DRD_SUPPORT from DWC3 host to xhci platform driver.
This enables xhci driver to handle deallocation's differently while in DRD mode.
Pass the quirk flag XHCI_NEEDS_LHC_RESET from DWC3 host to xhci platform
driver. This enables to do LHRESET during xhci_reset().

Signed-off-by: George Cherian <george.cherian@ti.com>
---
 drivers/usb/dwc3/host.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index dcb8ca0..257b5b5 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -53,6 +53,8 @@ int dwc3_host_init(struct dwc3 *dwc)
 #ifdef CONFIG_DWC3_HOST_USB3_LPM_ENABLE
 	pdata.usb3_lpm_capable = 1;
 #endif
+	pdata.usb_drd_support = 1;
+	pdata.usb_needs_lhc_reset = 1;
 
 	ret = platform_device_add_data(xhci, &pdata, sizeof(pdata));
 	if (ret) {
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 07/19] usb: host: xhci: Adapt xhci to use usb drd library
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
                   ` (5 preceding siblings ...)
  2014-11-25 13:11 ` [PATCH 06/19] usb: dwc3: host: Pass the XHCI_DRD_SUPPORT and " George Cherian
@ 2014-11-25 13:11 ` George Cherian
  2014-11-25 13:11 ` [PATCH 08/19] usb: dwc3: core: Add dwc3_drd_helper function George Cherian
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

Adapt the xhci-plat driver  to use drd library functions.
In prepration to support DRD on dwc3.

Signed-off-by: George Cherian <george.cherian@ti.com>
---
 drivers/usb/host/xhci-plat.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index d8d024d..fbbbd59 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -17,6 +17,8 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/drd.h>
 #include <linux/usb/xhci_pdriver.h>
 
 #include "xhci.h"
@@ -78,6 +80,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
 	struct resource         *res;
 	struct usb_hcd		*hcd;
 	struct clk              *clk;
+	struct usb_drd_host	*drd_host;
 	int			ret;
 	int			irq;
 
@@ -169,6 +172,17 @@ static int xhci_plat_probe(struct platform_device *pdev)
 	if (ret)
 		goto put_usb3_hcd;
 
+	drd_host = kzalloc(sizeof(*drd_host), GFP_KERNEL);
+	if (!drd_host)
+		return -ENOMEM;
+
+	drd_host->main_hcd = xhci->main_hcd;
+	drd_host->shared_hcd = xhci->shared_hcd;
+	drd_host->hcd_irq = irq;
+	drd_host->host_setup = NULL;
+
+	usb_drd_register_hcd(pdev->dev.parent, drd_host);
+
 	return 0;
 
 put_usb3_hcd:
@@ -200,6 +214,7 @@ static int xhci_plat_remove(struct platform_device *dev)
 	if (!IS_ERR(clk))
 		clk_disable_unprepare(clk);
 	usb_put_hcd(hcd);
+	usb_drd_unregister_hcd(dev->dev.parent);
 	kfree(xhci);
 
 	return 0;
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 08/19] usb: dwc3: core: Add dwc3_drd_helper function
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
                   ` (6 preceding siblings ...)
  2014-11-25 13:11 ` [PATCH 07/19] usb: host: xhci: Adapt xhci to use usb drd library George Cherian
@ 2014-11-25 13:11 ` George Cherian
  2014-11-25 13:11 ` [PATCH 09/19] usb: dwc3: dwc3-omap: Make the wrapper interrupt shared George Cherian
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

This helper function, facilitates to re-initialize the event buffers.
It re-initilizes the event buffers while switching role from
HOST to DEVICE mode.

The DWC3 IP shares internal RAM for both HOST and Device specific registers.
So while switching roles from HOST to Device modes, it's required to
re-initialize the EVENT buffer registers for the Device mode to continue
work properly. dwc3_event_buffers_setup() is exported out from core.c via
wrapper dwc3_core_gadget_helper() which will be invoked from dwc3 otg driver.

Signed-off-by: George Cherian <george.cherian@ti.com>
---
 drivers/usb/dwc3/core.c | 5 +++++
 drivers/usb/dwc3/core.h | 1 +
 2 files changed, 6 insertions(+)

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 25ddc39..fadd767 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -254,6 +254,11 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
 	}
 }
 
+int dwc3_core_gadget_helper(struct dwc3 *dwc)
+{
+	return dwc3_event_buffers_setup(dwc);
+}
+
 static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
 {
 	if (!dwc->has_hibernation)
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 4bb9aa6..6b38223 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -981,6 +981,7 @@ struct dwc3_gadget_ep_cmd_params {
 /* prototypes */
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
 int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
+int dwc3_core_gadget_helper(struct dwc3 *dwc);
 
 #if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
 int dwc3_host_init(struct dwc3 *dwc);
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 09/19] usb: dwc3: dwc3-omap: Make the wrapper interrupt shared
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
                   ` (7 preceding siblings ...)
  2014-11-25 13:11 ` [PATCH 08/19] usb: dwc3: core: Add dwc3_drd_helper function George Cherian
@ 2014-11-25 13:11 ` George Cherian
  2014-11-25 13:11 ` [PATCH 10/19] usb: dwc3: core: Adapt to named interrupts George Cherian
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

OTG interrupt and wrapper is shared

Signed-off-by: George Cherian <george.cherian@ti.com>
---
 drivers/usb/dwc3/dwc3-omap.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index 172d64e..f99e2ca 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -525,8 +525,8 @@ static int dwc3_omap_probe(struct platform_device *pdev)
 	reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
 	omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
 
-	ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
-			"dwc3-omap", omap);
+	ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, IRQF_SHARED,
+			       "dwc3-omap", omap);
 	if (ret) {
 		dev_err(dev, "failed to request IRQ #%d --> %d\n",
 				omap->irq, ret);
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 10/19] usb: dwc3: core: Adapt to named interrupts
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
                   ` (8 preceding siblings ...)
  2014-11-25 13:11 ` [PATCH 09/19] usb: dwc3: dwc3-omap: Make the wrapper interrupt shared George Cherian
@ 2014-11-25 13:11 ` George Cherian
  2014-11-25 13:11 ` [PATCH 11/19] usb: dwc3: Add seperate dwc3_gadget object to support gadget release George Cherian
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

From: Felipe Balbi <balbi@ti.com>

Add support to use interrupt names,

Following are the interrupt names

Peripheral Interrupt - peripheral
HOST Interrupt - host
OTG Interrupt - otg

Signed-off-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: George Cherian <george.cherian@ti.com>
---
 drivers/usb/dwc3/core.c | 12 ++++++++++++
 drivers/usb/dwc3/core.h |  7 +++++++
 2 files changed, 19 insertions(+)

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index fadd767..dbd5589 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -760,6 +760,18 @@ static int dwc3_probe(struct platform_device *pdev)
 	dwc->xhci_resources[1].flags = res->flags;
 	dwc->xhci_resources[1].name = res->name;
 
+	dwc->otg_irq = platform_get_irq_byname(pdev, "otg");
+	if (!dwc->otg_irq)
+		dev_err(dev, "missing OTG IRQ\n");
+
+	dwc->gadget_irq = platform_get_irq_byname(pdev, "peripheral");
+	if (!dwc->gadget_irq)
+		dev_err(dev, "missing peripheral IRQ\n");
+
+	dwc->xhci_irq = platform_get_irq_byname(pdev, "host");
+	if (!dwc->xhci_irq)
+		dev_err(dev, "missing HOST IRQ\n");
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		dev_err(dev, "missing memory resource\n");
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 6b38223..7c5ae37 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -651,6 +651,9 @@ struct dwc3_scratchpad_array {
  * @maximum_speed: maximum speed requested (mainly for testing purposes)
  * @revision: revision register contents
  * @dr_mode: requested mode of operation
+ * @xhci_irq: IRQ number for XHCI IRQs
+ * @gadget_irq: IRQ number for Peripheral IRQs
+ * @otg_irq: IRQ number for OTG IRQs
  * @usb2_phy: pointer to USB2 PHY
  * @usb3_phy: pointer to USB3 PHY
  * @usb2_generic_phy: pointer to USB2 PHY
@@ -747,6 +750,10 @@ struct dwc3 {
 
 	enum usb_dr_mode	dr_mode;
 
+	int			gadget_irq;
+	int			xhci_irq;
+	int			otg_irq;
+
 	/* used for suspend/resume */
 	u32			dcfg;
 	u32			gctl;
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 11/19] usb: dwc3: Add seperate dwc3_gadget object to support gadget release
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
                   ` (9 preceding siblings ...)
  2014-11-25 13:11 ` [PATCH 10/19] usb: dwc3: core: Adapt to named interrupts George Cherian
@ 2014-11-25 13:11 ` George Cherian
  2014-11-25 13:11 ` [PATCH 12/19] usb: dwc3: gadget: Adapt gadget to drd library George Cherian
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

With the current implementation it's impossible to release the gadget.
Add a separate dwc3_gadget object to dwc3 structure so that the same
can be freed during the gadget release.
This is in prepration to adapt dwc3 gadget driver to  drd library.
DRD library uses usb_del/add_gadget_udc while switching roles between
HOST and DEVICE modes. If the usb_gadget is not released during usb_del_gadget_udc,
the subsequent usb_add_gadget_udc would try to initialize an already initialized
kobject. To avoid this make sure we have an easily freeable object.

Signed-off-by: George Cherian <george.cherian@ti.com>
---
 drivers/usb/dwc3/core.h   |   7 ++-
 drivers/usb/dwc3/ep0.c    |  35 ++++++++------
 drivers/usb/dwc3/gadget.c | 113 ++++++++++++++++++++++++++++++----------------
 drivers/usb/dwc3/gadget.h |   1 +
 4 files changed, 101 insertions(+), 55 deletions(-)

diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 7c5ae37..7fbe736 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -626,6 +626,11 @@ struct dwc3_scratchpad_array {
 	__le64	dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS];
 };
 
+struct dwc3_gadget {
+	struct usb_gadget gadget;
+	struct dwc3 *dwc;
+};
+
 /**
  * struct dwc3 - representation of our controller
  * @ctrl_req: usb control request which is used for ep0
@@ -736,7 +741,7 @@ struct dwc3 {
 	struct dwc3_event_buffer **ev_buffs;
 	struct dwc3_ep		*eps[DWC3_ENDPOINTS_NUM];
 
-	struct usb_gadget	gadget;
+	struct dwc3_gadget	*dwc_gadget;
 	struct usb_gadget_driver *gadget_driver;
 
 	struct usb_phy		*usb2_phy;
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index baeedbd..e7409f1 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -109,6 +109,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
 		struct dwc3_request *req)
 {
 	struct dwc3		*dwc = dep->dwc;
+	struct dwc3_gadget	*dwc_gadget = dwc->dwc_gadget;
 
 	req->request.actual	= 0;
 	req->request.status	= -EINPROGRESS;
@@ -152,7 +153,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
 
 		direction = !dwc->ep0_expect_in;
 		dwc->delayed_status = false;
-		usb_gadget_set_state(&dwc->gadget, USB_STATE_CONFIGURED);
+		usb_gadget_set_state(&dwc_gadget->gadget, USB_STATE_CONFIGURED);
 
 		if (dwc->ep0state == EP0_STATUS_PHASE)
 			__dwc3_ep0_do_control_status(dwc, dwc->eps[direction]);
@@ -391,6 +392,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
 		struct usb_ctrlrequest *ctrl, int set)
 {
 	struct dwc3_ep		*dep;
+	struct dwc3_gadget	*dwc_gadget = dwc->dwc_gadget;
 	u32			recip;
 	u32			wValue;
 	u32			wIndex;
@@ -401,7 +403,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
 	wValue = le16_to_cpu(ctrl->wValue);
 	wIndex = le16_to_cpu(ctrl->wIndex);
 	recip = ctrl->bRequestType & USB_RECIP_MASK;
-	state = dwc->gadget.state;
+	state = dwc_gadget->gadget.state;
 
 	switch (recip) {
 	case USB_RECIP_DEVICE:
@@ -499,7 +501,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
 
 static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 {
-	enum usb_device_state state = dwc->gadget.state;
+	struct dwc3_gadget *dwc_gadget = dwc->dwc_gadget;
+	enum usb_device_state state = dwc_gadget->gadget.state;
 	u32 addr;
 	u32 reg;
 
@@ -521,26 +524,28 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
 
 	if (addr)
-		usb_gadget_set_state(&dwc->gadget, USB_STATE_ADDRESS);
+		usb_gadget_set_state(&dwc_gadget->gadget, USB_STATE_ADDRESS);
 	else
-		usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
+		usb_gadget_set_state(&dwc_gadget->gadget, USB_STATE_DEFAULT);
 
 	return 0;
 }
 
 static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 {
+	struct dwc3_gadget *dwc_gadget = dwc->dwc_gadget;
 	int ret;
 
 	spin_unlock(&dwc->lock);
-	ret = dwc->gadget_driver->setup(&dwc->gadget, ctrl);
+	ret = dwc->gadget_driver->setup(&dwc_gadget->gadget, ctrl);
 	spin_lock(&dwc->lock);
 	return ret;
 }
 
 static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 {
-	enum usb_device_state state = dwc->gadget.state;
+	struct dwc3_gadget *dwc_gadget = dwc->dwc_gadget;
+	enum usb_device_state state = dwc_gadget->gadget.state;
 	u32 cfg;
 	int ret;
 	u32 reg;
@@ -564,8 +569,8 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 			 * to change the state on the next usb_ep_queue()
 			 */
 			if (ret == 0)
-				usb_gadget_set_state(&dwc->gadget,
-						USB_STATE_CONFIGURED);
+				usb_gadget_set_state(&dwc_gadget->gadget,
+						     USB_STATE_CONFIGURED);
 
 			/*
 			 * Enable transition to U1/U2 state when
@@ -583,8 +588,8 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 	case USB_STATE_CONFIGURED:
 		ret = dwc3_ep0_delegate_req(dwc, ctrl);
 		if (!cfg && !ret)
-			usb_gadget_set_state(&dwc->gadget,
-					USB_STATE_ADDRESS);
+			usb_gadget_set_state(&dwc_gadget->gadget,
+					     USB_STATE_ADDRESS);
 		break;
 	default:
 		ret = -EINVAL;
@@ -639,7 +644,8 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
 static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 {
 	struct dwc3_ep	*dep;
-	enum usb_device_state state = dwc->gadget.state;
+	struct dwc3_gadget *dwc_gadget = dwc->dwc_gadget;
+	enum usb_device_state state = dwc_gadget->gadget.state;
 	u16		wLength;
 	u16		wValue;
 
@@ -918,6 +924,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
 		struct dwc3_ep *dep, struct dwc3_request *req)
 {
 	int			ret;
+	struct dwc3_gadget	*dwc_gadget = dwc->dwc_gadget;
 
 	req->direction = !!dep->number;
 
@@ -930,7 +937,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
 		u32	transfer_size;
 		u32	maxpacket;
 
-		ret = usb_gadget_map_request(&dwc->gadget, &req->request,
+		ret = usb_gadget_map_request(&dwc_gadget->gadget, &req->request,
 				dep->number);
 		if (ret) {
 			dev_dbg(dwc->dev, "failed to map request\n");
@@ -953,7 +960,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
 				dwc->ep0_bounce_addr, transfer_size,
 				DWC3_TRBCTL_CONTROL_DATA);
 	} else {
-		ret = usb_gadget_map_request(&dwc->gadget, &req->request,
+		ret = usb_gadget_map_request(&dwc_gadget->gadget, &req->request,
 				dep->number);
 		if (ret) {
 			dev_dbg(dwc->dev, "failed to map request\n");
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index f03b136..2c54d45 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -234,6 +234,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
 		int status)
 {
 	struct dwc3			*dwc = dep->dwc;
+	struct dwc3_gadget		*dwc_gadget = dwc->dwc_gadget;
 	int				i;
 
 	if (req->queued) {
@@ -261,8 +262,8 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
 	if (dwc->ep0_bounced && dep->number == 0)
 		dwc->ep0_bounced = false;
 	else
-		usb_gadget_unmap_request(&dwc->gadget, &req->request,
-				req->direction);
+		usb_gadget_unmap_request(&dwc_gadget->gadget, &req->request,
+					 req->direction);
 
 	dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
 			req, dep->name, req->request.actual,
@@ -407,6 +408,7 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
 		bool ignore, bool restore)
 {
 	struct dwc3_gadget_ep_cmd_params params;
+	struct dwc3_gadget *dwc_gadget = dwc->dwc_gadget;
 
 	memset(&params, 0x00, sizeof(params));
 
@@ -414,7 +416,7 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
 		| DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc));
 
 	/* Burst size is only needed in SuperSpeed mode */
-	if (dwc->gadget.speed == USB_SPEED_SUPER) {
+	if (dwc_gadget->gadget.speed == USB_SPEED_SUPER) {
 		u32 burst = dep->endpoint.maxburst - 1;
 
 		params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst);
@@ -928,6 +930,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
 	struct dwc3_gadget_ep_cmd_params params;
 	struct dwc3_request		*req;
 	struct dwc3			*dwc = dep->dwc;
+	struct dwc3_gadget		*dwc_gadget = dwc->dwc_gadget;
 	int				ret;
 	u32				cmd;
 
@@ -980,8 +983,8 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
 		 * here and stop, unmap, free and del each of the linked
 		 * requests instead of what we do now.
 		 */
-		usb_gadget_unmap_request(&dwc->gadget, &req->request,
-				req->direction);
+		usb_gadget_unmap_request(&dwc_gadget->gadget, &req->request,
+					 req->direction);
 		list_del(&req->list);
 		return ret;
 	}
@@ -1029,6 +1032,7 @@ static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
 static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 {
 	struct dwc3		*dwc = dep->dwc;
+	struct dwc3_gadget	*dwc_gadget = dwc->dwc_gadget;
 	int			ret;
 
 	req->request.actual	= 0;
@@ -1048,7 +1052,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 	 * This will also avoid Host cancelling URBs due to too
 	 * many NAKs.
 	 */
-	ret = usb_gadget_map_request(&dwc->gadget, &req->request,
+	ret = usb_gadget_map_request(&dwc_gadget->gadget, &req->request,
 			dep->direction);
 	if (ret)
 		return ret;
@@ -1320,7 +1324,8 @@ static const struct usb_ep_ops dwc3_gadget_ep_ops = {
 
 static int dwc3_gadget_get_frame(struct usb_gadget *g)
 {
-	struct dwc3		*dwc = gadget_to_dwc(g);
+	struct dwc3_gadget *dwc_gadget = gadget_to_dwc_gadget(g);
+	struct dwc3 *dwc = dwc_gadget->dwc;
 	u32			reg;
 
 	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
@@ -1329,7 +1334,8 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g)
 
 static int dwc3_gadget_wakeup(struct usb_gadget *g)
 {
-	struct dwc3		*dwc = gadget_to_dwc(g);
+	struct dwc3_gadget *dwc_gadget = gadget_to_dwc_gadget(g);
+	struct dwc3 *dwc = dwc_gadget->dwc;
 
 	unsigned long		timeout;
 	unsigned long		flags;
@@ -1410,7 +1416,8 @@ out:
 static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
 		int is_selfpowered)
 {
-	struct dwc3		*dwc = gadget_to_dwc(g);
+	struct dwc3_gadget *dwc_gadget = gadget_to_dwc_gadget(g);
+	struct dwc3 *dwc = dwc_gadget->dwc;
 	unsigned long		flags;
 
 	spin_lock_irqsave(&dwc->lock, flags);
@@ -1476,7 +1483,8 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
 
 static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 {
-	struct dwc3		*dwc = gadget_to_dwc(g);
+	struct dwc3_gadget *dwc_gadget = gadget_to_dwc_gadget(g);
+	struct dwc3 *dwc = dwc_gadget->dwc;
 	unsigned long		flags;
 	int			ret;
 
@@ -1519,7 +1527,8 @@ static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc);
 static int dwc3_gadget_start(struct usb_gadget *g,
 		struct usb_gadget_driver *driver)
 {
-	struct dwc3		*dwc = gadget_to_dwc(g);
+	struct dwc3_gadget *dwc_gadget = gadget_to_dwc_gadget(g);
+	struct dwc3 *dwc = dwc_gadget->dwc;
 	struct dwc3_ep		*dep;
 	unsigned long		flags;
 	int			ret = 0;
@@ -1539,7 +1548,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
 
 	if (dwc->gadget_driver) {
 		dev_err(dwc->dev, "%s is already bound to %s\n",
-				dwc->gadget.name,
+				dwc_gadget->gadget.name,
 				dwc->gadget_driver->driver.name);
 		ret = -EBUSY;
 		goto err1;
@@ -1632,7 +1641,8 @@ err0:
 
 static int dwc3_gadget_stop(struct usb_gadget *g)
 {
-	struct dwc3		*dwc = gadget_to_dwc(g);
+	struct dwc3_gadget *dwc_gadget = gadget_to_dwc_gadget(g);
+	struct dwc3 *dwc = dwc_gadget->dwc;
 	unsigned long		flags;
 	int			irq;
 
@@ -1667,6 +1677,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
 		u8 num, u32 direction)
 {
 	struct dwc3_ep			*dep;
+	struct dwc3_gadget		*dwc_gadget = dwc->dwc_gadget;
 	u8				i;
 
 	for (i = 0; i < num; i++) {
@@ -1693,7 +1704,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
 			dep->endpoint.maxburst = 1;
 			dep->endpoint.ops = &dwc3_gadget_ep0_ops;
 			if (!epnum)
-				dwc->gadget.ep0 = &dep->endpoint;
+				dwc_gadget->gadget.ep0 = &dep->endpoint;
 		} else {
 			int		ret;
 
@@ -1701,7 +1712,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
 			dep->endpoint.max_streams = 15;
 			dep->endpoint.ops = &dwc3_gadget_ep_ops;
 			list_add_tail(&dep->endpoint.ep_list,
-					&dwc->gadget.ep_list);
+					&dwc_gadget->gadget.ep_list);
 
 			ret = dwc3_alloc_trb_pool(dep);
 			if (ret)
@@ -1718,8 +1729,9 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
 static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
 {
 	int				ret;
+	struct dwc3_gadget		*dwc_gadget = dwc->dwc_gadget;
 
-	INIT_LIST_HEAD(&dwc->gadget.ep_list);
+	INIT_LIST_HEAD(&dwc_gadget->gadget.ep_list);
 
 	ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0);
 	if (ret < 0) {
@@ -2020,38 +2032,46 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
 
 static void dwc3_disconnect_gadget(struct dwc3 *dwc)
 {
+	struct dwc3_gadget *dwc_gadget = dwc->dwc_gadget;
+
 	if (dwc->gadget_driver && dwc->gadget_driver->disconnect) {
 		spin_unlock(&dwc->lock);
-		dwc->gadget_driver->disconnect(&dwc->gadget);
+		dwc->gadget_driver->disconnect(&dwc_gadget->gadget);
 		spin_lock(&dwc->lock);
 	}
 }
 
 static void dwc3_suspend_gadget(struct dwc3 *dwc)
 {
+	struct dwc3_gadget *dwc_gadget = dwc->dwc_gadget;
+
 	if (dwc->gadget_driver && dwc->gadget_driver->suspend) {
 		spin_unlock(&dwc->lock);
-		dwc->gadget_driver->suspend(&dwc->gadget);
+		dwc->gadget_driver->suspend(&dwc_gadget->gadget);
 		spin_lock(&dwc->lock);
 	}
 }
 
 static void dwc3_resume_gadget(struct dwc3 *dwc)
 {
+	struct dwc3_gadget *dwc_gadget = dwc->dwc_gadget;
+
 	if (dwc->gadget_driver && dwc->gadget_driver->resume) {
 		spin_unlock(&dwc->lock);
-		dwc->gadget_driver->resume(&dwc->gadget);
+		dwc->gadget_driver->resume(&dwc_gadget->gadget);
 	}
 }
 
 static void dwc3_reset_gadget(struct dwc3 *dwc)
 {
+	struct dwc3_gadget *dwc_gadget = dwc->dwc_gadget;
+
 	if (!dwc->gadget_driver)
 		return;
 
-	if (dwc->gadget.speed != USB_SPEED_UNKNOWN) {
+	if (dwc_gadget->gadget.speed != USB_SPEED_UNKNOWN) {
 		spin_unlock(&dwc->lock);
-		usb_gadget_udc_reset(&dwc->gadget, dwc->gadget_driver);
+		usb_gadget_udc_reset(&dwc_gadget->gadget, dwc->gadget_driver);
 		spin_lock(&dwc->lock);
 	}
 }
@@ -2145,6 +2165,7 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
 static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
 {
 	int			reg;
+	struct dwc3_gadget	*dwc_gadget = dwc->dwc_gadget;
 
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 	reg &= ~DWC3_DCTL_INITU1ENA;
@@ -2156,9 +2177,9 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
 	dwc3_disconnect_gadget(dwc);
 	dwc->start_config_issued = false;
 
-	dwc->gadget.speed = USB_SPEED_UNKNOWN;
+	dwc_gadget->gadget.speed = USB_SPEED_UNKNOWN;
 	dwc->setup_packet_pending = false;
-	usb_gadget_set_state(&dwc->gadget, USB_STATE_NOTATTACHED);
+	usb_gadget_set_state(&dwc_gadget->gadget, USB_STATE_NOTATTACHED);
 }
 
 static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
@@ -2241,6 +2262,7 @@ static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed)
 static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
 {
 	struct dwc3_ep		*dep;
+	struct dwc3_gadget	*dwc_gadget = dwc->dwc_gadget;
 	int			ret;
 	u32			reg;
 	u8			speed;
@@ -2270,24 +2292,24 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
 			dwc3_gadget_reset_interrupt(dwc);
 
 		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
-		dwc->gadget.ep0->maxpacket = 512;
-		dwc->gadget.speed = USB_SPEED_SUPER;
+		dwc_gadget->gadget.ep0->maxpacket = 512;
+		dwc_gadget->gadget.speed = USB_SPEED_SUPER;
 		break;
 	case DWC3_DCFG_HIGHSPEED:
 		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
-		dwc->gadget.ep0->maxpacket = 64;
-		dwc->gadget.speed = USB_SPEED_HIGH;
+		dwc_gadget->gadget.ep0->maxpacket = 64;
+		dwc_gadget->gadget.speed = USB_SPEED_HIGH;
 		break;
 	case DWC3_DCFG_FULLSPEED2:
 	case DWC3_DCFG_FULLSPEED1:
 		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
-		dwc->gadget.ep0->maxpacket = 64;
-		dwc->gadget.speed = USB_SPEED_FULL;
+		dwc_gadget->gadget.ep0->maxpacket = 64;
+		dwc_gadget->gadget.speed = USB_SPEED_FULL;
 		break;
 	case DWC3_DCFG_LOWSPEED:
 		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8);
-		dwc->gadget.ep0->maxpacket = 8;
-		dwc->gadget.speed = USB_SPEED_LOW;
+		dwc_gadget->gadget.ep0->maxpacket = 8;
+		dwc_gadget->gadget.speed = USB_SPEED_LOW;
 		break;
 	}
 
@@ -2351,12 +2373,13 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
 
 static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
 {
+	struct dwc3_gadget		*dwc_gadget = dwc->dwc_gadget;
 	/*
 	 * TODO take core out of low power mode when that's
 	 * implemented.
 	 */
 
-	dwc->gadget_driver->resume(&dwc->gadget);
+	dwc->gadget_driver->resume(&dwc_gadget->gadget);
 }
 
 static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
@@ -2667,6 +2690,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
 int dwc3_gadget_init(struct dwc3 *dwc)
 {
 	int					ret;
+	struct dwc3_gadget			*dwc_gadget;
 
 	dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
 			&dwc->ctrl_req_addr, GFP_KERNEL);
@@ -2699,17 +2723,24 @@ int dwc3_gadget_init(struct dwc3 *dwc)
 		goto err3;
 	}
 
-	dwc->gadget.ops			= &dwc3_gadget_ops;
-	dwc->gadget.max_speed		= USB_SPEED_SUPER;
-	dwc->gadget.speed		= USB_SPEED_UNKNOWN;
-	dwc->gadget.sg_supported	= true;
-	dwc->gadget.name		= "dwc3-gadget";
+	dwc_gadget = kzalloc(sizeof(*dwc_gadget), GFP_KERNEL);
+	if (!dwc_gadget) {
+		ret = -ENOMEM;
+		goto err3;
+	}
+
+	dwc_gadget->gadget.ops			= &dwc3_gadget_ops;
+	dwc_gadget->gadget.max_speed		= USB_SPEED_SUPER;
+	dwc_gadget->gadget.speed		= USB_SPEED_UNKNOWN;
+	dwc_gadget->gadget.sg_supported	= true;
+	dwc_gadget->gadget.name		= "dwc3-gadget";
+	dwc_gadget->dwc = dwc;
 
 	/*
 	 * Per databook, DWC3 needs buffer size to be aligned to MaxPacketSize
 	 * on ep out.
 	 */
-	dwc->gadget.quirk_ep_out_aligned_size = true;
+	dwc_gadget->gadget.quirk_ep_out_aligned_size = true;
 
 	/*
 	 * REVISIT: Here we should clear all pending IRQs to be
@@ -2720,7 +2751,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
 	if (ret)
 		goto err4;
 
-	ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
+	ret = usb_add_gadget_udc(dwc->dev, &dwc_gadget->gadget);
 	if (ret) {
 		dev_err(dwc->dev, "failed to register udc\n");
 		goto err4;
@@ -2752,7 +2783,9 @@ err0:
 
 void dwc3_gadget_exit(struct dwc3 *dwc)
 {
-	usb_del_gadget_udc(&dwc->gadget);
+	struct dwc3_gadget *dwc_gadget = dwc->dwc_gadget;
+
+	usb_del_gadget_udc(&dwc_gadget->gadget);
 
 	dwc3_gadget_free_endpoints(dwc);
 
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index 18ae3ea..b6c3e40 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -26,6 +26,7 @@
 struct dwc3;
 #define to_dwc3_ep(ep)		(container_of(ep, struct dwc3_ep, endpoint))
 #define gadget_to_dwc(g)	(container_of(g, struct dwc3, gadget))
+#define gadget_to_dwc_gadget(g)	(container_of(g, struct dwc3_gadget, gadget))
 
 /* DEPCFG parameter 1 */
 #define DWC3_DEPCFG_INT_NUM(n)		((n) << 0)
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 12/19] usb: dwc3: gadget: Adapt gadget to drd library
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
                   ` (10 preceding siblings ...)
  2014-11-25 13:11 ` [PATCH 11/19] usb: dwc3: Add seperate dwc3_gadget object to support gadget release George Cherian
@ 2014-11-25 13:11 ` George Cherian
  2014-11-25 13:11 ` [PATCH 13/19] usb: dwc3: core: Add DWC3 OTG specific register defines George Cherian
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

Adapt the dwc3 gadget to use drd library functions.
In prepration to support DRD on dwc3.

Signed-off-by: George Cherian <george.cherian@ti.com>
---
 drivers/usb/dwc3/gadget.c | 128 ++++++++++++++++++++++++++++++++++++----------
 1 file changed, 100 insertions(+), 28 deletions(-)

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 2c54d45..a75fae5 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -29,6 +29,7 @@
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/drd.h>
 
 #include "debug.h"
 #include "core.h"
@@ -2681,6 +2682,89 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
 	return ret;
 }
 
+void dwc3_gadget_release(struct device *dev)
+{
+	struct usb_gadget *gadget = container_of(dev, struct usb_gadget, dev);
+	struct dwc3_gadget *dwc_gadget = gadget_to_dwc_gadget(gadget);
+	struct dwc3 *dwc = dwc_gadget->dwc;
+
+	dev_dbg(dev, "releasing '%s'\n", dev_name(dev));
+	dwc3_gadget_free_endpoints(dwc);
+	dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
+			  dwc->ep0_bounce, dwc->ep0_bounce_addr);
+	kfree(dwc->setup_buf);
+	dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+			  dwc->ep0_trb, dwc->ep0_trb_addr);
+	dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+			  dwc->ctrl_req, dwc->ctrl_req_addr);
+	usb_drd_unregister_udc(dwc->dev);
+	kfree(dwc_gadget);
+}
+
+int dwc3_gadget_setup(void *data)
+{
+	struct dwc3 *dwc = data;
+	struct dwc3_gadget *dwc_gadget;
+	struct usb_drd_gadget *drd_gadget;
+	struct usb_drd_setup *gadget_setup;
+	int ret;
+
+	drd_gadget = kzalloc(sizeof(*drd_gadget), GFP_KERNEL);
+	if (!drd_gadget) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	gadget_setup = kzalloc(sizeof(*gadget_setup), GFP_KERNEL);
+	if (!gadget_setup) {
+		ret = -ENOMEM;
+		goto err2;
+	}
+
+	dwc_gadget = kzalloc(sizeof(*dwc_gadget), GFP_KERNEL);
+	if (!dwc_gadget) {
+		ret = -ENOMEM;
+		goto err3;
+	}
+
+	drd_gadget->g_driver = dwc->gadget_driver;
+
+	/*
+	 * Pass the DWC3 specific routines for
+	 * switching roles to the drd library
+	 */
+	gadget_setup->ll_start = NULL;
+	gadget_setup->ll_stop = NULL;
+	gadget_setup->ll_release = dwc3_gadget_release;
+	gadget_setup->data =  (void *)dwc;
+	drd_gadget->gadget_setup = gadget_setup;
+
+	dwc_gadget->gadget.ops			= &dwc3_gadget_ops;
+	dwc_gadget->gadget.max_speed		= USB_SPEED_SUPER;
+	dwc_gadget->gadget.speed		= USB_SPEED_UNKNOWN;
+	dwc_gadget->gadget.sg_supported		= true;
+	dwc_gadget->gadget.name			= "dwc3-gadget";
+	dwc_gadget->dwc				= dwc;
+	drd_gadget->gadget = &dwc_gadget->gadget;
+
+	/*
+	 * Per databook, DWC3 needs buffer size to be aligned to MaxPacketSize
+	 * on ep out.
+	 */
+	dwc_gadget->gadget.quirk_ep_out_aligned_size = true;
+	dwc->dwc_gadget = dwc_gadget;
+	usb_drd_register_udc(dwc->dev, drd_gadget);
+
+	return 0;
+
+err3:
+	kfree(gadget_setup);
+err2:
+	kfree(drd_gadget);
+err1:
+	return ret;
+}
+
 /**
  * dwc3_gadget_init - Initializes gadget related registers
  * @dwc: pointer to our controller context structure
@@ -2690,7 +2774,6 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
 int dwc3_gadget_init(struct dwc3 *dwc)
 {
 	int					ret;
-	struct dwc3_gadget			*dwc_gadget;
 
 	dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
 			&dwc->ctrl_req_addr, GFP_KERNEL);
@@ -2723,24 +2806,9 @@ int dwc3_gadget_init(struct dwc3 *dwc)
 		goto err3;
 	}
 
-	dwc_gadget = kzalloc(sizeof(*dwc_gadget), GFP_KERNEL);
-	if (!dwc_gadget) {
-		ret = -ENOMEM;
+	ret = dwc3_gadget_setup(dwc);
+	if (ret)
 		goto err3;
-	}
-
-	dwc_gadget->gadget.ops			= &dwc3_gadget_ops;
-	dwc_gadget->gadget.max_speed		= USB_SPEED_SUPER;
-	dwc_gadget->gadget.speed		= USB_SPEED_UNKNOWN;
-	dwc_gadget->gadget.sg_supported	= true;
-	dwc_gadget->gadget.name		= "dwc3-gadget";
-	dwc_gadget->dwc = dwc;
-
-	/*
-	 * Per databook, DWC3 needs buffer size to be aligned to MaxPacketSize
-	 * on ep out.
-	 */
-	dwc_gadget->gadget.quirk_ep_out_aligned_size = true;
 
 	/*
 	 * REVISIT: Here we should clear all pending IRQs to be
@@ -2751,7 +2819,8 @@ int dwc3_gadget_init(struct dwc3 *dwc)
 	if (ret)
 		goto err4;
 
-	ret = usb_add_gadget_udc(dwc->dev, &dwc_gadget->gadget);
+	ret = usb_add_gadget_udc_release(dwc->dev, &dwc->dwc_gadget->gadget,
+					 dwc3_gadget_release);
 	if (ret) {
 		dev_err(dwc->dev, "failed to register udc\n");
 		goto err4;
@@ -2760,6 +2829,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
 	return 0;
 
 err4:
+	usb_drd_unregister_udc(dwc->dev);
 	dwc3_gadget_free_endpoints(dwc);
 	dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
 			dwc->ep0_bounce, dwc->ep0_bounce_addr);
@@ -2785,20 +2855,22 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
 {
 	struct dwc3_gadget *dwc_gadget = dwc->dwc_gadget;
 
-	usb_del_gadget_udc(&dwc_gadget->gadget);
+	if (usb_drd_get_state(dwc->dev) & DRD_DEVICE_REGISTERED) {
+		usb_del_gadget_udc(&dwc_gadget->gadget);
 
-	dwc3_gadget_free_endpoints(dwc);
+		dwc3_gadget_free_endpoints(dwc);
 
-	dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
-			dwc->ep0_bounce, dwc->ep0_bounce_addr);
+		dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
+				  dwc->ep0_bounce, dwc->ep0_bounce_addr);
 
-	kfree(dwc->setup_buf);
+		kfree(dwc->setup_buf);
 
-	dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
-			dwc->ep0_trb, dwc->ep0_trb_addr);
+		dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+				  dwc->ep0_trb, dwc->ep0_trb_addr);
 
-	dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
-			dwc->ctrl_req, dwc->ctrl_req_addr);
+		dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+				  dwc->ctrl_req, dwc->ctrl_req_addr);
+	}
 }
 
 int dwc3_gadget_suspend(struct dwc3 *dwc)
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 13/19] usb: dwc3: core: Add DWC3 OTG specific register defines
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
                   ` (11 preceding siblings ...)
  2014-11-25 13:11 ` [PATCH 12/19] usb: dwc3: gadget: Adapt gadget to drd library George Cherian
@ 2014-11-25 13:11 ` George Cherian
  2014-11-25 13:11 ` [PATCH 14/19] usb: dwc3: otg: Add the initial otg driver for dwc3 George Cherian
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

Add OTG reggister defines to DWC3 core.h

Signed-off-by: George Cherian <george.cherian@ti.com>
---
 drivers/usb/dwc3/core.h | 68 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 7fbe736..eb2e970 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -381,6 +381,74 @@
 #define DWC3_DEPCMD_TYPE_BULK		2
 #define DWC3_DEPCMD_TYPE_INTR		3
 
+/* OTG Configuration Register */
+#define DWC3_OCFG_DISPWRCUTTOFF                (1 << 5)
+#define DWC3_OCFG_HIBDISMASK           (1 << 4)
+#define DWC3_OCFG_SFTRSTMASK           (1 << 3)
+#define DWC3_OCFG_OTGVERSION           (1 << 2)
+#define DWC3_OCFG_HNPCAP               (1 << 1)
+#define DWC3_OCFG_SRPCAP               (1 << 0)
+
+/* OTG CTL Register */
+#define DWC3_OCTL_OTG3GOERR            (1 << 7)
+#define DWC3_OCTL_PERIMODE             (1 << 6)
+#define DWC3_OCTL_PRTPWRCTL            (1 << 5)
+#define DWC3_OCTL_HNPREQ               (1 << 4)
+#define DWC3_OCTL_SESREQ               (1 << 3)
+#define DWC3_OCTL_TERMSELIDPULSE       (1 << 2)
+#define DWC3_OCTL_DEVSETHNPEN          (1 << 1)
+#define DWC3_OCTL_HOSTSETHNPEN         (1 << 0)
+
+/* OTG Event Register */
+#define DWC3_OEVT_DEVICEMODE           (1 << 31)
+#define DWC3_OEVT_XHCIRUNSTPSET                (1 << 27)
+#define DWC3_OEVT_DEVRUNSTPSET         (1 << 26)
+#define DWC3_OEVT_HIBENTRY             (1 << 25)
+#define DWC3_OEVT_IDSTSCHNG            (1 << 24)
+#define DWC3_OEVT_HRRCONFNOTIF         (1 << 23)
+#define DWC3_OEVT_HRRINITNOTIF         (1 << 22)
+#define DWC3_OEVT_ADEVIDLE             (1 << 21)
+#define DWC3_OEVT_ADEVBHOSTEND         (1 << 20)
+#define DWC3_OEVT_ADEVHOST             (1 << 19)
+#define DWC3_OEVT_ADEVHNPCHNG          (1 << 18)
+#define DWC3_OEVT_ADEVSRPDET           (1 << 17)
+#define DWC3_OEVT_ADEVSESSENDDET       (1 << 16)
+#define DWC3_OEVT_BDEVBHOSTEND         (1 << 11)
+#define DWC3_OEVT_BDEVHNPCHNG          (1 << 10)
+#define DWC3_OEVT_BDEVSESSVLDDET       (1 << 9)
+#define DWC3_OEVT_BDEVVBUSCHNG         (1 << 8)
+#define DWC3_OEVT_BSESSVLD             (1 << 3)
+#define DWC3_OEVT_HOSTNEGSTS           (1 << 2)
+#define DWC3_OEVT_SESSREQSTS           (1 << 1)
+#define DWC3_OEVT_ERR                  (1 << 0)
+
+/* OTG Event Enable Register */
+#define DWC3_OEVTEN_XHCIRUNSTPSETEN    (1 << 27)
+#define DWC3_OEVTEN_DEVRUNSTPSETEN     (1 << 26)
+#define DWC3_OEVTEN_HIBENTRYEN         (1 << 25)
+#define DWC3_OEVTEN_CONIDSTSCHNGEN     (1 << 24)
+#define DWC3_OEVTEN_HRRCONFNOTIFEN     (1 << 23)
+#define DWC3_OEVTEN_HRRINITNOTIFEN     (1 << 22)
+#define DWC3_OEVTEN_ADEVIDLEEN         (1 << 21)
+#define DWC3_OEVTEN_ADEVBHOSTENDEN     (1 << 20)
+#define DWC3_OEVTEN_ADEVHOSTEN         (1 << 19)
+#define DWC3_OEVTEN_ADEVHNPCHNGEN      (1 << 18)
+#define DWC3_OEVTEN_ADEVSRPDETEN       (1 << 17)
+#define DWC3_OEVTEN_ADEVSESSENDDETEN   (1 << 16)
+#define DWC3_OEVTEN_BDEVHOSTENDEN      (1 << 11)
+#define DWC3_OEVTEN_BDEVHNPCHNGEN      (1 << 10)
+#define DWC3_OEVTEN_BDEVSESSVLDDETEN   (1 << 9)
+#define DWC3_OEVTEN_BDEVVBUSCHNGEVNTEN (1 << 8)
+
+/* OTG Status Register */
+#define DWC3_OSTS_DEVRUNSTP            (1 << 13)
+#define DWC3_OSTS_XHCIRUNSTP           (1 << 12)
+#define DWC3_OSTS_PERIPHERALSTATE      (1 << 4)
+#define DWC3_OSTS_XHCIPORTPOWER                (1 << 3)
+#define DWC3_OSTS_BSESVLD              (1 << 2)
+#define DWC3_OSTS_VBUSVLD              (1 << 1)
+#define DWC3_OSTS_CONIDSTS             (1 << 0)
+
 /* Structures */
 
 struct dwc3_trb;
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 14/19] usb: dwc3: otg: Add the initial otg driver for dwc3.
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
                   ` (12 preceding siblings ...)
  2014-11-25 13:11 ` [PATCH 13/19] usb: dwc3: core: Add DWC3 OTG specific register defines George Cherian
@ 2014-11-25 13:11 ` George Cherian
  2014-11-25 13:11 ` [PATCH 15/19] arm: dts: am4372: Add named interrupt property " George Cherian
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

Add the Initial OTG driver for dwc3.
Currently support only
	* ID based Role switching.

Signed-off-by: George Cherian <george.cherian@ti.com>
---
 drivers/usb/dwc3/Makefile |   4 ++
 drivers/usb/dwc3/core.c   |  10 +---
 drivers/usb/dwc3/core.h   |  10 ++++
 drivers/usb/dwc3/otg.c    | 126 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 142 insertions(+), 8 deletions(-)
 create mode 100644 drivers/usb/dwc3/otg.c

diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index bb34fbc..fe7af97 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -12,6 +12,10 @@ ifneq ($(filter y,$(CONFIG_USB_DWC3_HOST) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
 	dwc3-y				+= host.o
 endif
 
+ifneq ($(CONFIG_USB_DWC3_DUAL_ROLE),)
+	dwc3-y				+= otg.o
+endif
+
 ifneq ($(filter y,$(CONFIG_USB_DWC3_GADGET) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
 	dwc3-y				+= gadget.o ep0.o
 endif
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index dbd5589..dd4af3f 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -685,15 +685,9 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
 		break;
 	case USB_DR_MODE_OTG:
 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
-		ret = dwc3_host_init(dwc);
-		if (ret) {
-			dev_err(dev, "failed to initialize host\n");
-			return ret;
-		}
-
-		ret = dwc3_gadget_init(dwc);
+		ret = dwc3_otg_init(dwc);
 		if (ret) {
-			dev_err(dev, "failed to initialize gadget\n");
+			dev_err(dev, "failed to initialize otg\n");
 			return ret;
 		}
 		break;
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index eb2e970..001d77d 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1103,6 +1103,16 @@ static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
 { return 0; }
 #endif
 
+#if IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
+int dwc3_otg_init(struct dwc3 *dwc);
+void dwc3_otg_exit(struct dwc3 *dwc);
+#else
+static inline int dwc3_otg_init(struct dwc3 *dwc)
+{ return 0; }
+static inline void dwc3_otg_exit(struct dwc3 *dwc)
+{ }
+#endif
+
 /* power management interface */
 #if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
 int dwc3_gadget_suspend(struct dwc3 *dwc);
diff --git a/drivers/usb/dwc3/otg.c b/drivers/usb/dwc3/otg.c
new file mode 100644
index 0000000..b5c31c0
--- /dev/null
+++ b/drivers/usb/dwc3/otg.c
@@ -0,0 +1,126 @@
+/**
+ * otg.c - DesignWare USB3 DRD Controller OTG
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: George Cherian <george.cherian@ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+
+#include <linux/usb/drd.h>
+#include "core.h"
+#include "io.h"
+
+#define DWC3_GSTS_OTG_IP (1 << 10)
+
+static irqreturn_t dwc3_otg_interrupt(int irq , void *_dwc)
+{
+	struct dwc3 *dwc = _dwc;
+	u32 reg;
+
+	spin_lock(&dwc->lock);
+	reg = dwc3_readl(dwc->regs, DWC3_GSTS);
+	if (reg & DWC3_GSTS_OTG_IP) {
+		reg = dwc3_readl(dwc->regs, DWC3_OEVT);
+		dev_vdbg(dwc->dev, "OTG Interrupt %x\n", reg);
+		dwc3_writel(dwc->regs, DWC3_OEVT, reg);
+		spin_unlock(&dwc->lock);
+		return IRQ_WAKE_THREAD;
+	}
+
+	spin_unlock(&dwc->lock);
+	return IRQ_NONE;
+}
+
+static irqreturn_t dwc3_otg_thread_interrupt(int irq, void *_dwc)
+{
+	struct dwc3 *dwc = _dwc;
+	u32 reg = dwc3_readl(dwc->regs, DWC3_OSTS);
+
+	dev_vdbg(dwc->dev, "OTG thread interrupt\n");
+	if ((reg & DWC3_OSTS_CONIDSTS)) {
+		usb_drd_stop_hcd(dwc->dev);
+		dwc3_writel(dwc->regs, DWC3_OCFG, DWC3_OCFG_SFTRSTMASK);
+		dwc3_writel(dwc->regs, DWC3_OCTL,
+			    DWC3_OCTL_SESREQ | DWC3_OCTL_PERIMODE);
+		if (usb_drd_get_state(dwc->dev) & DRD_DEVICE_REGISTERED) {
+			usb_drd_start_udc(dwc->dev);
+		} else {
+			dwc3_core_gadget_helper(dwc);
+			dwc3_gadget_init(dwc);
+		}
+		dwc3_writel(dwc->regs, DWC3_OEVTEN,
+			    DWC3_OEVTEN_CONIDSTSCHNGEN);
+	} else if (!(reg & DWC3_OSTS_CONIDSTS)) {
+		usb_drd_stop_udc(dwc->dev);
+		dwc3_writel(dwc->regs, DWC3_OCFG,
+			    DWC3_OCFG_DISPWRCUTTOFF | DWC3_OCFG_SFTRSTMASK);
+		dwc3_writel(dwc->regs, DWC3_OCTL, DWC3_OCTL_PRTPWRCTL);
+		if (usb_drd_get_state(dwc->dev) & DRD_HOST_REGISTERED)
+			usb_drd_start_hcd(dwc->dev);
+		else
+			dwc3_host_init(dwc);
+
+		dwc3_writel(dwc->regs, DWC3_OEVTEN,
+			    DWC3_OEVTEN_CONIDSTSCHNGEN);
+	}
+
+	return IRQ_HANDLED;
+}
+
+int dwc3_otg_init(struct dwc3 *dwc)
+{
+	u32 reg, ret;
+
+	usb_drd_add(dwc->dev);
+	dwc3_writel(dwc->regs, DWC3_OEVT, 0xFFFF);
+	if (dwc->otg_irq > 0) {
+		ret = devm_request_threaded_irq(dwc->dev, dwc->otg_irq,
+						dwc3_otg_interrupt,
+						dwc3_otg_thread_interrupt,
+						IRQF_SHARED, "dwc3-otg", dwc);
+	} else {
+		WARN(1, "Trying to request invalid otg_irq");
+		return -ENODEV;
+	}
+
+	dwc3_writel(dwc->regs, DWC3_OEVTEN, DWC3_OEVTEN_CONIDSTSCHNGEN);
+	dwc3_writel(dwc->regs, DWC3_OCTL, DWC3_OCTL_PERIMODE);
+
+	reg = dwc3_readl(dwc->regs, DWC3_OSTS);
+	if ((reg & DWC3_OSTS_CONIDSTS)) {
+		dev_vdbg(dwc->dev, "Gadget  init\n");
+		dwc3_writel(dwc->regs, DWC3_OCFG, DWC3_OCFG_SFTRSTMASK);
+		dwc3_writel(dwc->regs, DWC3_OCTL,
+			    DWC3_OCTL_SESREQ | DWC3_OCTL_PERIMODE);
+		dwc3_gadget_init(dwc);
+		dwc3_writel(dwc->regs, DWC3_OEVTEN,
+			    DWC3_OEVTEN_CONIDSTSCHNGEN);
+
+	} else if (!(reg & DWC3_OSTS_CONIDSTS)) {
+		dev_vdbg(dwc->dev, "Host  init\n");
+		dwc3_writel(dwc->regs, DWC3_OCFG,
+			    DWC3_OCFG_DISPWRCUTTOFF | DWC3_OCFG_SFTRSTMASK);
+		dwc3_writel(dwc->regs, DWC3_OCTL, DWC3_OCTL_PRTPWRCTL);
+		dwc3_host_init(dwc);
+		dwc3_writel(dwc->regs, DWC3_OEVTEN,
+			    DWC3_OEVTEN_CONIDSTSCHNGEN);
+	}
+
+	return 0;
+}
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 15/19] arm: dts: am4372: Add named interrupt property for dwc3
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
                   ` (13 preceding siblings ...)
  2014-11-25 13:11 ` [PATCH 14/19] usb: dwc3: otg: Add the initial otg driver for dwc3 George Cherian
@ 2014-11-25 13:11 ` George Cherian
  2014-11-25 13:11 ` [PATCH 16/19] arm: dts: omap5: " George Cherian
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

From: Felipe Balbi <balbi@ti.com>

Add interrupt names so that the same can be used for OTG easily.

Signed-off-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: George Cherian <george.cherian@ti.com>
---
 arch/arm/boot/dts/am4372.dtsi | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi
index e19068d..3dda4c8 100644
--- a/arch/arm/boot/dts/am4372.dtsi
+++ b/arch/arm/boot/dts/am4372.dtsi
@@ -810,8 +810,13 @@
 
 			usb1: usb@48390000 {
 				compatible = "synopsys,dwc3";
-				reg = <0x48390000 0x10000>;
-				interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+				reg = <0x48390000 0x17000>;
+				interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-names = "peripheral",
+						  "host",
+						  "otg";
 				phys = <&usb2_phy1>;
 				phy-names = "usb2-phy";
 				maximum-speed = "high-speed";
@@ -834,8 +839,13 @@
 
 			usb2: usb@483d0000 {
 				compatible = "synopsys,dwc3";
-				reg = <0x483d0000 0x10000>;
-				interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+				reg = <0x483d0000 0x17000>;
+				interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-names = "peripheral",
+						  "host",
+						  "otg";
 				phys = <&usb2_phy2>;
 				phy-names = "usb2-phy";
 				maximum-speed = "high-speed";
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 16/19] arm: dts: omap5: Add named interrupt property for dwc3
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
                   ` (14 preceding siblings ...)
  2014-11-25 13:11 ` [PATCH 15/19] arm: dts: am4372: Add named interrupt property " George Cherian
@ 2014-11-25 13:11 ` George Cherian
  2014-11-25 13:11 ` [PATCH 17/19] arm: dts: dra7: " George Cherian
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

Add interrupt names so that the same can be used for OTG easily.

Signed-off-by: George Cherian <george.cherian@ti.com>
---
 arch/arm/boot/dts/omap5.dtsi | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index 256b7f6..a712ad9 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -817,7 +817,12 @@
 			dwc3@4a030000 {
 				compatible = "snps,dwc3";
 				reg = <0x4a030000 0x10000>;
-				interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
+				interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-names = "peripheral",
+						  "host",
+						  "otg";
 				phys = <&usb2_phy>, <&usb3_phy>;
 				phy-names = "usb2-phy", "usb3-phy";
 				dr_mode = "peripheral";
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 17/19] arm: dts: dra7: Add named interrupt property for dwc3
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
                   ` (15 preceding siblings ...)
  2014-11-25 13:11 ` [PATCH 16/19] arm: dts: omap5: " George Cherian
@ 2014-11-25 13:11 ` George Cherian
  2014-11-25 13:11 ` [PATCH 18/19] arm: dts: exynos5250: " George Cherian
  2014-11-25 13:11 ` [PATCH 19/19] arm: dts: am43x evms: Make usb1 as OTG George Cherian
  18 siblings, 0 replies; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

Add interrupt names so that the same can be used for OTG easily.

Signed-off-by: George Cherian <george.cherian@ti.com>
---
 arch/arm/boot/dts/dra7.dtsi | 28 ++++++++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
index 9cc9843..78f1761 100644
--- a/arch/arm/boot/dts/dra7.dtsi
+++ b/arch/arm/boot/dts/dra7.dtsi
@@ -1153,7 +1153,12 @@
 			usb1: usb@48890000 {
 				compatible = "snps,dwc3";
 				reg = <0x48890000 0x17000>;
-				interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
+				interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-names = "peripheral",
+						  "host",
+						  "otg";
 				phys = <&usb2_phy1>, <&usb3_phy1>;
 				phy-names = "usb2-phy", "usb3-phy";
 				tx-fifo-resize;
@@ -1174,7 +1179,12 @@
 			usb2: usb@488d0000 {
 				compatible = "snps,dwc3";
 				reg = <0x488d0000 0x17000>;
-				interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+				interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-names = "peripheral",
+						  "host",
+						  "otg";
 				phys = <&usb2_phy2>;
 				phy-names = "usb2-phy";
 				tx-fifo-resize;
@@ -1197,7 +1207,12 @@
 			usb3: usb@48910000 {
 				compatible = "snps,dwc3";
 				reg = <0x48910000 0x17000>;
-				interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+				interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-names = "peripheral",
+						  "host",
+						  "otg";
 				tx-fifo-resize;
 				maximum-speed = "high-speed";
 				dr_mode = "otg";
@@ -1217,7 +1232,12 @@
 			usb4: usb@48950000 {
 				compatible = "snps,dwc3";
 				reg = <0x48950000 0x17000>;
-				interrupts = <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>;
+				interrupts = <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-names = "peripheral",
+						  "host",
+						  "otg";
 				tx-fifo-resize;
 				maximum-speed = "high-speed";
 				dr_mode = "otg";
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 18/19] arm: dts: exynos5250: Add named interrupt property for dwc3
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
                   ` (16 preceding siblings ...)
  2014-11-25 13:11 ` [PATCH 17/19] arm: dts: dra7: " George Cherian
@ 2014-11-25 13:11 ` George Cherian
  2014-11-25 13:11 ` [PATCH 19/19] arm: dts: am43x evms: Make usb1 as OTG George Cherian
  18 siblings, 0 replies; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

Add interrupt names so that the same can be used for OTG easily.

Signed-off-by: George Cherian <george.cherian@ti.com>
---
 arch/arm/boot/dts/exynos5250.dtsi | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index f21b9aa..c74cd8b 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -558,7 +558,12 @@
 		dwc3 {
 			compatible = "synopsys,dwc3";
 			reg = <0x12000000 0x10000>;
-			interrupts = <0 72 0>;
+			interrupts = <0 72 0>,
+				     <0 72 0>,
+				     <0 72 0>;
+			interrupt-names = "peripheral",
+					  "host",
+					  "otg";
 			phys = <&usbdrd_phy 0>, <&usbdrd_phy 1>;
 			phy-names = "usb2-phy", "usb3-phy";
 		};
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 19/19] arm: dts: am43x evms: Make usb1 as OTG
  2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
                   ` (17 preceding siblings ...)
  2014-11-25 13:11 ` [PATCH 18/19] arm: dts: exynos5250: " George Cherian
@ 2014-11-25 13:11 ` George Cherian
  18 siblings, 0 replies; 22+ messages in thread
From: George Cherian @ 2014-11-25 13:11 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt, George Cherian

USB1 of am43x EPOS EVM, am437x GP EVM and am437x SK EVM can be used as OTG.
Enable the same.

Signed-off-by: George Cherian <george.cherian@ti.com>
---
 arch/arm/boot/dts/am437x-gp-evm.dts  | 2 +-
 arch/arm/boot/dts/am437x-sk-evm.dts  | 2 +-
 arch/arm/boot/dts/am43x-epos-evm.dts | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts
index e7ac47f..a8b5752 100644
--- a/arch/arm/boot/dts/am437x-gp-evm.dts
+++ b/arch/arm/boot/dts/am437x-gp-evm.dts
@@ -380,7 +380,7 @@
 };
 
 &usb1 {
-	dr_mode = "peripheral";
+	dr_mode = "otg";
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/am437x-sk-evm.dts b/arch/arm/boot/dts/am437x-sk-evm.dts
index 859ff3d..b258826 100644
--- a/arch/arm/boot/dts/am437x-sk-evm.dts
+++ b/arch/arm/boot/dts/am437x-sk-evm.dts
@@ -478,7 +478,7 @@
 };
 
 &usb1 {
-	dr_mode = "peripheral";
+	dr_mode = "otg";
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts
index ac3e485..3d106e9 100644
--- a/arch/arm/boot/dts/am43x-epos-evm.dts
+++ b/arch/arm/boot/dts/am43x-epos-evm.dts
@@ -542,7 +542,7 @@
 };
 
 &usb1 {
-	dr_mode = "peripheral";
+	dr_mode = "otg";
 	status = "okay";
 };
 
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH 01/19] usb: common: drd-lib: Add DRD lib for USB.
  2014-11-25 13:11 ` [PATCH 01/19] usb: common: drd-lib: Add DRD lib for USB George Cherian
@ 2014-11-26  5:14   ` Peter Chen
  0 siblings, 0 replies; 22+ messages in thread
From: Peter Chen @ 2014-11-26  5:14 UTC (permalink / raw)
  To: George Cherian
  Cc: linux-arm-kernel, linux-kernel, linux-samsung-soc, linux-omap,
	linux-usb, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt

On Tue, Nov 25, 2014 at 06:41:37PM +0530, George Cherian wrote:
> Add USB DRD library. This Library facilitates to
> switch roles between HOST and Device modes.
> 
> A DRD should be added to the library using usb_drd_add().
> Register the HOST and UDC using usb_drd_register_hcd/udc().
> Un-Register the HOST and UDC using usb_drd_unregister_hcd/udc().
> 
> Depending on the state of IP -
> Call the following to start/stop HOST controller
> usb_drd_start/stop_hcd().
> This internally calls usb_add/remove_hcd() or IP specific low level start/stop
> defined in ll_start/stop
> 
> Call the following to start/stop UDC
> usb_drd_start/stop_udc().
> This internally calls udc_start/udc_stop() or IP specific low level start/stop
> defined in ll_start/stop
> 
> Signed-off-by: George Cherian <george.cherian@ti.com>
> ---
>  drivers/usb/Kconfig          |  15 ++
>  drivers/usb/common/Makefile  |   1 +
>  drivers/usb/common/drd-lib.c | 346 +++++++++++++++++++++++++++++++++++++++++++
>  include/linux/usb/drd.h      |  77 ++++++++++
>  4 files changed, 439 insertions(+)
>  create mode 100644 drivers/usb/common/drd-lib.c
>  create mode 100644 include/linux/usb/drd.h
> 
> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
> index ae481c3..ea0d944 100644
> --- a/drivers/usb/Kconfig
> +++ b/drivers/usb/Kconfig
> @@ -34,6 +34,21 @@ config USB_COMMON
>  	default y
>  	depends on USB || USB_GADGET
>  
> +config DRD_LIB
> +	tristate  "DRD Library support"
> +	default y
> +	depends on USB && USB_GADGET
> +	---help---
> +	  This option adds DRD Library support for Universal Serial Bus (USB).
> +	  DRD Library faciliatets the Role switching by HOST and DEVICE roles,
> +	  If your hardware has a Dual Role Device.
> +
> +	  The DRD Library uses USB core API's to start/stop HOST controllers,
> +	  UDC API's to start/stop DEVICE controllers, ther by enabling to
> +	  switch roles between HOST and Device modes.

%s/ther by/thereby

> +
> +	  Say N if unsure.
> +
>  config USB_ARCH_HAS_HCD
>  	def_bool y
>  
> diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile
> index ca2f8bd..e2c1593 100644
> --- a/drivers/usb/common/Makefile
> +++ b/drivers/usb/common/Makefile
> @@ -7,3 +7,4 @@ usb-common-y			  += common.o
>  usb-common-$(CONFIG_USB_LED_TRIG) += led.o
>  
>  obj-$(CONFIG_USB_OTG_FSM) += usb-otg-fsm.o
> +obj-$(CONFIG_DRD_LIB)       += drd-lib.o
> diff --git a/drivers/usb/common/drd-lib.c b/drivers/usb/common/drd-lib.c
> new file mode 100644
> index 0000000..6159436
> --- /dev/null
> +++ b/drivers/usb/common/drd-lib.c
> @@ -0,0 +1,346 @@
> +/**
> + * drd-lib.c - USB DRD library functions
> + *
> + * Copyright (C) 2014 Texas Instruments
> + * Author: George Cherian <george.cherian@ti.com>
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2  of
> + * the License as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/kernel.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/usb.h>
> +
> +#include <linux/usb/hcd.h>
> +#include <linux/usb/gadget.h>
> +#include <linux/usb/drd.h>
> +
> +/**
> + * struct usb_drd - describes one dual role device
> + * @host - the HOST controller device of this drd
> + * @gadget - the gadget of drd
> + * @parent - the device to the actual controller
> + * @list - for use by the drd lib
> + * @state - specifies the current state
> + *
> + * This represents the internal data structure which is used by the UDC-class
> + * to hold information about udc driver and gadget together.
> + */

It is dual role struct, why you only talk about device?

> +struct usb_drd {
> +	struct usb_drd_host	*host;
> +	struct usb_drd_gadget	*gadget;
> +	struct device		*parent;
> +	struct list_head	list;
> +	unsigned int		state;
> +};
> +
> +static LIST_HEAD(drd_list);
> +static DEFINE_SPINLOCK(drd_lock);
> +
> +static struct usb_drd *usb_drd_get_dev(struct device *parent)
> +{
> +	struct usb_drd *drd;
> +
> +	spin_lock(&drd_lock);
> +	list_for_each_entry(drd, &drd_list, list)
> +		if (drd->parent == parent)
> +			goto out;
> +	drd = NULL;
> +out:
> +	spin_unlock(&drd_lock);
> +
> +	return drd;
> +}
> +
> +int usb_drd_get_state(struct device *parent)
> +{
> +	struct usb_drd	*drd;
> +
> +	drd = usb_drd_get_dev(parent);
> +	if (!drd)
> +		return -ENODEV;
> +
> +	return drd->state;
> +}
> +EXPORT_SYMBOL_GPL(usb_drd_get_state);
> +
> +int usb_drd_release(struct device *parent)
> +{
> +	struct usb_drd	*drd;
> +	int ret;
> +
> +	spin_lock(&drd_lock);
> +	list_for_each_entry(drd, &drd_list, list) {
> +		if (drd->parent == parent) {
> +			kfree(drd);
> +			ret = 0;
> +			goto out;
> +		}
> +	}
> +	ret = -ENODEV;
> +out:
> +	spin_unlock(&drd_lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(usb_drd_release);
> +
> +int usb_drd_add(struct device *parent)
> +{
> +	struct usb_drd	*drd;
> +
> +	drd = kzalloc(sizeof(*drd), GFP_KERNEL);
> +	if (!drd)
> +		return -ENOMEM;
> +
> +	spin_lock(&drd_lock);
> +	drd->parent = parent;
> +	list_add_tail(&drd->list, &drd_list);
> +	drd->state = DRD_UNREGISTERED;
> +
> +	spin_unlock(&drd_lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_drd_add);
> +
> +int usb_drd_register_hcd(struct device *parent, struct usb_drd_host *host)
> +{
> +	struct usb_drd	*drd;
> +
> +	drd = usb_drd_get_dev(parent);
> +	if (!drd)
> +		return -ENODEV;
> +
> +	spin_lock(&drd_lock);
> +	drd->host = host;
> +	drd->state |= DRD_HOST_REGISTERED | DRD_HOST_ACTIVE;
> +	spin_unlock(&drd_lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_drd_register_hcd);
> +
> +int usb_drd_unregister_hcd(struct device *parent)
> +{
> +	struct usb_drd	*drd;
> +
> +	drd = usb_drd_get_dev(parent);
> +	if (!drd)
> +		return -ENODEV;
> +
> +	spin_lock(&drd_lock);
> +	drd->state &= ~(DRD_HOST_REGISTERED | DRD_HOST_ACTIVE);
> +	spin_unlock(&drd_lock);
> +	kfree(drd->host);

It is better to allocate and free memory at the same file, either
both at DRD LIB APIs, or at host controller and udc driver.

> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_drd_unregister_hcd);
> +
> +int usb_drd_start_hcd(struct device *parent)
> +{
> +	struct usb_drd	*drd;
> +	struct usb_drd_setup *setup;
> +
> +	drd = usb_drd_get_dev(parent);
> +	if (!drd)
> +		return -ENODEV;
> +
> +	if (WARN_ON(!(drd->state & DRD_HOST_REGISTERED)))
> +		return -EINVAL;
> +
> +	setup = drd->host->host_setup;
> +	if (setup && setup->ll_start)
> +		setup->ll_start(setup->data);
> +
> +	usb_add_hcd(drd->host->main_hcd,
> +		    drd->host->hcd_irq, IRQF_SHARED);
> +	if (drd->host->shared_hcd)
> +		usb_add_hcd(drd->host->shared_hcd,
> +			    drd->host->hcd_irq, IRQF_SHARED);

Check return value please.

Peter
> +
> +	spin_lock(&drd_lock);
> +	drd->state |= DRD_HOST_ACTIVE;
> +	spin_unlock(&drd_lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_drd_start_hcd);
> +
> +int usb_drd_stop_hcd(struct device *parent)
> +{
> +	struct usb_drd	*drd;
> +	struct usb_drd_setup *setup;
> +
> +	drd = usb_drd_get_dev(parent);
> +	if (!drd)
> +		return -ENODEV;
> +
> +	if (WARN_ON(!(drd->state & DRD_HOST_ACTIVE)))
> +		return -EINVAL;
> +
> +	setup = drd->host->host_setup;
> +	if (setup && setup->ll_stop)
> +		setup->ll_stop(setup->data);
> +	if (drd->host->shared_hcd)
> +		usb_remove_hcd(drd->host->shared_hcd);
> +
> +	usb_remove_hcd(drd->host->main_hcd);
> +
> +	spin_lock(&drd_lock);
> +	drd->state = drd->state & ~DRD_HOST_ACTIVE;
> +	spin_unlock(&drd_lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_drd_stop_hcd);
> +
> +int usb_drd_register_udc(struct device *parent, struct usb_drd_gadget *gadget)
> +{
> +	struct usb_drd	*drd;
> +
> +	drd = usb_drd_get_dev(parent);
> +	if (!drd)
> +		return -ENODEV;
> +
> +	spin_lock(&drd_lock);
> +	drd->gadget = gadget;
> +	drd->state |= DRD_DEVICE_REGISTERED;
> +	if (drd->gadget->g_driver)
> +		drd->state |= DRD_DEVICE_ACTIVE;
> +
> +	spin_unlock(&drd_lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_drd_register_udc);
> +
> +int usb_drd_register_udc_driver(struct device *parent,
> +				struct usb_gadget_driver *driver)
> +{
> +	struct usb_drd	*drd;
> +
> +	drd = usb_drd_get_dev(parent);
> +	if (!drd)
> +		return -ENODEV;
> +
> +	spin_lock(&drd_lock);
> +	drd->gadget->g_driver = driver;
> +	drd->state |= DRD_DEVICE_ACTIVE;
> +	spin_unlock(&drd_lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_drd_register_udc_driver);
> +
> +int usb_drd_unregister_udc(struct device *parent)
> +{
> +	struct usb_drd	*drd;
> +
> +	drd = usb_drd_get_dev(parent);
> +	if (!drd)
> +		return -ENODEV;
> +
> +	spin_lock(&drd_lock);
> +	drd->state &= ~(DRD_DEVICE_REGISTERED | DRD_DEVICE_ACTIVE);
> +	spin_unlock(&drd_lock);
> +	kfree(drd->gadget->gadget_setup);
> +	kfree(drd->gadget);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_drd_unregister_udc);
> +
> +int usb_drd_unregister_udc_driver(struct device *parent)
> +{
> +	struct usb_drd	*drd;
> +	struct usb_drd_gadget *drd_gadget;
> +
> +	drd = usb_drd_get_dev(parent);
> +	if (!drd)
> +		return -ENODEV;
> +	drd_gadget = drd->gadget;
> +
> +	spin_lock(&drd_lock);
> +	drd->state &= ~DRD_DEVICE_ACTIVE;
> +	drd_gadget->g_driver = NULL;
> +	spin_unlock(&drd_lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_drd_unregister_udc_driver);
> +
> +int usb_drd_start_udc(struct device *parent)
> +{
> +	struct usb_drd	*drd;
> +	struct usb_drd_gadget *drd_gadget;
> +	struct usb_drd_setup *setup;
> +
> +	drd = usb_drd_get_dev(parent);
> +	if (!drd)
> +		return -ENODEV;
> +
> +	if (WARN_ON(!(drd->state & DRD_DEVICE_REGISTERED)))
> +		return -EINVAL;
> +
> +	drd_gadget = drd->gadget;
> +	setup = drd_gadget->gadget_setup;
> +
> +	if (setup && setup->ll_start)
> +		setup->ll_start(setup->data);
> +
> +	usb_add_gadget_udc_release(parent, drd_gadget->gadget,
> +				   setup->ll_release);
> +	spin_lock(&drd_lock);
> +	drd->state |= DRD_DEVICE_ACTIVE;
> +	spin_unlock(&drd_lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_drd_start_udc);
> +
> +int usb_drd_stop_udc(struct device *parent)
> +{
> +	struct usb_drd	*drd;
> +	struct usb_drd_gadget *drd_gadget;
> +	struct usb_drd_setup *setup;
> +
> +	drd = usb_drd_get_dev(parent);
> +	if (!drd)
> +		return -ENODEV;
> +
> +	if (WARN_ON(!(drd->state & DRD_DEVICE_REGISTERED)))
> +		return -EINVAL;
> +
> +	drd_gadget = drd->gadget;
> +	setup = drd_gadget->gadget_setup;
> +	if (setup && setup->ll_stop)
> +		setup->ll_stop(setup->data);
> +
> +	usb_del_gadget_udc(drd_gadget->gadget);
> +
> +	spin_lock(&drd_lock);
> +	drd->state = drd->state & ~DRD_DEVICE_ACTIVE;
> +	spin_unlock(&drd_lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(usb_drd_stop_udc);
> +
> +MODULE_DESCRIPTION("USB-DRD Library");
> +MODULE_AUTHOR("George Cherian <george.cherian@ti.com>");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/usb/drd.h b/include/linux/usb/drd.h
> new file mode 100644
> index 0000000..71c64dc
> --- /dev/null
> +++ b/include/linux/usb/drd.h
> @@ -0,0 +1,77 @@
> +#include <linux/usb/gadget.h>
> +#include <linux/usb/otg.h>
> +#include <linux/usb/hcd.h>
> +
> +struct usb_drd_setup {
> +	int	(*ll_start)(void *);
> +	int	(*ll_stop)(void *);
> +	void	(*ll_release)(struct device *);
> +	void	*data;
> +};
> +
> +struct usb_drd_host {
> +	struct usb_hcd		*main_hcd;
> +	struct usb_hcd		*shared_hcd;
> +	int			hcd_irq;
> +	struct usb_drd_setup *host_setup;
> +};
> +
> +struct usb_drd_gadget {
> +	struct usb_gadget_driver *g_driver;
> +	struct usb_gadget *gadget;
> +	struct usb_drd_setup *gadget_setup;
> +};
> +
> +#define DRD_UNREGISTERED	0x0
> +#define DRD_DEVICE_REGISTERED	0x1
> +#define DRD_HOST_REGISTERED	0x2
> +#define DRD_HOST_ACTIVE		0x4
> +#define DRD_DEVICE_ACTIVE	0x8
> +
> +#if IS_ENABLED(CONFIG_DRD_LIB)
> +int usb_drd_release(struct device *parent);
> +int usb_drd_add(struct device *parent);
> +int usb_drd_register_udc(struct device *parent,
> +			 struct usb_drd_gadget *gadget);
> +int usb_drd_register_udc_driver(struct device *parent,
> +				struct usb_gadget_driver *driver);
> +int usb_drd_unregister_udc(struct device *parent);
> +int usb_drd_unregister_udc_driver(struct device *parent);
> +int usb_drd_register_hcd(struct device *parent,
> +			 struct usb_drd_host *host);
> +int usb_drd_unregister_hcd(struct device *parent);
> +int usb_drd_start_hcd(struct device *parent);
> +int usb_drd_stop_hcd(struct device *parent);
> +int usb_drd_start_udc(struct device *parent);
> +int usb_drd_stop_udc(struct device *parent);
> +int usb_drd_get_state(struct device *parent);
> +#else
> +static inline int usb_drd_release(struct device *parent)
> +{ return 0; }
> +static inline int usb_drd_add(struct device *parent)
> +{ return 0; }
> +static inline int usb_drd_register_udc(struct device *parent,
> +				       struct usb_drd_gadget *gadget)
> +{ return 0; }
> +static inline int usb_drd_register_udc_driver(struct device *parent,
> +					      struct usb_gadget_driver *driver)
> +{ return 0; }
> +static inline int usb_drd_unregister_udc(struct device *parent,
> +					 struct usb_drd_gadget *gadget)
> +{ return 0; }
> +static inline int usb_drd_unregister_udc_driver(struct device *parent)
> +{ return 0; }
> +static inline int usb_drd_register_hcd(struct device *parent,
> +				       struct usb_drd_host *host)
> +{ return 0; }
> +static inline int usb_drd_unregister_hcd(struct device *parent)
> +{ return 0; }
> +static inline int usb_drd_stop_hcd(struct device *parent)
> +{ return 0; }
> +static inline int usb_drd_start_udc(struct device *parent)
> +{ return 0; }
> +static inline int usb_drd_stop_udc(struct device *parent)
> +{ return 0; }
> +static inline int usb_drd_get_state(struct device *parent)
> +{ return 0; }
> +#endif
> -- 
> 1.8.3.1
> 

-- 

Best Regards,
Peter Chen

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 06/19] usb: dwc3: host: Pass the XHCI_DRD_SUPPORT and XHCI_NEEDS_LHC_RESET quirk
  2014-11-25 13:11 ` [PATCH 06/19] usb: dwc3: host: Pass the XHCI_DRD_SUPPORT and " George Cherian
@ 2014-11-27  2:00   ` Lu, Baolu
  0 siblings, 0 replies; 22+ messages in thread
From: Lu, Baolu @ 2014-11-27  2:00 UTC (permalink / raw)
  To: George Cherian, linux-arm-kernel, linux-kernel,
	linux-samsung-soc, linux-omap, linux-usb
  Cc: peter.chen, sojka, mathias.nyman, balbi, gregkh, tony, bcousson,
	kgene.kim, ben-linux, linux, galak, ijc+devicetree, mark.rutland,
	pawel.moll, robh+dt


On 2014年11月25日 21:11, George Cherian wrote:
> Pass the quir flag XHCI_DRD_SUPPORT from DWC3 host to xhci platform driver.
"quir" to "quirk"

Regards,
Baolu

> This enables xhci driver to handle deallocation's differently while in DRD mode.
> Pass the quirk flag XHCI_NEEDS_LHC_RESET from DWC3 host to xhci platform
> driver. This enables to do LHRESET during xhci_reset().
>
> Signed-off-by: George Cherian <george.cherian@ti.com>
> ---
>   drivers/usb/dwc3/host.c | 2 ++
>   1 file changed, 2 insertions(+)
>
> diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
> index dcb8ca0..257b5b5 100644
> --- a/drivers/usb/dwc3/host.c
> +++ b/drivers/usb/dwc3/host.c
> @@ -53,6 +53,8 @@ int dwc3_host_init(struct dwc3 *dwc)
>   #ifdef CONFIG_DWC3_HOST_USB3_LPM_ENABLE
>   	pdata.usb3_lpm_capable = 1;
>   #endif
> +	pdata.usb_drd_support = 1;
> +	pdata.usb_needs_lhc_reset = 1;
>   
>   	ret = platform_device_add_data(xhci, &pdata, sizeof(pdata));
>   	if (ret) {


^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2014-11-27  2:00 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-11-25 13:11 [PATCH 00/19] Add Support for USB DRD in AM437x George Cherian
2014-11-25 13:11 ` [PATCH 01/19] usb: common: drd-lib: Add DRD lib for USB George Cherian
2014-11-26  5:14   ` Peter Chen
2014-11-25 13:11 ` [PATCH 02/19] usb: host xhci: fix up deallocation code George Cherian
2014-11-25 13:11 ` [PATCH 03/19] usb: host: xhci-plat: Add support to pass XHCI_DRD_SUPPORT quirk George Cherian
2014-11-25 13:11 ` [PATCH 04/19] usb: host xhci: Add XHCI_NEEDS_LHC_RESET quirk George Cherian
2014-11-25 13:11 ` [PATCH 05/19] usb: host: xhci-plat: Add support to pass " George Cherian
2014-11-25 13:11 ` [PATCH 06/19] usb: dwc3: host: Pass the XHCI_DRD_SUPPORT and " George Cherian
2014-11-27  2:00   ` Lu, Baolu
2014-11-25 13:11 ` [PATCH 07/19] usb: host: xhci: Adapt xhci to use usb drd library George Cherian
2014-11-25 13:11 ` [PATCH 08/19] usb: dwc3: core: Add dwc3_drd_helper function George Cherian
2014-11-25 13:11 ` [PATCH 09/19] usb: dwc3: dwc3-omap: Make the wrapper interrupt shared George Cherian
2014-11-25 13:11 ` [PATCH 10/19] usb: dwc3: core: Adapt to named interrupts George Cherian
2014-11-25 13:11 ` [PATCH 11/19] usb: dwc3: Add seperate dwc3_gadget object to support gadget release George Cherian
2014-11-25 13:11 ` [PATCH 12/19] usb: dwc3: gadget: Adapt gadget to drd library George Cherian
2014-11-25 13:11 ` [PATCH 13/19] usb: dwc3: core: Add DWC3 OTG specific register defines George Cherian
2014-11-25 13:11 ` [PATCH 14/19] usb: dwc3: otg: Add the initial otg driver for dwc3 George Cherian
2014-11-25 13:11 ` [PATCH 15/19] arm: dts: am4372: Add named interrupt property " George Cherian
2014-11-25 13:11 ` [PATCH 16/19] arm: dts: omap5: " George Cherian
2014-11-25 13:11 ` [PATCH 17/19] arm: dts: dra7: " George Cherian
2014-11-25 13:11 ` [PATCH 18/19] arm: dts: exynos5250: " George Cherian
2014-11-25 13:11 ` [PATCH 19/19] arm: dts: am43x evms: Make usb1 as OTG George Cherian

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).