]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'usb/usb-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 22 Sep 2011 07:48:51 +0000 (17:48 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 22 Sep 2011 07:48:51 +0000 (17:48 +1000)
107 files changed:
Documentation/usb/dwc3.txt [new file with mode: 0644]
MAINTAINERS
arch/arm/mach-mmp/include/mach/pxa168.h
arch/arm/mach-mmp/pxa168.c
drivers/usb/Kconfig
drivers/usb/Makefile
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-wdm.c
drivers/usb/class/usbtmc.c
drivers/usb/core/config.c
drivers/usb/core/devices.c
drivers/usb/core/endpoint.c
drivers/usb/core/hub.c
drivers/usb/core/urb.c
drivers/usb/dwc3/Kconfig [new file with mode: 0644]
drivers/usb/dwc3/Makefile [new file with mode: 0644]
drivers/usb/dwc3/core.c [new file with mode: 0644]
drivers/usb/dwc3/core.h [new file with mode: 0644]
drivers/usb/dwc3/debug.h [new file with mode: 0644]
drivers/usb/dwc3/debugfs.c [new file with mode: 0644]
drivers/usb/dwc3/dwc3-omap.c [new file with mode: 0644]
drivers/usb/dwc3/dwc3-pci.c [new file with mode: 0644]
drivers/usb/dwc3/ep0.c [new file with mode: 0644]
drivers/usb/dwc3/gadget.c [new file with mode: 0644]
drivers/usb/dwc3/gadget.h [new file with mode: 0644]
drivers/usb/dwc3/io.h [new file with mode: 0644]
drivers/usb/gadget/Kconfig
drivers/usb/gadget/amd5536udc.c
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/atmel_usba_udc.c
drivers/usb/gadget/ci13xxx_udc.c
drivers/usb/gadget/composite.c
drivers/usb/gadget/dummy_hcd.c
drivers/usb/gadget/epautoconf.c
drivers/usb/gadget/f_mass_storage.c
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/fsl_qe_udc.c
drivers/usb/gadget/fsl_udc_core.c
drivers/usb/gadget/fusb300_udc.c
drivers/usb/gadget/gadget_chips.h
drivers/usb/gadget/imx_udc.c
drivers/usb/gadget/langwell_udc.c
drivers/usb/gadget/m66592-udc.c
drivers/usb/gadget/mv_udc_core.c
drivers/usb/gadget/net2272.c
drivers/usb/gadget/net2280.c
drivers/usb/gadget/omap_udc.c
drivers/usb/gadget/pch_udc.c
drivers/usb/gadget/pxa25x_udc.c
drivers/usb/gadget/pxa27x_udc.c
drivers/usb/gadget/r8a66597-udc.c
drivers/usb/gadget/s3c-hsotg.c
drivers/usb/gadget/s3c-hsudc.c
drivers/usb/gadget/s3c2410_udc.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-au1xxx.c
drivers/usb/host/ehci-dbg.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-pxa168.c [new file with mode: 0644]
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-s5p.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/ehci-xls.c [new file with mode: 0644]
drivers/usb/host/ehci.h
drivers/usb/host/fhci-hcd.c
drivers/usb/host/isp1362-hcd.c
drivers/usb/host/isp1760-hcd.c
drivers/usb/host/isp1760-hcd.h
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-omap3.c
drivers/usb/host/ohci-q.c
drivers/usb/host/ohci-xls.c [new file with mode: 0644]
drivers/usb/host/r8a66597-hcd.c
drivers/usb/host/uhci-q.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/misc/adutux.c
drivers/usb/misc/ftdi-elan.c
drivers/usb/misc/idmouse.c
drivers/usb/misc/iowarrior.c
drivers/usb/misc/ldusb.c
drivers/usb/misc/legousbtower.c
drivers/usb/misc/usblcd.c
drivers/usb/misc/usbled.c
drivers/usb/misc/usbtest.c
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_host.c
drivers/usb/otg/twl6030-usb.c
drivers/usb/renesas_usbhs/pipe.c
drivers/usb/serial/Kconfig
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/ipw.c
drivers/usb/serial/opticon.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/symbolserial.c
drivers/usb/serial/usb-serial.c
drivers/usb/storage/realtek_cr.c
drivers/usb/storage/usb.c
drivers/usb/usb-skeleton.c
drivers/usb/wusbcore/wa-hc.c
include/linux/usb.h
include/linux/usb/ch9.h

diff --git a/Documentation/usb/dwc3.txt b/Documentation/usb/dwc3.txt
new file mode 100644 (file)
index 0000000..2f65853
--- /dev/null
@@ -0,0 +1,53 @@
+
+ TODO
+~~~~~~
+Please pick something while reading :)
+
+- Implement streaming support for BULK endpoints
+  Tatyana's patch "usb: Add streams support to the gadget framework"
+  introduces streaming support for the gadget driver.
+  Every usb_request has new field called stream_id which holds its id.
+  Every usb_ep has a field num_supported_strms which describes the max
+  number of streams supported (for this ep).
+  UAS is AFAIK the only gadget with streaming support.
+
+- Convert interrupt handler to per-ep-thread-irq
+
+  As it turns out some DWC3-commands ~1ms to complete. Currently we spin
+  until the command completes which is bad.
+
+  Implementation idea:
+  - dwc core implements a demultiplexing irq chip for interrupts per
+    endpoint. The interrupt numbers are allocated during probe and belong
+    to the device. If MSI provides per-endpoint interrupt this dummy
+    interrupt chip can be replaced with "real" interrupts.
+  - interrupts are requested / allocated on usb_ep_enable() and removed on
+    usb_ep_disable(). Worst case are 32 interrupts, the lower limit is two
+    for ep0/1.
+  - dwc3_send_gadget_ep_cmd() will sleep in wait_for_completion_timeout()
+    until the command completes.
+  - the interrupt handler is split into the following pieces:
+    - primary handler of the device
+      goes through every event and calls generic_handle_irq() for event
+      it. On return from generic_handle_irq() in acknowledges the event
+      counter so interrupt goes away (eventually).
+
+    - threaded handler of the device
+      none
+
+    - primary handler of the EP-interrupt
+      reads the event and tries to process it. Everything that requries
+      sleeping is handed over to the Thread. The event is saved in an
+      per-endpoint data-structure.
+      We probably have to pay attention not to process events once we
+      handed something to thread so we don't process event X prio Y
+      where X > Y.
+
+    - threaded handler of the EP-interrupt
+      handles the remaining EP work which might sleep such as waiting
+      for command completion.
+
+  Latency:
+   There should be no increase in latency since the interrupt-thread has a
+   high priority and will be run before an average task in user land
+   (except the user changed priorities).
index 0b06467c1e92292601105a394a5f7194aed4ba43..f4cac62241ff216edad86325051acdafea3326a7 100644 (file)
@@ -2144,6 +2144,14 @@ M:       Matthew Garrett <mjg59@srcf.ucam.org>
 S:     Maintained
 F:     drivers/platform/x86/dell-wmi.c
 
+DESIGNWARE USB3 DRD IP DRIVER
+M:     Felipe Balbi <balbi@ti.com>
+L:     linux-usb@vger.kernel.org
+L:     linux-omap@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
+S:     Maintained
+F:     drivers/usb/dwc3/
+
 DEVICE NUMBER REGISTRY
 M:     Torben Mathiasen <device@lanana.org>
 W:     http://lanana.org/docs/device-list/index.html
index 7f005843a7075d1ae1ec334fa694dd309acf3c92..7fb568d2845b0da8f86c2614b6072b9526b3ee5e 100644 (file)
@@ -35,6 +35,13 @@ extern struct pxa_device_desc pxa168_device_fb;
 extern struct pxa_device_desc pxa168_device_keypad;
 extern struct pxa_device_desc pxa168_device_eth;
 
+struct pxa168_usb_pdata {
+       /* If NULL, default phy init routine for PXA168 would be called */
+       int (*phy_init)(void __iomem *usb_phy_reg_base);
+};
+/* pdata can be NULL */
+int __init pxa168_add_usb_host(struct pxa168_usb_pdata *pdata);
+
 static inline int pxa168_add_uart(int id)
 {
        struct pxa_device_desc *d = NULL;
index 9581551678070d44c2e0f04e7394cda022f25d45..e6f67893736c3afa7d46a4dca9b6171b18eb2644 100644 (file)
@@ -24,6 +24,9 @@
 #include <mach/dma.h>
 #include <mach/devices.h>
 #include <mach/mfp.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <mach/pxa168.h>
 
 #include "common.h"
 #include "clock.h"
@@ -82,6 +85,7 @@ static APBC_CLK(keypad, PXA168_KPC, 0, 32000);
 static APMU_CLK(nand, NAND, 0x19b, 156000000);
 static APMU_CLK(lcd, LCD, 0x7f, 312000000);
 static APMU_CLK(eth, ETH, 0x09, 0);
+static APMU_CLK(usb, USB, 0x12, 0);
 
 /* device and clock bindings */
 static struct clk_lookup pxa168_clkregs[] = {
@@ -103,6 +107,7 @@ static struct clk_lookup pxa168_clkregs[] = {
        INIT_CLKREG(&clk_lcd, "pxa168-fb", NULL),
        INIT_CLKREG(&clk_keypad, "pxa27x-keypad", NULL),
        INIT_CLKREG(&clk_eth, "pxa168-eth", "MFUCLK"),
+       INIT_CLKREG(&clk_usb, "pxa168-ehci", "PXA168-USBCLK"),
 };
 
 static int __init pxa168_init(void)
@@ -168,3 +173,44 @@ PXA168_DEVICE(ssp5, "pxa168-ssp", 4, SSP5, 0xd4021000, 0x40, 60, 61);
 PXA168_DEVICE(fb, "pxa168-fb", -1, LCD, 0xd420b000, 0x1c8);
 PXA168_DEVICE(keypad, "pxa27x-keypad", -1, KEYPAD, 0xd4012000, 0x4c);
 PXA168_DEVICE(eth, "pxa168-eth", -1, MFU, 0xc0800000, 0x0fff);
+
+struct resource pxa168_usb_host_resources[] = {
+       /* USB Host conroller register base */
+       [0] = {
+               .start  = 0xd4209000,
+               .end    = 0xd4209000 + 0x200,
+               .flags  = IORESOURCE_MEM,
+               .name   = "pxa168-usb-host",
+       },
+       /* USB PHY register base */
+       [1] = {
+               .start  = 0xd4206000,
+               .end    = 0xd4206000 + 0xff,
+               .flags  = IORESOURCE_MEM,
+               .name   = "pxa168-usb-phy",
+       },
+       [2] = {
+               .start  = IRQ_PXA168_USB2,
+               .end    = IRQ_PXA168_USB2,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static u64 pxa168_usb_host_dmamask = DMA_BIT_MASK(32);
+struct platform_device pxa168_device_usb_host = {
+       .name = "pxa168-ehci",
+       .id   = -1,
+       .dev  = {
+               .dma_mask = &pxa168_usb_host_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+
+       .num_resources = ARRAY_SIZE(pxa168_usb_host_resources),
+       .resource      = pxa168_usb_host_resources,
+};
+
+int __init pxa168_add_usb_host(struct pxa168_usb_pdata *pdata)
+{
+       pxa168_device_usb_host.dev.platform_data = pdata;
+       return platform_device_register(&pxa168_device_usb_host);
+}
index 48f1781352f154e9820eda618696c9e3d486c0af..2651852952beb36528908a628ef7174792fec7b1 100644 (file)
@@ -69,6 +69,7 @@ config USB_ARCH_HAS_EHCI
        default y if ARCH_MSM
        default y if MICROBLAZE
        default y if SPARC_LEON
+       default y if ARCH_MMP
        default PCI
 
 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
@@ -110,6 +111,8 @@ config USB
 
 source "drivers/usb/core/Kconfig"
 
+source "drivers/usb/dwc3/Kconfig"
+
 source "drivers/usb/mon/Kconfig"
 
 source "drivers/usb/wusbcore/Kconfig"
index 30ddf8dc4f72ed139b381d7389bc9b9bfc322c34..969b0a50bc9865cf0f1da65941eb6cc1d637e17e 100644 (file)
@@ -6,6 +6,8 @@
 
 obj-$(CONFIG_USB)              += core/
 
+obj-$(CONFIG_USB_DWC3)         += dwc3/
+
 obj-$(CONFIG_USB_MON)          += mon/
 
 obj-$(CONFIG_PCI)              += host/
index 94e6c5c09dd8c80cd842db2e2fbf952bd029c634..f0f390c289d8646ec662c67586f06a43dec82237 100644 (file)
@@ -1058,11 +1058,11 @@ made_compressed_probe:
                goto alloc_fail;
        }
 
-       ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
-       readsize = le16_to_cpu(epread->wMaxPacketSize) *
+       ctrlsize = usb_endpoint_maxp(epctrl);
+       readsize = usb_endpoint_maxp(epread) *
                                (quirks == SINGLE_RX_URB ? 1 : 2);
        acm->combined_interfaces = combined_interfaces;
-       acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
+       acm->writesize = usb_endpoint_maxp(epwrite) * 20;
        acm->control = control_interface;
        acm->data = data_interface;
        acm->minor = minor;
index 42f180aca3fbe1dd7a7761174bd8db3caed7f724..efe684908c1f092f79937fb1b196bcc32fd4751d 100644 (file)
@@ -682,7 +682,7 @@ next_desc:
        if (!ep || !usb_endpoint_is_int_in(ep))
                goto err;
 
-       desc->wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize);
+       desc->wMaxPacketSize = usb_endpoint_maxp(ep);
        desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0;
 
        desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
index 3f94ac34dce31b80440689ae7f0d319a7d2f908c..12cf5e7395a82c5fcadee6e9b775a1fe5f6f079f 100644 (file)
@@ -186,8 +186,7 @@ static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
        for (n = 0; n < current_setting->desc.bNumEndpoints; n++)
                if (current_setting->endpoint[n].desc.bEndpointAddress ==
                        data->bulk_in)
-                       max_size = le16_to_cpu(current_setting->endpoint[n].
-                                               desc.wMaxPacketSize);
+                       max_size = usb_endpoint_maxp(&current_setting->endpoint[n].desc);
 
        if (max_size == 0) {
                dev_err(dev, "Couldn't get wMaxPacketSize\n");
@@ -636,7 +635,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data *data)
        for (n = 0; n < current_setting->desc.bNumEndpoints; n++) {
                desc = &current_setting->endpoint[n].desc;
                if (desc->bEndpointAddress == data->bulk_in)
-                       max_size = le16_to_cpu(desc->wMaxPacketSize);
+                       max_size = usb_endpoint_maxp(desc);
        }
 
        if (max_size == 0) {
index 26678cadfb215340e35a9b56f5fe23954a13cdd9..9d5e07af55be0c154dab101ff11d85ee0bc95639 100644 (file)
@@ -124,9 +124,9 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
 
        if (usb_endpoint_xfer_isoc(&ep->desc))
                max_tx = (desc->bMaxBurst + 1) * (desc->bmAttributes + 1) *
-                       le16_to_cpu(ep->desc.wMaxPacketSize);
+                       usb_endpoint_maxp(&ep->desc);
        else if (usb_endpoint_xfer_int(&ep->desc))
-               max_tx = le16_to_cpu(ep->desc.wMaxPacketSize) *
+               max_tx = usb_endpoint_maxp(&ep->desc) *
                        (desc->bMaxBurst + 1);
        else
                max_tx = 999999;
@@ -241,7 +241,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
                    cfgno, inum, asnum, d->bEndpointAddress);
                endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;
                endpoint->desc.bInterval = 1;
-               if (le16_to_cpu(endpoint->desc.wMaxPacketSize) > 8)
+               if (usb_endpoint_maxp(&endpoint->desc) > 8)
                        endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
        }
 
@@ -254,7 +254,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
                        && usb_endpoint_xfer_bulk(d)) {
                unsigned maxp;
 
-               maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize) & 0x07ff;
+               maxp = usb_endpoint_maxp(&endpoint->desc) & 0x07ff;
                if (maxp != 512)
                        dev_warn(ddev, "config %d interface %d altsetting %d "
                                "bulk endpoint 0x%X has invalid maxpacket %d\n",
index 0149c0976e9ccbfa5e27cc4375933b243b3f7200..d9569658476274f34d8a51726da828d87bf44831 100644 (file)
@@ -190,7 +190,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
        dir = usb_endpoint_dir_in(desc) ? 'I' : 'O';
 
        if (speed == USB_SPEED_HIGH) {
-               switch (le16_to_cpu(desc->wMaxPacketSize) & (0x03 << 11)) {
+               switch (usb_endpoint_maxp(desc) & (0x03 << 11)) {
                case 1 << 11:
                        bandwidth = 2; break;
                case 2 << 11:
@@ -240,7 +240,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
 
        start += sprintf(start, format_endpt, desc->bEndpointAddress, dir,
                         desc->bmAttributes, type,
-                        (le16_to_cpu(desc->wMaxPacketSize) & 0x07ff) *
+                        (usb_endpoint_maxp(desc) & 0x07ff) *
                         bandwidth,
                         interval, unit);
        return start;
index df502a98d0df0611e206d7e32e12c1bf1a5b39df..db7fe50c23d4df96a90faddf880507ccfdd55d26 100644 (file)
@@ -56,7 +56,7 @@ static ssize_t show_ep_wMaxPacketSize(struct device *dev,
 {
        struct ep_device *ep = to_ep_device(dev);
        return sprintf(buf, "%04x\n",
-                       le16_to_cpu(ep->desc->wMaxPacketSize) & 0x07ff);
+                       usb_endpoint_maxp(ep->desc) & 0x07ff);
 }
 static DEVICE_ATTR(wMaxPacketSize, S_IRUGO, show_ep_wMaxPacketSize, NULL);
 
index ee50e0bf84e8cac59657a6033da50e75a2ce90bd..5ca3714a2febd7106a6541827cb154b7c1c7ee6e 100644 (file)
@@ -1636,11 +1636,6 @@ void usb_disconnect(struct usb_device **pdev)
        int                     i;
        struct usb_hcd          *hcd = bus_to_hcd(udev->bus);
 
-       if (!udev) {
-               pr_debug ("%s nodev\n", __func__);
-               return;
-       }
-
        /* mark the device as inactive, so any further urb submissions for
         * this device (and any of its children) will fail immediately.
         * this quiesces everything except pending urbs.
@@ -3023,7 +3018,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
                i = 512;
        else
                i = udev->descriptor.bMaxPacketSize0;
-       if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
+       if (usb_endpoint_maxp(&udev->ep0.desc) != i) {
                if (udev->speed == USB_SPEED_LOW ||
                                !(i == 8 || i == 16 || i == 32 || i == 64)) {
                        dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", i);
index ae334b067c13e873a2105497cf38a673a5f65f57..909625b91eb35a3a4096029d3fd46e0a6cb25bb4 100644 (file)
@@ -350,7 +350,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                        dev->state < USB_STATE_CONFIGURED)
                return -ENODEV;
 
-       max = le16_to_cpu(ep->desc.wMaxPacketSize);
+       max = usb_endpoint_maxp(&ep->desc);
        if (max <= 0) {
                dev_dbg(&dev->dev,
                        "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
new file mode 100644 (file)
index 0000000..3c1d67d
--- /dev/null
@@ -0,0 +1,25 @@
+config USB_DWC3
+       tristate "DesignWare USB3 DRD Core Support"
+       depends on (USB || USB_GADGET)
+       select USB_OTG_UTILS
+       help
+         Say Y or M here if your system has a Dual Role SuperSpeed
+         USB controller based on the DesignWare USB3 IP Core.
+
+         If you choose to build this driver is a dynamically linked
+         module, the module will be called dwc3.ko.
+
+if USB_DWC3
+
+config USB_DWC3_DEBUG
+       bool "Enable Debugging Messages"
+       help
+         Say Y here to enable debugging messages on DWC3 Driver.
+
+config USB_DWC3_VERBOSE
+       bool "Enable Verbose Debugging Messages"
+       depends on USB_DWC3_DEBUG
+       help
+         Say Y here to enable verbose debugging messages on DWC3 Driver.
+
+endif
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
new file mode 100644 (file)
index 0000000..593d1db
--- /dev/null
@@ -0,0 +1,36 @@
+ccflags-$(CONFIG_USB_DWC3_DEBUG)       := -DDEBUG
+ccflags-$(CONFIG_USB_DWC3_VERBOSE)     += -DVERBOSE_DEBUG
+
+obj-$(CONFIG_USB_DWC3)                 += dwc3.o
+
+dwc3-y                                 := core.o
+
+ifneq ($(CONFIG_USB_GADGET_DWC3),)
+       dwc3-y                          += gadget.o ep0.o
+endif
+
+ifneq ($(CONFIG_DEBUG_FS),)
+       dwc3-y                          += debugfs.o
+endif
+
+##
+# Platform-specific glue layers go here
+#
+# NOTICE: Make sure your glue layer doesn't depend on anything
+# which is arch-specific and that it compiles on all situations.
+#
+# We want to keep this requirement in order to be able to compile
+# the entire driver (with all its glue layers) on several architectures
+# and make sure it compiles fine. This will also help with allmodconfig
+# and allyesconfig builds.
+#
+# The only exception is the PCI glue layer, but that's only because
+# PCI doesn't provide nops if CONFIG_PCI isn't enabled.
+##
+
+obj-$(CONFIG_USB_DWC3)         += dwc3-omap.o
+
+ifneq ($(CONFIG_PCI),)
+       obj-$(CONFIG_USB_DWC3)          += dwc3-pci.o
+endif
+
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
new file mode 100644 (file)
index 0000000..443e4fb
--- /dev/null
@@ -0,0 +1,467 @@
+/**
+ * core.c - DesignWare USB3 DRD Controller Core file
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ * All rights reserved.
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+#include "debug.h"
+
+/**
+ * dwc3_core_soft_reset - Issues core soft reset and PHY reset
+ * @dwc: pointer to our context structure
+ */
+static void dwc3_core_soft_reset(struct dwc3 *dwc)
+{
+       u32             reg;
+
+       /* Before Resetting PHY, put Core in Reset */
+       reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+       reg |= DWC3_GCTL_CORESOFTRESET;
+       dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+       /* Assert USB3 PHY reset */
+       reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+       reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
+       dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+       /* Assert USB2 PHY reset */
+       reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+       reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
+       dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+       mdelay(100);
+
+       /* Clear USB3 PHY reset */
+       reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+       reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
+       dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+       /* Clear USB2 PHY reset */
+       reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+       reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
+       dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+       /* After PHYs are stable we can take Core out of reset state */
+       reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+       reg &= ~DWC3_GCTL_CORESOFTRESET;
+       dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+}
+
+/**
+ * dwc3_free_one_event_buffer - Frees one event buffer
+ * @dwc: Pointer to our controller context structure
+ * @evt: Pointer to event buffer to be freed
+ */
+static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
+               struct dwc3_event_buffer *evt)
+{
+       dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
+       kfree(evt);
+}
+
+/**
+ * dwc3_alloc_one_event_buffer - Allocated one event buffer structure
+ * @dwc: Pointer to our controller context structure
+ * @length: size of the event buffer
+ *
+ * Returns a pointer to the allocated event buffer structure on succes
+ * otherwise ERR_PTR(errno).
+ */
+static struct dwc3_event_buffer *__devinit
+dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length)
+{
+       struct dwc3_event_buffer        *evt;
+
+       evt = kzalloc(sizeof(*evt), GFP_KERNEL);
+       if (!evt)
+               return ERR_PTR(-ENOMEM);
+
+       evt->dwc        = dwc;
+       evt->length     = length;
+       evt->buf        = dma_alloc_coherent(dwc->dev, length,
+                       &evt->dma, GFP_KERNEL);
+       if (!evt->buf) {
+               kfree(evt);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       return evt;
+}
+
+/**
+ * dwc3_free_event_buffers - frees all allocated event buffers
+ * @dwc: Pointer to our controller context structure
+ */
+static void dwc3_free_event_buffers(struct dwc3 *dwc)
+{
+       struct dwc3_event_buffer        *evt;
+       int i;
+
+       for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) {
+               evt = dwc->ev_buffs[i];
+               if (evt) {
+                       dwc3_free_one_event_buffer(dwc, evt);
+                       dwc->ev_buffs[i] = NULL;
+               }
+       }
+}
+
+/**
+ * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
+ * @dwc: Pointer to out controller context structure
+ * @num: number of event buffers to allocate
+ * @length: size of event buffer
+ *
+ * Returns 0 on success otherwise negative errno. In error the case, dwc
+ * may contain some buffers allocated but not all which were requested.
+ */
+static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned num,
+               unsigned length)
+{
+       int                     i;
+
+       for (i = 0; i < num; i++) {
+               struct dwc3_event_buffer        *evt;
+
+               evt = dwc3_alloc_one_event_buffer(dwc, length);
+               if (IS_ERR(evt)) {
+                       dev_err(dwc->dev, "can't allocate event buffer\n");
+                       return PTR_ERR(evt);
+               }
+               dwc->ev_buffs[i] = evt;
+       }
+
+       return 0;
+}
+
+/**
+ * dwc3_event_buffers_setup - setup our allocated event buffers
+ * @dwc: Pointer to out controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)
+{
+       struct dwc3_event_buffer        *evt;
+       int                             n;
+
+       for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
+               evt = dwc->ev_buffs[n];
+               dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
+                               evt->buf, (unsigned long long) evt->dma,
+                               evt->length);
+
+               dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
+                               lower_32_bits(evt->dma));
+               dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
+                               upper_32_bits(evt->dma));
+               dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
+                               evt->length & 0xffff);
+               dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
+       }
+
+       return 0;
+}
+
+static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
+{
+       struct dwc3_event_buffer        *evt;
+       int                             n;
+
+       for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
+               evt = dwc->ev_buffs[n];
+               dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
+               dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
+               dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
+               dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
+       }
+}
+
+/**
+ * dwc3_core_init - Low-level initialization of DWC3 Core
+ * @dwc: Pointer to our controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int __devinit dwc3_core_init(struct dwc3 *dwc)
+{
+       unsigned long           timeout;
+       u32                     reg;
+       int                     ret;
+
+       dwc3_core_soft_reset(dwc);
+
+       /* issue device SoftReset too */
+       timeout = jiffies + msecs_to_jiffies(500);
+       dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
+       do {
+               reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+               if (!(reg & DWC3_DCTL_CSFTRST))
+                       break;
+
+               if (time_after(jiffies, timeout)) {
+                       dev_err(dwc->dev, "Reset Timed Out\n");
+                       ret = -ETIMEDOUT;
+                       goto err0;
+               }
+
+               cpu_relax();
+       } while (true);
+
+       reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
+       /* This should read as U3 followed by revision number */
+       if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
+               dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
+               ret = -ENODEV;
+               goto err0;
+       }
+
+       dwc->revision = reg & DWC3_GSNPSREV_MASK;
+
+       ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_NUM,
+                       DWC3_EVENT_BUFFERS_SIZE);
+       if (ret) {
+               dev_err(dwc->dev, "failed to allocate event buffers\n");
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       ret = dwc3_event_buffers_setup(dwc);
+       if (ret) {
+               dev_err(dwc->dev, "failed to setup event buffers\n");
+               goto err1;
+       }
+
+       return 0;
+
+err1:
+       dwc3_free_event_buffers(dwc);
+
+err0:
+       return ret;
+}
+
+static void dwc3_core_exit(struct dwc3 *dwc)
+{
+       dwc3_event_buffers_cleanup(dwc);
+       dwc3_free_event_buffers(dwc);
+}
+
+#define DWC3_ALIGN_MASK                (16 - 1)
+
+static int __devinit dwc3_probe(struct platform_device *pdev)
+{
+       const struct platform_device_id *id = platform_get_device_id(pdev);
+       struct resource         *res;
+       struct dwc3             *dwc;
+       void __iomem            *regs;
+       unsigned int            features = id->driver_data;
+       int                     ret = -ENOMEM;
+       int                     irq;
+       void                    *mem;
+
+       mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
+       if (!mem) {
+               dev_err(&pdev->dev, "not enough memory\n");
+               goto err0;
+       }
+       dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
+       dwc->mem = mem;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "missing resource\n");
+               goto err1;
+       }
+
+       res = request_mem_region(res->start, resource_size(res),
+                       dev_name(&pdev->dev));
+       if (!res) {
+               dev_err(&pdev->dev, "can't request mem region\n");
+               goto err1;
+       }
+
+       regs = ioremap(res->start, resource_size(res));
+       if (!regs) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               goto err2;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "missing IRQ\n");
+               goto err3;
+       }
+
+       spin_lock_init(&dwc->lock);
+       platform_set_drvdata(pdev, dwc);
+
+       dwc->regs       = regs;
+       dwc->regs_size  = resource_size(res);
+       dwc->dev        = &pdev->dev;
+       dwc->irq        = irq;
+
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
+       pm_runtime_forbid(&pdev->dev);
+
+       ret = dwc3_core_init(dwc);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to initialize core\n");
+               goto err3;
+       }
+
+       if (features & DWC3_HAS_PERIPHERAL) {
+               ret = dwc3_gadget_init(dwc);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to initialized gadget\n");
+                       goto err4;
+               }
+       }
+
+       ret = dwc3_debugfs_init(dwc);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to initialize debugfs\n");
+               goto err5;
+       }
+
+       pm_runtime_allow(&pdev->dev);
+
+       return 0;
+
+err5:
+       if (features & DWC3_HAS_PERIPHERAL)
+               dwc3_gadget_exit(dwc);
+
+err4:
+       dwc3_core_exit(dwc);
+
+err3:
+       iounmap(regs);
+
+err2:
+       release_mem_region(res->start, resource_size(res));
+
+err1:
+       kfree(dwc->mem);
+
+err0:
+       return ret;
+}
+
+static int __devexit dwc3_remove(struct platform_device *pdev)
+{
+       const struct platform_device_id *id = platform_get_device_id(pdev);
+       struct dwc3     *dwc = platform_get_drvdata(pdev);
+       struct resource *res;
+       unsigned int    features = id->driver_data;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       pm_runtime_put(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+
+       dwc3_debugfs_exit(dwc);
+
+       if (features & DWC3_HAS_PERIPHERAL)
+               dwc3_gadget_exit(dwc);
+
+       dwc3_core_exit(dwc);
+       release_mem_region(res->start, resource_size(res));
+       iounmap(dwc->regs);
+       kfree(dwc->mem);
+
+       return 0;
+}
+
+static const struct platform_device_id dwc3_id_table[] __devinitconst = {
+       {
+               .name   = "dwc3-omap",
+               .driver_data = (DWC3_HAS_PERIPHERAL
+                       | DWC3_HAS_XHCI
+                       | DWC3_HAS_OTG),
+       },
+       {
+               .name   = "dwc3-pci",
+               .driver_data = DWC3_HAS_PERIPHERAL,
+       },
+       {  },   /* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(platform, dwc3_id_table);
+
+static struct platform_driver dwc3_driver = {
+       .probe          = dwc3_probe,
+       .remove         = __devexit_p(dwc3_remove),
+       .driver         = {
+               .name   = "dwc3",
+       },
+       .id_table       = dwc3_id_table,
+};
+
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
+
+static int __devinit dwc3_init(void)
+{
+       return platform_driver_register(&dwc3_driver);
+}
+module_init(dwc3_init);
+
+static void __exit dwc3_exit(void)
+{
+       platform_driver_unregister(&dwc3_driver);
+}
+module_exit(dwc3_exit);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
new file mode 100644 (file)
index 0000000..83b2960
--- /dev/null
@@ -0,0 +1,709 @@
+/**
+ * core.h - DesignWare USB3 DRD Core Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ * All rights reserved.
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DRIVERS_USB_DWC3_CORE_H
+#define __DRIVERS_USB_DWC3_CORE_H
+
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/debugfs.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/* Global constants */
+#define DWC3_ENDPOINTS_NUM     32
+
+#define DWC3_EVENT_BUFFERS_NUM 2
+#define DWC3_EVENT_BUFFERS_SIZE        PAGE_SIZE
+#define DWC3_EVENT_TYPE_MASK   0xfe
+
+#define DWC3_EVENT_TYPE_DEV    0
+#define DWC3_EVENT_TYPE_CARKIT 3
+#define DWC3_EVENT_TYPE_I2C    4
+
+#define DWC3_DEVICE_EVENT_DISCONNECT           0
+#define DWC3_DEVICE_EVENT_RESET                        1
+#define DWC3_DEVICE_EVENT_CONNECT_DONE         2
+#define DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE   3
+#define DWC3_DEVICE_EVENT_WAKEUP               4
+#define DWC3_DEVICE_EVENT_EOPF                 6
+#define DWC3_DEVICE_EVENT_SOF                  7
+#define DWC3_DEVICE_EVENT_ERRATIC_ERROR                9
+#define DWC3_DEVICE_EVENT_CMD_CMPL             10
+#define DWC3_DEVICE_EVENT_OVERFLOW             11
+
+#define DWC3_GEVNTCOUNT_MASK   0xfffc
+#define DWC3_GSNPSID_MASK      0xffff0000
+#define DWC3_GSNPSREV_MASK     0xffff
+
+/* Global Registers */
+#define DWC3_GSBUSCFG0         0xc100
+#define DWC3_GSBUSCFG1         0xc104
+#define DWC3_GTXTHRCFG         0xc108
+#define DWC3_GRXTHRCFG         0xc10c
+#define DWC3_GCTL              0xc110
+#define DWC3_GEVTEN            0xc114
+#define DWC3_GSTS              0xc118
+#define DWC3_GSNPSID           0xc120
+#define DWC3_GGPIO             0xc124
+#define DWC3_GUID              0xc128
+#define DWC3_GUCTL             0xc12c
+#define DWC3_GBUSERRADDR0      0xc130
+#define DWC3_GBUSERRADDR1      0xc134
+#define DWC3_GPRTBIMAP0                0xc138
+#define DWC3_GPRTBIMAP1                0xc13c
+#define DWC3_GHWPARAMS0                0xc140
+#define DWC3_GHWPARAMS1                0xc144
+#define DWC3_GHWPARAMS2                0xc148
+#define DWC3_GHWPARAMS3                0xc14c
+#define DWC3_GHWPARAMS4                0xc150
+#define DWC3_GHWPARAMS5                0xc154
+#define DWC3_GHWPARAMS6                0xc158
+#define DWC3_GHWPARAMS7                0xc15c
+#define DWC3_GDBGFIFOSPACE     0xc160
+#define DWC3_GDBGLTSSM         0xc164
+#define DWC3_GPRTBIMAP_HS0     0xc180
+#define DWC3_GPRTBIMAP_HS1     0xc184
+#define DWC3_GPRTBIMAP_FS0     0xc188
+#define DWC3_GPRTBIMAP_FS1     0xc18c
+
+#define DWC3_GUSB2PHYCFG(n)    (0xc200 + (n * 0x04))
+#define DWC3_GUSB2I2CCTL(n)    (0xc240 + (n * 0x04))
+
+#define DWC3_GUSB2PHYACC(n)    (0xc280 + (n * 0x04))
+
+#define DWC3_GUSB3PIPECTL(n)   (0xc2c0 + (n * 0x04))
+
+#define DWC3_GTXFIFOSIZ(n)     (0xc300 + (n * 0x04))
+#define DWC3_GRXFIFOSIZ(n)     (0xc380 + (n * 0x04))
+
+#define DWC3_GEVNTADRLO(n)     (0xc400 + (n * 0x10))
+#define DWC3_GEVNTADRHI(n)     (0xc404 + (n * 0x10))
+#define DWC3_GEVNTSIZ(n)       (0xc408 + (n * 0x10))
+#define DWC3_GEVNTCOUNT(n)     (0xc40c + (n * 0x10))
+
+#define DWC3_GHWPARAMS8                0xc600
+
+/* Device Registers */
+#define DWC3_DCFG              0xc700
+#define DWC3_DCTL              0xc704
+#define DWC3_DEVTEN            0xc708
+#define DWC3_DSTS              0xc70c
+#define DWC3_DGCMDPAR          0xc710
+#define DWC3_DGCMD             0xc714
+#define DWC3_DALEPENA          0xc720
+#define DWC3_DEPCMDPAR2(n)     (0xc800 + (n * 0x10))
+#define DWC3_DEPCMDPAR1(n)     (0xc804 + (n * 0x10))
+#define DWC3_DEPCMDPAR0(n)     (0xc808 + (n * 0x10))
+#define DWC3_DEPCMD(n)         (0xc80c + (n * 0x10))
+
+/* OTG Registers */
+#define DWC3_OCFG              0xcc00
+#define DWC3_OCTL              0xcc04
+#define DWC3_OEVTEN            0xcc08
+#define DWC3_OSTS              0xcc0C
+
+/* Bit fields */
+
+/* Global Configuration Register */
+#define DWC3_GCTL_PWRDNSCALE(n)        (n << 19)
+#define DWC3_GCTL_U2RSTECN     16
+#define DWC3_GCTL_RAMCLKSEL(x) ((x & DWC3_GCTL_CLK_MASK) << 6)
+#define DWC3_GCTL_CLK_BUS      (0)
+#define DWC3_GCTL_CLK_PIPE     (1)
+#define DWC3_GCTL_CLK_PIPEHALF (2)
+#define DWC3_GCTL_CLK_MASK     (3)
+
+#define DWC3_GCTL_PRTCAPDIR(n) (n << 12)
+#define DWC3_GCTL_PRTCAP_HOST  1
+#define DWC3_GCTL_PRTCAP_DEVICE        2
+#define DWC3_GCTL_PRTCAP_OTG   3
+
+#define DWC3_GCTL_CORESOFTRESET        (1 << 11)
+#define DWC3_GCTL_DISSCRAMBLE  (1 << 3)
+
+/* Global USB2 PHY Configuration Register */
+#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
+#define DWC3_GUSB2PHYCFG_SUSPHY        (1 << 6)
+
+/* Global USB3 PIPE Control Register */
+#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
+#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
+
+/* Device Configuration Register */
+#define DWC3_DCFG_DEVADDR(addr)        ((addr) << 3)
+#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
+
+#define DWC3_DCFG_SPEED_MASK   (7 << 0)
+#define DWC3_DCFG_SUPERSPEED   (4 << 0)
+#define DWC3_DCFG_HIGHSPEED    (0 << 0)
+#define DWC3_DCFG_FULLSPEED2   (1 << 0)
+#define DWC3_DCFG_LOWSPEED     (2 << 0)
+#define DWC3_DCFG_FULLSPEED1   (3 << 0)
+
+/* Device Control Register */
+#define DWC3_DCTL_RUN_STOP     (1 << 31)
+#define DWC3_DCTL_CSFTRST      (1 << 30)
+#define DWC3_DCTL_LSFTRST      (1 << 29)
+
+#define DWC3_DCTL_HIRD_THRES_MASK      (0x1f << 24)
+#define DWC3_DCTL_HIRD_THRES(n)        (((n) & DWC3_DCTL_HIRD_THRES_MASK) >> 24)
+
+#define DWC3_DCTL_APPL1RES     (1 << 23)
+
+#define DWC3_DCTL_INITU2ENA    (1 << 12)
+#define DWC3_DCTL_ACCEPTU2ENA  (1 << 11)
+#define DWC3_DCTL_INITU1ENA    (1 << 10)
+#define DWC3_DCTL_ACCEPTU1ENA  (1 << 9)
+#define DWC3_DCTL_TSTCTRL_MASK (0xf << 1)
+
+#define DWC3_DCTL_ULSTCHNGREQ_MASK     (0x0f << 5)
+#define DWC3_DCTL_ULSTCHNGREQ(n) (((n) << 5) & DWC3_DCTL_ULSTCHNGREQ_MASK)
+
+#define DWC3_DCTL_ULSTCHNG_NO_ACTION   (DWC3_DCTL_ULSTCHNGREQ(0))
+#define DWC3_DCTL_ULSTCHNG_SS_DISABLED (DWC3_DCTL_ULSTCHNGREQ(4))
+#define DWC3_DCTL_ULSTCHNG_RX_DETECT   (DWC3_DCTL_ULSTCHNGREQ(5))
+#define DWC3_DCTL_ULSTCHNG_SS_INACTIVE (DWC3_DCTL_ULSTCHNGREQ(6))
+#define DWC3_DCTL_ULSTCHNG_RECOVERY    (DWC3_DCTL_ULSTCHNGREQ(8))
+#define DWC3_DCTL_ULSTCHNG_COMPLIANCE  (DWC3_DCTL_ULSTCHNGREQ(10))
+#define DWC3_DCTL_ULSTCHNG_LOOPBACK    (DWC3_DCTL_ULSTCHNGREQ(11))
+
+/* Device Event Enable Register */
+#define DWC3_DEVTEN_VNDRDEVTSTRCVEDEN  (1 << 12)
+#define DWC3_DEVTEN_EVNTOVERFLOWEN     (1 << 11)
+#define DWC3_DEVTEN_CMDCMPLTEN         (1 << 10)
+#define DWC3_DEVTEN_ERRTICERREN                (1 << 9)
+#define DWC3_DEVTEN_SOFEN              (1 << 7)
+#define DWC3_DEVTEN_EOPFEN             (1 << 6)
+#define DWC3_DEVTEN_WKUPEVTEN          (1 << 4)
+#define DWC3_DEVTEN_ULSTCNGEN          (1 << 3)
+#define DWC3_DEVTEN_CONNECTDONEEN      (1 << 2)
+#define DWC3_DEVTEN_USBRSTEN           (1 << 1)
+#define DWC3_DEVTEN_DISCONNEVTEN       (1 << 0)
+
+/* Device Status Register */
+#define DWC3_DSTS_PWRUPREQ             (1 << 24)
+#define DWC3_DSTS_COREIDLE             (1 << 23)
+#define DWC3_DSTS_DEVCTRLHLT           (1 << 22)
+
+#define DWC3_DSTS_USBLNKST_MASK                (0x0f << 18)
+#define DWC3_DSTS_USBLNKST(n)          (((n) & DWC3_DSTS_USBLNKST_MASK) >> 18)
+
+#define DWC3_DSTS_RXFIFOEMPTY          (1 << 17)
+
+#define DWC3_DSTS_SOFFN_MASK           (0x3ff << 3)
+#define DWC3_DSTS_SOFFN(n)             (((n) & DWC3_DSTS_SOFFN_MASK) >> 3)
+
+#define DWC3_DSTS_CONNECTSPD           (7 << 0)
+
+#define DWC3_DSTS_SUPERSPEED           (4 << 0)
+#define DWC3_DSTS_HIGHSPEED            (0 << 0)
+#define DWC3_DSTS_FULLSPEED2           (1 << 0)
+#define DWC3_DSTS_LOWSPEED             (2 << 0)
+#define DWC3_DSTS_FULLSPEED1           (3 << 0)
+
+/* Device Generic Command Register */
+#define DWC3_DGCMD_SET_LMP             0x01
+#define DWC3_DGCMD_SET_PERIODIC_PAR    0x02
+#define DWC3_DGCMD_XMIT_FUNCTION       0x03
+#define DWC3_DGCMD_SELECTED_FIFO_FLUSH 0x09
+#define DWC3_DGCMD_ALL_FIFO_FLUSH      0x0a
+#define DWC3_DGCMD_SET_ENDPOINT_NRDY   0x0c
+#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK        0x10
+
+/* Device Endpoint Command Register */
+#define DWC3_DEPCMD_PARAM_SHIFT                16
+#define DWC3_DEPCMD_PARAM(x)           (x << DWC3_DEPCMD_PARAM_SHIFT)
+#define DWC3_DEPCMD_GET_RSC_IDX(x)     ((x >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
+#define DWC3_DEPCMD_STATUS_MASK                (0x0f << 12)
+#define DWC3_DEPCMD_STATUS(x)          ((x & DWC3_DEPCMD_STATUS_MASK) >> 12)
+#define DWC3_DEPCMD_HIPRI_FORCERM      (1 << 11)
+#define DWC3_DEPCMD_CMDACT             (1 << 10)
+#define DWC3_DEPCMD_CMDIOC             (1 << 8)
+
+#define DWC3_DEPCMD_DEPSTARTCFG                (0x09 << 0)
+#define DWC3_DEPCMD_ENDTRANSFER                (0x08 << 0)
+#define DWC3_DEPCMD_UPDATETRANSFER     (0x07 << 0)
+#define DWC3_DEPCMD_STARTTRANSFER      (0x06 << 0)
+#define DWC3_DEPCMD_CLEARSTALL         (0x05 << 0)
+#define DWC3_DEPCMD_SETSTALL           (0x04 << 0)
+#define DWC3_DEPCMD_GETSEQNUMBER       (0x03 << 0)
+#define DWC3_DEPCMD_SETTRANSFRESOURCE  (0x02 << 0)
+#define DWC3_DEPCMD_SETEPCONFIG                (0x01 << 0)
+
+/* The EP number goes 0..31 so ep0 is always out and ep1 is always in */
+#define DWC3_DALEPENA_EP(n)            (1 << n)
+
+#define DWC3_DEPCMD_TYPE_CONTROL       0
+#define DWC3_DEPCMD_TYPE_ISOC          1
+#define DWC3_DEPCMD_TYPE_BULK          2
+#define DWC3_DEPCMD_TYPE_INTR          3
+
+/* Structures */
+
+struct dwc3_trb_hw;
+
+/**
+ * struct dwc3_event_buffer - Software event buffer representation
+ * @list: a list of event buffers
+ * @buf: _THE_ buffer
+ * @length: size of this buffer
+ * @dma: dma_addr_t
+ * @dwc: pointer to DWC controller
+ */
+struct dwc3_event_buffer {
+       void                    *buf;
+       unsigned                length;
+       unsigned int            lpos;
+
+       dma_addr_t              dma;
+
+       struct dwc3             *dwc;
+};
+
+#define DWC3_EP_FLAG_STALLED   (1 << 0)
+#define DWC3_EP_FLAG_WEDGED    (1 << 1)
+
+#define DWC3_EP_DIRECTION_TX   true
+#define DWC3_EP_DIRECTION_RX   false
+
+#define DWC3_TRB_NUM           32
+#define DWC3_TRB_MASK          (DWC3_TRB_NUM - 1)
+
+/**
+ * struct dwc3_ep - device side endpoint representation
+ * @endpoint: usb endpoint
+ * @request_list: list of requests for this endpoint
+ * @req_queued: list of requests on this ep which have TRBs setup
+ * @trb_pool: array of transaction buffers
+ * @trb_pool_dma: dma address of @trb_pool
+ * @free_slot: next slot which is going to be used
+ * @busy_slot: first slot which is owned by HW
+ * @desc: usb_endpoint_descriptor pointer
+ * @dwc: pointer to DWC controller
+ * @flags: endpoint flags (wedged, stalled, ...)
+ * @current_trb: index of current used trb
+ * @number: endpoint number (1 - 15)
+ * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
+ * @res_trans_idx: Resource transfer index
+ * @interval: the intervall on which the ISOC transfer is started
+ * @name: a human readable name e.g. ep1out-bulk
+ * @direction: true for TX, false for RX
+ */
+struct dwc3_ep {
+       struct usb_ep           endpoint;
+       struct list_head        request_list;
+       struct list_head        req_queued;
+
+       struct dwc3_trb_hw      *trb_pool;
+       dma_addr_t              trb_pool_dma;
+       u32                     free_slot;
+       u32                     busy_slot;
+       const struct usb_endpoint_descriptor *desc;
+       struct dwc3             *dwc;
+
+       unsigned                flags;
+#define DWC3_EP_ENABLED                (1 << 0)
+#define DWC3_EP_STALL          (1 << 1)
+#define DWC3_EP_WEDGE          (1 << 2)
+#define DWC3_EP_BUSY           (1 << 4)
+#define DWC3_EP_PENDING_REQUEST        (1 << 5)
+#define DWC3_EP_WILL_SHUTDOWN  (1 << 6)
+
+       unsigned                current_trb;
+
+       u8                      number;
+       u8                      type;
+       u8                      res_trans_idx;
+       u32                     interval;
+
+       char                    name[20];
+
+       unsigned                direction:1;
+};
+
+enum dwc3_phy {
+       DWC3_PHY_UNKNOWN = 0,
+       DWC3_PHY_USB3,
+       DWC3_PHY_USB2,
+};
+
+enum dwc3_ep0_state {
+       EP0_UNCONNECTED         = 0,
+       EP0_IDLE,
+       EP0_IN_DATA_PHASE,
+       EP0_OUT_DATA_PHASE,
+       EP0_IN_WAIT_GADGET,
+       EP0_OUT_WAIT_GADGET,
+       EP0_IN_WAIT_NRDY,
+       EP0_OUT_WAIT_NRDY,
+       EP0_IN_STATUS_PHASE,
+       EP0_OUT_STATUS_PHASE,
+       EP0_STALL,
+};
+
+enum dwc3_link_state {
+       /* In SuperSpeed */
+       DWC3_LINK_STATE_U0              = 0x00, /* in HS, means ON */
+       DWC3_LINK_STATE_U1              = 0x01,
+       DWC3_LINK_STATE_U2              = 0x02, /* in HS, means SLEEP */
+       DWC3_LINK_STATE_U3              = 0x03, /* in HS, means SUSPEND */
+       DWC3_LINK_STATE_SS_DIS          = 0x04,
+       DWC3_LINK_STATE_RX_DET          = 0x05, /* in HS, means Early Suspend */
+       DWC3_LINK_STATE_SS_INACT        = 0x06,
+       DWC3_LINK_STATE_POLL            = 0x07,
+       DWC3_LINK_STATE_RECOV           = 0x08,
+       DWC3_LINK_STATE_HRESET          = 0x09,
+       DWC3_LINK_STATE_CMPLY           = 0x0a,
+       DWC3_LINK_STATE_LPBK            = 0x0b,
+       DWC3_LINK_STATE_MASK            = 0x0f,
+};
+
+enum dwc3_device_state {
+       DWC3_DEFAULT_STATE,
+       DWC3_ADDRESS_STATE,
+       DWC3_CONFIGURED_STATE,
+};
+
+/**
+ * struct dwc3_trb - transfer request block
+ * @bpl: lower 32bit of the buffer
+ * @bph: higher 32bit of the buffer
+ * @length: buffer size (up to 16mb - 1)
+ * @pcm1: packet count m1
+ * @trbsts: trb status
+ *     0 = ok
+ *     1 = missed isoc
+ *     2 = setup pending
+ * @hwo: hardware owner of descriptor
+ * @lst: last trb
+ * @chn: chain buffers
+ * @csp: continue on short packets (only supported on isoc eps)
+ * @trbctl: trb control
+ *     1 = normal
+ *     2 = control-setup
+ *     3 = control-status-2
+ *     4 = control-status-3
+ *     5 = control-data (first trb of data stage)
+ *     6 = isochronous-first (first trb of service interval)
+ *     7 = isochronous
+ *     8 = link trb
+ *     others = reserved
+ * @isp_imi: interrupt on short packet / interrupt on missed isoc
+ * @ioc: interrupt on complete
+ * @sid_sofn: Stream ID / SOF Number
+ */
+struct dwc3_trb {
+       u64             bplh;
+
+       union {
+               struct {
+                       u32             length:24;
+                       u32             pcm1:2;
+                       u32             reserved27_26:2;
+                       u32             trbsts:4;
+#define DWC3_TRB_STS_OKAY                       0
+#define DWC3_TRB_STS_MISSED_ISOC                1
+#define DWC3_TRB_STS_SETUP_PENDING              2
+               };
+               u32 len_pcm;
+       };
+
+       union {
+               struct {
+                       u32             hwo:1;
+                       u32             lst:1;
+                       u32             chn:1;
+                       u32             csp:1;
+                       u32             trbctl:6;
+                       u32             isp_imi:1;
+                       u32             ioc:1;
+                       u32             reserved13_12:2;
+                       u32             sid_sofn:16;
+                       u32             reserved31_30:2;
+               };
+               u32 control;
+       };
+} __packed;
+
+/**
+ * struct dwc3_trb_hw - transfer request block (hw format)
+ * @bpl: DW0-3
+ * @bph: DW4-7
+ * @size: DW8-B
+ * @trl: DWC-F
+ */
+struct dwc3_trb_hw {
+       __le32          bpl;
+       __le32          bph;
+       __le32          size;
+       __le32          ctrl;
+} __packed;
+
+static inline void dwc3_trb_to_hw(struct dwc3_trb *nat, struct dwc3_trb_hw *hw)
+{
+       hw->bpl = cpu_to_le32(lower_32_bits(nat->bplh));
+       hw->bph = cpu_to_le32(upper_32_bits(nat->bplh));
+       hw->size = cpu_to_le32p(&nat->len_pcm);
+       /* HWO is written last */
+       hw->ctrl = cpu_to_le32p(&nat->control);
+}
+
+static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat)
+{
+       u64 bplh;
+
+       bplh = le32_to_cpup(&hw->bpl);
+       bplh |= (u64) le32_to_cpup(&hw->bph) << 32;
+       nat->bplh = bplh;
+
+       nat->len_pcm = le32_to_cpup(&hw->size);
+       nat->control = le32_to_cpup(&hw->ctrl);
+}
+
+/**
+ * struct dwc3 - representation of our controller
+ * ctrl_req: usb control request which is used for ep0
+ * ep0_trb: trb which is used for the ctrl_req
+ * setup_buf: used while precessing STD USB requests
+ * ctrl_req_addr: dma address of ctrl_req
+ * ep0_trb: dma address of ep0_trb
+ * ep0_usb_req: dummy req used while handling STD USB requests
+ * setup_buf_addr: dma address of setup_buf
+ * @lock: for synchronizing
+ * @dev: pointer to our struct device
+ * @event_buffer_list: a list of event buffers
+ * @gadget: device side representation of the peripheral controller
+ * @gadget_driver: pointer to the gadget driver
+ * @regs: base address for our registers
+ * @regs_size: address space size
+ * @irq: IRQ number
+ * @revision: revision register contents
+ * @is_selfpowered: true when we are selfpowered
+ * @three_stage_setup: set if we perform a three phase setup
+ * @ep0_status_pending: ep0 status response without a req is pending
+ * @ep0state: state of endpoint zero
+ * @link_state: link state
+ * @speed: device speed (super, high, full, low)
+ * @mem: points to start of memory which is used for this struct.
+ * @root: debugfs root folder pointer
+ */
+struct dwc3 {
+       struct usb_ctrlrequest  *ctrl_req;
+       struct dwc3_trb_hw      *ep0_trb;
+       u8                      *setup_buf;
+       dma_addr_t              ctrl_req_addr;
+       dma_addr_t              ep0_trb_addr;
+       dma_addr_t              setup_buf_addr;
+       struct usb_request      ep0_usb_req;
+       /* device lock */
+       spinlock_t              lock;
+       struct device           *dev;
+
+       struct dwc3_event_buffer *ev_buffs[DWC3_EVENT_BUFFERS_NUM];
+       struct dwc3_ep          *eps[DWC3_ENDPOINTS_NUM];
+
+       struct usb_gadget       gadget;
+       struct usb_gadget_driver *gadget_driver;
+
+       void __iomem            *regs;
+       size_t                  regs_size;
+
+       int                     irq;
+
+       u32                     revision;
+
+#define DWC3_REVISION_173A     0x5533173a
+#define DWC3_REVISION_175A     0x5533175a
+#define DWC3_REVISION_180A     0x5533180a
+#define DWC3_REVISION_183A     0x5533183a
+#define DWC3_REVISION_185A     0x5533185a
+#define DWC3_REVISION_188A     0x5533188a
+#define DWC3_REVISION_190A     0x5533190a
+
+       unsigned                is_selfpowered:1;
+       unsigned                three_stage_setup:1;
+       unsigned                ep0_status_pending:1;
+
+       enum dwc3_ep0_state     ep0state;
+       enum dwc3_link_state    link_state;
+       enum dwc3_device_state  dev_state;
+
+       u8                      speed;
+       void                    *mem;
+
+       struct dentry           *root;
+};
+
+/* -------------------------------------------------------------------------- */
+
+#define DWC3_TRBSTS_OK                 0
+#define DWC3_TRBSTS_MISSED_ISOC                1
+#define DWC3_TRBSTS_SETUP_PENDING      2
+
+#define DWC3_TRBCTL_NORMAL             1
+#define DWC3_TRBCTL_CONTROL_SETUP      2
+#define DWC3_TRBCTL_CONTROL_STATUS2    3
+#define DWC3_TRBCTL_CONTROL_STATUS3    4
+#define DWC3_TRBCTL_CONTROL_DATA       5
+#define DWC3_TRBCTL_ISOCHRONOUS_FIRST  6
+#define DWC3_TRBCTL_ISOCHRONOUS                7
+#define DWC3_TRBCTL_LINK_TRB           8
+
+/* -------------------------------------------------------------------------- */
+
+struct dwc3_event_type {
+       u32     is_devspec:1;
+       u32     type:6;
+       u32     reserved8_31:25;
+} __packed;
+
+#define DWC3_DEPEVT_XFERCOMPLETE       0x01
+#define DWC3_DEPEVT_XFERINPROGRESS     0x02
+#define DWC3_DEPEVT_XFERNOTREADY       0x03
+#define DWC3_DEPEVT_RXTXFIFOEVT                0x04
+#define DWC3_DEPEVT_STREAMEVT          0x06
+#define DWC3_DEPEVT_EPCMDCMPLT         0x07
+
+/**
+ * struct dwc3_event_depvt - Device Endpoint Events
+ * @one_bit: indicates this is an endpoint event (not used)
+ * @endpoint_number: number of the endpoint
+ * @endpoint_event: The event we have:
+ *     0x00    - Reserved
+ *     0x01    - XferComplete
+ *     0x02    - XferInProgress
+ *     0x03    - XferNotReady
+ *     0x04    - RxTxFifoEvt (IN->Underrun, OUT->Overrun)
+ *     0x05    - Reserved
+ *     0x06    - StreamEvt
+ *     0x07    - EPCmdCmplt
+ * @reserved11_10: Reserved, don't use.
+ * @status: Indicates the status of the event. Refer to databook for
+ *     more information.
+ * @parameters: Parameters of the current event. Refer to databook for
+ *     more information.
+ */
+struct dwc3_event_depevt {
+       u32     one_bit:1;
+       u32     endpoint_number:5;
+       u32     endpoint_event:4;
+       u32     reserved11_10:2;
+       u32     status:4;
+#define DEPEVT_STATUS_BUSERR    (1 << 0)
+#define DEPEVT_STATUS_SHORT     (1 << 1)
+#define DEPEVT_STATUS_IOC       (1 << 2)
+#define DEPEVT_STATUS_LST      (1 << 3)
+       u32     parameters:16;
+} __packed;
+
+/**
+ * struct dwc3_event_devt - Device Events
+ * @one_bit: indicates this is a non-endpoint event (not used)
+ * @device_event: indicates it's a device event. Should read as 0x00
+ * @type: indicates the type of device event.
+ *     0       - DisconnEvt
+ *     1       - USBRst
+ *     2       - ConnectDone
+ *     3       - ULStChng
+ *     4       - WkUpEvt
+ *     5       - Reserved
+ *     6       - EOPF
+ *     7       - SOF
+ *     8       - Reserved
+ *     9       - ErrticErr
+ *     10      - CmdCmplt
+ *     11      - EvntOverflow
+ *     12      - VndrDevTstRcved
+ * @reserved15_12: Reserved, not used
+ * @event_info: Information about this event
+ * @reserved31_24: Reserved, not used
+ */
+struct dwc3_event_devt {
+       u32     one_bit:1;
+       u32     device_event:7;
+       u32     type:4;
+       u32     reserved15_12:4;
+       u32     event_info:8;
+       u32     reserved31_24:8;
+} __packed;
+
+/**
+ * struct dwc3_event_gevt - Other Core Events
+ * @one_bit: indicates this is a non-endpoint event (not used)
+ * @device_event: indicates it's (0x03) Carkit or (0x04) I2C event.
+ * @phy_port_number: self-explanatory
+ * @reserved31_12: Reserved, not used.
+ */
+struct dwc3_event_gevt {
+       u32     one_bit:1;
+       u32     device_event:7;
+       u32     phy_port_number:4;
+       u32     reserved31_12:20;
+} __packed;
+
+/**
+ * union dwc3_event - representation of Event Buffer contents
+ * @raw: raw 32-bit event
+ * @type: the type of the event
+ * @depevt: Device Endpoint Event
+ * @devt: Device Event
+ * @gevt: Global Event
+ */
+union dwc3_event {
+       u32                             raw;
+       struct dwc3_event_type          type;
+       struct dwc3_event_depevt        depevt;
+       struct dwc3_event_devt          devt;
+       struct dwc3_event_gevt          gevt;
+};
+
+/*
+ * DWC3 Features to be used as Driver Data
+ */
+
+#define DWC3_HAS_PERIPHERAL            BIT(0)
+#define DWC3_HAS_XHCI                  BIT(1)
+#define DWC3_HAS_OTG                   BIT(3)
+
+#endif /* __DRIVERS_USB_DWC3_CORE_H */
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
new file mode 100644 (file)
index 0000000..ee3ba73
--- /dev/null
@@ -0,0 +1,51 @@
+/**
+ * debug.h - DesignWare USB3 DRD Controller Debug Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ * All rights reserved.
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+
+#ifdef CONFIG_DEBUG_FS
+extern int dwc3_debugfs_init(struct dwc3 *);
+extern void dwc3_debugfs_exit(struct dwc3 *);
+#else
+static inline int dwc3_debugfs_init(struct dwc3 *d)
+{  return 0;  }
+static inline void dwc3_debugfs_exit(struct dwc3 *d)
+{  }
+#endif
+
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
new file mode 100644 (file)
index 0000000..432df53
--- /dev/null
@@ -0,0 +1,534 @@
+/**
+ * debugfs.c - DesignWare USB3 DRD Controller DebugFS file
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ * All rights reserved.
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+struct dwc3_register {
+       const char      *name;
+       u32             offset;
+};
+
+#define dump_register(nm)                              \
+{                                                      \
+       .name   = __stringify(nm),                      \
+       .offset = DWC3_ ##nm,                           \
+}
+
+static const struct dwc3_register dwc3_regs[] = {
+       dump_register(GSBUSCFG0),
+       dump_register(GSBUSCFG1),
+       dump_register(GTXTHRCFG),
+       dump_register(GRXTHRCFG),
+       dump_register(GCTL),
+       dump_register(GEVTEN),
+       dump_register(GSTS),
+       dump_register(GSNPSID),
+       dump_register(GGPIO),
+       dump_register(GUID),
+       dump_register(GUCTL),
+       dump_register(GBUSERRADDR0),
+       dump_register(GBUSERRADDR1),
+       dump_register(GPRTBIMAP0),
+       dump_register(GPRTBIMAP1),
+       dump_register(GHWPARAMS0),
+       dump_register(GHWPARAMS1),
+       dump_register(GHWPARAMS2),
+       dump_register(GHWPARAMS3),
+       dump_register(GHWPARAMS4),
+       dump_register(GHWPARAMS5),
+       dump_register(GHWPARAMS6),
+       dump_register(GHWPARAMS7),
+       dump_register(GDBGFIFOSPACE),
+       dump_register(GDBGLTSSM),
+       dump_register(GPRTBIMAP_HS0),
+       dump_register(GPRTBIMAP_HS1),
+       dump_register(GPRTBIMAP_FS0),
+       dump_register(GPRTBIMAP_FS1),
+
+       dump_register(GUSB2PHYCFG(0)),
+       dump_register(GUSB2PHYCFG(1)),
+       dump_register(GUSB2PHYCFG(2)),
+       dump_register(GUSB2PHYCFG(3)),
+       dump_register(GUSB2PHYCFG(4)),
+       dump_register(GUSB2PHYCFG(5)),
+       dump_register(GUSB2PHYCFG(6)),
+       dump_register(GUSB2PHYCFG(7)),
+       dump_register(GUSB2PHYCFG(8)),
+       dump_register(GUSB2PHYCFG(9)),
+       dump_register(GUSB2PHYCFG(10)),
+       dump_register(GUSB2PHYCFG(11)),
+       dump_register(GUSB2PHYCFG(12)),
+       dump_register(GUSB2PHYCFG(13)),
+       dump_register(GUSB2PHYCFG(14)),
+       dump_register(GUSB2PHYCFG(15)),
+
+       dump_register(GUSB2I2CCTL(0)),
+       dump_register(GUSB2I2CCTL(1)),
+       dump_register(GUSB2I2CCTL(2)),
+       dump_register(GUSB2I2CCTL(3)),
+       dump_register(GUSB2I2CCTL(4)),
+       dump_register(GUSB2I2CCTL(5)),
+       dump_register(GUSB2I2CCTL(6)),
+       dump_register(GUSB2I2CCTL(7)),
+       dump_register(GUSB2I2CCTL(8)),
+       dump_register(GUSB2I2CCTL(9)),
+       dump_register(GUSB2I2CCTL(10)),
+       dump_register(GUSB2I2CCTL(11)),
+       dump_register(GUSB2I2CCTL(12)),
+       dump_register(GUSB2I2CCTL(13)),
+       dump_register(GUSB2I2CCTL(14)),
+       dump_register(GUSB2I2CCTL(15)),
+
+       dump_register(GUSB2PHYACC(0)),
+       dump_register(GUSB2PHYACC(1)),
+       dump_register(GUSB2PHYACC(2)),
+       dump_register(GUSB2PHYACC(3)),
+       dump_register(GUSB2PHYACC(4)),
+       dump_register(GUSB2PHYACC(5)),
+       dump_register(GUSB2PHYACC(6)),
+       dump_register(GUSB2PHYACC(7)),
+       dump_register(GUSB2PHYACC(8)),
+       dump_register(GUSB2PHYACC(9)),
+       dump_register(GUSB2PHYACC(10)),
+       dump_register(GUSB2PHYACC(11)),
+       dump_register(GUSB2PHYACC(12)),
+       dump_register(GUSB2PHYACC(13)),
+       dump_register(GUSB2PHYACC(14)),
+       dump_register(GUSB2PHYACC(15)),
+
+       dump_register(GUSB3PIPECTL(0)),
+       dump_register(GUSB3PIPECTL(1)),
+       dump_register(GUSB3PIPECTL(2)),
+       dump_register(GUSB3PIPECTL(3)),
+       dump_register(GUSB3PIPECTL(4)),
+       dump_register(GUSB3PIPECTL(5)),
+       dump_register(GUSB3PIPECTL(6)),
+       dump_register(GUSB3PIPECTL(7)),
+       dump_register(GUSB3PIPECTL(8)),
+       dump_register(GUSB3PIPECTL(9)),
+       dump_register(GUSB3PIPECTL(10)),
+       dump_register(GUSB3PIPECTL(11)),
+       dump_register(GUSB3PIPECTL(12)),
+       dump_register(GUSB3PIPECTL(13)),
+       dump_register(GUSB3PIPECTL(14)),
+       dump_register(GUSB3PIPECTL(15)),
+
+       dump_register(GTXFIFOSIZ(0)),
+       dump_register(GTXFIFOSIZ(1)),
+       dump_register(GTXFIFOSIZ(2)),
+       dump_register(GTXFIFOSIZ(3)),
+       dump_register(GTXFIFOSIZ(4)),
+       dump_register(GTXFIFOSIZ(5)),
+       dump_register(GTXFIFOSIZ(6)),
+       dump_register(GTXFIFOSIZ(7)),
+       dump_register(GTXFIFOSIZ(8)),
+       dump_register(GTXFIFOSIZ(9)),
+       dump_register(GTXFIFOSIZ(10)),
+       dump_register(GTXFIFOSIZ(11)),
+       dump_register(GTXFIFOSIZ(12)),
+       dump_register(GTXFIFOSIZ(13)),
+       dump_register(GTXFIFOSIZ(14)),
+       dump_register(GTXFIFOSIZ(15)),
+       dump_register(GTXFIFOSIZ(16)),
+       dump_register(GTXFIFOSIZ(17)),
+       dump_register(GTXFIFOSIZ(18)),
+       dump_register(GTXFIFOSIZ(19)),
+       dump_register(GTXFIFOSIZ(20)),
+       dump_register(GTXFIFOSIZ(21)),
+       dump_register(GTXFIFOSIZ(22)),
+       dump_register(GTXFIFOSIZ(23)),
+       dump_register(GTXFIFOSIZ(24)),
+       dump_register(GTXFIFOSIZ(25)),
+       dump_register(GTXFIFOSIZ(26)),
+       dump_register(GTXFIFOSIZ(27)),
+       dump_register(GTXFIFOSIZ(28)),
+       dump_register(GTXFIFOSIZ(29)),
+       dump_register(GTXFIFOSIZ(30)),
+       dump_register(GTXFIFOSIZ(31)),
+
+       dump_register(GRXFIFOSIZ(0)),
+       dump_register(GRXFIFOSIZ(1)),
+       dump_register(GRXFIFOSIZ(2)),
+       dump_register(GRXFIFOSIZ(3)),
+       dump_register(GRXFIFOSIZ(4)),
+       dump_register(GRXFIFOSIZ(5)),
+       dump_register(GRXFIFOSIZ(6)),
+       dump_register(GRXFIFOSIZ(7)),
+       dump_register(GRXFIFOSIZ(8)),
+       dump_register(GRXFIFOSIZ(9)),
+       dump_register(GRXFIFOSIZ(10)),
+       dump_register(GRXFIFOSIZ(11)),
+       dump_register(GRXFIFOSIZ(12)),
+       dump_register(GRXFIFOSIZ(13)),
+       dump_register(GRXFIFOSIZ(14)),
+       dump_register(GRXFIFOSIZ(15)),
+       dump_register(GRXFIFOSIZ(16)),
+       dump_register(GRXFIFOSIZ(17)),
+       dump_register(GRXFIFOSIZ(18)),
+       dump_register(GRXFIFOSIZ(19)),
+       dump_register(GRXFIFOSIZ(20)),
+       dump_register(GRXFIFOSIZ(21)),
+       dump_register(GRXFIFOSIZ(22)),
+       dump_register(GRXFIFOSIZ(23)),
+       dump_register(GRXFIFOSIZ(24)),
+       dump_register(GRXFIFOSIZ(25)),
+       dump_register(GRXFIFOSIZ(26)),
+       dump_register(GRXFIFOSIZ(27)),
+       dump_register(GRXFIFOSIZ(28)),
+       dump_register(GRXFIFOSIZ(29)),
+       dump_register(GRXFIFOSIZ(30)),
+       dump_register(GRXFIFOSIZ(31)),
+
+       dump_register(GEVNTADRLO(0)),
+       dump_register(GEVNTADRHI(0)),
+       dump_register(GEVNTSIZ(0)),
+       dump_register(GEVNTCOUNT(0)),
+
+       dump_register(GHWPARAMS8),
+       dump_register(DCFG),
+       dump_register(DCTL),
+       dump_register(DEVTEN),
+       dump_register(DSTS),
+       dump_register(DGCMDPAR),
+       dump_register(DGCMD),
+       dump_register(DALEPENA),
+
+       dump_register(DEPCMDPAR2(0)),
+       dump_register(DEPCMDPAR2(1)),
+       dump_register(DEPCMDPAR2(2)),
+       dump_register(DEPCMDPAR2(3)),
+       dump_register(DEPCMDPAR2(4)),
+       dump_register(DEPCMDPAR2(5)),
+       dump_register(DEPCMDPAR2(6)),
+       dump_register(DEPCMDPAR2(7)),
+       dump_register(DEPCMDPAR2(8)),
+       dump_register(DEPCMDPAR2(9)),
+       dump_register(DEPCMDPAR2(10)),
+       dump_register(DEPCMDPAR2(11)),
+       dump_register(DEPCMDPAR2(12)),
+       dump_register(DEPCMDPAR2(13)),
+       dump_register(DEPCMDPAR2(14)),
+       dump_register(DEPCMDPAR2(15)),
+       dump_register(DEPCMDPAR2(16)),
+       dump_register(DEPCMDPAR2(17)),
+       dump_register(DEPCMDPAR2(18)),
+       dump_register(DEPCMDPAR2(19)),
+       dump_register(DEPCMDPAR2(20)),
+       dump_register(DEPCMDPAR2(21)),
+       dump_register(DEPCMDPAR2(22)),
+       dump_register(DEPCMDPAR2(23)),
+       dump_register(DEPCMDPAR2(24)),
+       dump_register(DEPCMDPAR2(25)),
+       dump_register(DEPCMDPAR2(26)),
+       dump_register(DEPCMDPAR2(27)),
+       dump_register(DEPCMDPAR2(28)),
+       dump_register(DEPCMDPAR2(29)),
+       dump_register(DEPCMDPAR2(30)),
+       dump_register(DEPCMDPAR2(31)),
+
+       dump_register(DEPCMDPAR1(0)),
+       dump_register(DEPCMDPAR1(1)),
+       dump_register(DEPCMDPAR1(2)),
+       dump_register(DEPCMDPAR1(3)),
+       dump_register(DEPCMDPAR1(4)),
+       dump_register(DEPCMDPAR1(5)),
+       dump_register(DEPCMDPAR1(6)),
+       dump_register(DEPCMDPAR1(7)),
+       dump_register(DEPCMDPAR1(8)),
+       dump_register(DEPCMDPAR1(9)),
+       dump_register(DEPCMDPAR1(10)),
+       dump_register(DEPCMDPAR1(11)),
+       dump_register(DEPCMDPAR1(12)),
+       dump_register(DEPCMDPAR1(13)),
+       dump_register(DEPCMDPAR1(14)),
+       dump_register(DEPCMDPAR1(15)),
+       dump_register(DEPCMDPAR1(16)),
+       dump_register(DEPCMDPAR1(17)),
+       dump_register(DEPCMDPAR1(18)),
+       dump_register(DEPCMDPAR1(19)),
+       dump_register(DEPCMDPAR1(20)),
+       dump_register(DEPCMDPAR1(21)),
+       dump_register(DEPCMDPAR1(22)),
+       dump_register(DEPCMDPAR1(23)),
+       dump_register(DEPCMDPAR1(24)),
+       dump_register(DEPCMDPAR1(25)),
+       dump_register(DEPCMDPAR1(26)),
+       dump_register(DEPCMDPAR1(27)),
+       dump_register(DEPCMDPAR1(28)),
+       dump_register(DEPCMDPAR1(29)),
+       dump_register(DEPCMDPAR1(30)),
+       dump_register(DEPCMDPAR1(31)),
+
+       dump_register(DEPCMDPAR0(0)),
+       dump_register(DEPCMDPAR0(1)),
+       dump_register(DEPCMDPAR0(2)),
+       dump_register(DEPCMDPAR0(3)),
+       dump_register(DEPCMDPAR0(4)),
+       dump_register(DEPCMDPAR0(5)),
+       dump_register(DEPCMDPAR0(6)),
+       dump_register(DEPCMDPAR0(7)),
+       dump_register(DEPCMDPAR0(8)),
+       dump_register(DEPCMDPAR0(9)),
+       dump_register(DEPCMDPAR0(10)),
+       dump_register(DEPCMDPAR0(11)),
+       dump_register(DEPCMDPAR0(12)),
+       dump_register(DEPCMDPAR0(13)),
+       dump_register(DEPCMDPAR0(14)),
+       dump_register(DEPCMDPAR0(15)),
+       dump_register(DEPCMDPAR0(16)),
+       dump_register(DEPCMDPAR0(17)),
+       dump_register(DEPCMDPAR0(18)),
+       dump_register(DEPCMDPAR0(19)),
+       dump_register(DEPCMDPAR0(20)),
+       dump_register(DEPCMDPAR0(21)),
+       dump_register(DEPCMDPAR0(22)),
+       dump_register(DEPCMDPAR0(23)),
+       dump_register(DEPCMDPAR0(24)),
+       dump_register(DEPCMDPAR0(25)),
+       dump_register(DEPCMDPAR0(26)),
+       dump_register(DEPCMDPAR0(27)),
+       dump_register(DEPCMDPAR0(28)),
+       dump_register(DEPCMDPAR0(29)),
+       dump_register(DEPCMDPAR0(30)),
+       dump_register(DEPCMDPAR0(31)),
+
+       dump_register(DEPCMD(0)),
+       dump_register(DEPCMD(1)),
+       dump_register(DEPCMD(2)),
+       dump_register(DEPCMD(3)),
+       dump_register(DEPCMD(4)),
+       dump_register(DEPCMD(5)),
+       dump_register(DEPCMD(6)),
+       dump_register(DEPCMD(7)),
+       dump_register(DEPCMD(8)),
+       dump_register(DEPCMD(9)),
+       dump_register(DEPCMD(10)),
+       dump_register(DEPCMD(11)),
+       dump_register(DEPCMD(12)),
+       dump_register(DEPCMD(13)),
+       dump_register(DEPCMD(14)),
+       dump_register(DEPCMD(15)),
+       dump_register(DEPCMD(16)),
+       dump_register(DEPCMD(17)),
+       dump_register(DEPCMD(18)),
+       dump_register(DEPCMD(19)),
+       dump_register(DEPCMD(20)),
+       dump_register(DEPCMD(21)),
+       dump_register(DEPCMD(22)),
+       dump_register(DEPCMD(23)),
+       dump_register(DEPCMD(24)),
+       dump_register(DEPCMD(25)),
+       dump_register(DEPCMD(26)),
+       dump_register(DEPCMD(27)),
+       dump_register(DEPCMD(28)),
+       dump_register(DEPCMD(29)),
+       dump_register(DEPCMD(30)),
+       dump_register(DEPCMD(31)),
+
+       dump_register(OCFG),
+       dump_register(OCTL),
+       dump_register(OEVTEN),
+       dump_register(OSTS),
+};
+
+static int dwc3_regdump_show(struct seq_file *s, void *unused)
+{
+       struct dwc3             *dwc = s->private;
+       int                     i;
+
+       seq_printf(s, "DesignWare USB3 Core Register Dump\n");
+
+       for (i = 0; i < ARRAY_SIZE(dwc3_regs); i++) {
+               seq_printf(s, "%-20s :    %08x\n", dwc3_regs[i].name,
+                               dwc3_readl(dwc->regs, dwc3_regs[i].offset));
+       }
+
+       return 0;
+}
+
+static int dwc3_regdump_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dwc3_regdump_show, inode->i_private);
+}
+
+static const struct file_operations dwc3_regdump_fops = {
+       .open                   = dwc3_regdump_open,
+       .read                   = seq_read,
+       .release                = single_release,
+};
+
+
+static int dwc3_send_testmode_cmd(struct dwc3 *dwc, int mode)
+{
+       u32 timeout = 250;
+
+       dwc3_writel(dwc->regs, DWC3_DGCMDPAR, mode);
+       dwc3_writel(dwc->regs, DWC3_DGCMD, DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK |
+                       DWC3_DEPCMD_CMDACT);
+       do {
+               u32 reg;
+
+               reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
+               if (!(reg & DWC3_DEPCMD_CMDACT))
+                       return 0;
+               timeout--;
+               if (!timeout)
+                       return -ETIMEDOUT;
+               mdelay(1);
+       } while (1);
+}
+
+static struct dwc3_trb_hw trb_0 __aligned(16);
+static struct dwc3_trb_hw trb_1 __aligned(16);
+
+#define BUF_SIZE       4096
+static int dwc3_testmode_open(struct inode *inode, struct file *file)
+{
+       struct dwc3 *dwc = inode->i_private;
+       struct dwc3_gadget_ep_cmd_params par0;
+       struct dwc3_gadget_ep_cmd_params par1;
+       struct dwc3_trb         trb;
+       int ret;
+       u8 *buf0;
+       u8 *buf1;
+
+       buf0 = kmalloc(BUF_SIZE, GFP_KERNEL);
+       if (!buf0)
+               return -ENOMEM;
+       buf1 = kmalloc(BUF_SIZE, GFP_KERNEL);
+       if (!buf1)
+               return -ENOMEM;
+
+       memset(buf0, 0xaa, BUF_SIZE);
+       memset(buf1, 0x33, BUF_SIZE);
+
+       memset(&trb, 0, sizeof(trb));
+       memset(&par0, 0, sizeof(par0));
+       memset(&par1, 0, sizeof(par1));
+
+       trb.lst = 1;
+       trb.trbctl = DWC3_TRBCTL_NORMAL;
+       trb.length = BUF_SIZE;
+       trb.hwo = 1;
+
+       trb.bplh = virt_to_phys(buf0);
+       dwc3_trb_to_hw(&trb, &trb_0);
+
+       trb.bplh = virt_to_phys(buf1);
+       dwc3_trb_to_hw(&trb, &trb_1);
+
+       par0.param0.depstrtxfer.transfer_desc_addr_high =
+               upper_32_bits(virt_to_phys(&trb_0));
+       par0.param1.depstrtxfer.transfer_desc_addr_low =
+               lower_32_bits(virt_to_phys(&trb_0));
+
+       par1.param0.depstrtxfer.transfer_desc_addr_high =
+               upper_32_bits(virt_to_phys(&trb_1));
+       par1.param1.depstrtxfer.transfer_desc_addr_low =
+               lower_32_bits(virt_to_phys(&trb_1));
+
+       dwc3_send_testmode_cmd(dwc, 1);
+
+       ret = dwc3_send_gadget_ep_cmd(dwc, 0, DWC3_DEPCMD_STARTTRANSFER, &par0);
+       ret = dwc3_send_gadget_ep_cmd(dwc, 1, DWC3_DEPCMD_STARTTRANSFER, &par1);
+
+       dwc3_send_testmode_cmd(dwc, 0);
+       return -EBUSY;
+}
+
+static const struct file_operations dwc3_testmode_fops = {
+       .open                   = dwc3_testmode_open,
+       .read                   = seq_read,
+       .release                = single_release,
+};
+
+int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
+{
+       struct dentry           *root;
+       struct dentry           *file;
+       int                     ret;
+
+       root = debugfs_create_dir(dev_name(dwc->dev), NULL);
+       if (IS_ERR(root)){
+               ret = PTR_ERR(root);
+               goto err0;
+       }
+
+       dwc->root = root;
+
+       file = debugfs_create_file("regdump", S_IRUGO, root, dwc,
+                       &dwc3_regdump_fops);
+       if (IS_ERR(file)) {
+               ret = PTR_ERR(file);
+               goto err1;
+       }
+       file = debugfs_create_file("testmode", S_IRUGO, root, dwc,
+                       &dwc3_testmode_fops);
+       if (IS_ERR(file)) {
+               ret = PTR_ERR(file);
+               goto err1;
+       }
+
+       return 0;
+
+err1:
+       debugfs_remove_recursive(root);
+
+err0:
+       return ret;
+}
+
+void __devexit dwc3_debugfs_exit(struct dwc3 *dwc)
+{
+       debugfs_remove_recursive(dwc->root);
+       dwc->root = NULL;
+}
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
new file mode 100644 (file)
index 0000000..08fffe6
--- /dev/null
@@ -0,0 +1,410 @@
+/**
+ * dwc3-omap.c - OMAP Specific Glue layer
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ * All rights reserved.
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+
+#include "io.h"
+
+/*
+ * All these registers belong to OMAP's Wrapper around the
+ * DesignWare USB3 Core.
+ */
+
+#define USBOTGSS_REVISION                      0x0000
+#define USBOTGSS_SYSCONFIG                     0x0010
+#define USBOTGSS_IRQ_EOI                       0x0020
+#define USBOTGSS_IRQSTATUS_RAW_0               0x0024
+#define USBOTGSS_IRQSTATUS_0                   0x0028
+#define USBOTGSS_IRQENABLE_SET_0               0x002c
+#define USBOTGSS_IRQENABLE_CLR_0               0x0030
+#define USBOTGSS_IRQSTATUS_RAW_1               0x0034
+#define USBOTGSS_IRQSTATUS_1                   0x0038
+#define USBOTGSS_IRQENABLE_SET_1               0x003c
+#define USBOTGSS_IRQENABLE_CLR_1               0x0040
+#define USBOTGSS_UTMI_OTG_CTRL                 0x0080
+#define USBOTGSS_UTMI_OTG_STATUS               0x0084
+#define USBOTGSS_MMRAM_OFFSET                  0x0100
+#define USBOTGSS_FLADJ                         0x0104
+#define USBOTGSS_DEBUG_CFG                     0x0108
+#define USBOTGSS_DEBUG_DATA                    0x010c
+
+/* SYSCONFIG REGISTER */
+#define USBOTGSS_SYSCONFIG_DMADISABLE          (1 << 16)
+#define USBOTGSS_SYSCONFIG_STANDBYMODE(x)      ((x) << 4)
+#define USBOTGSS_SYSCONFIG_IDLEMODE(x)         ((x) << 2)
+
+/* IRQ_EOI REGISTER */
+#define USBOTGSS_IRQ_EOI_LINE_NUMBER           (1 << 0)
+
+/* IRQS0 BITS */
+#define USBOTGSS_IRQO_COREIRQ_ST               (1 << 0)
+
+/* IRQ1 BITS */
+#define USBOTGSS_IRQ1_DMADISABLECLR            (1 << 17)
+#define USBOTGSS_IRQ1_OEVT                     (1 << 16)
+#define USBOTGSS_IRQ1_DRVVBUS_RISE             (1 << 13)
+#define USBOTGSS_IRQ1_CHRGVBUS_RISE            (1 << 12)
+#define USBOTGSS_IRQ1_DISCHRGVBUS_RISE         (1 << 11)
+#define USBOTGSS_IRQ1_IDPULLUP_RISE            (1 << 8)
+#define USBOTGSS_IRQ1_DRVVBUS_FALL             (1 << 5)
+#define USBOTGSS_IRQ1_CHRGVBUS_FALL            (1 << 4)
+#define USBOTGSS_IRQ1_DISCHRGVBUS_FALL         (1 << 3)
+#define USBOTGSS_IRQ1_IDPULLUP_FALL            (1 << 0)
+
+/* UTMI_OTG_CTRL REGISTER */
+#define USBOTGSS_UTMI_OTG_CTRL_DRVVBUS         (1 << 5)
+#define USBOTGSS_UTMI_OTG_CTRL_CHRGVBUS                (1 << 4)
+#define USBOTGSS_UTMI_OTG_CTRL_DISCHRGVBUS     (1 << 3)
+#define USBOTGSS_UTMI_OTG_CTRL_IDPULLUP                (1 << 0)
+
+/* UTMI_OTG_STATUS REGISTER */
+#define USBOTGSS_UTMI_OTG_STATUS_SW_MODE       (1 << 31)
+#define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT  (1 << 9)
+#define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE (1 << 8)
+#define USBOTGSS_UTMI_OTG_STATUS_IDDIG         (1 << 4)
+#define USBOTGSS_UTMI_OTG_STATUS_SESSEND       (1 << 3)
+#define USBOTGSS_UTMI_OTG_STATUS_SESSVALID     (1 << 2)
+#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID     (1 << 1)
+
+struct dwc3_omap {
+       /* device lock */
+       spinlock_t              lock;
+
+       struct platform_device  *dwc3;
+       struct device           *dev;
+
+       int                     irq;
+       void __iomem            *base;
+
+       void                    *context;
+       u32                     resource_size;
+
+       u32                     dma_status:1;
+};
+
+#ifdef CONFIG_PM
+static int dwc3_omap_suspend(struct device *dev)
+{
+       struct dwc3_omap        *omap = dev_get_drvdata(dev);
+
+       memcpy_fromio(omap->context, omap->base, omap->resource_size);
+
+       return 0;
+}
+
+static int dwc3_omap_resume(struct device *dev)
+{
+       struct dwc3_omap        *omap = dev_get_drvdata(dev);
+
+       memcpy_toio(omap->base, omap->context, omap->resource_size);
+
+       return 0;
+}
+
+static int dwc3_omap_idle(struct device *dev)
+{
+       struct dwc3_omap        *omap = dev_get_drvdata(dev);
+       u32                     reg;
+
+       /* stop DMA Engine */
+       reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG);
+       reg &= ~(USBOTGSS_SYSCONFIG_DMADISABLE);
+       dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
+
+       return 0;
+}
+
+static UNIVERSAL_DEV_PM_OPS(dwc3_omap_pm_ops, dwc3_omap_suspend,
+               dwc3_omap_resume, dwc3_omap_idle);
+
+#define DEV_PM_OPS     (&dwc3_omap_pm_ops)
+#else
+#define DEV_PM_OPS     NULL
+#endif
+
+static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
+{
+       struct dwc3_omap        *omap = _omap;
+       u32                     reg;
+       u32                     ctrl;
+
+       spin_lock(&omap->lock);
+
+       reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_1);
+       ctrl = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_CTRL);
+
+       if (reg & USBOTGSS_IRQ1_DMADISABLECLR) {
+               dev_dbg(omap->base, "DMA Disable was Cleared\n");
+               omap->dma_status = false;
+       }
+
+       if (reg & USBOTGSS_IRQ1_OEVT)
+               dev_dbg(omap->base, "OTG Event\n");
+
+       if (reg & USBOTGSS_IRQ1_DRVVBUS_RISE) {
+               dev_dbg(omap->base, "DRVVBUS Rise\n");
+               ctrl |= USBOTGSS_UTMI_OTG_CTRL_DRVVBUS;
+       }
+
+       if (reg & USBOTGSS_IRQ1_CHRGVBUS_RISE) {
+               dev_dbg(omap->base, "CHRGVBUS Rise\n");
+               ctrl |= USBOTGSS_UTMI_OTG_CTRL_CHRGVBUS;
+       }
+
+       if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_RISE) {
+               dev_dbg(omap->base, "DISCHRGVBUS Rise\n");
+               ctrl |= USBOTGSS_UTMI_OTG_CTRL_DISCHRGVBUS;
+       }
+
+       if (reg & USBOTGSS_IRQ1_IDPULLUP_RISE) {
+               dev_dbg(omap->base, "IDPULLUP Rise\n");
+               ctrl |= USBOTGSS_UTMI_OTG_CTRL_IDPULLUP;
+       }
+
+       if (reg & USBOTGSS_IRQ1_DRVVBUS_FALL) {
+               dev_dbg(omap->base, "DRVVBUS Fall\n");
+               ctrl &= ~USBOTGSS_UTMI_OTG_CTRL_DRVVBUS;
+       }
+
+       if (reg & USBOTGSS_IRQ1_CHRGVBUS_FALL) {
+               dev_dbg(omap->base, "CHRGVBUS Fall\n");
+               ctrl &= ~USBOTGSS_UTMI_OTG_CTRL_CHRGVBUS;
+       }
+
+       if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_FALL) {
+               dev_dbg(omap->base, "DISCHRGVBUS Fall\n");
+               ctrl &= ~USBOTGSS_UTMI_OTG_CTRL_DISCHRGVBUS;
+       }
+
+       if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL) {
+               dev_dbg(omap->base, "IDPULLUP Fall\n");
+               ctrl &= ~USBOTGSS_UTMI_OTG_CTRL_IDPULLUP;
+       }
+
+       dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_CTRL, ctrl);
+
+       spin_unlock(&omap->lock);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit dwc3_omap_probe(struct platform_device *pdev)
+{
+       struct platform_device  *dwc3;
+       struct dwc3_omap        *omap;
+       struct resource         *res;
+
+       int                     ret = -ENOMEM;
+       int                     irq;
+
+       u32                     reg;
+
+       void __iomem            *base;
+       void                    *context;
+
+       omap = kzalloc(sizeof(*omap), GFP_KERNEL);
+       if (!omap) {
+               dev_err(&pdev->dev, "not enough memory\n");
+               goto err0;
+       }
+
+       platform_set_drvdata(pdev, omap);
+
+       irq = platform_get_irq(pdev, 1);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "missing IRQ resource\n");
+               ret = -EINVAL;
+               goto err1;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res) {
+               dev_err(&pdev->dev, "missing memory base resource\n");
+               ret = -EINVAL;
+               goto err1;
+       }
+
+       base = ioremap_nocache(res->start, resource_size(res));
+       if (!base) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               goto err1;
+       }
+
+       dwc3 = platform_device_alloc("dwc3-omap", -1);
+       if (!dwc3) {
+               dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
+               goto err2;
+       }
+
+       context = kzalloc(resource_size(res), GFP_KERNEL);
+       if (!context) {
+               dev_err(&pdev->dev, "couldn't allocate dwc3 context memory\n");
+               goto err3;
+       }
+
+       spin_lock_init(&omap->lock);
+       dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
+
+       dwc3->dev.parent = &pdev->dev;
+       dwc3->dev.dma_mask = pdev->dev.dma_mask;
+       dwc3->dev.dma_parms = pdev->dev.dma_parms;
+       omap->resource_size = resource_size(res);
+       omap->context   = context;
+       omap->dev       = &pdev->dev;
+       omap->irq       = irq;
+       omap->base      = base;
+       omap->dwc3      = dwc3;
+
+       /* check the DMA Status */
+       reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG);
+       omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
+
+       ret = request_irq(omap->irq, dwc3_omap_interrupt, 0,
+                       "dwc3-wrapper", omap);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to request IRQ #%d --> %d\n",
+                               omap->irq, ret);
+               goto err4;
+       }
+
+       /* enable all IRQs */
+       dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, 0x01);
+
+       reg = (USBOTGSS_IRQ1_DMADISABLECLR |
+                       USBOTGSS_IRQ1_OEVT |
+                       USBOTGSS_IRQ1_DRVVBUS_RISE |
+                       USBOTGSS_IRQ1_CHRGVBUS_RISE |
+                       USBOTGSS_IRQ1_DISCHRGVBUS_RISE |
+                       USBOTGSS_IRQ1_IDPULLUP_RISE |
+                       USBOTGSS_IRQ1_DRVVBUS_FALL |
+                       USBOTGSS_IRQ1_CHRGVBUS_FALL |
+                       USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
+                       USBOTGSS_IRQ1_IDPULLUP_FALL);
+
+       dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
+
+       ret = platform_device_add_resources(dwc3, pdev->resource,
+                       pdev->num_resources);
+       if (ret) {
+               dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
+               goto err5;
+       }
+
+       ret = platform_device_add(dwc3);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register dwc3 device\n");
+               goto err5;
+       }
+
+       return 0;
+
+err5:
+       free_irq(omap->irq, omap);
+
+err4:
+       kfree(omap->context);
+
+err3:
+       platform_device_put(dwc3);
+
+err2:
+       iounmap(base);
+
+err1:
+       kfree(omap);
+
+err0:
+       return ret;
+}
+
+static int __devexit dwc3_omap_remove(struct platform_device *pdev)
+{
+       struct dwc3_omap        *omap = platform_get_drvdata(pdev);
+
+       platform_device_unregister(omap->dwc3);
+
+       free_irq(omap->irq, omap);
+       iounmap(omap->base);
+
+       kfree(omap->context);
+       kfree(omap);
+
+       return 0;
+}
+
+static const struct of_device_id of_dwc3_matach[] = {
+       {
+               "ti,dwc3",
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, of_dwc3_matach);
+
+static struct platform_driver dwc3_omap_driver = {
+       .probe          = dwc3_omap_probe,
+       .remove         = __devexit_p(dwc3_omap_remove),
+       .driver         = {
+               .name   = "omap-dwc3",
+               .pm     = DEV_PM_OPS,
+               .of_match_table = of_dwc3_matach,
+       },
+};
+
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer");
+
+static int __devinit dwc3_omap_init(void)
+{
+       return platform_driver_register(&dwc3_omap_driver);
+}
+module_init(dwc3_omap_init);
+
+static void __exit dwc3_omap_exit(void)
+{
+       platform_driver_unregister(&dwc3_omap_driver);
+}
+module_exit(dwc3_omap_exit);
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
new file mode 100644 (file)
index 0000000..e3b77d2
--- /dev/null
@@ -0,0 +1,220 @@
+/**
+ * dwc3-pci.c - PCI Specific glue layer
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ * All rights reserved.
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+/* FIXME define these in <linux/pci_ids.h> */
+#define PCI_VENDOR_ID_SYNOPSYS         0x16c3
+#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3        0xabcd
+
+#define DWC3_PCI_DEVS_POSSIBLE 32
+
+struct dwc3_pci {
+       struct device           *dev;
+       struct platform_device  *dwc3;
+};
+
+static DECLARE_BITMAP(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
+
+static int dwc3_pci_get_device_id(struct dwc3_pci *glue)
+{
+       int             id;
+
+again:
+       id = find_first_zero_bit(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
+       if (id < DWC3_PCI_DEVS_POSSIBLE) {
+               int old;
+
+               old = test_and_set_bit(id, dwc3_pci_devs);
+               if (old)
+                       goto again;
+       } else {
+               dev_err(glue->dev, "no space for new device\n");
+               id = -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void dwc3_pci_put_device_id(struct dwc3_pci *glue, int id)
+{
+       int                     ret;
+
+       if (id < 0)
+               return;
+
+       ret = test_bit(id, dwc3_pci_devs);
+       WARN(!ret, "Device: %s\nID %d not in use\n",
+                       dev_driver_string(glue->dev), id);
+       clear_bit(id, dwc3_pci_devs);
+}
+
+static int __devinit dwc3_pci_probe(struct pci_dev *pci,
+               const struct pci_device_id *id)
+{
+       struct resource         res[2];
+       struct platform_device  *dwc3;
+       struct dwc3_pci         *glue;
+       int                     ret = -ENOMEM;
+       int                     devid;
+
+       glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+       if (!glue) {
+               dev_err(&pci->dev, "not enough memory\n");
+               goto err0;
+       }
+
+       glue->dev       = &pci->dev;
+
+       ret = pci_enable_device(pci);
+       if (ret) {
+               dev_err(&pci->dev, "failed to enable pci device\n");
+               goto err1;
+       }
+
+       pci_set_power_state(pci, PCI_D0);
+       pci_set_master(pci);
+
+       devid = dwc3_pci_get_device_id(glue);
+       if (devid < 0)
+               goto err2;
+
+       dwc3 = platform_device_alloc("dwc3-pci", devid);
+       if (!dwc3) {
+               dev_err(&pci->dev, "couldn't allocate dwc3 device\n");
+               goto err3;
+       }
+
+       memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
+
+       res[0].start    = pci_resource_start(pci, 0);
+       res[0].end      = pci_resource_end(pci, 0);
+       res[0].name     = "dwc_usb3";
+       res[0].flags    = IORESOURCE_MEM;
+
+       res[1].start    = pci->irq;
+       res[1].name     = "dwc_usb3";
+       res[1].flags    = IORESOURCE_IRQ;
+
+       ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
+       if (ret) {
+               dev_err(&pci->dev, "couldn't add resources to dwc3 device\n");
+               goto err4;
+       }
+
+       pci_set_drvdata(pci, glue);
+
+       dma_set_coherent_mask(&dwc3->dev, pci->dev.coherent_dma_mask);
+
+       dwc3->dev.dma_mask = pci->dev.dma_mask;
+       dwc3->dev.dma_parms = pci->dev.dma_parms;
+       dwc3->dev.parent = &pci->dev;
+       glue->dwc3      = dwc3;
+
+       ret = platform_device_add(dwc3);
+       if (ret) {
+               dev_err(&pci->dev, "failed to register dwc3 device\n");
+               goto err4;
+       }
+
+       return 0;
+
+err4:
+       pci_set_drvdata(pci, NULL);
+       platform_device_put(dwc3);
+
+err3:
+       dwc3_pci_put_device_id(glue, devid);
+
+err2:
+       pci_disable_device(pci);
+
+err1:
+       kfree(pci);
+
+err0:
+       return ret;
+}
+
+static void __devexit dwc3_pci_remove(struct pci_dev *pci)
+{
+       struct dwc3_pci *glue = pci_get_drvdata(pci);
+
+       dwc3_pci_put_device_id(glue, glue->dwc3->id);
+       platform_device_unregister(glue->dwc3);
+       pci_set_drvdata(pci, NULL);
+       pci_disable_device(pci);
+       kfree(glue);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
+                               PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
+       },
+       {  }    /* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
+
+static struct pci_driver dwc3_pci_driver = {
+       .name           = "pci-dwc3",
+       .id_table       = dwc3_pci_id_table,
+       .probe          = dwc3_pci_probe,
+       .remove         = __devexit_p(dwc3_pci_remove),
+};
+
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
+
+static int __devinit dwc3_pci_init(void)
+{
+       return pci_register_driver(&dwc3_pci_driver);
+}
+module_init(dwc3_pci_init);
+
+static void __exit dwc3_pci_exit(void)
+{
+       pci_unregister_driver(&dwc3_pci_driver);
+}
+module_exit(dwc3_pci_exit);
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
new file mode 100644 (file)
index 0000000..4698fe0
--- /dev/null
@@ -0,0 +1,782 @@
+/**
+ * ep0.c - DesignWare USB3 DRD Controller Endpoint 0 Handling
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ * All rights reserved.
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
+               const struct dwc3_event_depevt *event);
+
+static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
+{
+       switch (state) {
+       case EP0_UNCONNECTED:
+               return "Unconnected";
+       case EP0_IDLE:
+               return "Idle";
+       case EP0_IN_DATA_PHASE:
+               return "IN Data Phase";
+       case EP0_OUT_DATA_PHASE:
+               return "OUT Data Phase";
+       case EP0_IN_WAIT_GADGET:
+               return "IN Wait Gadget";
+       case EP0_OUT_WAIT_GADGET:
+               return "OUT Wait Gadget";
+       case EP0_IN_WAIT_NRDY:
+               return "IN Wait NRDY";
+       case EP0_OUT_WAIT_NRDY:
+               return "OUT Wait NRDY";
+       case EP0_IN_STATUS_PHASE:
+               return "IN Status Phase";
+       case EP0_OUT_STATUS_PHASE:
+               return "OUT Status Phase";
+       case EP0_STALL:
+               return "Stall";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
+               u32 len)
+{
+       struct dwc3_gadget_ep_cmd_params params;
+       struct dwc3_trb_hw              *trb_hw;
+       struct dwc3_trb                 trb;
+       struct dwc3_ep                  *dep;
+
+       int                             ret;
+
+       dep = dwc->eps[epnum];
+
+       trb_hw = dwc->ep0_trb;
+       memset(&trb, 0, sizeof(trb));
+
+       switch (dwc->ep0state) {
+       case EP0_IDLE:
+               trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
+               break;
+
+       case EP0_IN_WAIT_NRDY:
+       case EP0_OUT_WAIT_NRDY:
+       case EP0_IN_STATUS_PHASE:
+       case EP0_OUT_STATUS_PHASE:
+               if (dwc->three_stage_setup)
+                       trb.trbctl = DWC3_TRBCTL_CONTROL_STATUS3;
+               else
+                       trb.trbctl = DWC3_TRBCTL_CONTROL_STATUS2;
+
+               if (dwc->ep0state == EP0_IN_WAIT_NRDY)
+                       dwc->ep0state = EP0_IN_STATUS_PHASE;
+               else if (dwc->ep0state == EP0_OUT_WAIT_NRDY)
+                       dwc->ep0state = EP0_OUT_STATUS_PHASE;
+               break;
+
+       case EP0_IN_WAIT_GADGET:
+               dwc->ep0state = EP0_IN_WAIT_NRDY;
+               return 0;
+               break;
+
+       case EP0_OUT_WAIT_GADGET:
+               dwc->ep0state = EP0_OUT_WAIT_NRDY;
+               return 0;
+
+               break;
+
+       case EP0_IN_DATA_PHASE:
+       case EP0_OUT_DATA_PHASE:
+               trb.trbctl = DWC3_TRBCTL_CONTROL_DATA;
+               break;
+
+       default:
+               dev_err(dwc->dev, "%s() can't in state %d\n", __func__,
+                               dwc->ep0state);
+               return -EINVAL;
+       }
+
+       trb.bplh = buf_dma;
+       trb.length = len;
+
+       trb.hwo = 1;
+       trb.lst = 1;
+       trb.ioc = 1;
+       trb.isp_imi = 1;
+
+       dwc3_trb_to_hw(&trb, trb_hw);
+
+       memset(&params, 0, sizeof(params));
+       params.param0.depstrtxfer.transfer_desc_addr_high =
+               upper_32_bits(dwc->ep0_trb_addr);
+       params.param1.depstrtxfer.transfer_desc_addr_low =
+               lower_32_bits(dwc->ep0_trb_addr);
+
+       ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+                       DWC3_DEPCMD_STARTTRANSFER, &params);
+       if (ret < 0) {
+               dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n");
+               return ret;
+       }
+
+       dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
+                       dep->number);
+
+       return 0;
+}
+
+static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
+               struct dwc3_request *req)
+{
+       struct dwc3             *dwc = dep->dwc;
+       int                     ret;
+
+       req->request.actual     = 0;
+       req->request.status     = -EINPROGRESS;
+       req->direction          = dep->direction;
+       req->epnum              = dep->number;
+
+       list_add_tail(&req->list, &dep->request_list);
+       dwc3_map_buffer_to_dma(req);
+
+       ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma,
+                       req->request.length);
+       if (ret < 0) {
+               list_del(&req->list);
+               dwc3_unmap_buffer_from_dma(req);
+       }
+
+       return ret;
+}
+
+int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
+               gfp_t gfp_flags)
+{
+       struct dwc3_request             *req = to_dwc3_request(request);
+       struct dwc3_ep                  *dep = to_dwc3_ep(ep);
+       struct dwc3                     *dwc = dep->dwc;
+
+       unsigned long                   flags;
+
+       int                             ret;
+
+       switch (dwc->ep0state) {
+       case EP0_IN_DATA_PHASE:
+       case EP0_IN_WAIT_GADGET:
+       case EP0_IN_WAIT_NRDY:
+       case EP0_IN_STATUS_PHASE:
+               dep = dwc->eps[1];
+               break;
+
+       case EP0_OUT_DATA_PHASE:
+       case EP0_OUT_WAIT_GADGET:
+       case EP0_OUT_WAIT_NRDY:
+       case EP0_OUT_STATUS_PHASE:
+               dep = dwc->eps[0];
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&dwc->lock, flags);
+       if (!dep->desc) {
+               dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
+                               request, dep->name);
+               ret = -ESHUTDOWN;
+               goto out;
+       }
+
+       /* we share one TRB for ep0/1 */
+       if (!list_empty(&dwc->eps[0]->request_list) ||
+                       !list_empty(&dwc->eps[1]->request_list) ||
+                       dwc->ep0_status_pending) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       dev_vdbg(dwc->dev, "queueing request %p to %s length %d, state '%s'\n",
+                       request, dep->name, request->length,
+                       dwc3_ep0_state_string(dwc->ep0state));
+
+       ret = __dwc3_gadget_ep0_queue(dep, req);
+
+out:
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return ret;
+}
+
+static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
+{
+       /* stall is always issued on EP0 */
+       __dwc3_gadget_ep_set_halt(dwc->eps[0], 1);
+       dwc->eps[0]->flags &= ~DWC3_EP_STALL;
+       dwc->ep0state = EP0_IDLE;
+       dwc3_ep0_out_start(dwc);
+}
+
+void dwc3_ep0_out_start(struct dwc3 *dwc)
+{
+       struct dwc3_ep                  *dep;
+       int                             ret;
+
+       dep = dwc->eps[0];
+
+       ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8);
+       WARN_ON(ret < 0);
+}
+
+/*
+ * Send a zero length packet for the status phase of the control transfer
+ */
+static void dwc3_ep0_do_setup_status(struct dwc3 *dwc,
+               const struct dwc3_event_depevt *event)
+{
+       struct dwc3_ep                  *dep;
+       int                             ret;
+       u32                             epnum;
+
+       epnum = event->endpoint_number;
+       dep = dwc->eps[epnum];
+
+       if (epnum)
+               dwc->ep0state = EP0_IN_STATUS_PHASE;
+       else
+               dwc->ep0state = EP0_OUT_STATUS_PHASE;
+
+       /*
+        * Not sure Why I need a buffer for a zero transfer. Maybe the
+        * HW reacts strange on a NULL pointer
+        */
+       ret = dwc3_ep0_start_trans(dwc, epnum, dwc->ctrl_req_addr, 0);
+       if (ret) {
+               dev_dbg(dwc->dev, "failed to start transfer, stalling\n");
+               dwc3_ep0_stall_and_restart(dwc);
+       }
+}
+
+static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le)
+{
+       struct dwc3_ep          *dep;
+       u32                     windex = le16_to_cpu(wIndex_le);
+       u32                     epnum;
+
+       epnum = (windex & USB_ENDPOINT_NUMBER_MASK) << 1;
+       if ((windex & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+               epnum |= 1;
+
+       dep = dwc->eps[epnum];
+       if (dep->flags & DWC3_EP_ENABLED)
+               return dep;
+
+       return NULL;
+}
+
+static void dwc3_ep0_send_status_response(struct dwc3 *dwc)
+{
+       u32 epnum;
+
+       if (dwc->ep0state == EP0_IN_DATA_PHASE)
+               epnum = 1;
+       else
+               epnum = 0;
+
+       dwc3_ep0_start_trans(dwc, epnum, dwc->ctrl_req_addr,
+                       dwc->ep0_usb_req.length);
+       dwc->ep0_status_pending = 1;
+}
+
+/*
+ * ch 9.4.5
+ */
+static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+       struct dwc3_ep          *dep;
+       u32                     recip;
+       u16                     usb_status = 0;
+       __le16                  *response_pkt;
+
+       recip = ctrl->bRequestType & USB_RECIP_MASK;
+       switch (recip) {
+       case USB_RECIP_DEVICE:
+               /*
+                * We are self-powered. U1/U2/LTM will be set later
+                * once we handle this states. RemoteWakeup is 0 on SS
+                */
+               usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
+               break;
+
+       case USB_RECIP_INTERFACE:
+               /*
+                * Function Remote Wake Capable D0
+                * Function Remote Wakeup       D1
+                */
+               break;
+
+       case USB_RECIP_ENDPOINT:
+               dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
+               if (!dep)
+                      return -EINVAL;
+
+               if (dep->flags & DWC3_EP_STALL)
+                       usb_status = 1 << USB_ENDPOINT_HALT;
+               break;
+       default:
+               return -EINVAL;
+       };
+
+       response_pkt = (__le16 *) dwc->setup_buf;
+       *response_pkt = cpu_to_le16(usb_status);
+       dwc->ep0_usb_req.length = sizeof(*response_pkt);
+       dwc3_ep0_send_status_response(dwc);
+
+       return 0;
+}
+
+static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
+               struct usb_ctrlrequest *ctrl, int set)
+{
+       struct dwc3_ep          *dep;
+       u32                     recip;
+       u32                     wValue;
+       u32                     wIndex;
+       u32                     reg;
+       int                     ret;
+       u32                     mode;
+
+       wValue = le16_to_cpu(ctrl->wValue);
+       wIndex = le16_to_cpu(ctrl->wIndex);
+       recip = ctrl->bRequestType & USB_RECIP_MASK;
+       switch (recip) {
+       case USB_RECIP_DEVICE:
+
+               /*
+                * 9.4.1 says only only for SS, in AddressState only for
+                * default control pipe
+                */
+               switch (wValue) {
+               case USB_DEVICE_U1_ENABLE:
+               case USB_DEVICE_U2_ENABLE:
+               case USB_DEVICE_LTM_ENABLE:
+                       if (dwc->dev_state != DWC3_CONFIGURED_STATE)
+                               return -EINVAL;
+                       if (dwc->speed != DWC3_DSTS_SUPERSPEED)
+                               return -EINVAL;
+               }
+
+               /* XXX add U[12] & LTM */
+               switch (wValue) {
+               case USB_DEVICE_REMOTE_WAKEUP:
+                       break;
+               case USB_DEVICE_U1_ENABLE:
+                       break;
+               case USB_DEVICE_U2_ENABLE:
+                       break;
+               case USB_DEVICE_LTM_ENABLE:
+                       break;
+
+               case USB_DEVICE_TEST_MODE:
+                       if ((wIndex & 0xff) != 0)
+                               return -EINVAL;
+                       if (!set)
+                               return -EINVAL;
+
+                       mode = wIndex >> 8;
+                       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+                       reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+
+                       switch (mode) {
+                       case TEST_J:
+                       case TEST_K:
+                       case TEST_SE0_NAK:
+                       case TEST_PACKET:
+                       case TEST_FORCE_EN:
+                               reg |= mode << 1;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+                       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       case USB_RECIP_INTERFACE:
+               switch (wValue) {
+               case USB_INTRF_FUNC_SUSPEND:
+                       if (wIndex & USB_INTRF_FUNC_SUSPEND_LP)
+                               /* XXX enable Low power suspend */
+                               ;
+                       if (wIndex & USB_INTRF_FUNC_SUSPEND_RW)
+                               /* XXX enable remote wakeup */
+                               ;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       case USB_RECIP_ENDPOINT:
+               switch (wValue) {
+               case USB_ENDPOINT_HALT:
+
+                       dep =  dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
+                       if (!dep)
+                               return -EINVAL;
+                       ret = __dwc3_gadget_ep_set_halt(dep, set);
+                       if (ret)
+                               return -EINVAL;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       default:
+               return -EINVAL;
+       };
+
+       dwc->ep0state = EP0_IN_WAIT_NRDY;
+
+       return 0;
+}
+
+static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+       int ret = 0;
+       u32 addr;
+       u32 reg;
+
+       addr = le16_to_cpu(ctrl->wValue);
+       if (addr > 127)
+               return -EINVAL;
+
+       switch (dwc->dev_state) {
+       case DWC3_DEFAULT_STATE:
+       case DWC3_ADDRESS_STATE:
+               /*
+                * Not sure if we should program DevAddr now or later
+                */
+               reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+               reg &= ~(DWC3_DCFG_DEVADDR_MASK);
+               reg |= DWC3_DCFG_DEVADDR(addr);
+               dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+               if (addr)
+                       dwc->dev_state = DWC3_ADDRESS_STATE;
+               else
+                       dwc->dev_state = DWC3_DEFAULT_STATE;
+               break;
+
+       case DWC3_CONFIGURED_STATE:
+               ret = -EINVAL;
+               break;
+       }
+       dwc->ep0state = EP0_IN_WAIT_NRDY;
+       return ret;
+}
+
+static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+       int ret;
+
+       spin_unlock(&dwc->lock);
+       ret = dwc->gadget_driver->setup(&dwc->gadget, ctrl);
+       spin_lock(&dwc->lock);
+       return ret;
+}
+
+static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+       u32 cfg;
+       int ret;
+
+       cfg = le16_to_cpu(ctrl->wValue);
+
+       switch (dwc->dev_state) {
+       case DWC3_DEFAULT_STATE:
+               return -EINVAL;
+               break;
+
+       case DWC3_ADDRESS_STATE:
+               ret = dwc3_ep0_delegate_req(dwc, ctrl);
+               /* if the cfg matches and the cfg is non zero */
+               if (!ret && cfg)
+                       dwc->dev_state = DWC3_CONFIGURED_STATE;
+               break;
+
+       case DWC3_CONFIGURED_STATE:
+               ret = dwc3_ep0_delegate_req(dwc, ctrl);
+               if (!cfg)
+                       dwc->dev_state = DWC3_ADDRESS_STATE;
+               break;
+       }
+       return 0;
+}
+
+static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+       int ret;
+
+       switch (ctrl->bRequest) {
+       case USB_REQ_GET_STATUS:
+               dev_vdbg(dwc->dev, "USB_REQ_GET_STATUS\n");
+               ret = dwc3_ep0_handle_status(dwc, ctrl);
+               break;
+       case USB_REQ_CLEAR_FEATURE:
+               dev_vdbg(dwc->dev, "USB_REQ_CLEAR_FEATURE\n");
+               ret = dwc3_ep0_handle_feature(dwc, ctrl, 0);
+               break;
+       case USB_REQ_SET_FEATURE:
+               dev_vdbg(dwc->dev, "USB_REQ_SET_FEATURE\n");
+               ret = dwc3_ep0_handle_feature(dwc, ctrl, 1);
+               break;
+       case USB_REQ_SET_ADDRESS:
+               dev_vdbg(dwc->dev, "USB_REQ_SET_ADDRESS\n");
+               ret = dwc3_ep0_set_address(dwc, ctrl);
+               break;
+       case USB_REQ_SET_CONFIGURATION:
+               dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n");
+               ret = dwc3_ep0_set_config(dwc, ctrl);
+               break;
+       default:
+               dev_vdbg(dwc->dev, "Forwarding to gadget driver\n");
+               ret = dwc3_ep0_delegate_req(dwc, ctrl);
+               break;
+       };
+
+       return ret;
+}
+
+static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
+               const struct dwc3_event_depevt *event)
+{
+       struct usb_ctrlrequest *ctrl = dwc->ctrl_req;
+       int ret;
+       u32 len;
+
+       if (!dwc->gadget_driver)
+               goto err;
+
+       len = le16_to_cpu(ctrl->wLength);
+       if (!len) {
+               dwc->ep0state = EP0_IN_WAIT_GADGET;
+               dwc->three_stage_setup = 0;
+       } else {
+               dwc->three_stage_setup = 1;
+               if (ctrl->bRequestType & USB_DIR_IN)
+                       dwc->ep0state = EP0_IN_DATA_PHASE;
+               else
+                       dwc->ep0state = EP0_OUT_DATA_PHASE;
+       }
+
+       if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
+               ret = dwc3_ep0_std_request(dwc, ctrl);
+       else
+               ret = dwc3_ep0_delegate_req(dwc, ctrl);
+
+       if (ret >= 0)
+               return;
+
+err:
+       dwc3_ep0_stall_and_restart(dwc);
+}
+
+static void dwc3_ep0_complete_data(struct dwc3 *dwc,
+               const struct dwc3_event_depevt *event)
+{
+       struct dwc3_request     *r = NULL;
+       struct usb_request      *ur;
+       struct dwc3_trb         trb;
+       struct dwc3_ep          *dep;
+       u32                     transfered;
+       u8                      epnum;
+
+       epnum = event->endpoint_number;
+       dep = dwc->eps[epnum];
+
+       if (!dwc->ep0_status_pending) {
+               r = next_request(&dep->request_list);
+               ur = &r->request;
+       } else {
+               ur = &dwc->ep0_usb_req;
+               dwc->ep0_status_pending = 0;
+       }
+
+       dwc3_trb_to_nat(dwc->ep0_trb, &trb);
+
+       transfered = ur->length - trb.length;
+       ur->actual += transfered;
+
+       if ((epnum & 1) && ur->actual < ur->length) {
+               /* for some reason we did not get everything out */
+
+               dwc3_ep0_stall_and_restart(dwc);
+               dwc3_gadget_giveback(dep, r, -ECONNRESET);
+       } else {
+               /*
+                * handle the case where we have to send a zero packet. This
+                * seems to be case when req.length > maxpacket. Could it be?
+                */
+               /* The transfer is complete, wait for HOST */
+               if (epnum & 1)
+                       dwc->ep0state = EP0_IN_WAIT_NRDY;
+               else
+                       dwc->ep0state = EP0_OUT_WAIT_NRDY;
+
+               if (r)
+                       dwc3_gadget_giveback(dep, r, 0);
+       }
+}
+
+static void dwc3_ep0_complete_req(struct dwc3 *dwc,
+               const struct dwc3_event_depevt *event)
+{
+       struct dwc3_request     *r;
+       struct dwc3_ep          *dep;
+       u8                      epnum;
+
+       epnum = event->endpoint_number;
+       dep = dwc->eps[epnum];
+
+       if (!list_empty(&dep->request_list)) {
+               r = next_request(&dep->request_list);
+
+               dwc3_gadget_giveback(dep, r, 0);
+       }
+
+       dwc->ep0state = EP0_IDLE;
+       dwc3_ep0_out_start(dwc);
+}
+
+static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
+                       const struct dwc3_event_depevt *event)
+{
+       switch (dwc->ep0state) {
+       case EP0_IDLE:
+               dwc3_ep0_inspect_setup(dwc, event);
+               break;
+
+       case EP0_IN_DATA_PHASE:
+       case EP0_OUT_DATA_PHASE:
+               dwc3_ep0_complete_data(dwc, event);
+               break;
+
+       case EP0_IN_STATUS_PHASE:
+       case EP0_OUT_STATUS_PHASE:
+               dwc3_ep0_complete_req(dwc, event);
+               break;
+
+       case EP0_IN_WAIT_NRDY:
+       case EP0_OUT_WAIT_NRDY:
+       case EP0_IN_WAIT_GADGET:
+       case EP0_OUT_WAIT_GADGET:
+       case EP0_UNCONNECTED:
+       case EP0_STALL:
+               break;
+       }
+}
+
+static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
+               const struct dwc3_event_depevt *event)
+{
+       switch (dwc->ep0state) {
+       case EP0_IN_WAIT_GADGET:
+               dwc->ep0state = EP0_IN_WAIT_NRDY;
+               break;
+       case EP0_OUT_WAIT_GADGET:
+               dwc->ep0state = EP0_OUT_WAIT_NRDY;
+               break;
+
+       case EP0_IN_WAIT_NRDY:
+       case EP0_OUT_WAIT_NRDY:
+               dwc3_ep0_do_setup_status(dwc, event);
+               break;
+
+       case EP0_IDLE:
+       case EP0_IN_STATUS_PHASE:
+       case EP0_OUT_STATUS_PHASE:
+       case EP0_IN_DATA_PHASE:
+       case EP0_OUT_DATA_PHASE:
+       case EP0_UNCONNECTED:
+       case EP0_STALL:
+               break;
+       }
+}
+
+void dwc3_ep0_interrupt(struct dwc3 *dwc,
+               const const struct dwc3_event_depevt *event)
+{
+       u8                      epnum = event->endpoint_number;
+
+       dev_dbg(dwc->dev, "%s while ep%d%s in state '%s'\n",
+                       dwc3_ep_event_string(event->endpoint_event),
+                       epnum, (epnum & 1) ? "in" : "out",
+                       dwc3_ep0_state_string(dwc->ep0state));
+
+       switch (event->endpoint_event) {
+       case DWC3_DEPEVT_XFERCOMPLETE:
+               dwc3_ep0_xfer_complete(dwc, event);
+               break;
+
+       case DWC3_DEPEVT_XFERNOTREADY:
+               dwc3_ep0_xfernotready(dwc, event);
+               break;
+
+       case DWC3_DEPEVT_XFERINPROGRESS:
+       case DWC3_DEPEVT_RXTXFIFOEVT:
+       case DWC3_DEPEVT_STREAMEVT:
+       case DWC3_DEPEVT_EPCMDCMPLT:
+               break;
+       }
+}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
new file mode 100644 (file)
index 0000000..cebaef7
--- /dev/null
@@ -0,0 +1,2062 @@
+/**
+ * gadget.c - DesignWare USB3 DRD Controller Gadget Framework Link
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ * All rights reserved.
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+#define        DMA_ADDR_INVALID        (~(dma_addr_t)0)
+
+void dwc3_map_buffer_to_dma(struct dwc3_request *req)
+{
+       struct dwc3                     *dwc = req->dep->dwc;
+
+       if (req->request.dma == DMA_ADDR_INVALID) {
+               req->request.dma = dma_map_single(dwc->dev, req->request.buf,
+                               req->request.length, req->direction
+                               ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               req->mapped = true;
+       } else {
+               dma_sync_single_for_device(dwc->dev, req->request.dma,
+                               req->request.length, req->direction
+                               ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               req->mapped = false;
+       }
+}
+
+void dwc3_unmap_buffer_from_dma(struct dwc3_request *req)
+{
+       struct dwc3                     *dwc = req->dep->dwc;
+
+       if (req->mapped) {
+               dma_unmap_single(dwc->dev, req->request.dma,
+                               req->request.length, req->direction
+                               ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               req->mapped = 0;
+       } else {
+               dma_sync_single_for_cpu(dwc->dev, req->request.dma,
+                               req->request.length, req->direction
+                               ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+       }
+}
+
+void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
+               int status)
+{
+       struct dwc3                     *dwc = dep->dwc;
+
+       if (req->queued) {
+               dep->busy_slot++;
+               /*
+                * Skip LINK TRB. We can't use req->trb and check for
+                * DWC3_TRBCTL_LINK_TRB because it points the TRB we just
+                * completed (not the LINK TRB).
+                */
+               if (((dep->busy_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
+                               usb_endpoint_xfer_isoc(dep->desc))
+                       dep->busy_slot++;
+       }
+       list_del(&req->list);
+
+       if (req->request.status == -EINPROGRESS)
+               req->request.status = status;
+
+       dwc3_unmap_buffer_from_dma(req);
+
+       dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
+                       req, dep->name, req->request.actual,
+                       req->request.length, status);
+
+       spin_unlock(&dwc->lock);
+       req->request.complete(&req->dep->endpoint, &req->request);
+       spin_lock(&dwc->lock);
+}
+
+static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
+{
+       switch (cmd) {
+       case DWC3_DEPCMD_DEPSTARTCFG:
+               return "Start New Configuration";
+       case DWC3_DEPCMD_ENDTRANSFER:
+               return "End Transfer";
+       case DWC3_DEPCMD_UPDATETRANSFER:
+               return "Update Transfer";
+       case DWC3_DEPCMD_STARTTRANSFER:
+               return "Start Transfer";
+       case DWC3_DEPCMD_CLEARSTALL:
+               return "Clear Stall";
+       case DWC3_DEPCMD_SETSTALL:
+               return "Set Stall";
+       case DWC3_DEPCMD_GETSEQNUMBER:
+               return "Get Data Sequence Number";
+       case DWC3_DEPCMD_SETTRANSFRESOURCE:
+               return "Set Endpoint Transfer Resource";
+       case DWC3_DEPCMD_SETEPCONFIG:
+               return "Set Endpoint Configuration";
+       default:
+               return "UNKNOWN command";
+       }
+}
+
+int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+               unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
+{
+       struct dwc3_ep          *dep = dwc->eps[ep];
+       unsigned long           timeout = 500;
+       u32                     reg;
+
+       dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n",
+                       dep->name,
+                       dwc3_gadget_ep_cmd_string(cmd), params->param0.raw,
+                       params->param1.raw, params->param2.raw);
+
+       dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0.raw);
+       dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1.raw);
+       dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2.raw);
+
+       dwc3_writel(dwc->regs, DWC3_DEPCMD(ep), cmd | DWC3_DEPCMD_CMDACT);
+       do {
+               reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep));
+               if (!(reg & DWC3_DEPCMD_CMDACT)) {
+                       dev_vdbg(dwc->dev, "CMD Compl Status %d DEPCMD %04x\n",
+                                       ((reg & 0xf000) >> 12), reg);
+                       return 0;
+               }
+
+               /*
+                * XXX Figure out a sane timeout here. 500ms is way too much.
+                * We can't sleep here, because it is also called from
+                * interrupt context.
+                */
+               timeout--;
+               if (!timeout)
+                       return -ETIMEDOUT;
+
+               mdelay(1);
+       } while (1);
+}
+
+static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
+               struct dwc3_trb_hw *trb)
+{
+       u32             offset = trb - dep->trb_pool;
+
+       return dep->trb_pool_dma + offset;
+}
+
+static int dwc3_alloc_trb_pool(struct dwc3_ep *dep)
+{
+       struct dwc3             *dwc = dep->dwc;
+
+       if (dep->trb_pool)
+               return 0;
+
+       if (dep->number == 0 || dep->number == 1)
+               return 0;
+
+       dep->trb_pool = dma_alloc_coherent(dwc->dev,
+                       sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
+                       &dep->trb_pool_dma, GFP_KERNEL);
+       if (!dep->trb_pool) {
+               dev_err(dep->dwc->dev, "failed to allocate trb pool for %s\n",
+                               dep->name);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void dwc3_free_trb_pool(struct dwc3_ep *dep)
+{
+       struct dwc3             *dwc = dep->dwc;
+
+       dma_free_coherent(dwc->dev, sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
+                       dep->trb_pool, dep->trb_pool_dma);
+
+       dep->trb_pool = NULL;
+       dep->trb_pool_dma = 0;
+}
+
+static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+       struct dwc3_gadget_ep_cmd_params params;
+       u32                     cmd;
+
+       memset(&params, 0x00, sizeof(params));
+
+       if (dep->number != 1) {
+               cmd = DWC3_DEPCMD_DEPSTARTCFG;
+               /* XferRscIdx == 0 for ep0 and 2 for the remaining */
+               if (dep->number > 1)
+                       cmd |= DWC3_DEPCMD_PARAM(2);
+
+               return dwc3_send_gadget_ep_cmd(dwc, 0, cmd, &params);
+       }
+
+       return 0;
+}
+
+static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
+               const struct usb_endpoint_descriptor *desc)
+{
+       struct dwc3_gadget_ep_cmd_params params;
+
+       memset(&params, 0x00, sizeof(params));
+
+       params.param0.depcfg.ep_type = usb_endpoint_type(desc);
+       params.param0.depcfg.max_packet_size = usb_endpoint_maxp(desc);
+
+       params.param1.depcfg.xfer_complete_enable = true;
+       params.param1.depcfg.xfer_not_ready_enable = true;
+
+       if (usb_endpoint_xfer_isoc(desc))
+               params.param1.depcfg.xfer_in_progress_enable = true;
+
+       /*
+        * We are doing 1:1 mapping for endpoints, meaning
+        * Physical Endpoints 2 maps to Logical Endpoint 2 and
+        * so on. We consider the direction bit as part of the physical
+        * endpoint number. So USB endpoint 0x81 is 0x03.
+        */
+       params.param1.depcfg.ep_number = dep->number;
+
+       /*
+        * We must use the lower 16 TX FIFOs even though
+        * HW might have more
+        */
+       if (dep->direction)
+               params.param0.depcfg.fifo_number = dep->number >> 1;
+
+       if (desc->bInterval) {
+               params.param1.depcfg.binterval_m1 = desc->bInterval - 1;
+               dep->interval = 1 << (desc->bInterval - 1);
+       }
+
+       return dwc3_send_gadget_ep_cmd(dwc, dep->number,
+                       DWC3_DEPCMD_SETEPCONFIG, &params);
+}
+
+static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+       struct dwc3_gadget_ep_cmd_params params;
+
+       memset(&params, 0x00, sizeof(params));
+
+       params.param0.depxfercfg.number_xfer_resources = 1;
+
+       return dwc3_send_gadget_ep_cmd(dwc, dep->number,
+                       DWC3_DEPCMD_SETTRANSFRESOURCE, &params);
+}
+
+/**
+ * __dwc3_gadget_ep_enable - Initializes a HW endpoint
+ * @dep: endpoint to be initialized
+ * @desc: USB Endpoint Descriptor
+ *
+ * Caller should take care of locking
+ */
+static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
+               const struct usb_endpoint_descriptor *desc)
+{
+       struct dwc3             *dwc = dep->dwc;
+       u32                     reg;
+       int                     ret = -ENOMEM;
+
+       if (!(dep->flags & DWC3_EP_ENABLED)) {
+               ret = dwc3_gadget_start_config(dwc, dep);
+               if (ret)
+                       return ret;
+       }
+
+       ret = dwc3_gadget_set_ep_config(dwc, dep, desc);
+       if (ret)
+               return ret;
+
+       if (!(dep->flags & DWC3_EP_ENABLED)) {
+               struct dwc3_trb_hw      *trb_st_hw;
+               struct dwc3_trb_hw      *trb_link_hw;
+               struct dwc3_trb         trb_link;
+
+               ret = dwc3_gadget_set_xfer_resource(dwc, dep);
+               if (ret)
+                       return ret;
+
+               dep->desc = desc;
+               dep->type = usb_endpoint_type(desc);
+               dep->flags |= DWC3_EP_ENABLED;
+
+               reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
+               reg |= DWC3_DALEPENA_EP(dep->number);
+               dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
+
+               if (!usb_endpoint_xfer_isoc(desc))
+                       return 0;
+
+               memset(&trb_link, 0, sizeof(trb_link));
+
+               /* Link TRB for ISOC. The HWO but is never reset */
+               trb_st_hw = &dep->trb_pool[0];
+
+               trb_link.bplh = dwc3_trb_dma_offset(dep, trb_st_hw);
+               trb_link.trbctl = DWC3_TRBCTL_LINK_TRB;
+               trb_link.hwo = true;
+
+               trb_link_hw = &dep->trb_pool[DWC3_TRB_NUM - 1];
+               dwc3_trb_to_hw(&trb_link, trb_link_hw);
+       }
+
+       return 0;
+}
+
+static void dwc3_gadget_nuke_reqs(struct dwc3_ep *dep, const int status)
+{
+       struct dwc3_request             *req;
+
+       while (!list_empty(&dep->request_list)) {
+               req = next_request(&dep->request_list);
+
+               dwc3_gadget_giveback(dep, req, status);
+       }
+       /* nuke queued TRBs as well on command complete */
+       dep->flags |= DWC3_EP_WILL_SHUTDOWN;
+}
+
+/**
+ * __dwc3_gadget_ep_disable - Disables a HW endpoint
+ * @dep: the endpoint to disable
+ *
+ * Caller should take care of locking
+ */
+static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum);
+static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
+{
+       struct dwc3             *dwc = dep->dwc;
+       u32                     reg;
+
+       dep->flags &= ~DWC3_EP_ENABLED;
+       dwc3_stop_active_transfer(dwc, dep->number);
+       dwc3_gadget_nuke_reqs(dep, -ESHUTDOWN);
+
+       reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
+       reg &= ~DWC3_DALEPENA_EP(dep->number);
+       dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
+
+       dep->desc = NULL;
+       dep->type = 0;
+
+       return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_ep0_enable(struct usb_ep *ep,
+               const struct usb_endpoint_descriptor *desc)
+{
+       return -EINVAL;
+}
+
+static int dwc3_gadget_ep0_disable(struct usb_ep *ep)
+{
+       return -EINVAL;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_ep_enable(struct usb_ep *ep,
+               const struct usb_endpoint_descriptor *desc)
+{
+       struct dwc3_ep                  *dep;
+       struct dwc3                     *dwc;
+       unsigned long                   flags;
+       int                             ret;
+
+       if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
+               pr_debug("dwc3: invalid parameters\n");
+               return -EINVAL;
+       }
+
+       if (!desc->wMaxPacketSize) {
+               pr_debug("dwc3: missing wMaxPacketSize\n");
+               return -EINVAL;
+       }
+
+       dep = to_dwc3_ep(ep);
+       dwc = dep->dwc;
+
+       switch (usb_endpoint_type(desc)) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               strncat(dep->name, "-control", sizeof(dep->name));
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               strncat(dep->name, "-isoc", sizeof(dep->name));
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               strncat(dep->name, "-bulk", sizeof(dep->name));
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               strncat(dep->name, "-int", sizeof(dep->name));
+               break;
+       default:
+               dev_err(dwc->dev, "invalid endpoint transfer type\n");
+       }
+
+       if (dep->flags & DWC3_EP_ENABLED) {
+               dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n",
+                               dep->name);
+               return 0;
+       }
+
+       dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
+
+       spin_lock_irqsave(&dwc->lock, flags);
+       ret = __dwc3_gadget_ep_enable(dep, desc);
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return ret;
+}
+
+static int dwc3_gadget_ep_disable(struct usb_ep *ep)
+{
+       struct dwc3_ep                  *dep;
+       struct dwc3                     *dwc;
+       unsigned long                   flags;
+       int                             ret;
+
+       if (!ep) {
+               pr_debug("dwc3: invalid parameters\n");
+               return -EINVAL;
+       }
+
+       dep = to_dwc3_ep(ep);
+       dwc = dep->dwc;
+
+       if (!(dep->flags & DWC3_EP_ENABLED)) {
+               dev_WARN_ONCE(dwc->dev, true, "%s is already disabled\n",
+                               dep->name);
+               return 0;
+       }
+
+       snprintf(dep->name, sizeof(dep->name), "ep%d%s",
+                       dep->number >> 1,
+                       (dep->number & 1) ? "in" : "out");
+
+       spin_lock_irqsave(&dwc->lock, flags);
+       ret = __dwc3_gadget_ep_disable(dep);
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return ret;
+}
+
+static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep,
+       gfp_t gfp_flags)
+{
+       struct dwc3_request             *req;
+       struct dwc3_ep                  *dep = to_dwc3_ep(ep);
+       struct dwc3                     *dwc = dep->dwc;
+
+       req = kzalloc(sizeof(*req), gfp_flags);
+       if (!req) {
+               dev_err(dwc->dev, "not enough memory\n");
+               return NULL;
+       }
+
+       req->epnum      = dep->number;
+       req->dep        = dep;
+       req->request.dma = DMA_ADDR_INVALID;
+
+       return &req->request;
+}
+
+static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
+               struct usb_request *request)
+{
+       struct dwc3_request             *req = to_dwc3_request(request);
+
+       kfree(req);
+}
+
+/*
+ * dwc3_prepare_trbs - setup TRBs from requests
+ * @dep: endpoint for which requests are being prepared
+ * @starting: true if the endpoint is idle and no requests are queued.
+ *
+ * The functions goes through the requests list and setups TRBs for the
+ * transfers. The functions returns once there are not more TRBs available or
+ * it run out of requests.
+ */
+static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,
+               bool starting)
+{
+       struct dwc3_request     *req, *n, *ret = NULL;
+       struct dwc3_trb_hw      *trb_hw;
+       struct dwc3_trb         trb;
+       u32                     trbs_left;
+
+       BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
+
+       /* the first request must not be queued */
+       trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
+       /*
+        * if busy & slot are equal than it is either full or empty. If we are
+        * starting to proceed requests then we are empty. Otherwise we ar
+        * full and don't do anything
+        */
+       if (!trbs_left) {
+               if (!starting)
+                       return NULL;
+               trbs_left = DWC3_TRB_NUM;
+               /*
+                * In case we start from scratch, we queue the ISOC requests
+                * starting from slot 1. This is done because we use ring
+                * buffer and have no LST bit to stop us. Instead, we place
+                * IOC bit TRB_NUM/4. We try to avoid to having an interrupt
+                * after the first request so we start at slot 1 and have
+                * 7 requests proceed before we hit the first IOC.
+                * Other transfer types don't use the ring buffer and are
+                * processed from the first TRB until the last one. Since we
+                * don't wrap around we have to start at the beginning.
+                */
+               if (usb_endpoint_xfer_isoc(dep->desc)) {
+                       dep->busy_slot = 1;
+                       dep->free_slot = 1;
+               } else {
+                       dep->busy_slot = 0;
+                       dep->free_slot = 0;
+               }
+       }
+
+       /* The last TRB is a link TRB, not used for xfer */
+       if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc))
+               return NULL;
+
+       list_for_each_entry_safe(req, n, &dep->request_list, list) {
+               unsigned int last_one = 0;
+               unsigned int cur_slot;
+
+               trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+               cur_slot = dep->free_slot;
+               dep->free_slot++;
+
+               /* Skip the LINK-TRB on ISOC */
+               if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
+                               usb_endpoint_xfer_isoc(dep->desc))
+                       continue;
+
+               dwc3_gadget_move_request_queued(req);
+               memset(&trb, 0, sizeof(trb));
+               trbs_left--;
+
+               /* Is our TRB pool empty? */
+               if (!trbs_left)
+                       last_one = 1;
+               /* Is this the last request? */
+               if (list_empty(&dep->request_list))
+                       last_one = 1;
+
+               /*
+                * FIXME we shouldn't need to set LST bit always but we are
+                * facing some weird problem with the Hardware where it doesn't
+                * complete even though it has been previously started.
+                *
+                * While we're debugging the problem, as a workaround to
+                * multiple TRBs handling, use only one TRB at a time.
+                */
+               last_one = 1;
+
+               req->trb = trb_hw;
+               if (!ret)
+                       ret = req;
+
+               trb.bplh = req->request.dma;
+
+               if (usb_endpoint_xfer_isoc(dep->desc)) {
+                       trb.isp_imi = true;
+                       trb.csp = true;
+               } else {
+                       trb.lst = last_one;
+               }
+
+               switch (usb_endpoint_type(dep->desc)) {
+               case USB_ENDPOINT_XFER_CONTROL:
+                       trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
+                       break;
+
+               case USB_ENDPOINT_XFER_ISOC:
+                       trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS;
+
+                       /* IOC every DWC3_TRB_NUM / 4 so we can refill */
+                       if (!(cur_slot % (DWC3_TRB_NUM / 4)))
+                               trb.ioc = last_one;
+                       break;
+
+               case USB_ENDPOINT_XFER_BULK:
+               case USB_ENDPOINT_XFER_INT:
+                       trb.trbctl = DWC3_TRBCTL_NORMAL;
+                       break;
+               default:
+                       /*
+                        * This is only possible with faulty memory because we
+                        * checked it already :)
+                        */
+                       BUG();
+               }
+
+               trb.length      = req->request.length;
+               trb.hwo = true;
+
+               dwc3_trb_to_hw(&trb, trb_hw);
+               req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
+
+               if (last_one)
+                       break;
+       }
+
+       return ret;
+}
+
+static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
+               int start_new)
+{
+       struct dwc3_gadget_ep_cmd_params params;
+       struct dwc3_request             *req;
+       struct dwc3                     *dwc = dep->dwc;
+       int                             ret;
+       u32                             cmd;
+
+       if (start_new && (dep->flags & DWC3_EP_BUSY)) {
+               dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name);
+               return -EBUSY;
+       }
+       dep->flags &= ~DWC3_EP_PENDING_REQUEST;
+
+       /*
+        * If we are getting here after a short-out-packet we don't enqueue any
+        * new requests as we try to set the IOC bit only on the last request.
+        */
+       if (start_new) {
+               if (list_empty(&dep->req_queued))
+                       dwc3_prepare_trbs(dep, start_new);
+
+               /* req points to the first request which will be sent */
+               req = next_request(&dep->req_queued);
+       } else {
+               /*
+                * req points to the first request where HWO changed
+                * from 0 to 1
+                */
+               req = dwc3_prepare_trbs(dep, start_new);
+       }
+       if (!req) {
+               dep->flags |= DWC3_EP_PENDING_REQUEST;
+               return 0;
+       }
+
+       memset(&params, 0, sizeof(params));
+       params.param0.depstrtxfer.transfer_desc_addr_high =
+               upper_32_bits(req->trb_dma);
+       params.param1.depstrtxfer.transfer_desc_addr_low =
+               lower_32_bits(req->trb_dma);
+
+       if (start_new)
+               cmd = DWC3_DEPCMD_STARTTRANSFER;
+       else
+               cmd = DWC3_DEPCMD_UPDATETRANSFER;
+
+       cmd |= DWC3_DEPCMD_PARAM(cmd_param);
+       ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+       if (ret < 0) {
+               dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n");
+
+               /*
+                * FIXME we need to iterate over the list of requests
+                * here and stop, unmap, free and del each of the linked
+                * requests instead of we do now.
+                */
+               dwc3_unmap_buffer_from_dma(req);
+               list_del(&req->list);
+               return ret;
+       }
+
+       dep->flags |= DWC3_EP_BUSY;
+       dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
+                       dep->number);
+       if (!dep->res_trans_idx)
+               printk_once(KERN_ERR "%s() res_trans_idx is invalid\n", __func__);
+       return 0;
+}
+
+static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
+{
+       req->request.actual     = 0;
+       req->request.status     = -EINPROGRESS;
+       req->direction          = dep->direction;
+       req->epnum              = dep->number;
+
+       /*
+        * We only add to our list of requests now and
+        * start consuming the list once we get XferNotReady
+        * IRQ.
+        *
+        * That way, we avoid doing anything that we don't need
+        * to do now and defer it until the point we receive a
+        * particular token from the Host side.
+        *
+        * This will also avoid Host cancelling URBs due to too
+        * many NACKs.
+        */
+       dwc3_map_buffer_to_dma(req);
+       list_add_tail(&req->list, &dep->request_list);
+
+       /*
+        * There is one special case: XferNotReady with
+        * empty list of requests. We need to kick the
+        * transfer here in that situation, otherwise
+        * we will be NAKing forever.
+        *
+        * If we get XferNotReady before gadget driver
+        * has a chance to queue a request, we will ACK
+        * the IRQ but won't be able to receive the data
+        * until the next request is queued. The following
+        * code is handling exactly that.
+        */
+       if (dep->flags & DWC3_EP_PENDING_REQUEST) {
+               int ret;
+               int start_trans;
+
+               start_trans = 1;
+               if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+                               dep->flags & DWC3_EP_BUSY)
+                       start_trans = 0;
+
+               ret =  __dwc3_gadget_kick_transfer(dep, 0, start_trans);
+               if (ret && ret != -EBUSY) {
+                       struct dwc3     *dwc = dep->dwc;
+
+                       dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+                                       dep->name);
+               }
+       };
+
+       return 0;
+}
+
+static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
+       gfp_t gfp_flags)
+{
+       struct dwc3_request             *req = to_dwc3_request(request);
+       struct dwc3_ep                  *dep = to_dwc3_ep(ep);
+       struct dwc3                     *dwc = dep->dwc;
+
+       unsigned long                   flags;
+
+       int                             ret;
+
+       if (!dep->desc) {
+               dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
+                               request, ep->name);
+               return -ESHUTDOWN;
+       }
+
+       dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
+                       request, ep->name, request->length);
+
+       spin_lock_irqsave(&dwc->lock, flags);
+       ret = __dwc3_gadget_ep_queue(dep, req);
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return ret;
+}
+
+static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
+               struct usb_request *request)
+{
+       struct dwc3_request             *req = to_dwc3_request(request);
+       struct dwc3_request             *r = NULL;
+
+       struct dwc3_ep                  *dep = to_dwc3_ep(ep);
+       struct dwc3                     *dwc = dep->dwc;
+
+       unsigned long                   flags;
+       int                             ret = 0;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+
+       list_for_each_entry(r, &dep->request_list, list) {
+               if (r == req)
+                       break;
+       }
+
+       if (r != req) {
+               list_for_each_entry(r, &dep->req_queued, list) {
+                       if (r == req)
+                               break;
+               }
+               if (r == req) {
+                       /* wait until it is processed */
+                       dwc3_stop_active_transfer(dwc, dep->number);
+                       goto out0;
+               }
+               dev_err(dwc->dev, "request %p was not queued to %s\n",
+                               request, ep->name);
+               ret = -EINVAL;
+               goto out0;
+       }
+
+       /* giveback the request */
+       dwc3_gadget_giveback(dep, req, -ECONNRESET);
+
+out0:
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return ret;
+}
+
+int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
+{
+       struct dwc3_gadget_ep_cmd_params        params;
+       struct dwc3                             *dwc = dep->dwc;
+       int                                     ret;
+
+       memset(&params, 0x00, sizeof(params));
+
+       if (value) {
+               if (dep->number == 0 || dep->number == 1)
+                       dwc->ep0state = EP0_STALL;
+
+               ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+                       DWC3_DEPCMD_SETSTALL, &params);
+               if (ret)
+                       dev_err(dwc->dev, "failed to %s STALL on %s\n",
+                                       value ? "set" : "clear",
+                                       dep->name);
+               else
+                       dep->flags |= DWC3_EP_STALL;
+       } else {
+               ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+                       DWC3_DEPCMD_CLEARSTALL, &params);
+               if (ret)
+                       dev_err(dwc->dev, "failed to %s STALL on %s\n",
+                                       value ? "set" : "clear",
+                                       dep->name);
+               else
+                       dep->flags &= ~DWC3_EP_STALL;
+       }
+       return ret;
+}
+
+static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
+{
+       struct dwc3_ep                  *dep = to_dwc3_ep(ep);
+       struct dwc3                     *dwc = dep->dwc;
+
+       unsigned long                   flags;
+
+       int                             ret;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+
+       if (usb_endpoint_xfer_isoc(dep->desc)) {
+               dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = __dwc3_gadget_ep_set_halt(dep, value);
+out:
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return ret;
+}
+
+static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
+{
+       struct dwc3_ep                  *dep = to_dwc3_ep(ep);
+
+       dep->flags |= DWC3_EP_WEDGE;
+
+       return usb_ep_set_halt(ep);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static struct usb_endpoint_descriptor dwc3_gadget_ep0_desc = {
+       .bLength        = USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType = USB_DT_ENDPOINT,
+       .bmAttributes   = USB_ENDPOINT_XFER_CONTROL,
+};
+
+static const struct usb_ep_ops dwc3_gadget_ep0_ops = {
+       .enable         = dwc3_gadget_ep0_enable,
+       .disable        = dwc3_gadget_ep0_disable,
+       .alloc_request  = dwc3_gadget_ep_alloc_request,
+       .free_request   = dwc3_gadget_ep_free_request,
+       .queue          = dwc3_gadget_ep0_queue,
+       .dequeue        = dwc3_gadget_ep_dequeue,
+       .set_halt       = dwc3_gadget_ep_set_halt,
+       .set_wedge      = dwc3_gadget_ep_set_wedge,
+};
+
+static const struct usb_ep_ops dwc3_gadget_ep_ops = {
+       .enable         = dwc3_gadget_ep_enable,
+       .disable        = dwc3_gadget_ep_disable,
+       .alloc_request  = dwc3_gadget_ep_alloc_request,
+       .free_request   = dwc3_gadget_ep_free_request,
+       .queue          = dwc3_gadget_ep_queue,
+       .dequeue        = dwc3_gadget_ep_dequeue,
+       .set_halt       = dwc3_gadget_ep_set_halt,
+       .set_wedge      = dwc3_gadget_ep_set_wedge,
+};
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_get_frame(struct usb_gadget *g)
+{
+       struct dwc3             *dwc = gadget_to_dwc(g);
+       u32                     reg;
+
+       reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+       return DWC3_DSTS_SOFFN(reg);
+}
+
+static int dwc3_gadget_wakeup(struct usb_gadget *g)
+{
+       struct dwc3             *dwc = gadget_to_dwc(g);
+
+       unsigned long           timeout;
+       unsigned long           flags;
+
+       u32                     reg;
+
+       int                     ret = 0;
+
+       u8                      link_state;
+       u8                      speed;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+
+       /*
+        * According to the Databook Remote wakeup request should
+        * be issued only when the device is in early suspend state.
+        *
+        * We can check that via USB Link State bits in DSTS register.
+        */
+       reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+       speed = reg & DWC3_DSTS_CONNECTSPD;
+       if (speed == DWC3_DSTS_SUPERSPEED) {
+               dev_dbg(dwc->dev, "no wakeup on SuperSpeed\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       link_state = DWC3_DSTS_USBLNKST(reg);
+
+       switch (link_state) {
+       case DWC3_LINK_STATE_RX_DET:    /* in HS, means Early Suspend */
+       case DWC3_LINK_STATE_U3:        /* in HS, means SUSPEND */
+               break;
+       default:
+               dev_dbg(dwc->dev, "can't wakeup from link state %d\n",
+                               link_state);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+
+       /*
+        * Switch link state to Recovery. In HS/FS/LS this means
+        * RemoteWakeup Request
+        */
+       reg |= DWC3_DCTL_ULSTCHNG_RECOVERY;
+       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+       /* wait for at least 2000us */
+       usleep_range(2000, 2500);
+
+       /* write zeroes to Link Change Request */
+       reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
+       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+       /* pool until Link State change to ON */
+       timeout = jiffies + msecs_to_jiffies(100);
+
+       while (!(time_after(jiffies, timeout))) {
+               reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+               /* in HS, means ON */
+               if (DWC3_DSTS_USBLNKST(reg) == DWC3_LINK_STATE_U0)
+                       break;
+       }
+
+       if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) {
+               dev_err(dwc->dev, "failed to send remote wakeup\n");
+               ret = -EINVAL;
+       }
+
+out:
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return ret;
+}
+
+static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
+               int is_selfpowered)
+{
+       struct dwc3             *dwc = gadget_to_dwc(g);
+
+       dwc->is_selfpowered = !!is_selfpowered;
+
+       return 0;
+}
+
+static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
+{
+       u32                     reg;
+       unsigned long           timeout = 500;
+
+       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+       if (is_on)
+               reg |= DWC3_DCTL_RUN_STOP;
+       else
+               reg &= ~DWC3_DCTL_RUN_STOP;
+
+       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+       do {
+               reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+               if (is_on) {
+                       if (!(reg & DWC3_DSTS_DEVCTRLHLT))
+                               break;
+               } else {
+                       if (reg & DWC3_DSTS_DEVCTRLHLT)
+                               break;
+               }
+               /*
+                * XXX reduce the 500ms delay
+                */
+               timeout--;
+               if (!timeout)
+                       break;
+               mdelay(1);
+       } while (1);
+
+       dev_vdbg(dwc->dev, "gadget %s data soft-%s\n",
+                       dwc->gadget_driver
+                       ? dwc->gadget_driver->function : "no-function",
+                       is_on ? "connect" : "disconnect");
+}
+
+static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
+{
+       struct dwc3             *dwc = gadget_to_dwc(g);
+       unsigned long           flags;
+
+       is_on = !!is_on;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+       dwc3_gadget_run_stop(dwc, is_on);
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return 0;
+}
+
+static int dwc3_gadget_start(struct usb_gadget *g,
+               struct usb_gadget_driver *driver)
+{
+       struct dwc3             *dwc = gadget_to_dwc(g);
+       struct dwc3_ep          *dep;
+       unsigned long           flags;
+       int                     ret = 0;
+       u32                     reg;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+
+       if (dwc->gadget_driver) {
+               dev_err(dwc->dev, "%s is already bound to %s\n",
+                               dwc->gadget.name,
+                               dwc->gadget_driver->driver.name);
+               ret = -EBUSY;
+               goto err0;
+       }
+
+       dwc->gadget_driver      = driver;
+       dwc->gadget.dev.driver  = &driver->driver;
+
+       reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+
+       /*
+        * REVISIT: power down scale might be different
+        * depending on PHY used, need to pass that via platform_data
+        */
+       reg |= DWC3_GCTL_PWRDNSCALE(0x61a)
+               | DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE);
+       reg &= ~DWC3_GCTL_DISSCRAMBLE;
+
+       /*
+        * WORKAROUND: DWC3 revisions <1.90a have a bug
+        * when The device fails to connect at SuperSpeed
+        * and falls back to high-speed mode which causes
+        * the device to enter in a Connect/Disconnect loop
+        */
+       if (dwc->revision < DWC3_REVISION_190A)
+               reg |= DWC3_GCTL_U2RSTECN;
+
+       dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+       reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+       reg &= ~(DWC3_DCFG_SPEED_MASK);
+       reg |= DWC3_DCFG_SUPERSPEED;
+       dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+       /* Start with SuperSpeed Default */
+       dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+
+       dep = dwc->eps[0];
+       ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+       if (ret) {
+               dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+               goto err0;
+       }
+
+       dep = dwc->eps[1];
+       ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+       if (ret) {
+               dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+               goto err1;
+       }
+
+       /* begin to receive SETUP packets */
+       dwc->ep0state = EP0_IDLE;
+       dwc3_ep0_out_start(dwc);
+
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return 0;
+
+err1:
+       __dwc3_gadget_ep_disable(dwc->eps[0]);
+
+err0:
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return ret;
+}
+
+static int dwc3_gadget_stop(struct usb_gadget *g,
+               struct usb_gadget_driver *driver)
+{
+       struct dwc3             *dwc = gadget_to_dwc(g);
+       unsigned long           flags;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+
+       __dwc3_gadget_ep_disable(dwc->eps[0]);
+       __dwc3_gadget_ep_disable(dwc->eps[1]);
+
+       dwc->gadget_driver      = NULL;
+       dwc->gadget.dev.driver  = NULL;
+
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return 0;
+}
+static const struct usb_gadget_ops dwc3_gadget_ops = {
+       .get_frame              = dwc3_gadget_get_frame,
+       .wakeup                 = dwc3_gadget_wakeup,
+       .set_selfpowered        = dwc3_gadget_set_selfpowered,
+       .pullup                 = dwc3_gadget_pullup,
+       .udc_start              = dwc3_gadget_start,
+       .udc_stop               = dwc3_gadget_stop,
+};
+
+/* -------------------------------------------------------------------------- */
+
+static int __devinit dwc3_gadget_init_endpoints(struct dwc3 *dwc)
+{
+       struct dwc3_ep                  *dep;
+       u8                              epnum;
+
+       INIT_LIST_HEAD(&dwc->gadget.ep_list);
+
+       for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+               dep = kzalloc(sizeof(*dep), GFP_KERNEL);
+               if (!dep) {
+                       dev_err(dwc->dev, "can't allocate endpoint %d\n",
+                                       epnum);
+                       return -ENOMEM;
+               }
+
+               dep->dwc = dwc;
+               dep->number = epnum;
+               dwc->eps[epnum] = dep;
+
+               snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
+                               (epnum & 1) ? "in" : "out");
+               dep->endpoint.name = dep->name;
+               dep->direction = (epnum & 1);
+
+               if (epnum == 0 || epnum == 1) {
+                       dep->endpoint.maxpacket = 512;
+                       dep->endpoint.ops = &dwc3_gadget_ep0_ops;
+                       if (!epnum)
+                               dwc->gadget.ep0 = &dep->endpoint;
+               } else {
+                       int             ret;
+
+                       dep->endpoint.maxpacket = 1024;
+                       dep->endpoint.ops = &dwc3_gadget_ep_ops;
+                       list_add_tail(&dep->endpoint.ep_list,
+                                       &dwc->gadget.ep_list);
+
+                       ret = dwc3_alloc_trb_pool(dep);
+                       if (ret) {
+                               dev_err(dwc->dev, "%s: failed to allocate TRB pool\n", dep->name);
+                               return ret;
+                       }
+               }
+               INIT_LIST_HEAD(&dep->request_list);
+               INIT_LIST_HEAD(&dep->req_queued);
+       }
+
+       return 0;
+}
+
+static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
+{
+       struct dwc3_ep                  *dep;
+       u8                              epnum;
+
+       for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+               dep = dwc->eps[epnum];
+               dwc3_free_trb_pool(dep);
+
+               if (epnum != 0 && epnum != 1)
+                       list_del(&dep->endpoint.ep_list);
+
+               kfree(dep);
+       }
+}
+
+static void dwc3_gadget_release(struct device *dev)
+{
+       dev_dbg(dev, "%s\n", __func__);
+}
+
+/* -------------------------------------------------------------------------- */
+static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
+               const struct dwc3_event_depevt *event, int status)
+{
+       struct dwc3_request     *req;
+       struct dwc3_trb         trb;
+       unsigned int            count;
+       unsigned int            s_pkt = 0;
+
+       do {
+               req = next_request(&dep->req_queued);
+               if (!req)
+                       break;
+
+               dwc3_trb_to_nat(req->trb, &trb);
+
+               if (trb.hwo) {
+                       dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n",
+                                       dep->name, req->trb);
+                       continue;
+               }
+               count = trb.length;
+
+               if (dep->direction) {
+                       if (count) {
+                               dev_err(dwc->dev, "incomplete IN transfer %s\n",
+                                               dep->name);
+                               status = -ECONNRESET;
+                       }
+               } else {
+                       if (count && (event->status & DEPEVT_STATUS_SHORT))
+                               s_pkt = 1;
+               }
+
+               /*
+                * We assume here we will always receive the entire data block
+                * which we should receive. Meaning, if we program RX to
+                * receive 4K but we receive only 2K, we assume that's all we
+                * should receive and we simply bounce the request back to the
+                * gadget driver for further processing.
+                */
+               req->request.actual += req->request.length - count;
+               dwc3_gadget_giveback(dep, req, status);
+               if (s_pkt)
+                       break;
+               if ((event->status & DEPEVT_STATUS_LST) && trb.lst)
+                       break;
+               if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+                       break;
+       } while (1);
+
+       if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+               return 0;
+       return 1;
+}
+
+static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
+               struct dwc3_ep *dep, const struct dwc3_event_depevt *event,
+               int start_new)
+{
+       unsigned                status = 0;
+       int                     clean_busy;
+
+       if (event->status & DEPEVT_STATUS_BUSERR)
+               status = -ECONNRESET;
+
+       clean_busy =  dwc3_cleanup_done_reqs(dwc, dep, event, status);
+       if (clean_busy)
+               dep->flags &= ~DWC3_EP_BUSY;
+}
+
+static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
+               struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
+{
+       u32 uf;
+
+       if (list_empty(&dep->request_list)) {
+               dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
+                       dep->name);
+               return;
+       }
+
+       if (event->parameters) {
+               u32 mask;
+
+               mask = ~(dep->interval - 1);
+               uf = event->parameters & mask;
+               /* 4 micro frames in the future */
+               uf += dep->interval * 4;
+       } else {
+               uf = 0;
+       }
+
+       __dwc3_gadget_kick_transfer(dep, uf, 1);
+}
+
+static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep,
+               const struct dwc3_event_depevt *event)
+{
+       struct dwc3 *dwc = dep->dwc;
+       struct dwc3_event_depevt mod_ev = *event;
+
+       /*
+        * We were asked to remove one requests. It is possible that this
+        * request and a few other were started together and have the same
+        * transfer index. Since we stopped the complete endpoint we don't
+        * know how many requests were already completed (and not yet)
+        * reported and how could be done (later). We purge them all until
+        * the end of the list.
+        */
+       mod_ev.status = DEPEVT_STATUS_LST;
+       dwc3_cleanup_done_reqs(dwc, dep, &mod_ev, -ESHUTDOWN);
+       dep->flags &= ~DWC3_EP_BUSY;
+       /* pending requets are ignored and are queued on XferNotReady */
+
+       if (dep->flags & DWC3_EP_WILL_SHUTDOWN) {
+               while (!list_empty(&dep->req_queued)) {
+                       struct dwc3_request     *req;
+
+                       req = next_request(&dep->req_queued);
+                       dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+               }
+               dep->flags &= DWC3_EP_WILL_SHUTDOWN;
+       }
+}
+
+static void dwc3_ep_cmd_compl(struct dwc3_ep *dep,
+               const struct dwc3_event_depevt *event)
+{
+       u32 param = event->parameters;
+       u32 cmd_type = (param >> 8) & ((1 << 5) - 1);
+
+       switch (cmd_type) {
+       case DWC3_DEPCMD_ENDTRANSFER:
+               dwc3_process_ep_cmd_complete(dep, event);
+               break;
+       case DWC3_DEPCMD_STARTTRANSFER:
+               dep->res_trans_idx = param & 0x7f;
+               break;
+       default:
+               printk(KERN_ERR "%s() unknown /unexpected type: %d\n",
+                               __func__, cmd_type);
+               break;
+       };
+}
+
+static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
+               const struct dwc3_event_depevt *event)
+{
+       struct dwc3_ep          *dep;
+       u8                      epnum = event->endpoint_number;
+
+       dep = dwc->eps[epnum];
+
+       dev_vdbg(dwc->dev, "%s: %s\n", dep->name,
+                       dwc3_ep_event_string(event->endpoint_event));
+
+       if (epnum == 0 || epnum == 1) {
+               dwc3_ep0_interrupt(dwc, event);
+               return;
+       }
+
+       switch (event->endpoint_event) {
+       case DWC3_DEPEVT_XFERCOMPLETE:
+               if (usb_endpoint_xfer_isoc(dep->desc)) {
+                       dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
+                                       dep->name);
+                       return;
+               }
+
+               dwc3_endpoint_transfer_complete(dwc, dep, event, 1);
+               break;
+       case DWC3_DEPEVT_XFERINPROGRESS:
+               if (!usb_endpoint_xfer_isoc(dep->desc)) {
+                       dev_dbg(dwc->dev, "%s is not an Isochronous endpoint\n",
+                                       dep->name);
+                       return;
+               }
+
+               dwc3_endpoint_transfer_complete(dwc, dep, event, 0);
+               break;
+       case DWC3_DEPEVT_XFERNOTREADY:
+               if (usb_endpoint_xfer_isoc(dep->desc)) {
+                       dwc3_gadget_start_isoc(dwc, dep, event);
+               } else {
+                       int ret;
+
+                       dev_vdbg(dwc->dev, "%s: reason %s\n",
+                                       dep->name, event->status
+                                       ? "Transfer Active"
+                                       : "Transfer Not Active");
+
+                       ret = __dwc3_gadget_kick_transfer(dep, 0, 1);
+                       if (!ret || ret == -EBUSY)
+                               return;
+
+                       dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+                                       dep->name);
+               }
+
+               break;
+       case DWC3_DEPEVT_RXTXFIFOEVT:
+               dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name);
+               break;
+       case DWC3_DEPEVT_STREAMEVT:
+               dev_dbg(dwc->dev, "%s Stream Event\n", dep->name);
+               break;
+       case DWC3_DEPEVT_EPCMDCMPLT:
+               dwc3_ep_cmd_compl(dep, event);
+               break;
+       }
+}
+
+static void dwc3_disconnect_gadget(struct dwc3 *dwc)
+{
+       if (dwc->gadget_driver && dwc->gadget_driver->disconnect) {
+               spin_unlock(&dwc->lock);
+               dwc->gadget_driver->disconnect(&dwc->gadget);
+               spin_lock(&dwc->lock);
+       }
+}
+
+static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
+{
+       struct dwc3_ep *dep;
+       struct dwc3_gadget_ep_cmd_params params;
+       u32 cmd;
+       int ret;
+
+       dep = dwc->eps[epnum];
+
+       if (dep->res_trans_idx) {
+               cmd = DWC3_DEPCMD_ENDTRANSFER;
+               cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
+               cmd |= DWC3_DEPCMD_PARAM(dep->res_trans_idx);
+               memset(&params, 0, sizeof(params));
+               ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+               WARN_ON_ONCE(ret);
+       }
+}
+
+static void dwc3_stop_active_transfers(struct dwc3 *dwc)
+{
+       u32 epnum;
+
+       for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+               struct dwc3_ep *dep;
+
+               dep = dwc->eps[epnum];
+               if (!(dep->flags & DWC3_EP_ENABLED))
+                       continue;
+
+               __dwc3_gadget_ep_disable(dep);
+       }
+}
+
+static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
+{
+       u32 epnum;
+
+       for (epnum = 1; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+               struct dwc3_ep *dep;
+               struct dwc3_gadget_ep_cmd_params params;
+               int ret;
+
+               dep = dwc->eps[epnum];
+
+               if (!(dep->flags & DWC3_EP_STALL))
+                       continue;
+
+               dep->flags &= ~DWC3_EP_STALL;
+
+               memset(&params, 0, sizeof(params));
+               ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+                               DWC3_DEPCMD_CLEARSTALL, &params);
+               WARN_ON_ONCE(ret);
+       }
+}
+
+static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
+{
+       dev_vdbg(dwc->dev, "%s\n", __func__);
+#if 0
+       XXX
+       U1/U2 is powersave optimization. Skip it for now. Anyway we need to
+       enable it before we can disable it.
+
+       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+       reg &= ~DWC3_DCTL_INITU1ENA;
+       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+       reg &= ~DWC3_DCTL_INITU2ENA;
+       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+#endif
+
+       dwc3_stop_active_transfers(dwc);
+       dwc3_disconnect_gadget(dwc);
+
+       dwc->gadget.speed = USB_SPEED_UNKNOWN;
+}
+
+static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on)
+{
+       u32                     reg;
+
+       reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+
+       if (on)
+               reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
+       else
+               reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+
+       dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+}
+
+static void dwc3_gadget_usb2_phy_power(struct dwc3 *dwc, int on)
+{
+       u32                     reg;
+
+       reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+
+       if (on)
+               reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+       else
+               reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+
+       dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+}
+
+static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
+{
+       u32                     reg;
+
+       dev_vdbg(dwc->dev, "%s\n", __func__);
+
+       /* Enable PHYs */
+       dwc3_gadget_usb2_phy_power(dwc, true);
+       dwc3_gadget_usb3_phy_power(dwc, true);
+
+       if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
+               dwc3_disconnect_gadget(dwc);
+
+       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+       reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+       dwc3_stop_active_transfers(dwc);
+       dwc3_clear_stall_all_ep(dwc);
+
+       /* Reset device address to zero */
+       reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+       reg &= ~(DWC3_DCFG_DEVADDR_MASK);
+       dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+       /*
+        * Wait for RxFifo to drain
+        *
+        * REVISIT probably shouldn't wait forever.
+        * In case Hardware ends up in a screwed up
+        * case, we error out, notify the user and,
+        * maybe, WARN() or BUG() but leave the rest
+        * of the kernel working fine.
+        *
+        * REVISIT the below is rather CPU intensive,
+        * maybe we should read and if it doesn't work
+        * sleep (not busy wait) for a few useconds.
+        *
+        * REVISIT why wait until the RXFIFO is empty anyway?
+        */
+       while (!(dwc3_readl(dwc->regs, DWC3_DSTS)
+                               & DWC3_DSTS_RXFIFOEMPTY))
+               cpu_relax();
+}
+
+static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed)
+{
+       u32 reg;
+       u32 usb30_clock = DWC3_GCTL_CLK_BUS;
+
+       /*
+        * We change the clock only at SS but I dunno why I would want to do
+        * this. Maybe it becomes part of the power saving plan.
+        */
+
+       if (speed != DWC3_DSTS_SUPERSPEED)
+               return;
+
+       /*
+        * RAMClkSel is reset to 0 after USB reset, so it must be reprogrammed
+        * each time on Connect Done.
+        */
+       if (!usb30_clock)
+               return;
+
+       reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+       reg |= DWC3_GCTL_RAMCLKSEL(usb30_clock);
+       dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+}
+
+static void dwc3_gadget_disable_phy(struct dwc3 *dwc, u8 speed)
+{
+       switch (speed) {
+       case USB_SPEED_SUPER:
+               dwc3_gadget_usb2_phy_power(dwc, false);
+               break;
+       case USB_SPEED_HIGH:
+       case USB_SPEED_FULL:
+       case USB_SPEED_LOW:
+               dwc3_gadget_usb3_phy_power(dwc, false);
+               break;
+       }
+}
+
+static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
+{
+       struct dwc3_gadget_ep_cmd_params params;
+       struct dwc3_ep          *dep;
+       int                     ret;
+       u32                     reg;
+       u8                      speed;
+
+       dev_vdbg(dwc->dev, "%s\n", __func__);
+
+       memset(&params, 0x00, sizeof(params));
+
+       dwc->ep0state = EP0_IDLE;
+       reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+       speed = reg & DWC3_DSTS_CONNECTSPD;
+       dwc->speed = speed;
+
+       dwc3_update_ram_clk_sel(dwc, speed);
+
+       switch (speed) {
+       case DWC3_DCFG_SUPERSPEED:
+               dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+               dwc->gadget.ep0->maxpacket = 512;
+               dwc->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;
+               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;
+               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;
+               break;
+       }
+
+       /* Disable unneded PHY */
+       dwc3_gadget_disable_phy(dwc, dwc->gadget.speed);
+
+       dep = dwc->eps[0];
+       ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+       if (ret) {
+               dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+               return;
+       }
+
+       dep = dwc->eps[1];
+       ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+       if (ret) {
+               dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+               return;
+       }
+
+       /*
+        * Configure PHY via GUSB3PIPECTLn if required.
+        *
+        * Update GTXFIFOSIZn
+        *
+        * In both cases reset values should be sufficient.
+        */
+}
+
+static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
+{
+       dev_vdbg(dwc->dev, "%s\n", __func__);
+
+       /*
+        * TODO take core out of low power mode when that's
+        * implemented.
+        */
+
+       dwc->gadget_driver->resume(&dwc->gadget);
+}
+
+static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
+               unsigned int evtinfo)
+{
+       dev_vdbg(dwc->dev, "%s\n", __func__);
+
+       /*  The fith bit says SuperSpeed yes or no. */
+       dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK;
+}
+
+static void dwc3_gadget_interrupt(struct dwc3 *dwc,
+               const struct dwc3_event_devt *event)
+{
+       switch (event->type) {
+       case DWC3_DEVICE_EVENT_DISCONNECT:
+               dwc3_gadget_disconnect_interrupt(dwc);
+               break;
+       case DWC3_DEVICE_EVENT_RESET:
+               dwc3_gadget_reset_interrupt(dwc);
+               break;
+       case DWC3_DEVICE_EVENT_CONNECT_DONE:
+               dwc3_gadget_conndone_interrupt(dwc);
+               break;
+       case DWC3_DEVICE_EVENT_WAKEUP:
+               dwc3_gadget_wakeup_interrupt(dwc);
+               break;
+       case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
+               dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
+               break;
+       case DWC3_DEVICE_EVENT_EOPF:
+               dev_vdbg(dwc->dev, "End of Periodic Frame\n");
+               break;
+       case DWC3_DEVICE_EVENT_SOF:
+               dev_vdbg(dwc->dev, "Start of Periodic Frame\n");
+               break;
+       case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+               dev_vdbg(dwc->dev, "Erratic Error\n");
+               break;
+       case DWC3_DEVICE_EVENT_CMD_CMPL:
+               dev_vdbg(dwc->dev, "Command Complete\n");
+               break;
+       case DWC3_DEVICE_EVENT_OVERFLOW:
+               dev_vdbg(dwc->dev, "Overflow\n");
+               break;
+       default:
+               dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
+       }
+}
+
+static void dwc3_process_event_entry(struct dwc3 *dwc,
+               const union dwc3_event *event)
+{
+       /* Endpoint IRQ, handle it and return early */
+       if (event->type.is_devspec == 0) {
+               /* depevt */
+               return dwc3_endpoint_interrupt(dwc, &event->depevt);
+       }
+
+       switch (event->type.type) {
+       case DWC3_EVENT_TYPE_DEV:
+               dwc3_gadget_interrupt(dwc, &event->devt);
+               break;
+       /* REVISIT what to do with Carkit and I2C events ? */
+       default:
+               dev_err(dwc->dev, "UNKNOWN IRQ type %d\n", event->raw);
+       }
+}
+
+static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
+{
+       struct dwc3_event_buffer *evt;
+       int left;
+       u32 count;
+
+       count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
+       count &= DWC3_GEVNTCOUNT_MASK;
+       if (!count)
+               return IRQ_NONE;
+
+       evt = dwc->ev_buffs[buf];
+       left = count;
+
+       while (left > 0) {
+               union dwc3_event event;
+
+               memcpy(&event.raw, (evt->buf + evt->lpos), sizeof(event.raw));
+               dwc3_process_event_entry(dwc, &event);
+               /*
+                * XXX we wrap around correctly to the next entry as almost all
+                * entries are 4 bytes in size. There is one entry which has 12
+                * bytes which is a regular entry followed by 8 bytes data. ATM
+                * I don't know how things are organized if were get next to the
+                * a boundary so I worry about that once we try to handle that.
+                */
+               evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
+               left -= 4;
+
+               dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
+{
+       struct dwc3                     *dwc = _dwc;
+       int                             i;
+       irqreturn_t                     ret = IRQ_NONE;
+
+       spin_lock(&dwc->lock);
+
+       for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) {
+               irqreturn_t status;
+
+               status = dwc3_process_event_buf(dwc, i);
+               if (status == IRQ_HANDLED)
+                       ret = status;
+       }
+
+       spin_unlock(&dwc->lock);
+
+       return ret;
+}
+
+/**
+ * dwc3_gadget_init - Initializes gadget related registers
+ * @dwc: Pointer to out controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+int __devinit dwc3_gadget_init(struct dwc3 *dwc)
+{
+       u32                                     reg;
+       int                                     ret;
+       int                                     irq;
+
+       dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+                       &dwc->ctrl_req_addr, GFP_KERNEL);
+       if (!dwc->ctrl_req) {
+               dev_err(dwc->dev, "failed to allocate ctrl request\n");
+               ret = -ENOMEM;
+               goto err0;
+       }
+
+       dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+                       &dwc->ep0_trb_addr, GFP_KERNEL);
+       if (!dwc->ep0_trb) {
+               dev_err(dwc->dev, "failed to allocate ep0 trb\n");
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       dwc->setup_buf = dma_alloc_coherent(dwc->dev,
+                       sizeof(*dwc->setup_buf) * 2,
+                       &dwc->setup_buf_addr, GFP_KERNEL);
+       if (!dwc->setup_buf) {
+               dev_err(dwc->dev, "failed to allocate setup buffer\n");
+               ret = -ENOMEM;
+               goto err2;
+       }
+
+       dev_set_name(&dwc->gadget.dev, "gadget");
+
+       dwc->gadget.ops                 = &dwc3_gadget_ops;
+       dwc->gadget.is_dualspeed        = true;
+       dwc->gadget.speed               = USB_SPEED_UNKNOWN;
+       dwc->gadget.dev.parent          = dwc->dev;
+
+       dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask);
+
+       dwc->gadget.dev.dma_parms       = dwc->dev->dma_parms;
+       dwc->gadget.dev.dma_mask        = dwc->dev->dma_mask;
+       dwc->gadget.dev.release         = dwc3_gadget_release;
+       dwc->gadget.name                = "dwc3-gadget";
+
+       /*
+        * REVISIT: Here we should clear all pending IRQs to be
+        * sure we're starting from a well known location.
+        */
+
+       ret = dwc3_gadget_init_endpoints(dwc);
+       if (ret)
+               goto err3;
+
+       irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+
+       ret = request_irq(irq, dwc3_interrupt, IRQF_SHARED,
+                       "dwc3", dwc);
+       if (ret) {
+               dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+                               irq, ret);
+               goto err4;
+       }
+
+       /* Enable all but Start and End of Frame IRQs */
+       reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
+                       DWC3_DEVTEN_EVNTOVERFLOWEN |
+                       DWC3_DEVTEN_CMDCMPLTEN |
+                       DWC3_DEVTEN_ERRTICERREN |
+                       DWC3_DEVTEN_WKUPEVTEN |
+                       DWC3_DEVTEN_ULSTCNGEN |
+                       DWC3_DEVTEN_CONNECTDONEEN |
+                       DWC3_DEVTEN_USBRSTEN |
+                       DWC3_DEVTEN_DISCONNEVTEN);
+       dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
+
+       ret = device_register(&dwc->gadget.dev);
+       if (ret) {
+               dev_err(dwc->dev, "failed to register gadget device\n");
+               put_device(&dwc->gadget.dev);
+               goto err5;
+       }
+
+       ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
+       if (ret) {
+               dev_err(dwc->dev, "failed to register udc\n");
+               goto err6;
+       }
+
+       return 0;
+
+err6:
+       device_unregister(&dwc->gadget.dev);
+
+err5:
+       dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
+       free_irq(irq, dwc);
+
+err4:
+       dwc3_gadget_free_endpoints(dwc);
+
+err3:
+       dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
+                       dwc->setup_buf, dwc->setup_buf_addr);
+
+err2:
+       dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+                       dwc->ep0_trb, dwc->ep0_trb_addr);
+
+err1:
+       dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+                       dwc->ctrl_req, dwc->ctrl_req_addr);
+
+err0:
+       return ret;
+}
+
+void dwc3_gadget_exit(struct dwc3 *dwc)
+{
+       int                     irq;
+       int                     i;
+
+       usb_del_gadget_udc(&dwc->gadget);
+       irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+
+       dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
+       free_irq(irq, dwc);
+
+       for (i = 0; i < ARRAY_SIZE(dwc->eps); i++)
+               __dwc3_gadget_ep_disable(dwc->eps[i]);
+
+       dwc3_gadget_free_endpoints(dwc);
+
+       dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
+                       dwc->setup_buf, dwc->setup_buf_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);
+
+       device_unregister(&dwc->gadget.dev);
+}
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
new file mode 100644 (file)
index 0000000..4809ac8
--- /dev/null
@@ -0,0 +1,297 @@
+/**
+ * gadget.h - DesignWare USB3 DRD Gadget Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ * All rights reserved.
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DRIVERS_USB_DWC3_GADGET_H
+#define __DRIVERS_USB_DWC3_GADGET_H
+
+#include <linux/list.h>
+#include <linux/usb/gadget.h>
+#include "io.h"
+
+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))
+
+/**
+ * struct dwc3_gadget_ep_depcfg_param1 - DEPCMDPAR0 for DEPCFG command
+ * @interrupt_number: self-explanatory
+ * @reserved7_5: set to zero
+ * @xfer_complete_enable: event generated when transfer completed
+ * @xfer_in_progress_enable: event generated when transfer in progress
+ * @xfer_not_ready_enable: event generated when transfer not read
+ * @fifo_error_enable: generates events when FIFO Underrun (IN eps)
+ *     or FIFO Overrun (OUT) eps
+ * @reserved_12: set to zero
+ * @stream_event_enable: event generated on stream
+ * @reserved14_15: set to zero
+ * @binterval_m1: bInterval minus 1
+ * @stream_capable: this EP is capable of handling streams
+ * @ep_number: self-explanatory
+ * @bulk_based: Set to â€˜1’ if this isochronous endpoint represents a bulk
+ *     data stream that ignores the relationship of bus time to the
+ *     intervals programmed in TRBs.
+ * @fifo_based: Set to â€˜1’ if this isochronous endpoint represents a
+ *     FIFO-based data stream where TRBs have fixed values and are never
+ *     written back by the core.
+ */
+struct dwc3_gadget_ep_depcfg_param1 {
+       u32     interrupt_number:5;
+       u32     reserved7_5:3;          /* set to zero */
+       u32     xfer_complete_enable:1;
+       u32     xfer_in_progress_enable:1;
+       u32     xfer_not_ready_enable:1;
+       u32     fifo_error_enable:1;    /* IN-underrun, OUT-overrun */
+       u32     reserved12:1;           /* set to zero */
+       u32     stream_event_enable:1;
+       u32     reserved14_15:2;
+       u32     binterval_m1:8;         /* bInterval minus 1 */
+       u32     stream_capable:1;
+       u32     ep_number:5;
+       u32     bulk_based:1;
+       u32     fifo_based:1;
+} __packed;
+
+/**
+ * struct dwc3_gadget_ep_depcfg_param0 - Parameter 0 for DEPCFG
+ * @reserved0: set to zero
+ * @ep_type: Endpoint Type (control, bulk, iso, interrupt)
+ * @max_packet_size: max packet size in bytes
+ * @reserved16_14: set to zero
+ * @fifo_number: self-explanatory
+ * @burst_size: burst size minus 1
+ * @data_sequence_number: Must be 0 when an endpoint is initially configured
+ *     May be non-zero when an endpoint is configured after a power transition
+ *     that requires a save/restore.
+ * @ignore_sequence_number: Set to â€˜1’ to avoid resetting the sequence
+ *     number. This setting is used by software to modify the DEPEVTEN
+ *     event enable bits without modifying other endpoint settings.
+ */
+struct dwc3_gadget_ep_depcfg_param0 {
+       u32     reserved0:1;
+       u32     ep_type:2;
+       u32     max_packet_size:11;
+       u32     reserved16_14:3;
+       u32     fifo_number:5;
+       u32     burst_size:4;
+       u32     data_sequence_number:5;
+       u32     ignore_sequence_number:1;
+} __packed;
+
+/**
+ * struct dwc3_gadget_ep_depxfercfg_param0 - Parameter 0 of DEPXFERCFG
+ * @number_xfer_resources: Defines the number of Transfer Resources allocated
+ *     to this endpoint.  This field must be set to 1.
+ * @reserved16_31: set to zero;
+ */
+struct dwc3_gadget_ep_depxfercfg_param0 {
+       u32             number_xfer_resources:16;
+       u32             reserved16_31:16;
+} __packed;
+
+/**
+ * struct dwc3_gadget_ep_depstrtxfer_param1 - Parameter 1 of DEPSTRTXFER
+ * @transfer_desc_addr_low: Indicates the lower 32 bits of the external
+ *     memory's start address for the transfer descriptor. Because TRBs
+ *     must be aligned to a 16-byte boundary, the lower 4 bits of this
+ *     address must be 0.
+ */
+struct dwc3_gadget_ep_depstrtxfer_param1 {
+       u32             transfer_desc_addr_low;
+} __packed;
+
+/**
+ * struct dwc3_gadget_ep_depstrtxfer_param1 - Parameter 1 of DEPSTRTXFER
+ * @transfer_desc_addr_high: Indicates the higher 32 bits of the external
+ *     memory’s start address for the transfer descriptor.
+ */
+struct dwc3_gadget_ep_depstrtxfer_param0 {
+       u32             transfer_desc_addr_high;
+} __packed;
+
+struct dwc3_gadget_ep_cmd_params {
+       union {
+               u32     raw;
+       } param2;
+
+       union {
+               u32     raw;
+               struct dwc3_gadget_ep_depcfg_param1 depcfg;
+               struct dwc3_gadget_ep_depstrtxfer_param1 depstrtxfer;
+       } param1;
+
+       union {
+               u32     raw;
+               struct dwc3_gadget_ep_depcfg_param0 depcfg;
+               struct dwc3_gadget_ep_depxfercfg_param0 depxfercfg;
+               struct dwc3_gadget_ep_depstrtxfer_param0 depstrtxfer;
+       } param0;
+} __packed;
+
+/* -------------------------------------------------------------------------- */
+
+struct dwc3_request {
+       struct usb_request      request;
+       struct list_head        list;
+       struct dwc3_ep          *dep;
+
+       u8                      epnum;
+       struct dwc3_trb_hw      *trb;
+       dma_addr_t              trb_dma;
+
+       unsigned                direction:1;
+       unsigned                mapped:1;
+       unsigned                queued:1;
+};
+#define to_dwc3_request(r)     (container_of(r, struct dwc3_request, request))
+
+static inline struct dwc3_request *next_request(struct list_head *list)
+{
+       if (list_empty(list))
+               return NULL;
+
+       return list_first_entry(list, struct dwc3_request, list);
+}
+
+static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
+{
+       struct dwc3_ep          *dep = req->dep;
+
+       req->queued = true;
+       list_move_tail(&req->list, &dep->req_queued);
+}
+
+#if defined(CONFIG_USB_GADGET_DWC3) || defined(CONFIG_USB_GADGET_DWC3_MODULE)
+int dwc3_gadget_init(struct dwc3 *dwc);
+void dwc3_gadget_exit(struct dwc3 *dwc);
+#else
+static inline int dwc3_gadget_init(struct dwc3 *dwc) { return 0; }
+static inline void dwc3_gadget_exit(struct dwc3 *dwc) { }
+static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+               unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
+{
+       return 0;
+}
+#endif
+
+void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
+               int status);
+
+void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event);
+void dwc3_ep0_out_start(struct dwc3 *dwc);
+int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
+               gfp_t gfp_flags);
+int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
+int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+               unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
+void dwc3_map_buffer_to_dma(struct dwc3_request *req);
+void dwc3_unmap_buffer_from_dma(struct dwc3_request *req);
+
+/**
+ * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
+ * @dwc: DesignWare USB3 Pointer
+ * @number: DWC endpoint number
+ *
+ * Caller should take care of locking
+ */
+static inline u32 dwc3_gadget_ep_get_transfer_index(struct dwc3 *dwc, u8 number)
+{
+       u32                     res_id;
+
+       res_id = dwc3_readl(dwc->regs, DWC3_DEPCMD(number));
+
+       return DWC3_DEPCMD_GET_RSC_IDX(res_id);
+}
+
+/**
+ * dwc3_gadget_event_string - returns event name
+ * @event: the event code
+ */
+static inline const char *dwc3_gadget_event_string(u8 event)
+{
+       switch (event) {
+       case DWC3_DEVICE_EVENT_DISCONNECT:
+               return "Disconnect";
+       case DWC3_DEVICE_EVENT_RESET:
+               return "Reset";
+       case DWC3_DEVICE_EVENT_CONNECT_DONE:
+               return "Connection Done";
+       case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
+               return "Link Status Change";
+       case DWC3_DEVICE_EVENT_WAKEUP:
+               return "WakeUp";
+       case DWC3_DEVICE_EVENT_EOPF:
+               return "End-Of-Frame";
+       case DWC3_DEVICE_EVENT_SOF:
+               return "Start-Of-Frame";
+       case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+               return "Erratic Error";
+       case DWC3_DEVICE_EVENT_CMD_CMPL:
+               return "Command Complete";
+       case DWC3_DEVICE_EVENT_OVERFLOW:
+               return "Overflow";
+       }
+
+       return "UNKNOWN";
+}
+
+/**
+ * dwc3_ep_event_string - returns event name
+ * @event: then event code
+ */
+static inline const char *dwc3_ep_event_string(u8 event)
+{
+       switch (event) {
+       case DWC3_DEPEVT_XFERCOMPLETE:
+               return "Transfer Complete";
+       case DWC3_DEPEVT_XFERINPROGRESS:
+               return "Transfer In-Progress";
+       case DWC3_DEPEVT_XFERNOTREADY:
+               return "Transfer Not Ready";
+       case DWC3_DEPEVT_RXTXFIFOEVT:
+               return "FIFO";
+       case DWC3_DEPEVT_STREAMEVT:
+               return "Stream";
+       case DWC3_DEPEVT_EPCMDCMPLT:
+               return "Endpoint Command Complete";
+       }
+
+       return "UNKNOWN";
+}
+
+#endif /* __DRIVERS_USB_DWC3_GADGET_H */
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
new file mode 100644 (file)
index 0000000..0c4e2a9
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ * io.h - DesignWare USB3 DRD IO Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ * All rights reserved.
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DRIVERS_USB_DWC3_IO_H
+#define __DRIVERS_USB_DWC3_IO_H
+
+#include <asm/io.h>
+
+static inline u32 dwc3_readl(void __iomem *base, u32 offset)
+{
+       return readl(base + offset);
+}
+
+static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
+{
+       writel(value, base + offset);
+}
+
+#endif /* __DRIVERS_USB_DWC3_IO_H */
index 5a084b9cfa3c67971bfe86628cbf38de8c49ec3b..fe56379838927ae026da3bcab9be2e75213e70b7 100644 (file)
@@ -255,12 +255,11 @@ config USB_S3C_HSOTG
          integrated into the S3C64XX series SoC.
 
 config USB_IMX
-       tristate "Freescale IMX USB Peripheral Controller"
-       depends on ARCH_MX1
+       tristate "Freescale i.MX1 USB Peripheral Controller"
+       depends on ARCH_MXC
        help
-          Freescale's IMX series include an integrated full speed
-          USB 1.1 device controller.  The controller in the IMX series
-          is register-compatible.
+          Freescale's i.MX1 includes an integrated full speed
+          USB 1.1 device controller.
 
           It has Six fixed-function endpoints, as well as endpoint
           zero (for control transfers).
@@ -303,6 +302,18 @@ config USB_PXA_U2O
          PXA9xx Processor series include a high speed USB2.0 device
          controller, which support high speed and full speed USB peripheral.
 
+config USB_GADGET_DWC3
+       tristate "DesignWare USB3.0 (DRD) Controller"
+       depends on USB_DWC3
+       select USB_GADGET_DUALSPEED
+       select USB_GADGET_SUPERSPEED
+       help
+         DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
+         which can be configured for peripheral-only, host-only, hub-only
+         and Dual-Role operation. This Controller was first integrated into
+         the OMAP5 series of processors. More information about the OMAP5
+         version of this controller, refer to http://www.ti.com/omap5.
+
 #
 # Controllers available in both integrated and discrete versions
 #
index 70f2b376c86d27d4b4af607d5fa70492560ebd3c..d65d8392be754269477ef6b749f40084b9c41204 100644 (file)
@@ -354,7 +354,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
        writel(tmp, &dev->ep[ep->num].regs->ctl);
 
        /* set max packet size */
-       maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+       maxpacket = usb_endpoint_maxp(desc);
        tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
        tmp = AMD_ADDBITS(tmp, maxpacket, UDC_EP_MAX_PKT_SIZE);
        ep->ep.maxpacket = maxpacket;
index 205498de77447264f4f6f0d578a60e67e3c86a5b..e267ffe16b4c453dd844e183770a92de53654081 100644 (file)
@@ -487,7 +487,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
                        || !desc || ep->desc
                        || _ep->name == ep0name
                        || desc->bDescriptorType != USB_DT_ENDPOINT
-                       || (maxpacket = le16_to_cpu(desc->wMaxPacketSize)) == 0
+                       || (maxpacket = usb_endpoint_maxp(desc)) == 0
                        || maxpacket > ep->maxpacket) {
                DBG("bad ep or descriptor\n");
                return -EINVAL;
index 5b1665eb1bef89e346dd02cfc3be2e22776b40d5..722c468e9b3cf72b0b22c1b57a8d3e50743791e0 100644 (file)
@@ -527,7 +527,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 
        DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc);
 
-       maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
+       maxpacket = usb_endpoint_maxp(desc) & 0x7ff;
 
        if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index)
                        || ep->index == 0
@@ -571,7 +571,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
                 * Bits 11:12 specify number of _additional_
                 * transactions per microframe.
                 */
-               nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1;
+               nr_trans = ((usb_endpoint_maxp(desc) >> 11) & 3) + 1;
                if (nr_trans > 3)
                        return -EINVAL;
 
index 1265a8502ea0fe90348bdcdfa41b2f4df337c02d..83428f56253bd5283a8962448fa8cd7b899aee96 100644 (file)
@@ -2101,7 +2101,7 @@ static int ep_enable(struct usb_ep *ep,
        mEp->num  = usb_endpoint_num(desc);
        mEp->type = usb_endpoint_type(desc);
 
-       mEp->ep.maxpacket = __constant_le16_to_cpu(desc->wMaxPacketSize);
+       mEp->ep.maxpacket = usb_endpoint_maxp(desc);
 
        dbg_event(_usb_addr(mEp), "ENABLE", 0);
 
index aef47414f5d5cb621408d5c95a8cfe63d5d924c8..8065464523b182016e8e2a5ccd94b4b30951b8d7 100644 (file)
@@ -164,7 +164,7 @@ int config_ep_by_speed(struct usb_gadget *g,
 
 ep_found:
        /* commit results */
-       _ep->maxpacket = le16_to_cpu(chosen_desc->wMaxPacketSize);
+       _ep->maxpacket = usb_endpoint_maxp(chosen_desc);
        _ep->desc = chosen_desc;
        _ep->comp_desc = NULL;
        _ep->maxburst = 0;
index e755a9d267fc6a9028a89051d98161a85475e31d..7b06d39d6203f4c994a2f81a021b03ff6a32b804 100644 (file)
@@ -439,7 +439,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
         * maximum packet size.
         * For SS devices the wMaxPacketSize is limited by 1024.
         */
-       max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
+       max = usb_endpoint_maxp(desc) & 0x7ff;
 
        /* drivers must not request bad settings, since lower levels
         * (hardware or its drivers) may not check.  some endpoints
@@ -1277,7 +1277,7 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
                int     tmp;
 
                /* high bandwidth mode */
-               tmp = le16_to_cpu(ep->desc->wMaxPacketSize);
+               tmp = usb_endpoint_maxp(ep->desc);
                tmp = (tmp >> 11) & 0x03;
                tmp *= 8 /* applies to entire frame */;
                limit += limit * tmp;
index 7a7e6b7e1fd614639f53a8fa9b19fd83648b9d6d..cdca7ebb7b48e9d0232953a0ef1b9c02d89e9e36 100644 (file)
@@ -158,7 +158,7 @@ ep_matches (
         * where it's an output parameter representing the full speed limit.
         * the usb spec fixes high speed bulk maxpacket at 512 bytes.
         */
-       max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
+       max = 0x7ff & usb_endpoint_maxp(desc);
        switch (type) {
        case USB_ENDPOINT_XFER_INT:
                /* INT:  limit 64 bytes full speed, 1024 high/super speed */
index 5b933958200772179fc8c6b28d4cf8cf056fcf55..4ce3decda1db8b1a8118abf4448915cc4639b989 100644 (file)
@@ -2401,8 +2401,7 @@ reset:
                goto reset;
        fsg->bulk_out->driver_data = common;
        fsg->bulk_out_enabled = 1;
-       common->bulk_out_maxpacket =
-               le16_to_cpu(fsg->bulk_out->desc->wMaxPacketSize);
+       common->bulk_out_maxpacket = usb_endpoint_maxp(fsg->bulk_out->desc);
        clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
 
        /* Allocate the requests */
index 639e14a2fd15e4c5f6fd899f19631ff9beec3212..39ece40a045fb0a90b998ed48d64246d7ccd8911 100644 (file)
@@ -2801,7 +2801,7 @@ reset:
        if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
                goto reset;
        fsg->bulk_out_enabled = 1;
-       fsg->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
+       fsg->bulk_out_maxpacket = usb_endpoint_maxp(d);
        clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
 
        if (transport_is_cbi()) {
index 3bf872e1ad39a55ce74cb3485b8b9d89280140f2..2a03e4de11c1a277cfe27b670ac48f11cabc006a 100644 (file)
@@ -540,7 +540,7 @@ static int qe_ep_init(struct qe_udc *udc,
        int reval = 0;
        u16 max = 0;
 
-       max = le16_to_cpu(desc->wMaxPacketSize);
+       max = usb_endpoint_maxp(desc);
 
        /* check the max package size validate for this endpoint */
        /* Refer to USB2.0 spec table 9-13,
index de24a4233c2563701f7cdec2f1b125e8002e7fdb..d6993507165b16e3b8d49f61e5bd025463ce02aa 100644 (file)
@@ -559,7 +559,7 @@ static int fsl_ep_enable(struct usb_ep *_ep,
        if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN))
                return -ESHUTDOWN;
 
-       max = le16_to_cpu(desc->wMaxPacketSize);
+       max = usb_endpoint_maxp(desc);
 
        /* Disable automatic zlp generation.  Driver is responsible to indicate
         * explicitly through req->req.zero.  This is needed to enable multi-td
index 4ec888f900029ac823f2a136ef47ab18f03b5826..d9ee6c37a6c1642f1a45d72df4bef13409014ff4 100644 (file)
@@ -220,7 +220,7 @@ static int config_ep(struct fusb300_ep *ep,
 
        info.type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
        info.dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0;
-       info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+       info.maxpacket = usb_endpoint_maxp(desc);
        info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
 
        if ((info.type == USB_ENDPOINT_XFER_INT) ||
index f3a83cd0ef5043276a9986e2a9d77bdc4cff7dd7..a8855d0b7f3bdf19fbdc76eab8a25992f07884b0 100644 (file)
@@ -31,6 +31,7 @@
 #define gadget_is_ci13xxx_msm(g)       (!strcmp("ci13xxx_msm", (g)->name))
 #define gadget_is_ci13xxx_pci(g)       (!strcmp("ci13xxx_pci", (g)->name))
 #define gadget_is_dummy(g)             (!strcmp("dummy_udc", (g)->name))
+#define gadget_is_dwc3(g)              (!strcmp("dwc3-gadget", (g)->name))
 #define gadget_is_fsl_qe(g)            (!strcmp("fsl_qe_udc", (g)->name))
 #define gadget_is_fsl_usb2(g)          (!strcmp("fsl-usb2-udc", (g)->name))
 #define gadget_is_goku(g)              (!strcmp("goku_udc", (g)->name))
@@ -115,6 +116,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
                return 0x30;
        else if (gadget_is_net2272(gadget))
                return 0x31;
+       else if (gadget_is_dwc3(gadget))
+               return 0x32;
 
        return -ENOENT;
 }
index 692fd9b2248b35e2b20c7ec4f6300c69edc79c9a..bf08bfcd90b894517c26a759ae31017906ad00fd 100644 (file)
@@ -689,7 +689,7 @@ static int imx_ep_enable(struct usb_ep *usb_ep,
                return -EINVAL;
        }
 
-       if (imx_ep->fifosize < le16_to_cpu(desc->wMaxPacketSize)) {
+       if (imx_ep->fifosize < usb_endpoint_maxp(desc)) {
                D_ERR(imx_usb->dev,
                        "<%s> bad %s maxpacket\n", __func__, usb_ep->name);
                return -ERANGE;
index ff4d40d77c30338f87043d8b6d4c98870ba1b51b..52575b137787d5e49fe5e9e0e5c8de3d505920a8 100644 (file)
@@ -283,7 +283,7 @@ static int langwell_ep_enable(struct usb_ep *_ep,
        if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
                return -ESHUTDOWN;
 
-       max = le16_to_cpu(desc->wMaxPacketSize);
+       max = usb_endpoint_maxp(desc);
 
        /*
         * disable HW zero length termination select
index 491f825ed5c93b1e1e525c2f5ae8ffefdf88c23a..5e597c3c44f3adc1426fbec1c75d191e459c46dd 100644 (file)
@@ -370,7 +370,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
 
        ep->pipectr = get_pipectr_addr(pipenum);
        ep->pipenum = pipenum;
-       ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+       ep->ep.maxpacket = usb_endpoint_maxp(desc);
        m66592->pipenum2ep[pipenum] = ep;
        m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep;
        INIT_LIST_HEAD(&ep->queue);
@@ -447,7 +447,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
        ep->type = info.type;
 
        info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-       info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+       info.maxpacket = usb_endpoint_maxp(desc);
        info.interval = desc->bInterval;
        if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
                info.dir_in = 1;
index 0b3b8d0462db76e5b231dab6bc5259862fe391a1..d34fc05094123854d8e716ca543f7cdd94c2fae7 100644 (file)
@@ -493,7 +493,7 @@ static int mv_ep_enable(struct usb_ep *_ep,
                return -ESHUTDOWN;
 
        direction = ep_dir(ep);
-       max = le16_to_cpu(desc->wMaxPacketSize);
+       max = usb_endpoint_maxp(desc);
 
        /*
         * disable HW zero length termination select
index ab98ea926a11b6e227cfe4b800e4b94dd50c27f2..6fef1c02448e9edca9632051973d0d1772af738f 100644 (file)
@@ -204,7 +204,7 @@ net2272_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
        if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
                return -ESHUTDOWN;
 
-       max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff;
+       max = usb_endpoint_maxp(desc) & 0x1fff;
 
        spin_lock_irqsave(&dev->lock, flags);
        _ep->maxpacket = max & 0x7fff;
index a218a4de5dc90a25205104d8cb7d8de49fc7b773..75d4038d640ecb1a6e88d94463337bbf98f62cbd 100644 (file)
@@ -169,7 +169,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
                return -EDOM;
 
        /* sanity check ep-e/ep-f since their fifos are small */
-       max = le16_to_cpu (desc->wMaxPacketSize) & 0x1fff;
+       max = usb_endpoint_maxp (desc) & 0x1fff;
        if (ep->num > 4 && max > 64)
                return -ERANGE;
 
@@ -1640,7 +1640,7 @@ show_queues (struct device *_dev, struct device_attribute *attr, char *buf)
                                 default:
                                        val = "iso"; break;
                                 }; val; }),
-                               le16_to_cpu (d->wMaxPacketSize) & 0x1fff,
+                               usb_endpoint_maxp (d) & 0x1fff,
                                ep->dma ? "dma" : "pio", ep->fifo_size
                                );
                } else /* ep0 should only have one transfer queued */
index 740c7daed2798020da01c7f5a5b209cb618b727c..b7a7799ddd4f5b6cba5c43b09fe2f426780b4dbb 100644 (file)
@@ -166,15 +166,14 @@ static int omap_ep_enable(struct usb_ep *_ep,
        if (!_ep || !desc || ep->desc
                        || desc->bDescriptorType != USB_DT_ENDPOINT
                        || ep->bEndpointAddress != desc->bEndpointAddress
-                       || ep->maxpacket < le16_to_cpu
-                                               (desc->wMaxPacketSize)) {
+                       || ep->maxpacket < usb_endpoint_maxp(desc)) {
                DBG("%s, bad ep or descriptor\n", __func__);
                return -EINVAL;
        }
-       maxp = le16_to_cpu (desc->wMaxPacketSize);
+       maxp = usb_endpoint_maxp(desc);
        if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
                                && maxp != ep->maxpacket)
-                       || le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket
+                       || usb_endpoint_maxp(desc) > ep->maxpacket
                        || !desc->wMaxPacketSize) {
                DBG("%s, bad %s maxpacket\n", __func__, _ep->name);
                return -ERANGE;
index f96615ab6b773eaad3f55bd97c962c9f8042c36d..b69ae3eec687b3e9398efeb852867b8ae7a35f88 100644 (file)
@@ -947,7 +947,7 @@ static void pch_udc_ep_enable(struct pch_udc_ep *ep,
        else
                buff_size = UDC_EPOUT_BUFF_SIZE;
        pch_udc_ep_set_bufsz(ep, buff_size, ep->in);
-       pch_udc_ep_set_maxpkt(ep, le16_to_cpu(desc->wMaxPacketSize));
+       pch_udc_ep_set_maxpkt(ep, usb_endpoint_maxp(desc));
        pch_udc_ep_set_nak(ep);
        pch_udc_ep_fifo_flush(ep, ep->in);
        /* Configure the endpoint */
@@ -957,7 +957,7 @@ static void pch_udc_ep_enable(struct pch_udc_ep *ep,
              (cfg->cur_cfg << UDC_CSR_NE_CFG_SHIFT) |
              (cfg->cur_intf << UDC_CSR_NE_INTF_SHIFT) |
              (cfg->cur_alt << UDC_CSR_NE_ALT_SHIFT) |
-             le16_to_cpu(desc->wMaxPacketSize) << UDC_CSR_NE_MAX_PKT_SHIFT;
+             usb_endpoint_maxp(desc) << UDC_CSR_NE_MAX_PKT_SHIFT;
 
        if (ep->in)
                pch_udc_write_csr(ep->dev, val, UDC_EPIN_IDX(ep->num));
@@ -1466,7 +1466,7 @@ static int pch_udc_pcd_ep_enable(struct usb_ep *usbep,
        ep->desc = desc;
        ep->halted = 0;
        pch_udc_ep_enable(ep, &ep->dev->cfg_data, desc);
-       ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+       ep->ep.maxpacket = usb_endpoint_maxp(desc);
        pch_udc_enable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num));
        spin_unlock_irqrestore(&dev->lock, iflags);
        return 0;
index e4e59b4de25db5ff776748fa25b91bf86f0a40a2..7862465291d11ba8946635d2efc371c72a99336c 100644 (file)
@@ -232,8 +232,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep,
        if (!_ep || !desc || ep->desc || _ep->name == ep0name
                        || desc->bDescriptorType != USB_DT_ENDPOINT
                        || ep->bEndpointAddress != desc->bEndpointAddress
-                       || ep->fifo_size < le16_to_cpu
-                                               (desc->wMaxPacketSize)) {
+                       || ep->fifo_size < usb_endpoint_maxp (desc)) {
                DMSG("%s, bad ep or descriptor\n", __func__);
                return -EINVAL;
        }
@@ -248,7 +247,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep,
 
        /* hardware _could_ do smaller, but driver doesn't */
        if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
-                               && le16_to_cpu (desc->wMaxPacketSize)
+                               && usb_endpoint_maxp (desc)
                                                != BULK_FIFO_SIZE)
                        || !desc->wMaxPacketSize) {
                DMSG("%s, bad %s maxpacket\n", __func__, _ep->name);
@@ -264,7 +263,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep,
        ep->desc = desc;
        ep->stopped = 0;
        ep->pio_irqs = 0;
-       ep->ep.maxpacket = le16_to_cpu (desc->wMaxPacketSize);
+       ep->ep.maxpacket = usb_endpoint_maxp (desc);
 
        /* flush fifo (mostly for OUT buffers) */
        pxa25x_ep_fifo_flush (_ep);
@@ -401,7 +400,7 @@ write_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
 {
        unsigned                max;
 
-       max = le16_to_cpu(ep->desc->wMaxPacketSize);
+       max = usb_endpoint_maxp(ep->desc);
        do {
                unsigned        count;
                int             is_last, is_short;
@@ -671,8 +670,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
         * we can report per-packet status.  that also helps with dma.
         */
        if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
-                       && req->req.length > le16_to_cpu
-                                               (ep->desc->wMaxPacketSize)))
+                       && req->req.length > usb_endpoint_maxp (ep->desc)))
                return -EMSGSIZE;
 
        DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n",
@@ -1105,7 +1103,7 @@ udc_seq_show(struct seq_file *m, void *_d)
                        tmp = *dev->ep [i].reg_udccs;
                        seq_printf(m,
                                "%s max %d %s udccs %02x irqs %lu\n",
-                               ep->ep.name, le16_to_cpu(desc->wMaxPacketSize),
+                               ep->ep.name, usb_endpoint_maxp(desc),
                                "pio", tmp, ep->pio_irqs);
                        /* TODO translate all five groups of udccs bits! */
 
index 85b68c75dc9da57a82f183bcb90107f7a68a0980..d21455f457e21d095f504fa7211dc35c397e69b5 100644 (file)
@@ -1439,7 +1439,7 @@ static int pxa_ep_enable(struct usb_ep *_ep,
                return -EINVAL;
        }
 
-       if (ep->fifo_size < le16_to_cpu(desc->wMaxPacketSize)) {
+       if (ep->fifo_size < usb_endpoint_maxp(desc)) {
                ep_err(ep, "bad maxpacket\n");
                return -ERANGE;
        }
index 50991e5bd5e8e6e9238f9382e4e8af0202055228..61d0c65802e8fb917d4cd41ae1a7b8c0bf779552 100644 (file)
@@ -341,7 +341,7 @@ static void r8a66597_ep_setting(struct r8a66597 *r8a66597,
 
        ep->pipectr = get_pipectr_addr(pipenum);
        ep->pipenum = pipenum;
-       ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+       ep->ep.maxpacket = usb_endpoint_maxp(desc);
        r8a66597->pipenum2ep[pipenum] = ep;
        r8a66597->epaddr2ep[desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK]
                = ep;
@@ -420,7 +420,7 @@ static int alloc_pipe_config(struct r8a66597_ep *ep,
        ep->type = info.type;
 
        info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-       info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+       info.maxpacket = usb_endpoint_maxp(desc);
        info.interval = desc->bInterval;
        if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
                info.dir_in = 1;
index 8bdee67ce09a55cf605169105cfab4e98b23b6ae..39b134dec94c3bd019efd17a4813b5be0f8668e0 100644 (file)
@@ -2297,7 +2297,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
                return -EINVAL;
        }
 
-       mps = le16_to_cpu(desc->wMaxPacketSize);
+       mps = usb_endpoint_maxp(desc);
 
        /* note, we handle this here instead of s3c_hsotg_set_ep_maxpacket */
 
index 3fa717c5f4bc6b214e997a11768ffbd18fbcb651..25829b4398da9b2f28a591bb03952e02124da660 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/clk.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
 #include <linux/prefetch.h>
 
 #include <mach/regs-s3c2443-clock.h>
@@ -137,6 +138,7 @@ struct s3c_hsudc {
        struct usb_gadget_driver *driver;
        struct device *dev;
        struct s3c24xx_hsudc_platdata *pd;
+       struct otg_transceiver *transceiver;
        spinlock_t lock;
        void __iomem *regs;
        struct resource *mem_rsrc;
@@ -759,11 +761,11 @@ static int s3c_hsudc_ep_enable(struct usb_ep *_ep,
        if (!_ep || !desc || hsep->desc || _ep->name == ep0name
                || desc->bDescriptorType != USB_DT_ENDPOINT
                || hsep->bEndpointAddress != desc->bEndpointAddress
-               || ep_maxpacket(hsep) < le16_to_cpu(desc->wMaxPacketSize))
+               || ep_maxpacket(hsep) < usb_endpoint_maxp(desc))
                return -EINVAL;
 
        if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
-               && le16_to_cpu(desc->wMaxPacketSize) != ep_maxpacket(hsep))
+               && usb_endpoint_maxp(desc) != ep_maxpacket(hsep))
                || !desc->wMaxPacketSize)
                return -ERANGE;
 
@@ -779,7 +781,7 @@ static int s3c_hsudc_ep_enable(struct usb_ep *_ep,
 
        hsep->stopped = hsep->wedge = 0;
        hsep->desc = desc;
-       hsep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+       hsep->ep.maxpacket = usb_endpoint_maxp(desc);
 
        s3c_hsudc_set_halt(_ep, 0);
        __set_bit(ep_index(hsep), hsudc->regs + S3C_EIER);
@@ -1171,6 +1173,22 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver,
                return ret;
        }
 
+       /* connect to bus through transceiver */
+       if (hsudc->transceiver) {
+               ret = otg_set_peripheral(hsudc->transceiver, &hsudc->gadget);
+               if (ret) {
+                       dev_err(hsudc->dev, "%s: can't bind to transceiver\n",
+                                       hsudc->gadget.name);
+                       driver->unbind(&hsudc->gadget);
+
+                       device_del(&hsudc->gadget.dev);
+
+                       hsudc->driver = NULL;
+                       hsudc->gadget.dev.driver = NULL;
+                       return ret;
+               }
+       }
+
        enable_irq(hsudc->irq);
        dev_info(hsudc->dev, "bound driver %s\n", driver->driver.name);
 
@@ -1201,6 +1219,9 @@ static int s3c_hsudc_stop(struct usb_gadget_driver *driver)
        s3c_hsudc_stop_activity(hsudc, driver);
        spin_unlock_irqrestore(&hsudc->lock, flags);
 
+       if (hsudc->transceiver)
+               (void) otg_set_peripheral(hsudc->transceiver, NULL);
+
        driver->unbind(&hsudc->gadget);
        device_del(&hsudc->gadget.dev);
        disable_irq(hsudc->irq);
@@ -1247,6 +1268,8 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
        hsudc->dev = dev;
        hsudc->pd = pdev->dev.platform_data;
 
+       hsudc->transceiver = otg_get_transceiver();
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(dev, "unable to obtain driver resource data\n");
@@ -1269,19 +1292,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
                goto err_remap;
        }
 
-       ret = platform_get_irq(pdev, 0);
-       if (ret < 0) {
-               dev_err(dev, "unable to obtain IRQ number\n");
-               goto err_irq;
-       }
-       hsudc->irq = ret;
-
-       ret = request_irq(hsudc->irq, s3c_hsudc_irq, 0, driver_name, hsudc);
-       if (ret < 0) {
-               dev_err(dev, "irq request failed\n");
-               goto err_irq;
-       }
-
        spin_lock_init(&hsudc->lock);
 
        device_initialize(&hsudc->gadget.dev);
@@ -1299,6 +1309,19 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
 
        s3c_hsudc_setup_ep(hsudc);
 
+       ret = platform_get_irq(pdev, 0);
+       if (ret < 0) {
+               dev_err(dev, "unable to obtain IRQ number\n");
+               goto err_irq;
+       }
+       hsudc->irq = ret;
+
+       ret = request_irq(hsudc->irq, s3c_hsudc_irq, 0, driver_name, hsudc);
+       if (ret < 0) {
+               dev_err(dev, "irq request failed\n");
+               goto err_irq;
+       }
+
        hsudc->uclk = clk_get(&pdev->dev, "usb-device");
        if (IS_ERR(hsudc->uclk)) {
                dev_err(dev, "failed to find usb-device clock source\n");
index 8d31848aab091534ae998e588f7803c88ea121c9..2572854486781665ee12c485f46c5b0d00ee65de 100644 (file)
@@ -1082,7 +1082,7 @@ static int s3c2410_udc_ep_enable(struct usb_ep *_ep,
        if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
                return -ESHUTDOWN;
 
-       max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff;
+       max = usb_endpoint_maxp(desc) & 0x1fff;
 
        local_irq_save (flags);
        _ep->maxpacket = max & 0x7ff;
index ab085f12d570ec2e246070f1ed7bab601019f527..13e1f672926ddf46dd10d5cce43280385e9d4039 100644 (file)
@@ -544,11 +544,11 @@ config USB_HWA_HCD
          will be called "hwa-hc".
 
 config USB_IMX21_HCD
-       tristate "iMX21 HCD support"
-       depends on USB && ARM && MACH_MX21
+       tristate "i.MX21 HCD support"
+       depends on USB && ARM && ARCH_MXC
        help
          This driver enables support for the on-chip USB host in the
-         iMX21 processor.
+         i.MX21 processor.
 
          To compile this driver as a module, choose M here: the
          module will be called "imx21-hcd".
@@ -578,3 +578,10 @@ config USB_OCTEON_OHCI
 config USB_OCTEON2_COMMON
        bool
        default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI
+
+config USB_PXA168_EHCI
+       bool "Marvell PXA168 on-chip EHCI HCD support"
+       depends on USB_EHCI_HCD && ARCH_MMP
+       help
+         Enable support for Marvell PXA168 SoC's on-chip EHCI
+         host controller
index 42ae57409908750b329385e27ebb3ec36d5c9c24..4363fea85151ace424b583100aac7a3393b9fd27 100644 (file)
@@ -293,7 +293,7 @@ static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
        /* here we "know" root ports should always stay powered */
        ehci_port_power(ehci, 1);
 
-       hcd->state = HC_STATE_SUSPENDED;
+       ehci->rh_state = EHCI_RH_SUSPENDED;
 
        return 0;
 }
index 40a844c1dbb4945044a9afe2d94d2097bad29af3..9952505d2357ebd7b96b806c09d8b26e9fee00cf 100644 (file)
@@ -697,6 +697,19 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
 }
 #undef DBG_SCHED_LIMIT
 
+static const char *rh_state_string(struct ehci_hcd *ehci)
+{
+       switch (ehci->rh_state) {
+       case EHCI_RH_HALTED:
+               return "halted";
+       case EHCI_RH_SUSPENDED:
+               return "suspended";
+       case EHCI_RH_RUNNING:
+               return "running";
+       }
+       return "?";
+}
+
 static ssize_t fill_registers_buffer(struct debug_buffer *buf)
 {
        struct usb_hcd          *hcd;
@@ -730,11 +743,11 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
        temp = scnprintf (next, size,
                "bus %s, device %s\n"
                "%s\n"
-               "EHCI %x.%02x, hcd state %d\n",
+               "EHCI %x.%02x, rh state %s\n",
                hcd->self.controller->bus->name,
                dev_name(hcd->self.controller),
                hcd->product_desc,
-               i >> 8, i & 0x0ff, hcd->state);
+               i >> 8, i & 0x0ff, rh_state_string(ehci));
        size -= temp;
        next += temp;
 
index 34a3140d1e5f169e182d2c2ce37762fd8413e8d6..3bf9f16b4fd890ecf945934458b9e9c10b8c5759 100644 (file)
@@ -392,7 +392,7 @@ static int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
 
        dev_dbg(dev, "suspending...\n");
 
-       hcd->state = HC_STATE_SUSPENDED;
+       ehci->rh_state = EHCI_RH_SUSPENDED;
        dev->power.power_state = PMSG_SUSPEND;
 
        /* ignore non-host interrupts */
@@ -481,7 +481,7 @@ static int ehci_fsl_mpc512x_drv_resume(struct device *dev)
        ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]);
 
        set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-       hcd->state = HC_STATE_RUNNING;
+       ehci->rh_state = EHCI_RH_RUNNING;
        dev->power.power_state = PMSG_ON;
 
        tmp = ehci_readl(ehci, &ehci->regs->command);
index f72ae0b6ee7f27ec1f2122b8738d0799fbd7aa60..8696489cde566e94c35c46bfc3ce0e512578630b 100644 (file)
@@ -238,7 +238,7 @@ static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
        error = handshake(ehci, ptr, mask, done, usec);
        if (error) {
                ehci_halt(ehci);
-               ehci_to_hcd(ehci)->state = HC_STATE_HALT;
+               ehci->rh_state = EHCI_RH_HALTED;
                ehci_err(ehci, "force halt; handshake %p %08x %08x -> %d\n",
                        ptr, mask, done, error);
        }
@@ -278,7 +278,7 @@ static int ehci_reset (struct ehci_hcd *ehci)
        command |= CMD_RESET;
        dbg_cmd (ehci, "reset", command);
        ehci_writel(ehci, command, &ehci->regs->command);
-       ehci_to_hcd(ehci)->state = HC_STATE_HALT;
+       ehci->rh_state = EHCI_RH_HALTED;
        ehci->next_statechange = jiffies;
        retval = handshake (ehci, &ehci->regs->command,
                            CMD_RESET, 0, 250 * 1000);
@@ -307,7 +307,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
        u32     temp;
 
 #ifdef DEBUG
-       if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
+       if (ehci->rh_state != EHCI_RH_RUNNING)
                BUG ();
 #endif
 
@@ -356,7 +356,7 @@ static void ehci_iaa_watchdog(unsigned long param)
         */
        if (ehci->reclaim
                        && !timer_pending(&ehci->iaa_watchdog)
-                       && HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
+                       && ehci->rh_state == EHCI_RH_RUNNING) {
                u32 cmd, status;
 
                /* If we get here, IAA is *REALLY* late.  It's barely
@@ -496,7 +496,7 @@ static void ehci_work (struct ehci_hcd *ehci)
         * misplace IRQs, and should let us run completely without IRQs.
         * such lossage has been observed on both VT6202 and VT8235.
         */
-       if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state) &&
+       if (ehci->rh_state == EHCI_RH_RUNNING &&
                        (ehci->async->qh_next.ptr != NULL ||
                         ehci->periodic_sched != 0))
                timer_action (ehci, TIMER_IO_WATCHDOG);
@@ -516,7 +516,7 @@ static void ehci_stop (struct usb_hcd *hcd)
        del_timer_sync(&ehci->iaa_watchdog);
 
        spin_lock_irq(&ehci->lock);
-       if (HC_IS_RUNNING (hcd->state))
+       if (ehci->rh_state == EHCI_RH_RUNNING)
                ehci_quiesce (ehci);
 
        ehci_silence_controller(ehci);
@@ -741,7 +741,7 @@ static int ehci_run (struct usb_hcd *hcd)
         * be started before the port switching actions could complete.
         */
        down_write(&ehci_cf_port_reset_rwsem);
-       hcd->state = HC_STATE_RUNNING;
+       ehci->rh_state = EHCI_RH_RUNNING;
        ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
        ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
        msleep(5);
@@ -788,7 +788,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 
        /* Shared IRQ? */
        masked_status = status & INTR_MASK;
-       if (!masked_status || unlikely(hcd->state == HC_STATE_HALT)) {
+       if (!masked_status || unlikely(ehci->rh_state == EHCI_RH_HALTED)) {
                spin_unlock(&ehci->lock);
                return IRQ_NONE;
        }
@@ -952,7 +952,7 @@ static int ehci_urb_enqueue (
 static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
        /* failfast */
-       if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state) && ehci->reclaim)
+       if (ehci->rh_state != EHCI_RH_RUNNING && ehci->reclaim)
                end_unlink_async(ehci);
 
        /* If the QH isn't linked then there's nothing we can do
@@ -1079,7 +1079,7 @@ rescan:
                goto idle_timeout;
        }
 
-       if (!HC_IS_RUNNING (hcd->state))
+       if (ehci->rh_state != EHCI_RH_RUNNING)
                qh->qh_state = QH_STATE_IDLE;
        switch (qh->qh_state) {
        case QH_STATE_LINKED:
@@ -1291,6 +1291,16 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER                ehci_grlib_driver
 #endif
 
+#ifdef CONFIG_USB_PXA168_EHCI
+#include "ehci-pxa168.c"
+#define PLATFORM_DRIVER                ehci_pxa168_driver
+#endif
+
+#ifdef CONFIG_NLM_XLR
+#include "ehci-xls.c"
+#define PLATFORM_DRIVER                ehci_xls_driver
+#endif
+
 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
     !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
     !defined(XILINX_OF_PLATFORM_DRIVER)
index 4c32cb19b405f7f5c4fc589e37acc3455ab15448..77bbb2357e478a5e021118076bbe2a7f84811af4 100644 (file)
@@ -236,10 +236,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
        }
 
        /* stop schedules, clean any completed work */
-       if (HC_IS_RUNNING(hcd->state)) {
+       if (ehci->rh_state == EHCI_RH_RUNNING)
                ehci_quiesce (ehci);
-               hcd->state = HC_STATE_QUIESCING;
-       }
        ehci->command = ehci_readl(ehci, &ehci->regs->command);
        ehci_work(ehci);
 
@@ -313,7 +311,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
 
        /* turn off now-idle HC */
        ehci_halt (ehci);
-       hcd->state = HC_STATE_SUSPENDED;
+       ehci->rh_state = EHCI_RH_SUSPENDED;
 
        if (ehci->reclaim)
                end_unlink_async(ehci);
@@ -382,6 +380,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
 
        /* restore CMD_RUN, framelist size, and irq threshold */
        ehci_writel(ehci, ehci->command, &ehci->regs->command);
+       ehci->rh_state = EHCI_RH_RUNNING;
 
        /* Some controller/firmware combinations need a delay during which
         * they set up the port statuses.  See Bugzilla #8190. */
@@ -451,7 +450,6 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
        }
 
        ehci->next_statechange = jiffies + msecs_to_jiffies(5);
-       hcd->state = HC_STATE_RUNNING;
 
        /* Now we can safely re-enable irqs */
        ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
@@ -563,7 +561,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
        u32             ppcd = 0;
 
        /* if !USB_SUSPEND, root hub timers won't get shut down ... */
-       if (!HC_IS_RUNNING(hcd->state))
+       if (ehci->rh_state != EHCI_RH_RUNNING)
                return 0;
 
        /* init status to no-changes */
index 1102ce65a3a9eff69fee9c612f65f4a6ead9c3a9..8311de7c0a75036002f903a4f5949a3962b81a17 100644 (file)
@@ -439,7 +439,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
        /* here we "know" root ports should always stay powered */
        ehci_port_power(ehci, 1);
 
-       hcd->state = HC_STATE_SUSPENDED;
+       ehci->rh_state = EHCI_RH_SUSPENDED;
        return 0;
 }
 #endif
diff --git a/drivers/usb/host/ehci-pxa168.c b/drivers/usb/host/ehci-pxa168.c
new file mode 100644 (file)
index 0000000..ac0c16e
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * drivers/usb/host/ehci-pxa168.c
+ *
+ * Tanmay Upadhyay <tanmay.upadhyay@einfochips.com>
+ *
+ * Based on drivers/usb/host/ehci-orion.c
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <mach/pxa168.h>
+
+#define USB_PHY_CTRL_REG 0x4
+#define USB_PHY_PLL_REG  0x8
+#define USB_PHY_TX_REG   0xc
+
+#define FBDIV_SHIFT      4
+
+#define ICP_SHIFT        12
+#define ICP_15            2
+#define ICP_20            3
+#define ICP_25            4
+
+#define KVCO_SHIFT       15
+
+#define PLLCALI12_SHIFT  25
+#define CALI12_VDD        0
+#define CALI12_09         1
+#define CALI12_10         2
+#define CALI12_11         3
+
+#define PLLVDD12_SHIFT   27
+#define VDD12_VDD         0
+#define VDD12_10          1
+#define VDD12_11          2
+#define VDD12_12          3
+
+#define PLLVDD18_SHIFT   29
+#define VDD18_19          0
+#define VDD18_20          1
+#define VDD18_21          2
+#define VDD18_22          3
+
+
+#define PLL_READY        (1 << 23)
+#define VCOCAL_START     (1 << 21)
+#define REG_RCAL_START   (1 << 12)
+
+struct pxa168_usb_drv_data {
+       struct ehci_hcd ehci;
+       struct clk      *pxa168_usb_clk;
+       struct resource *usb_phy_res;
+       void __iomem    *usb_phy_reg_base;
+};
+
+static int ehci_pxa168_setup(struct usb_hcd *hcd)
+{
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+       int retval;
+
+       ehci_reset(ehci);
+       retval = ehci_halt(ehci);
+       if (retval)
+               return retval;
+
+       /*
+        * data structure init
+        */
+       retval = ehci_init(hcd);
+       if (retval)
+               return retval;
+
+       hcd->has_tt = 1;
+
+       ehci_port_power(ehci, 0);
+
+       return retval;
+}
+
+static const struct hc_driver ehci_pxa168_hc_driver = {
+       .description = hcd_name,
+       .product_desc = "Marvell PXA168 EHCI",
+       .hcd_priv_size = sizeof(struct pxa168_usb_drv_data),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq = ehci_irq,
+       .flags = HCD_MEMORY | HCD_USB2,
+
+       /*
+        * basic lifecycle operations
+        */
+       .reset = ehci_pxa168_setup,
+       .start = ehci_run,
+       .stop = ehci_stop,
+       .shutdown = ehci_shutdown,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue = ehci_urb_enqueue,
+       .urb_dequeue = ehci_urb_dequeue,
+       .endpoint_disable = ehci_endpoint_disable,
+       .endpoint_reset = ehci_endpoint_reset,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number = ehci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data = ehci_hub_status_data,
+       .hub_control = ehci_hub_control,
+       .bus_suspend = ehci_bus_suspend,
+       .bus_resume = ehci_bus_resume,
+       .relinquish_port = ehci_relinquish_port,
+       .port_handed_over = ehci_port_handed_over,
+
+       .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static int pxa168_usb_phy_init(struct platform_device *pdev)
+{
+       struct resource *res;
+       void __iomem *usb_phy_reg_base;
+       struct pxa168_usb_pdata *pdata;
+       struct pxa168_usb_drv_data *drv_data;
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+       unsigned long reg_val;
+       int pll_retry_cont = 10000, err = 0;
+
+       drv_data = (struct pxa168_usb_drv_data *)hcd->hcd_priv;
+       pdata = (struct pxa168_usb_pdata *)pdev->dev.platform_data;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res) {
+               dev_err(&pdev->dev,
+                       "Found HC with no PHY register addr. Check %s setup!\n",
+                       dev_name(&pdev->dev));
+               return -ENODEV;
+       }
+
+       if (!request_mem_region(res->start, resource_size(res),
+                               ehci_pxa168_hc_driver.description)) {
+               dev_dbg(&pdev->dev, "controller already in use\n");
+               return -EBUSY;
+       }
+
+       usb_phy_reg_base = ioremap(res->start, resource_size(res));
+       if (usb_phy_reg_base == NULL) {
+               dev_dbg(&pdev->dev, "error mapping memory\n");
+               err = -EFAULT;
+               goto err1;
+       }
+       drv_data->usb_phy_reg_base = usb_phy_reg_base;
+       drv_data->usb_phy_res = res;
+
+       /* If someone wants to init USB phy in board specific way */
+       if (pdata && pdata->phy_init)
+               return pdata->phy_init(usb_phy_reg_base);
+
+       /* Power up the PHY and PLL */
+       writel(readl(usb_phy_reg_base + USB_PHY_CTRL_REG) | 0x3,
+               usb_phy_reg_base + USB_PHY_CTRL_REG);
+
+       /* Configure PHY PLL */
+       reg_val = readl(usb_phy_reg_base + USB_PHY_PLL_REG) & ~(0x7e03ffff);
+       reg_val |= (VDD18_22 << PLLVDD18_SHIFT | VDD12_12 << PLLVDD12_SHIFT |
+               CALI12_11 << PLLCALI12_SHIFT | 3 << KVCO_SHIFT |
+               ICP_15 << ICP_SHIFT | 0xee << FBDIV_SHIFT | 0xb);
+       writel(reg_val, usb_phy_reg_base + USB_PHY_PLL_REG);
+
+       /* Make sure PHY PLL is ready */
+       while (!(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & PLL_READY)) {
+               if (!(pll_retry_cont--)) {
+                       dev_dbg(&pdev->dev, "USB PHY PLL not ready\n");
+                       err = -EIO;
+                       goto err2;
+               }
+       }
+
+       /* Toggle VCOCAL_START bit of U2PLL for PLL calibration */
+       udelay(200);
+       writel(readl(usb_phy_reg_base + USB_PHY_PLL_REG) | VCOCAL_START,
+               usb_phy_reg_base + USB_PHY_PLL_REG);
+       udelay(40);
+       writel(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & ~VCOCAL_START,
+               usb_phy_reg_base + USB_PHY_PLL_REG);
+
+       /* Toggle REG_RCAL_START bit of U2PTX for impedance calibration */
+       udelay(400);
+       writel(readl(usb_phy_reg_base + USB_PHY_TX_REG) | REG_RCAL_START,
+               usb_phy_reg_base + USB_PHY_TX_REG);
+       udelay(40);
+       writel(readl(usb_phy_reg_base + USB_PHY_TX_REG) & ~REG_RCAL_START,
+               usb_phy_reg_base + USB_PHY_TX_REG);
+
+       /* Make sure PHY PLL is ready again */
+       pll_retry_cont = 0;
+       while (!(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & PLL_READY)) {
+               if (!(pll_retry_cont--)) {
+                       dev_dbg(&pdev->dev, "USB PHY PLL not ready\n");
+                       err = -EIO;
+                       goto err2;
+               }
+       }
+
+       return 0;
+err2:
+       iounmap(usb_phy_reg_base);
+err1:
+       release_mem_region(res->start, resource_size(res));
+       return err;
+}
+
+static int __devinit ehci_pxa168_drv_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct usb_hcd *hcd;
+       struct ehci_hcd *ehci;
+       struct pxa168_usb_drv_data *drv_data;
+       void __iomem *regs;
+       int irq, err = 0;
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       pr_debug("Initializing pxa168-SoC USB Host Controller\n");
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               dev_err(&pdev->dev,
+                       "Found HC with no IRQ. Check %s setup!\n",
+                       dev_name(&pdev->dev));
+               err = -ENODEV;
+               goto err1;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev,
+                       "Found HC with no register addr. Check %s setup!\n",
+                       dev_name(&pdev->dev));
+               err = -ENODEV;
+               goto err1;
+       }
+
+       if (!request_mem_region(res->start, resource_size(res),
+                               ehci_pxa168_hc_driver.description)) {
+               dev_dbg(&pdev->dev, "controller already in use\n");
+               err = -EBUSY;
+               goto err1;
+       }
+
+       regs = ioremap(res->start, resource_size(res));
+       if (regs == NULL) {
+               dev_dbg(&pdev->dev, "error mapping memory\n");
+               err = -EFAULT;
+               goto err2;
+       }
+
+       hcd = usb_create_hcd(&ehci_pxa168_hc_driver,
+                       &pdev->dev, dev_name(&pdev->dev));
+       if (!hcd) {
+               err = -ENOMEM;
+               goto err3;
+       }
+
+       drv_data = (struct pxa168_usb_drv_data *)hcd->hcd_priv;
+
+       /* Enable USB clock */
+       drv_data->pxa168_usb_clk = clk_get(&pdev->dev, "PXA168-USBCLK");
+       if (IS_ERR(drv_data->pxa168_usb_clk)) {
+               dev_err(&pdev->dev, "Couldn't get USB clock\n");
+               err = PTR_ERR(drv_data->pxa168_usb_clk);
+               goto err4;
+       }
+       clk_enable(drv_data->pxa168_usb_clk);
+
+       err = pxa168_usb_phy_init(pdev);
+       if (err) {
+               dev_err(&pdev->dev, "USB PHY initialization failed\n");
+               goto err5;
+       }
+
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = resource_size(res);
+       hcd->regs = regs;
+
+       ehci = hcd_to_ehci(hcd);
+       ehci->caps = hcd->regs + 0x100;
+       ehci->regs = hcd->regs + 0x100 +
+               HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+       ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+       hcd->has_tt = 1;
+       ehci->sbrn = 0x20;
+
+       err = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED);
+       if (err)
+               goto err5;
+
+       return 0;
+
+err5:
+       clk_disable(drv_data->pxa168_usb_clk);
+       clk_put(drv_data->pxa168_usb_clk);
+err4:
+       usb_put_hcd(hcd);
+err3:
+       iounmap(regs);
+err2:
+       release_mem_region(res->start, resource_size(res));
+err1:
+       dev_err(&pdev->dev, "init %s fail, %d\n",
+               dev_name(&pdev->dev), err);
+
+       return err;
+}
+
+static int __exit ehci_pxa168_drv_remove(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+       struct pxa168_usb_drv_data *drv_data =
+               (struct pxa168_usb_drv_data *)hcd->hcd_priv;
+
+       usb_remove_hcd(hcd);
+
+       /* Power down PHY & PLL */
+       writel(readl(drv_data->usb_phy_reg_base + USB_PHY_CTRL_REG) & (~0x3),
+               drv_data->usb_phy_reg_base + USB_PHY_CTRL_REG);
+
+       clk_disable(drv_data->pxa168_usb_clk);
+       clk_put(drv_data->pxa168_usb_clk);
+
+       iounmap(hcd->regs);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+       iounmap(drv_data->usb_phy_reg_base);
+       release_mem_region(drv_data->usb_phy_res->start,
+                       resource_size(drv_data->usb_phy_res));
+
+       usb_put_hcd(hcd);
+
+       return 0;
+}
+
+MODULE_ALIAS("platform:pxa168-ehci");
+
+static struct platform_driver ehci_pxa168_driver = {
+       .probe          = ehci_pxa168_drv_probe,
+       .remove         = __exit_p(ehci_pxa168_drv_remove),
+       .shutdown       = usb_hcd_platform_shutdown,
+       .driver.name    = "pxa168-ehci",
+};
index 0917e3a32465064903dd884cc2c258baadadc0f2..6ce0b3a9a0f9af53366a7c8092046e36e89ae29c 100644 (file)
@@ -153,7 +153,7 @@ static void ehci_clear_tt_buffer_complete(struct usb_hcd *hcd,
        spin_lock_irqsave(&ehci->lock, flags);
        qh->clearing_tt = 0;
        if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list)
-                       && HC_IS_RUNNING(hcd->state))
+                       && ehci->rh_state == EHCI_RH_RUNNING)
                qh_link_async(ehci, qh);
        spin_unlock_irqrestore(&ehci->lock, flags);
 }
@@ -425,7 +425,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
                /* stop scanning when we reach qtds the hc is using */
                } else if (likely (!stopped
-                               && HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) {
+                               && ehci->rh_state == EHCI_RH_RUNNING)) {
                        break;
 
                /* scan the whole queue for unlinks whenever it stops */
@@ -433,7 +433,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
                        stopped = 1;
 
                        /* cancel everything if we halt, suspend, etc */
-                       if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))
+                       if (ehci->rh_state != EHCI_RH_RUNNING)
                                last_status = -ESHUTDOWN;
 
                        /* this qtd is active; skip it unless a previous qtd
@@ -977,9 +977,8 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
                        /* in case a clear of CMD_ASE didn't take yet */
                        (void)handshake(ehci, &ehci->regs->status,
                                        STS_ASS, 0, 150);
-                       cmd |= CMD_ASE | CMD_RUN;
+                       cmd |= CMD_ASE;
                        ehci_writel(ehci, cmd, &ehci->regs->command);
-                       ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
                        /* posted write need not be known to HC yet ... */
                }
        }
@@ -1168,14 +1167,13 @@ static void end_unlink_async (struct ehci_hcd *ehci)
 
        qh_completions (ehci, qh);
 
-       if (!list_empty (&qh->qtd_list)
-                       && HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
+       if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) {
                qh_link_async (ehci, qh);
-       else {
+       else {
                /* it's not free to turn the async schedule on/off; leave it
                 * active but idle for a while once it empties.
                 */
-               if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state)
+               if (ehci->rh_state == EHCI_RH_RUNNING
                                && ehci->async->qh_next.qh == NULL)
                        timer_action (ehci, TIMER_ASYNC_OFF);
        }
@@ -1211,7 +1209,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
        /* stop async schedule right now? */
        if (unlikely (qh == ehci->async)) {
                /* can't get here without STS_ASS set */
-               if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
+               if (ehci->rh_state != EHCI_RH_HALTED
                                && !ehci->reclaim) {
                        /* ... and CMD_IAAD clear */
                        ehci_writel(ehci, cmd & ~CMD_ASE,
@@ -1237,7 +1235,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
        wmb ();
 
        /* If the controller isn't running, we don't have to wait for it */
-       if (unlikely(!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))) {
+       if (unlikely(ehci->rh_state != EHCI_RH_RUNNING)) {
                /* if (unlikely (qh->reclaim != 0))
                 *      this will recurse, probably not much
                 */
@@ -1260,7 +1258,7 @@ static void scan_async (struct ehci_hcd *ehci)
        enum ehci_timer_action  action = TIMER_IO_WATCHDOG;
 
        timer_action_done (ehci, TIMER_ASYNC_SHRINK);
-       stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state);
+       stopped = (ehci->rh_state != EHCI_RH_RUNNING);
 
        ehci->qh_scan_next = ehci->async->qh_next.qh;
        while (ehci->qh_scan_next) {
index 9e77f1c8bdbdc1d62e31565f9c8303e292f8026f..64bcf66d304027ce387aca459d8a1fbc799eb9d5 100644 (file)
@@ -270,7 +270,7 @@ static int s5p_ehci_resume(struct device *dev)
        /* here we "know" root ports should always stay powered */
        ehci_port_power(ehci, 1);
 
-       hcd->state = HC_STATE_SUSPENDED;
+       ehci->rh_state = EHCI_RH_SUSPENDED;
 
        return 0;
 }
index 2abf8543f083fe69b26e6224f8dd8edeffb050ac..488151bb45cb1e0b2eb6bbc23b34eea76b52185f 100644 (file)
@@ -479,7 +479,6 @@ static int enable_periodic (struct ehci_hcd *ehci)
        cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
        ehci_writel(ehci, cmd, &ehci->regs->command);
        /* posted write ... PSS happens later */
-       ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
 
        /* make sure ehci_work scans these */
        ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
@@ -677,7 +676,7 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
        /* reschedule QH iff another request is queued */
        if (!list_empty(&qh->qtd_list) &&
-                       HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
+                       ehci->rh_state == EHCI_RH_RUNNING) {
                rc = qh_schedule(ehci, qh);
 
                /* An error here likely indicates handshake failure
@@ -2275,7 +2274,7 @@ scan_periodic (struct ehci_hcd *ehci)
         * Touches as few pages as possible:  cache-friendly.
         */
        now_uframe = ehci->next_uframe;
-       if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
+       if (ehci->rh_state == EHCI_RH_RUNNING) {
                clock = ehci_readl(ehci, &ehci->regs->frame_index);
                clock_frame = (clock >> 3) & (ehci->periodic_size - 1);
        } else  {
@@ -2310,7 +2309,7 @@ restart:
                        union ehci_shadow       temp;
                        int                     live;
 
-                       live = HC_IS_RUNNING (ehci_to_hcd(ehci)->state);
+                       live = (ehci->rh_state == EHCI_RH_RUNNING);
                        switch (hc32_to_cpu(ehci, type)) {
                        case Q_TYPE_QH:
                                /* handle any completions */
@@ -2435,7 +2434,7 @@ restart:
                 * We can't advance our scan without collecting the ISO
                 * transfers that are still pending in this frame.
                 */
-               if (incomplete && HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
+               if (incomplete && ehci->rh_state == EHCI_RH_RUNNING) {
                        ehci->next_uframe = now_uframe;
                        break;
                }
@@ -2451,7 +2450,7 @@ restart:
                if (now_uframe == clock) {
                        unsigned        now;
 
-                       if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)
+                       if (ehci->rh_state != EHCI_RH_RUNNING
                                        || ehci->periodic_sched == 0)
                                break;
                        ehci->next_uframe = now_uframe;
diff --git a/drivers/usb/host/ehci-xls.c b/drivers/usb/host/ehci-xls.c
new file mode 100644 (file)
index 0000000..fe74bd6
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * EHCI HCD for Netlogic XLS processors.
+ *
+ * (C) Copyright 2011 Netlogic Microsystems Inc.
+ *
+ *  Based on various ehci-*.c drivers
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/platform_device.h>
+
+static int ehci_xls_setup(struct usb_hcd *hcd)
+{
+       int     retval;
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+       ehci->caps = hcd->regs;
+       ehci->regs = hcd->regs +
+               HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+       dbg_hcs_params(ehci, "reset");
+       dbg_hcc_params(ehci, "reset");
+
+       /* cache this readonly data; minimize chip reads */
+       ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+       retval = ehci_halt(ehci);
+       if (retval)
+               return retval;
+
+       /* data structure init */
+       retval = ehci_init(hcd);
+       if (retval)
+               return retval;
+
+       ehci_reset(ehci);
+
+       return retval;
+}
+
+int ehci_xls_probe_internal(const struct hc_driver *driver,
+       struct platform_device *pdev)
+{
+       struct usb_hcd  *hcd;
+       struct resource *res;
+       int retval, irq;
+
+       /* Get our IRQ from an earlier registered Platform Resource */
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "Found HC with no IRQ. Check %s setup!\n",
+                               dev_name(&pdev->dev));
+               return -ENODEV;
+       }
+
+       /* Get our Memory Handle */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Error: MMIO Handle %s setup!\n",
+                               dev_name(&pdev->dev));
+               return -ENODEV;
+       }
+       hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
+       if (!hcd) {
+               retval = -ENOMEM;
+               goto err1;
+       }
+
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = res->end - res->start + 1;
+
+       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+                               driver->description)) {
+               dev_dbg(&pdev->dev, "controller already in use\n");
+               retval = -EBUSY;
+               goto err2;
+       }
+       hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+
+       if (hcd->regs == NULL) {
+               dev_dbg(&pdev->dev, "error mapping memory\n");
+               retval = -EFAULT;
+               goto err3;
+       }
+
+       retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
+       if (retval != 0)
+               goto err4;
+       return retval;
+
+err4:
+       iounmap(hcd->regs);
+err3:
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err2:
+       usb_put_hcd(hcd);
+err1:
+       dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev),
+                       retval);
+       return retval;
+}
+
+static struct hc_driver ehci_xls_hc_driver = {
+       .description    = hcd_name,
+       .product_desc   = "XLS EHCI Host Controller",
+       .hcd_priv_size  = sizeof(struct ehci_hcd),
+       .irq            = ehci_irq,
+       .flags          = HCD_USB2 | HCD_MEMORY,
+       .reset          = ehci_xls_setup,
+       .start          = ehci_run,
+       .stop           = ehci_stop,
+       .shutdown       = ehci_shutdown,
+
+       .urb_enqueue    = ehci_urb_enqueue,
+       .urb_dequeue    = ehci_urb_dequeue,
+       .endpoint_disable = ehci_endpoint_disable,
+       .endpoint_reset = ehci_endpoint_reset,
+
+       .get_frame_number = ehci_get_frame,
+
+       .hub_status_data = ehci_hub_status_data,
+       .hub_control    = ehci_hub_control,
+       .bus_suspend    = ehci_bus_suspend,
+       .bus_resume     = ehci_bus_resume,
+       .relinquish_port = ehci_relinquish_port,
+       .port_handed_over = ehci_port_handed_over,
+
+       .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static int ehci_xls_probe(struct platform_device *pdev)
+{
+       if (usb_disabled())
+               return -ENODEV;
+
+       return ehci_xls_probe_internal(&ehci_xls_hc_driver, pdev);
+}
+
+static int ehci_xls_remove(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+       usb_remove_hcd(hcd);
+       iounmap(hcd->regs);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+       usb_put_hcd(hcd);
+       return 0;
+}
+
+MODULE_ALIAS("ehci-xls");
+
+static struct platform_driver ehci_xls_driver = {
+       .probe          = ehci_xls_probe,
+       .remove         = ehci_xls_remove,
+       .shutdown       = usb_hcd_platform_shutdown,
+       .driver         = {
+               .name = "ehci-xls",
+       },
+};
index cc7d337ec35535bb24e2097775dc653381560b6b..c161d97de7ddb208b55fb2fbf9dcbd8b8c0333d4 100644 (file)
@@ -62,6 +62,12 @@ struct ehci_stats {
 
 #define        EHCI_MAX_ROOT_PORTS     15              /* see HCS_N_PORTS */
 
+enum ehci_rh_state {
+       EHCI_RH_HALTED,
+       EHCI_RH_SUSPENDED,
+       EHCI_RH_RUNNING
+};
+
 struct ehci_hcd {                      /* one per controller */
        /* glue to PCI and HCD framework */
        struct ehci_caps __iomem *caps;
@@ -70,6 +76,7 @@ struct ehci_hcd {                     /* one per controller */
 
        __u32                   hcs_params;     /* cached register copy */
        spinlock_t              lock;
+       enum ehci_rh_state      rh_state;
 
        /* async schedule support */
        struct ehci_qh          *async;
index 572ea53b0226eb084d6134b1b7fe853bf0d67374..484a74f7553a970b89c00b85d8cfd0d63cb56808 100644 (file)
@@ -621,12 +621,15 @@ static int __devinit of_fhci_probe(struct platform_device *ofdev)
                goto err_pram;
        }
 
-       pram_addr = cpm_muram_alloc_fixed(iprop[2], FHCI_PRAM_SIZE);
+       pram_addr = cpm_muram_alloc(FHCI_PRAM_SIZE, 64);
        if (IS_ERR_VALUE(pram_addr)) {
                dev_err(dev, "failed to allocate usb pram\n");
                ret = -ENOMEM;
                goto err_pram;
        }
+
+       qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, QE_CR_SUBBLOCK_USB,
+                    QE_CR_PROTOCOL_UNSPECIFIED, pram_addr);
        fhci->pram = cpm_muram_addr(pram_addr);
 
        /* GPIOs and pins */
index 9c37dad3e8168989eaf919cf8993fafb499d6126..21efca98a78c585b4d012892043de6a0d549fc9e 100644 (file)
@@ -2358,7 +2358,7 @@ static int isp1362_hc_reset(struct usb_hcd *hcd)
        unsigned long flags;
        int clkrdy = 0;
 
-       pr_info("%s:\n", __func__);
+       pr_debug("%s:\n", __func__);
 
        if (isp1362_hcd->board && isp1362_hcd->board->reset) {
                isp1362_hcd->board->reset(hcd->self.controller, 1);
@@ -2395,7 +2395,7 @@ static void isp1362_hc_stop(struct usb_hcd *hcd)
        unsigned long flags;
        u32 tmp;
 
-       pr_info("%s:\n", __func__);
+       pr_debug("%s:\n", __func__);
 
        del_timer_sync(&hcd->rh_timer);
 
@@ -2523,7 +2523,7 @@ static int isp1362_hc_start(struct usb_hcd *hcd)
        u16 chipid;
        unsigned long flags;
 
-       pr_info("%s:\n", __func__);
+       pr_debug("%s:\n", __func__);
 
        spin_lock_irqsave(&isp1362_hcd->lock, flags);
        chipid = isp1362_read_reg16(isp1362_hcd, HCCHIPID);
index 840beda66dd94aa378c506918ffad093e1ba4052..5b08bd743accfe7edb6d2ad9dc6cb6ce55cb1a93 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/mm.h>
+#include <linux/timer.h>
 #include <asm/unaligned.h>
 #include <asm/cacheflush.h>
 
@@ -39,7 +40,6 @@ struct isp1760_hcd {
        int                     int_done_map;
        struct memory_chunk memory_pool[BLOCKS];
        struct list_head        controlqhs, bulkqhs, interruptqhs;
-       int active_ptds;
 
        /* periodic schedule support */
 #define        DEFAULT_I_TDPS          1024
@@ -114,6 +114,7 @@ struct isp1760_qh {
        u32 toggle;
        u32 ping;
        int slot;
+       int tt_buffer_dirty;    /* See USB2.0 spec section 11.17.5 */
 };
 
 struct urb_listitem {
@@ -489,10 +490,6 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
                           16 : 32, (priv->devflags & ISP1760_FLAG_ANALOG_OC) ?
                           "analog" : "digital");
 
-       /* This is weird: at the first plug-in of a device there seems to be
-          one packet queued that never gets returned? */
-       priv->active_ptds = -1;
-
        /* ATL reset */
        reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET);
        mdelay(10);
@@ -514,83 +511,6 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
        return priv_init(hcd);
 }
 
-static void isp1760_init_maps(struct usb_hcd *hcd)
-{
-       /*set last maps, for iso its only 1, else 32 tds bitmap*/
-       reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000);
-       reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000);
-       reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001);
-
-       reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff);
-       reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff);
-       reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff);
-
-       reg_write32(hcd->regs, HC_BUFFER_STATUS_REG,
-                                               ATL_BUF_FILL | INT_BUF_FILL);
-}
-
-static void isp1760_enable_interrupts(struct usb_hcd *hcd)
-{
-       reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0);
-       reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff);
-       reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0);
-       reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff);
-       reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0);
-       reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff);
-       /* step 23 passed */
-}
-
-static int isp1760_run(struct usb_hcd *hcd)
-{
-       int retval;
-       u32 temp;
-       u32 command;
-       u32 chipid;
-
-       hcd->uses_new_polling = 1;
-
-       hcd->state = HC_STATE_RUNNING;
-       isp1760_enable_interrupts(hcd);
-       temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
-       reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN);
-
-       command = reg_read32(hcd->regs, HC_USBCMD);
-       command &= ~(CMD_LRESET|CMD_RESET);
-       command |= CMD_RUN;
-       reg_write32(hcd->regs, HC_USBCMD, command);
-
-       retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000);
-       if (retval)
-               return retval;
-
-       /*
-        * XXX
-        * Spec says to write FLAG_CF as last config action, priv code grabs
-        * the semaphore while doing so.
-        */
-       down_write(&ehci_cf_port_reset_rwsem);
-       reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF);
-
-       retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000);
-       up_write(&ehci_cf_port_reset_rwsem);
-       if (retval)
-               return retval;
-
-       chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG);
-       dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n",
-                                       chipid & 0xffff, chipid >> 16);
-
-       /* PTD Register Init Part 2, Step 28 */
-       /* enable INTs */
-       isp1760_init_maps(hcd);
-
-       /* GRR this is run-once init(), being done every time the HC starts.
-        * So long as they're part of class devices, we can't do it init()
-        * since the class device isn't created that early.
-        */
-       return 0;
-}
-
 static u32 base_to_chip(u32 base)
 {
        return ((base - 0x400) >> 3);
@@ -813,28 +733,29 @@ static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
        WARN_ON(slots[slot].qh);
        WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC);
 
-       slots[slot].qtd = qtd;
-       slots[slot].qh = qh;
-       qh->slot = slot;
-       qtd->status = QTD_XFER_STARTED; /* Set this before writing ptd, since
-               interrupt routine may preempt and expects this value. */
-       ptd_write(hcd->regs, ptd_offset, slot, ptd);
-       priv->active_ptds++;
-
        /* Make sure done map has not triggered from some unlinked transfer */
        if (ptd_offset == ATL_PTD_OFFSET) {
                priv->atl_done_map |= reg_read32(hcd->regs,
                                                HC_ATL_PTD_DONEMAP_REG);
-               priv->atl_done_map &= ~(1 << qh->slot);
+               priv->atl_done_map &= ~(1 << slot);
+       } else {
+               priv->int_done_map |= reg_read32(hcd->regs,
+                                               HC_INT_PTD_DONEMAP_REG);
+               priv->int_done_map &= ~(1 << slot);
+       }
 
+       qh->slot = slot;
+       qtd->status = QTD_XFER_STARTED;
+       slots[slot].timestamp = jiffies;
+       slots[slot].qtd = qtd;
+       slots[slot].qh = qh;
+       ptd_write(hcd->regs, ptd_offset, slot, ptd);
+
+       if (ptd_offset == ATL_PTD_OFFSET) {
                skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
                skip_map &= ~(1 << qh->slot);
                reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
        } else {
-               priv->int_done_map |= reg_read32(hcd->regs,
-                                               HC_INT_PTD_DONEMAP_REG);
-               priv->int_done_map &= ~(1 << qh->slot);
-
                skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
                skip_map &= ~(1 << qh->slot);
                reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
@@ -858,10 +779,7 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
                if (qtd->status < QTD_XFER_COMPLETE)
                        break;
 
-               if (list_is_last(&qtd->qtd_list, &qh->qtd_list))
-                       last_qtd = 1;
-               else
-                       last_qtd = qtd->urb != qtd_next->urb;
+               last_qtd = last_qtd_of_urb(qtd, qh);
 
                if ((!last_qtd) && (qtd->status == QTD_RETIRE))
                        qtd_next->status = QTD_RETIRE;
@@ -902,7 +820,7 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
                        urb_listitem = kmem_cache_zalloc(urb_listitem_cachep,
                                                                GFP_ATOMIC);
                        if (unlikely(!urb_listitem))
-                               break;
+                               break; /* Try again on next call */
                        urb_listitem->urb = qtd->urb;
                        list_add_tail(&urb_listitem->urb_list, urb_list);
                }
@@ -928,6 +846,10 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
                return;
        }
 
+       /* Make sure this endpoint's TT buffer is clean before queueing ptds */
+       if (qh->tt_buffer_dirty)
+               return;
+
        if (usb_pipeint(list_entry(qh->qtd_list.next, struct isp1760_qtd,
                                                        qtd_list)->urb->pipe)) {
                ptd_offset = INT_PTD_OFFSET;
@@ -1168,11 +1090,9 @@ static int check_atl_transfer(struct usb_hcd *hcd, struct ptd *ptd,
        return PTD_STATE_QTD_DONE;
 }
 
-static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
+static void handle_done_ptds(struct usb_hcd *hcd)
 {
        struct isp1760_hcd *priv = hcd_to_priv(hcd);
-       u32 imask;
-       irqreturn_t irqret = IRQ_NONE;
        struct ptd ptd;
        struct isp1760_qh *qh;
        int slot;
@@ -1181,27 +1101,14 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
        u32 ptd_offset;
        struct isp1760_qtd *qtd;
        int modified;
-       static int last_active_ptds;
-       int int_skip_map, atl_skip_map;
-
-       spin_lock(&priv->lock);
-
-       if (!(hcd->state & HC_STATE_RUNNING))
-               goto leave;
-
-       imask = reg_read32(hcd->regs, HC_INTERRUPT_REG);
-       if (unlikely(!imask))
-               goto leave;
-       reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */
+       int skip_map;
 
-       int_skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
-       atl_skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
-       priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG);
-       priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG);
-       priv->int_done_map &= ~int_skip_map;
-       priv->atl_done_map &= ~atl_skip_map;
+       skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
+       priv->int_done_map &= ~skip_map;
+       skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
+       priv->atl_done_map &= ~skip_map;
 
-       modified = priv->int_done_map | priv->atl_done_map;
+       modified = priv->int_done_map || priv->atl_done_map;
 
        while (priv->int_done_map || priv->atl_done_map) {
                if (priv->int_done_map) {
@@ -1240,7 +1147,6 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
                slots[slot].qtd = NULL;
                qh = slots[slot].qh;
                slots[slot].qh = NULL;
-               priv->active_ptds--;
                qh->slot = -1;
 
                WARN_ON(qtd->status != QTD_XFER_STARTED);
@@ -1281,6 +1187,15 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
 
                case PTD_STATE_URB_RETIRE:
                        qtd->status = QTD_RETIRE;
+                       if ((qtd->urb->dev->speed != USB_SPEED_HIGH) &&
+                                       (qtd->urb->status != -EPIPE) &&
+                                       (qtd->urb->status != -EREMOTEIO)) {
+                               qh->tt_buffer_dirty = 1;
+                               if (usb_hub_clear_tt_buffer(qtd->urb))
+                                       /* Clear failed; let's hope things work
+                                          anyway */
+                                       qh->tt_buffer_dirty = 0;
+                       }
                        qtd = NULL;
                        qh->toggle = 0;
                        qh->ping = 0;
@@ -1311,22 +1226,28 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
 
        if (modified)
                schedule_ptds(hcd);
+}
+
+static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
+{
+       struct isp1760_hcd *priv = hcd_to_priv(hcd);
+       u32 imask;
+       irqreturn_t irqret = IRQ_NONE;
 
-       /* ISP1760 Errata 2 explains that interrupts may be missed (or not
-          happen?) if two USB devices are running simultaneously. Perhaps
-          this happens when a PTD is finished during interrupt handling;
-          enable SOF interrupts if PTDs are still scheduled when exiting this
-          interrupt handler, just to be safe. */
+       spin_lock(&priv->lock);
 
-       if (priv->active_ptds != last_active_ptds) {
-               if (priv->active_ptds > 0)
-                       reg_write32(hcd->regs, HC_INTERRUPT_ENABLE,
-                                               INTERRUPT_ENABLE_SOT_MASK);
-               else
-                       reg_write32(hcd->regs, HC_INTERRUPT_ENABLE,
-                                               INTERRUPT_ENABLE_MASK);
-               last_active_ptds = priv->active_ptds;
-       }
+       if (!(hcd->state & HC_STATE_RUNNING))
+               goto leave;
+
+       imask = reg_read32(hcd->regs, HC_INTERRUPT_REG);
+       if (unlikely(!imask))
+               goto leave;
+       reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */
+
+       priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG);
+       priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG);
+
+       handle_done_ptds(hcd);
 
        irqret = IRQ_HANDLED;
 leave:
@@ -1335,6 +1256,138 @@ leave:
        return irqret;
 }
 
+/*
+ * Workaround for problem described in chip errata 2:
+ *
+ * Sometimes interrupts are not generated when ATL (not INT?) completion occurs.
+ * One solution suggested in the errata is to use SOF interrupts _instead_of_
+ * ATL done interrupts (the "instead of" might be important since it seems
+ * enabling ATL interrupts also causes the chip to sometimes - rarely - "forget"
+ * to set the PTD's done bit in addition to not generating an interrupt!).
+ *
+ * So if we use SOF + ATL interrupts, we sometimes get stale PTDs since their
+ * done bit is not being set. This is bad - it blocks the endpoint until reboot.
+ *
+ * If we use SOF interrupts only, we get latency between ptd completion and the
+ * actual handling. This is very noticeable in testusb runs which takes several
+ * minutes longer without ATL interrupts.
+ *
+ * A better solution is to run the code below every SLOT_CHECK_PERIOD ms. If it
+ * finds active ATL slots which are older than SLOT_TIMEOUT ms, it checks the
+ * slot's ACTIVE and VALID bits. If these are not set, the ptd is considered
+ * completed and its done map bit is set.
+ *
+ * The values of SLOT_TIMEOUT and SLOT_CHECK_PERIOD have been arbitrarily chosen
+ * not to cause too much lag when this HW bug occurs, while still hopefully
+ * ensuring that the check does not falsely trigger.
+ */
+#define SLOT_TIMEOUT 300
+#define SLOT_CHECK_PERIOD 200
+static struct timer_list errata2_timer;
+
+void errata2_function(unsigned long data)
+{
+       struct usb_hcd *hcd = (struct usb_hcd *) data;
+       struct isp1760_hcd *priv = hcd_to_priv(hcd);
+       int slot;
+       struct ptd ptd;
+       unsigned long spinflags;
+
+       spin_lock_irqsave(&priv->lock, spinflags);
+
+       for (slot = 0; slot < 32; slot++)
+               if (priv->atl_slots[slot].qh && time_after(jiffies,
+                                       priv->atl_slots[slot].timestamp +
+                                       SLOT_TIMEOUT * HZ / 1000)) {
+                       ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
+                       if (!FROM_DW0_VALID(ptd.dw0) &&
+                                       !FROM_DW3_ACTIVE(ptd.dw3))
+                               priv->atl_done_map |= 1 << slot;
+               }
+
+       if (priv->atl_done_map)
+               handle_done_ptds(hcd);
+
+       spin_unlock_irqrestore(&priv->lock, spinflags);
+
+       errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
+       add_timer(&errata2_timer);
+}
+
+static int isp1760_run(struct usb_hcd *hcd)
+{
+       int retval;
+       u32 temp;
+       u32 command;
+       u32 chipid;
+
+       hcd->uses_new_polling = 1;
+
+       hcd->state = HC_STATE_RUNNING;
+
+       /* Set PTD interrupt AND & OR maps */
+       reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0);
+       reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff);
+       reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0);
+       reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff);
+       reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0);
+       reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff);
+       /* step 23 passed */
+
+       temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
+       reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN);
+
+       command = reg_read32(hcd->regs, HC_USBCMD);
+       command &= ~(CMD_LRESET|CMD_RESET);
+       command |= CMD_RUN;
+       reg_write32(hcd->regs, HC_USBCMD, command);
+
+       retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000);
+       if (retval)
+               return retval;
+
+       /*
+        * XXX
+        * Spec says to write FLAG_CF as last config action, priv code grabs
+        * the semaphore while doing so.
+        */
+       down_write(&ehci_cf_port_reset_rwsem);
+       reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF);
+
+       retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000);
+       up_write(&ehci_cf_port_reset_rwsem);
+       if (retval)
+               return retval;
+
+       init_timer(&errata2_timer);
+       errata2_timer.function = errata2_function;
+       errata2_timer.data = (unsigned long) hcd;
+       errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
+       add_timer(&errata2_timer);
+
+       chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG);
+       dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n",
+                                       chipid & 0xffff, chipid >> 16);
+
+       /* PTD Register Init Part 2, Step 28 */
+
+       /* Setup registers controlling PTD checking */
+       reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000);
+       reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000);
+       reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001);
+       reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff);
+       reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff);
+       reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff);
+       reg_write32(hcd->regs, HC_BUFFER_STATUS_REG,
+                                               ATL_BUF_FILL | INT_BUF_FILL);
+
+       /* GRR this is run-once init(), being done every time the HC starts.
+        * So long as they're part of class devices, we can't do it init()
+        * since the class device isn't created that early.
+        */
+       return 0;
+}
+
 static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len)
 {
        qtd->data_buffer = databuffer;
@@ -1503,7 +1556,6 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
        packetize_urb(hcd, urb, &new_qtds, mem_flags);
        if (list_empty(&new_qtds))
                return -ENOMEM;
-       urb->hcpriv = NULL; /* Used to signal unlink to interrupt handler */
 
        retval = 0;
        spin_lock_irqsave(&priv->lock, spinflags);
@@ -1531,6 +1583,7 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
                qh = qh_alloc(GFP_ATOMIC);
                if (!qh) {
                        retval = -ENOMEM;
+                       usb_hcd_unlink_urb_from_ep(hcd, urb);
                        goto out;
                }
                list_add_tail(&qh->qh_list, ep_queue);
@@ -1570,7 +1623,41 @@ static void kill_transfer(struct usb_hcd *hcd, struct urb *urb,
        }
 
        qh->slot = -1;
-       priv->active_ptds--;
+}
+
+/*
+ * Retire the qtds beginning at 'qtd' and belonging all to the same urb, killing
+ * any active transfer belonging to the urb in the process.
+ */
+static void dequeue_urb_from_qtd(struct usb_hcd *hcd, struct isp1760_qh *qh,
+                                               struct isp1760_qtd *qtd)
+{
+       struct urb *urb;
+       int urb_was_running;
+
+       urb = qtd->urb;
+       urb_was_running = 0;
+       list_for_each_entry_from(qtd, &qh->qtd_list, qtd_list) {
+               if (qtd->urb != urb)
+                       break;
+
+               if (qtd->status >= QTD_XFER_STARTED)
+                       urb_was_running = 1;
+               if (last_qtd_of_urb(qtd, qh) &&
+                                       (qtd->status >= QTD_XFER_COMPLETE))
+                       urb_was_running = 0;
+
+               if (qtd->status == QTD_XFER_STARTED)
+                       kill_transfer(hcd, urb, qh);
+               qtd->status = QTD_RETIRE;
+       }
+
+       if ((urb->dev->speed != USB_SPEED_HIGH) && urb_was_running) {
+               qh->tt_buffer_dirty = 1;
+               if (usb_hub_clear_tt_buffer(urb))
+                       /* Clear failed; let's hope things work anyway */
+                       qh->tt_buffer_dirty = 0;
+       }
 }
 
 static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
@@ -1595,9 +1682,8 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
 
        list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
                if (qtd->urb == urb) {
-                       if (qtd->status == QTD_XFER_STARTED)
-                               kill_transfer(hcd, urb, qh);
-                       qtd->status = QTD_RETIRE;
+                       dequeue_urb_from_qtd(hcd, qh, qtd);
+                       break;
                }
 
        urb->status = status;
@@ -1622,12 +1708,11 @@ static void isp1760_endpoint_disable(struct usb_hcd *hcd,
        if (!qh)
                goto out;
 
-       list_for_each_entry(qtd, &qh->qtd_list, qtd_list) {
-               if (qtd->status == QTD_XFER_STARTED)
-                       kill_transfer(hcd, qtd->urb, qh);
-               qtd->status = QTD_RETIRE;
-               qtd->urb->status = -ECONNRESET;
-       }
+       list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
+               if (qtd->status != QTD_RETIRE) {
+                       dequeue_urb_from_qtd(hcd, qh, qtd);
+                       qtd->urb->status = -ECONNRESET;
+               }
 
        ep->hcpriv = NULL;
        /* Cannot free qh here since it will be parsed by schedule_ptds() */
@@ -2021,6 +2106,8 @@ static void isp1760_stop(struct usb_hcd *hcd)
        struct isp1760_hcd *priv = hcd_to_priv(hcd);
        u32 temp;
 
+       del_timer(&errata2_timer);
+
        isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1,
                        NULL, 0);
        mdelay(20);
@@ -2048,6 +2135,23 @@ static void isp1760_shutdown(struct usb_hcd *hcd)
        reg_write32(hcd->regs, HC_USBCMD, command);
 }
 
+static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd,
+                                               struct usb_host_endpoint *ep)
+{
+       struct isp1760_hcd *priv = hcd_to_priv(hcd);
+       struct isp1760_qh *qh = ep->hcpriv;
+       unsigned long spinflags;
+
+       if (!qh)
+               return;
+
+       spin_lock_irqsave(&priv->lock, spinflags);
+       qh->tt_buffer_dirty = 0;
+       schedule_ptds(hcd);
+       spin_unlock_irqrestore(&priv->lock, spinflags);
+}
+
+
 static const struct hc_driver isp1760_hc_driver = {
        .description            = "isp1760-hcd",
        .product_desc           = "NXP ISP1760 USB Host Controller",
@@ -2064,6 +2168,7 @@ static const struct hc_driver isp1760_hc_driver = {
        .get_frame_number       = isp1760_get_frame,
        .hub_status_data        = isp1760_hub_status_data,
        .hub_control            = isp1760_hub_control,
+       .clear_tt_buffer_complete       = isp1760_clear_tt_buffer_complete,
 };
 
 int __init init_kmem_once(void)
index 014a7dfadf9112d70bfc6aa2c86dc691bcb02510..fda0f2d54e3dd4629cd3c647ea4b073e70d82f2a 100644 (file)
@@ -73,7 +73,6 @@ void deinit_kmem_cache(void);
 #define HC_EOT_INT             (1 << 3)
 #define HC_SOT_INT             (1 << 1)
 #define INTERRUPT_ENABLE_MASK  (HC_INTL_INT | HC_ATL_INT)
-#define INTERRUPT_ENABLE_SOT_MASK      (HC_SOT_INT)
 
 #define HC_ISO_IRQ_MASK_OR_REG 0x318
 #define HC_INT_IRQ_MASK_OR_REG 0x31C
@@ -107,6 +106,7 @@ struct ptd {
 struct slotinfo {
        struct isp1760_qh *qh;
        struct isp1760_qtd *qtd;
+       unsigned long timestamp;
 };
 
 
@@ -188,6 +188,7 @@ struct memory_chunk {
 #define DW3_BABBLE_BIT                 (1 << 29)
 #define DW3_HALT_BIT                   (1 << 30)
 #define DW3_ACTIVE_BIT                 (1 << 31)
+#define FROM_DW3_ACTIVE(x)             (((x) >> 31) & 0x01)
 
 #define INT_UNDERRUN                   (1 << 2)
 #define INT_BABBLE                     (1 << 1)
index f9cf3f04b7424bd2299dc52f1662cdd6443e050b..34efd479e068cbd8133fbd98f8c2a2cd47efa862 100644 (file)
@@ -1114,6 +1114,11 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER                ohci_hcd_ath79_driver
 #endif
 
+#ifdef CONFIG_NLM_XLR
+#include "ohci-xls.c"
+#define PLATFORM_DRIVER                ohci_xls_driver
+#endif
+
 #if    !defined(PCI_DRIVER) &&         \
        !defined(PLATFORM_DRIVER) &&    \
        !defined(OMAP1_PLATFORM_DRIVER) &&      \
index 6048f2f64f73128356989bf51097984ba2247412..853ad8dacb7ee05f995c34bbcee42ecfeb83a04b 100644 (file)
@@ -149,7 +149,7 @@ static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev)
 
        res = platform_get_resource_byname(pdev,
                                IORESOURCE_MEM, "ohci");
-       if (!ret) {
+       if (!res) {
                dev_err(dev, "UHH OHCI get resource failed\n");
                return -ENOMEM;
        }
index dd24fc115e4892cc9649da9adae214a4fca7a6d9..15dc51ded61a5460b3e253004827669be7bceebb 100644 (file)
@@ -428,7 +428,7 @@ static struct ed *ed_get (
                ed->type = usb_pipetype(pipe);
 
                info |= (ep->desc.bEndpointAddress & ~USB_DIR_IN) << 7;
-               info |= le16_to_cpu(ep->desc.wMaxPacketSize) << 16;
+               info |= usb_endpoint_maxp(&ep->desc) << 16;
                if (udev->speed == USB_SPEED_LOW)
                        info |= ED_LOWSPEED;
                /* only control transfers store pids in tds */
@@ -444,7 +444,7 @@ static struct ed *ed_get (
                                ed->load = usb_calc_bus_time (
                                        udev->speed, !is_out,
                                        ed->type == PIPE_ISOCHRONOUS,
-                                       le16_to_cpu(ep->desc.wMaxPacketSize))
+                                       usb_endpoint_maxp(&ep->desc))
                                                / 1000;
                        }
                }
diff --git a/drivers/usb/host/ohci-xls.c b/drivers/usb/host/ohci-xls.c
new file mode 100644 (file)
index 0000000..a3a9c6f
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * OHCI HCD for Netlogic XLS processors.
+ *
+ * (C) Copyright 2011 Netlogic Microsystems Inc.
+ *
+ *  Based on ohci-au1xxx.c, and other Linux OHCI drivers.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/signal.h>
+
+static int ohci_xls_probe_internal(const struct hc_driver *driver,
+                       struct platform_device *dev)
+{
+       struct resource *res;
+       struct usb_hcd *hcd;
+       int retval, irq;
+
+       /* Get our IRQ from an earlier registered Platform Resource */
+       irq = platform_get_irq(dev, 0);
+       if (irq < 0) {
+               dev_err(&dev->dev, "Found HC with no IRQ\n");
+               return -ENODEV;
+       }
+
+       /* Get our Memory Handle */
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&dev->dev, "MMIO Handle incorrect!\n");
+               return -ENODEV;
+       }
+
+       hcd = usb_create_hcd(driver, &dev->dev, "XLS");
+       if (!hcd) {
+               retval = -ENOMEM;
+               goto err1;
+       }
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = res->end - res->start + 1;
+
+       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+                       driver->description)) {
+               dev_dbg(&dev->dev, "Controller already in use\n");
+               retval = -EBUSY;
+               goto err2;
+       }
+
+       hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+       if (hcd->regs == NULL) {
+               dev_dbg(&dev->dev, "error mapping memory\n");
+               retval = -EFAULT;
+               goto err3;
+       }
+
+       retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+       if (retval != 0)
+               goto err4;
+       return retval;
+
+err4:
+       iounmap(hcd->regs);
+err3:
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err2:
+       usb_put_hcd(hcd);
+err1:
+       dev_err(&dev->dev, "init fail, %d\n", retval);
+       return retval;
+}
+
+static int ohci_xls_reset(struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+       ohci_hcd_init(ohci);
+       return ohci_init(ohci);
+}
+
+static int __devinit ohci_xls_start(struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci;
+       int ret;
+
+       ohci = hcd_to_ohci(hcd);
+       ret = ohci_run(ohci);
+       if (ret < 0) {
+               err("can't start %s", hcd->self.bus_name);
+               ohci_stop(hcd);
+               return ret;
+       }
+       return 0;
+}
+
+static struct hc_driver ohci_xls_hc_driver = {
+       .description    = hcd_name,
+       .product_desc   = "XLS OHCI Host Controller",
+       .hcd_priv_size  = sizeof(struct ohci_hcd),
+       .irq            = ohci_irq,
+       .flags          = HCD_MEMORY | HCD_USB11,
+       .reset          = ohci_xls_reset,
+       .start          = ohci_xls_start,
+       .stop           = ohci_stop,
+       .shutdown       = ohci_shutdown,
+       .urb_enqueue    = ohci_urb_enqueue,
+       .urb_dequeue    = ohci_urb_dequeue,
+       .endpoint_disable = ohci_endpoint_disable,
+       .get_frame_number = ohci_get_frame,
+       .hub_status_data = ohci_hub_status_data,
+       .hub_control    = ohci_hub_control,
+#ifdef CONFIG_PM
+       .bus_suspend    = ohci_bus_suspend,
+       .bus_resume     = ohci_bus_resume,
+#endif
+       .start_port_reset = ohci_start_port_reset,
+};
+
+static int ohci_xls_probe(struct platform_device *dev)
+{
+       int ret;
+
+       pr_debug("In ohci_xls_probe");
+       if (usb_disabled())
+               return -ENODEV;
+       ret = ohci_xls_probe_internal(&ohci_xls_hc_driver, dev);
+       return ret;
+}
+
+static int ohci_xls_remove(struct platform_device *dev)
+{
+       struct usb_hcd *hcd = platform_get_drvdata(dev);
+
+       usb_remove_hcd(hcd);
+       iounmap(hcd->regs);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+       usb_put_hcd(hcd);
+       return 0;
+}
+
+static struct platform_driver ohci_xls_driver = {
+       .probe          = ohci_xls_probe,
+       .remove         = ohci_xls_remove,
+       .shutdown       = usb_hcd_platform_shutdown,
+       .driver         = {
+               .name   = "ohci-xls-0",
+               .owner  = THIS_MODULE,
+       },
+};
index 40a0d8b03ad74b38f1658b1b1c6a617fcecf81b7..a6f256436e777c91efb879433ad35ebc04187eeb 100644 (file)
@@ -959,7 +959,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
        info.pipenum = get_empty_pipenum(r8a66597, ep);
        info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
        info.epnum = usb_endpoint_num(ep);
-       info.maxpacket = le16_to_cpu(ep->wMaxPacketSize);
+       info.maxpacket = usb_endpoint_maxp(ep);
        info.type = get_r8a66597_type(usb_endpoint_type(ep));
        info.bufnum = get_bufnum(info.pipenum);
        info.buf_bsize = get_buf_bsize(info.pipenum);
index 84ed28b34f934d86ecef647d73580309baf3f2b8..f6ca80ee4cec0ddbe9d44159bb1862b3a9c19843 100644 (file)
@@ -280,7 +280,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
                        qh->load = usb_calc_bus_time(udev->speed,
                                        usb_endpoint_dir_in(&hep->desc),
                                        qh->type == USB_ENDPOINT_XFER_ISOC,
-                                       le16_to_cpu(hep->desc.wMaxPacketSize))
+                                       usb_endpoint_maxp(&hep->desc))
                                / 1000 + 1;
 
        } else {                /* Skeleton QH */
@@ -792,7 +792,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
 {
        struct uhci_td *td;
        unsigned long destination, status;
-       int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
+       int maxsze = usb_endpoint_maxp(&qh->hep->desc);
        int len = urb->transfer_buffer_length;
        dma_addr_t data = urb->transfer_dma;
        __hc32 *plink;
@@ -918,7 +918,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
 {
        struct uhci_td *td;
        unsigned long destination, status;
-       int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
+       int maxsze = usb_endpoint_maxp(&qh->hep->desc);
        int len = urb->transfer_buffer_length;
        int this_sg_len;
        dma_addr_t data;
index d446886b22b0275681b29e314c211465aa7ba67b..d873a0330c9ea490e3e8ce09831b0f7527efbe19 100644 (file)
@@ -1141,8 +1141,8 @@ static u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci,
        if (udev->speed == USB_SPEED_SUPER)
                return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval);
 
-       max_packet = GET_MAX_PACKET(le16_to_cpu(ep->desc.wMaxPacketSize));
-       max_burst = (le16_to_cpu(ep->desc.wMaxPacketSize) & 0x1800) >> 11;
+       max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
+       max_burst = (usb_endpoint_maxp(&ep->desc) & 0x1800) >> 11;
        /* A 0 in max burst means 1 transfer per ESIT */
        return max_packet * (max_burst + 1);
 }
@@ -1211,7 +1211,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
        /* Set the max packet size and max burst */
        switch (udev->speed) {
        case USB_SPEED_SUPER:
-               max_packet = le16_to_cpu(ep->desc.wMaxPacketSize);
+               max_packet = usb_endpoint_maxp(&ep->desc);
                ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
                /* dig out max burst from ep companion desc */
                max_packet = ep->ss_ep_comp.bMaxBurst;
@@ -1223,14 +1223,14 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
                 */
                if (usb_endpoint_xfer_isoc(&ep->desc) ||
                                usb_endpoint_xfer_int(&ep->desc)) {
-                       max_burst = (le16_to_cpu(ep->desc.wMaxPacketSize)
+                       max_burst = (usb_endpoint_maxp(&ep->desc)
                                     & 0x1800) >> 11;
                        ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_burst));
                }
                /* Fall through */
        case USB_SPEED_FULL:
        case USB_SPEED_LOW:
-               max_packet = GET_MAX_PACKET(le16_to_cpu(ep->desc.wMaxPacketSize));
+               max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
                ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
                break;
        default:
index 952e2ded61af50737c0627d85560b0fe179528f0..635e04e1f1ebb3ad24ab460a23da754149e39867 100644 (file)
@@ -2711,7 +2711,7 @@ static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len,
         * running_total.
         */
        packets_transferred = (running_total + trb_buff_len) /
-               le16_to_cpu(urb->ep->desc.wMaxPacketSize);
+               usb_endpoint_maxp(&urb->ep->desc);
 
        return xhci_td_remainder(total_packet_count - packets_transferred);
 }
@@ -2741,7 +2741,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        num_trbs = count_sg_trbs_needed(xhci, urb);
        num_sgs = urb->num_sgs;
        total_packet_count = roundup(urb->transfer_buffer_length,
-                       le16_to_cpu(urb->ep->desc.wMaxPacketSize));
+                       usb_endpoint_maxp(&urb->ep->desc));
 
        trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id],
                        ep_index, urb->stream_id,
@@ -2948,7 +2948,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
 
        running_total = 0;
        total_packet_count = roundup(urb->transfer_buffer_length,
-                       le16_to_cpu(urb->ep->desc.wMaxPacketSize));
+                       usb_endpoint_maxp(&urb->ep->desc));
        /* How much data is in the first TRB? */
        addr = (u64) urb->transfer_dma;
        trb_buff_len = TRB_MAX_BUFF_SIZE -
@@ -3269,7 +3269,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                td_len = urb->iso_frame_desc[i].length;
                td_remain_len = td_len;
                total_packet_count = roundup(td_len,
-                               le16_to_cpu(urb->ep->desc.wMaxPacketSize));
+                               usb_endpoint_maxp(&urb->ep->desc));
                /* A zero-length transfer still involves at least one packet. */
                if (total_packet_count == 0)
                        total_packet_count++;
index 3a0f695138f4195d4caf988c2fb0266ca7678e5f..f647d918a886de0ee077ec417b385ed0776bbf9e 100644 (file)
@@ -987,7 +987,7 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
        out_ctx = xhci->devs[slot_id]->out_ctx;
        ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
        hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
-       max_packet_size = le16_to_cpu(urb->dev->ep0.desc.wMaxPacketSize);
+       max_packet_size = usb_endpoint_maxp(&urb->dev->ep0.desc);
        if (hw_max_packet_size != max_packet_size) {
                xhci_dbg(xhci, "Max Packet Size for ep 0 changed.\n");
                xhci_dbg(xhci, "Max packet size in usb_device = %d\n",
index a6afd15f6a467bf70a2f308e1ab3b3d85d26d4d8..fe858711651cc16acf1b662a6ceb0de538e60e56 100644 (file)
@@ -213,7 +213,7 @@ static void adu_interrupt_in_callback(struct urb *urb)
 
        if (urb->actual_length > 0 && dev->interrupt_in_buffer[0] != 0x00) {
                if (dev->read_buffer_length <
-                   (4 * le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize)) -
+                   (4 * usb_endpoint_maxp(dev->interrupt_in_endpoint)) -
                     (urb->actual_length)) {
                        memcpy (dev->read_buffer_primary +
                                dev->read_buffer_length,
@@ -315,7 +315,7 @@ static int adu_open(struct inode *inode, struct file *file)
                         usb_rcvintpipe(dev->udev,
                                        dev->interrupt_in_endpoint->bEndpointAddress),
                         dev->interrupt_in_buffer,
-                        le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
+                        usb_endpoint_maxp(dev->interrupt_in_endpoint),
                         adu_interrupt_in_callback, dev,
                         dev->interrupt_in_endpoint->bInterval);
        dev->read_urb_finished = 0;
@@ -483,7 +483,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
                                                         usb_rcvintpipe(dev->udev,
                                                                        dev->interrupt_in_endpoint->bEndpointAddress),
                                                         dev->interrupt_in_buffer,
-                                                        le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
+                                                        usb_endpoint_maxp(dev->interrupt_in_endpoint),
                                                         adu_interrupt_in_callback,
                                                         dev,
                                                         dev->interrupt_in_endpoint->bInterval);
@@ -536,7 +536,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
                                 usb_rcvintpipe(dev->udev,
                                                dev->interrupt_in_endpoint->bEndpointAddress),
                                dev->interrupt_in_buffer,
-                               le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
+                               usb_endpoint_maxp(dev->interrupt_in_endpoint),
                                adu_interrupt_in_callback,
                                dev,
                                dev->interrupt_in_endpoint->bInterval);
@@ -622,7 +622,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
                        dbg(4," %s : sending, count = %Zd", __func__, count);
 
                        /* write the data into interrupt_out_buffer from userspace */
-                       buffer_size = le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize);
+                       buffer_size = usb_endpoint_maxp(dev->interrupt_out_endpoint);
                        bytes_to_write = count > buffer_size ? buffer_size : count;
                        dbg(4," %s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd",
                            __func__, buffer_size, count, bytes_to_write);
@@ -752,8 +752,8 @@ static int adu_probe(struct usb_interface *interface,
                goto error;
        }
 
-       in_end_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize);
-       out_end_size = le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize);
+       in_end_size = usb_endpoint_maxp(dev->interrupt_in_endpoint);
+       out_end_size = usb_endpoint_maxp(dev->interrupt_out_endpoint);
 
        dev->read_buffer_primary = kmalloc((4 * in_end_size), GFP_KERNEL);
        if (!dev->read_buffer_primary) {
index 2f41089cd854a7793dda2309d65e9dede81f21c0..2dbe600fbc1137bda53ecfae1a4468061f4a30ba 100644 (file)
@@ -2777,7 +2777,7 @@ static int ftdi_elan_probe(struct usb_interface *interface,
                 endpoint = &iface_desc->endpoint[i].desc;
                 if (!ftdi->bulk_in_endpointAddr &&
                    usb_endpoint_is_bulk_in(endpoint)) {
-                        buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+                        buffer_size = usb_endpoint_maxp(endpoint);
                         ftdi->bulk_in_size = buffer_size;
                         ftdi->bulk_in_endpointAddr = endpoint->bEndpointAddress;
                         ftdi->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
index c6184b4d169551d8c3795971377d8069d81fccf2..515b67fffab10480f2d53235590a5091fc7cbe22 100644 (file)
@@ -359,7 +359,7 @@ static int idmouse_probe(struct usb_interface *interface,
        endpoint = &iface_desc->endpoint[0].desc;
        if (!dev->bulk_in_endpointAddr && usb_endpoint_is_bulk_in(endpoint)) {
                /* we found a bulk in endpoint */
-               dev->orig_bi_size = le16_to_cpu(endpoint->wMaxPacketSize);
+               dev->orig_bi_size = usb_endpoint_maxp(endpoint);
                dev->bulk_in_size = 0x200; /* works _much_ faster */
                dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
                dev->bulk_in_buffer =
index a2190b983f526d67fc951c74672b2b5aa858823a..81457904d6ba026481ebc2c734b0c8c790020fa8 100644 (file)
@@ -803,7 +803,7 @@ static int iowarrior_probe(struct usb_interface *interface,
                        dev->int_out_endpoint = endpoint;
        }
        /* we have to check the report_size often, so remember it in the endianess suitable for our machine */
-       dev->report_size = le16_to_cpu(dev->int_in_endpoint->wMaxPacketSize);
+       dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint);
        if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) &&
            (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56))
                /* IOWarrior56 has wMaxPacketSize different from report size */
index cb4096201e2917442570be6311ae59134a7a129a..48c166f0d76420910b56ddb3b6f4fee35c8fcc14 100644 (file)
@@ -721,7 +721,7 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
        if (dev->interrupt_out_endpoint == NULL)
                dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n");
 
-       dev->interrupt_in_endpoint_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize);
+       dev->interrupt_in_endpoint_size = usb_endpoint_maxp(dev->interrupt_in_endpoint);
        dev->ring_buffer = kmalloc(ring_buffer_size*(sizeof(size_t)+dev->interrupt_in_endpoint_size), GFP_KERNEL);
        if (!dev->ring_buffer) {
                dev_err(&intf->dev, "Couldn't allocate ring_buffer\n");
@@ -737,7 +737,7 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
                dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n");
                goto error;
        }
-       dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize) :
+       dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? usb_endpoint_maxp(dev->interrupt_out_endpoint) :
                                                                         udev->descriptor.bMaxPacketSize0;
        dev->interrupt_out_buffer = kmalloc(write_buffer_size*dev->interrupt_out_endpoint_size, GFP_KERNEL);
        if (!dev->interrupt_out_buffer) {
index 6482c6e2e6bd291af584576aaeee869d9eedf6fe..a989356f693ec180edf9e737885388b929574d3c 100644 (file)
@@ -409,7 +409,7 @@ static int tower_open (struct inode *inode, struct file *file)
                          dev->udev,
                          usb_rcvintpipe(dev->udev, dev->interrupt_in_endpoint->bEndpointAddress),
                          dev->interrupt_in_buffer,
-                         le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
+                         usb_endpoint_maxp(dev->interrupt_in_endpoint),
                          tower_interrupt_in_callback,
                          dev,
                          dev->interrupt_in_interval);
@@ -928,7 +928,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
                err("Couldn't allocate read_buffer");
                goto error;
        }
-       dev->interrupt_in_buffer = kmalloc (le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize), GFP_KERNEL);
+       dev->interrupt_in_buffer = kmalloc (usb_endpoint_maxp(dev->interrupt_in_endpoint), GFP_KERNEL);
        if (!dev->interrupt_in_buffer) {
                err("Couldn't allocate interrupt_in_buffer");
                goto error;
index 51648154bb44c418309b8f573da7f3f644755853..1871cdf10da3fe9ff4926a8df457e8e17f4b7775 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/mutex.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/usb.h>
 
 #define DRIVER_VERSION "USBLCD Driver Version 1.05"
@@ -34,22 +34,29 @@ static const struct usb_device_id id_table[] = {
        { .idVendor = 0x10D2, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, },
        { },
 };
-MODULE_DEVICE_TABLE (usb, id_table);
+MODULE_DEVICE_TABLE(usb, id_table);
 
 static DEFINE_MUTEX(open_disc_mutex);
 
 
 struct usb_lcd {
-       struct usb_device *     udev;                   /* init: probe_lcd */
-       struct usb_interface *  interface;              /* the interface for this device */
-       unsigned char *         bulk_in_buffer;         /* the buffer to receive data */
-       size_t                  bulk_in_size;           /* the size of the receive buffer */
-       __u8                    bulk_in_endpointAddr;   /* the address of the bulk in endpoint */
-       __u8                    bulk_out_endpointAddr;  /* the address of the bulk out endpoint */
+       struct usb_device       *udev;                  /* init: probe_lcd */
+       struct usb_interface    *interface;             /* the interface for
+                                                          this device */
+       unsigned char           *bulk_in_buffer;        /* the buffer to receive
+                                                          data */
+       size_t                  bulk_in_size;           /* the size of the
+                                                          receive buffer */
+       __u8                    bulk_in_endpointAddr;   /* the address of the
+                                                          bulk in endpoint */
+       __u8                    bulk_out_endpointAddr;  /* the address of the
+                                                          bulk out endpoint */
        struct kref             kref;
-       struct semaphore        limit_sem;              /* to stop writes at full throttle from
-                                                        * using up all RAM */
-       struct usb_anchor       submitted;              /* URBs to wait for before suspend */
+       struct semaphore        limit_sem;              /* to stop writes at
+                                                          full throttle from
+                                                          using up all RAM */
+       struct usb_anchor       submitted;              /* URBs to wait for
+                                                          before suspend */
 };
 #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref)
 
@@ -63,8 +70,8 @@ static void lcd_delete(struct kref *kref)
        struct usb_lcd *dev = to_lcd_dev(kref);
 
        usb_put_dev(dev->udev);
-       kfree (dev->bulk_in_buffer);
-       kfree (dev);
+       kfree(dev->bulk_in_buffer);
+       kfree(dev);
 }
 
 
@@ -80,7 +87,7 @@ static int lcd_open(struct inode *inode, struct file *file)
        interface = usb_find_interface(&lcd_driver, subminor);
        if (!interface) {
                mutex_unlock(&lcd_mutex);
-               err ("USBLCD: %s - error, can't find device for minor %d",
+               err("USBLCD: %s - error, can't find device for minor %d",
                     __func__, subminor);
                return -ENODEV;
        }
@@ -126,7 +133,8 @@ static int lcd_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static ssize_t lcd_read(struct file *file, char __user * buffer, size_t count, loff_t *ppos)
+static ssize_t lcd_read(struct file *file, char __user * buffer,
+                       size_t count, loff_t *ppos)
 {
        struct usb_lcd *dev;
        int retval = 0;
@@ -135,8 +143,9 @@ static ssize_t lcd_read(struct file *file, char __user * buffer, size_t count, l
        dev = file->private_data;
 
        /* do a blocking bulk read to get data from the device */
-       retval = usb_bulk_msg(dev->udev, 
-                             usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
+       retval = usb_bulk_msg(dev->udev,
+                             usb_rcvbulkpipe(dev->udev,
+                                             dev->bulk_in_endpointAddr),
                              dev->bulk_in_buffer,
                              min(dev->bulk_in_size, count),
                              &bytes_read, 10000);
@@ -161,23 +170,23 @@ static long lcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        dev = file->private_data;
        if (dev == NULL)
                return -ENODEV;
-       
+
        switch (cmd) {
        case IOCTL_GET_HARD_VERSION:
                mutex_lock(&lcd_mutex);
                bcdDevice = le16_to_cpu((dev->udev)->descriptor.bcdDevice);
-               sprintf(buf,"%1d%1d.%1d%1d",
+               sprintf(buf, "%1d%1d.%1d%1d",
                        (bcdDevice & 0xF000)>>12,
                        (bcdDevice & 0xF00)>>8,
                        (bcdDevice & 0xF0)>>4,
                        (bcdDevice & 0xF));
                mutex_unlock(&lcd_mutex);
-               if (copy_to_user((void __user *)arg,buf,strlen(buf))!=0)
+               if (copy_to_user((void __user *)arg, buf, strlen(buf)) != 0)
                        return -EFAULT;
                break;
        case IOCTL_GET_DRV_VERSION:
-               sprintf(buf,DRIVER_VERSION);
-               if (copy_to_user((void __user *)arg,buf,strlen(buf))!=0)
+               sprintf(buf, DRIVER_VERSION);
+               if (copy_to_user((void __user *)arg, buf, strlen(buf)) != 0)
                        return -EFAULT;
                break;
        default:
@@ -199,7 +208,7 @@ static void lcd_write_bulk_callback(struct urb *urb)
        if (status &&
            !(status == -ENOENT ||
              status == -ECONNRESET ||
-              status == -ESHUTDOWN)) {
+             status == -ESHUTDOWN)) {
                dbg("USBLCD: %s - nonzero write bulk status received: %d",
                    __func__, status);
        }
@@ -210,15 +219,16 @@ static void lcd_write_bulk_callback(struct urb *urb)
        up(&dev->limit_sem);
 }
 
-static ssize_t lcd_write(struct file *file, const char __user * user_buffer, size_t count, loff_t *ppos)
+static ssize_t lcd_write(struct file *file, const char __user * user_buffer,
+                        size_t count, loff_t *ppos)
 {
        struct usb_lcd *dev;
-        int retval = 0, r;
+       int retval = 0, r;
        struct urb *urb = NULL;
        char *buf = NULL;
-       
+
        dev = file->private_data;
-       
+
        /* verify that we actually have some data to write */
        if (count == 0)
                goto exit;
@@ -233,34 +243,38 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz
                retval = -ENOMEM;
                goto err_no_buf;
        }
-       
-       buf = usb_alloc_coherent(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);
+
+       buf = usb_alloc_coherent(dev->udev, count, GFP_KERNEL,
+                                &urb->transfer_dma);
        if (!buf) {
                retval = -ENOMEM;
                goto error;
        }
-       
+
        if (copy_from_user(buf, user_buffer, count)) {
                retval = -EFAULT;
                goto error;
        }
-       
+
        /* initialize the urb properly */
        usb_fill_bulk_urb(urb, dev->udev,
-                         usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
+                         usb_sndbulkpipe(dev->udev,
+                         dev->bulk_out_endpointAddr),
                          buf, count, lcd_write_bulk_callback, dev);
        urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
        usb_anchor_urb(urb, &dev->submitted);
-       
+
        /* send the data out the bulk port */
        retval = usb_submit_urb(urb, GFP_KERNEL);
        if (retval) {
-               err("USBLCD: %s - failed submitting write urb, error %d", __func__, retval);
+               err("USBLCD: %s - failed submitting write urb, error %d",
+                   __func__, retval);
                goto error_unanchor;
        }
-       
-       /* release our reference to this urb, the USB core will eventually free it entirely */
+
+       /* release our reference to this urb,
+          the USB core will eventually free it entirely */
        usb_free_urb(urb);
 
 exit:
@@ -276,13 +290,13 @@ err_no_buf:
 }
 
 static const struct file_operations lcd_fops = {
-        .owner =        THIS_MODULE,
-        .read =         lcd_read,
-        .write =        lcd_write,
-        .open =         lcd_open,
+       .owner =        THIS_MODULE,
+       .read =         lcd_read,
+       .write =        lcd_write,
+       .open =         lcd_open,
        .unlocked_ioctl = lcd_ioctl,
-        .release =      lcd_release,
-        .llseek =       noop_llseek,
+       .release =      lcd_release,
+       .llseek =        noop_llseek,
 };
 
 /*
@@ -290,12 +304,13 @@ static const struct file_operations lcd_fops = {
  * and to have the device registered with the driver core
  */
 static struct usb_class_driver lcd_class = {
-        .name =         "lcd%d",
-        .fops =         &lcd_fops,
-        .minor_base =   USBLCD_MINOR,
+       .name =         "lcd%d",
+       .fops =         &lcd_fops,
+       .minor_base =   USBLCD_MINOR,
 };
 
-static int lcd_probe(struct usb_interface *interface, const struct usb_device_id *id)
+static int lcd_probe(struct usb_interface *interface,
+                    const struct usb_device_id *id)
 {
        struct usb_lcd *dev = NULL;
        struct usb_host_interface *iface_desc;
@@ -322,7 +337,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
                retval = -ENODEV;
                goto error;
        }
-       
+
        /* set up the endpoint information */
        /* use only the first bulk-in and bulk-out endpoints */
        iface_desc = interface->cur_altsetting;
@@ -332,7 +347,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
                if (!dev->bulk_in_endpointAddr &&
                    usb_endpoint_is_bulk_in(endpoint)) {
                        /* we found a bulk in endpoint */
-                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+                       buffer_size = usb_endpoint_maxp(endpoint);
                        dev->bulk_in_size = buffer_size;
                        dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
                        dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
@@ -369,7 +384,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
 
        dev_info(&interface->dev, "USBLCD Version %1d%1d.%1d%1d found "
                 "at address %d\n", (i & 0xF000)>>12, (i & 0xF00)>>8,
-                (i & 0xF0)>>4,(i & 0xF), dev->udev->devnum);
+                (i & 0xF0)>>4, (i & 0xF), dev->udev->devnum);
 
        /* let the user know what node this device is now attached to */
        dev_info(&interface->dev, "USB LCD device now attached to USBLCD-%d\n",
@@ -401,7 +416,7 @@ static int lcd_suspend(struct usb_interface *intf, pm_message_t message)
        return 0;
 }
 
-static int lcd_resume (struct usb_interface *intf)
+static int lcd_resume(struct usb_interface *intf)
 {
        return 0;
 }
@@ -409,16 +424,16 @@ static int lcd_resume (struct usb_interface *intf)
 static void lcd_disconnect(struct usb_interface *interface)
 {
        struct usb_lcd *dev;
-        int minor = interface->minor;
+       int minor = interface->minor;
 
        mutex_lock(&open_disc_mutex);
-        dev = usb_get_intfdata(interface);
-        usb_set_intfdata(interface, NULL);
+       dev = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
        mutex_unlock(&open_disc_mutex);
 
-        /* give back our minor */
-        usb_deregister_dev(interface, &lcd_class);
+       /* give back our minor */
+       usb_deregister_dev(interface, &lcd_class);
+
        /* decrement our usage count */
        kref_put(&dev->kref, lcd_delete);
 
@@ -438,7 +453,7 @@ static struct usb_driver lcd_driver = {
 static int __init usb_lcd_init(void)
 {
        int result;
-       
+
        result = usb_register(&lcd_driver);
        if (result)
                err("usb_register failed. Error number %d", result);
index 1616ad1793a4ac28970e33a5b0a58efd0fcb56a6..43f84e50d514bc4667b93e52f807a7448c305e10 100644 (file)
@@ -33,10 +33,10 @@ static const struct usb_device_id id_table[] = {
                        .driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER },
        { },
 };
-MODULE_DEVICE_TABLE (usb, id_table);
+MODULE_DEVICE_TABLE(usb, id_table);
 
 struct usb_led {
-       struct usb_device *     udev;
+       struct usb_device       *udev;
        unsigned char           blue;
        unsigned char           red;
        unsigned char           green;
@@ -113,14 +113,16 @@ static void change_color(struct usb_led *led)
 }
 
 #define show_set(value)        \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf)              \
+static ssize_t show_##value(struct device *dev, struct device_attribute *attr,\
+                           char *buf)                                  \
 {                                                                      \
        struct usb_interface *intf = to_usb_interface(dev);             \
        struct usb_led *led = usb_get_intfdata(intf);                   \
                                                                        \
        return sprintf(buf, "%d\n", led->value);                        \
 }                                                                      \
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)   \
+static ssize_t set_##value(struct device *dev, struct device_attribute *attr,\
+                          const char *buf, size_t count)               \
 {                                                                      \
        struct usb_interface *intf = to_usb_interface(dev);             \
        struct usb_led *led = usb_get_intfdata(intf);                   \
@@ -135,7 +137,8 @@ show_set(blue);
 show_set(red);
 show_set(green);
 
-static int led_probe(struct usb_interface *interface, const struct usb_device_id *id)
+static int led_probe(struct usb_interface *interface,
+                    const struct usb_device_id *id)
 {
        struct usb_device *udev = interface_to_usbdev(interface);
        struct usb_led *dev = NULL;
@@ -150,7 +153,7 @@ static int led_probe(struct usb_interface *interface, const struct usb_device_id
        dev->udev = usb_get_dev(udev);
        dev->type = id->driver_info;
 
-       usb_set_intfdata (interface, dev);
+       usb_set_intfdata(interface, dev);
 
        retval = device_create_file(&interface->dev, &dev_attr_blue);
        if (retval)
@@ -194,7 +197,7 @@ error:
        device_remove_file(&interface->dev, &dev_attr_blue);
        device_remove_file(&interface->dev, &dev_attr_red);
        device_remove_file(&interface->dev, &dev_attr_green);
-       usb_set_intfdata (interface, NULL);
+       usb_set_intfdata(interface, NULL);
        usb_put_dev(dev->udev);
        kfree(dev);
 error_mem:
@@ -205,14 +208,14 @@ static void led_disconnect(struct usb_interface *interface)
 {
        struct usb_led *dev;
 
-       dev = usb_get_intfdata (interface);
+       dev = usb_get_intfdata(interface);
 
        device_remove_file(&interface->dev, &dev_attr_blue);
        device_remove_file(&interface->dev, &dev_attr_red);
        device_remove_file(&interface->dev, &dev_attr_green);
 
        /* first remove the files, then set the pointer to NULL */
-       usb_set_intfdata (interface, NULL);
+       usb_set_intfdata(interface, NULL);
 
        usb_put_dev(dev->udev);
 
@@ -243,8 +246,8 @@ static void __exit usb_led_exit(void)
        usb_deregister(&led_driver);
 }
 
-module_init (usb_led_init);
-module_exit (usb_led_exit);
+module_init(usb_led_init);
+module_exit(usb_led_exit);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
index bb10846affc30b39a1f7514acf5084174cb43f37..930962f49276da95dadbf1a9e04a8637c1d7aa26 100644 (file)
@@ -359,8 +359,10 @@ static int simple_io(
        urb->context = &completion;
        while (retval == 0 && iterations-- > 0) {
                init_completion(&completion);
-               if (usb_pipeout(urb->pipe))
+               if (usb_pipeout(urb->pipe)) {
                        simple_fill_buf(urb);
+                       urb->transfer_flags |= URB_ZERO_PACKET;
+               }
                retval = usb_submit_urb(urb, GFP_KERNEL);
                if (retval != 0)
                        break;
@@ -1583,8 +1585,8 @@ static struct urb *iso_alloc_urb(
 
        if (bytes < 0 || !desc)
                return NULL;
-       maxp = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
-       maxp *= 1 + (0x3 & (le16_to_cpu(desc->wMaxPacketSize) >> 11));
+       maxp = 0x7ff & usb_endpoint_maxp(desc);
+       maxp *= 1 + (0x3 & (usb_endpoint_maxp(desc) >> 11));
        packets = DIV_ROUND_UP(bytes, maxp);
 
        urb = usb_alloc_urb(packets, GFP_KERNEL);
@@ -1654,7 +1656,7 @@ test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param,
                "... iso period %d %sframes, wMaxPacket %04x\n",
                1 << (desc->bInterval - 1),
                (udev->speed == USB_SPEED_HIGH) ? "micro" : "",
-               le16_to_cpu(desc->wMaxPacketSize));
+               usb_endpoint_maxp(desc));
 
        for (i = 0; i < param->sglen; i++) {
                urbs[i] = iso_alloc_urb(udev, pipe, desc,
index fe8d14cac4367ff00135d73c134931f8e01aa79a..4165a4eafc3205a82cc7aabeab6ef46d74a870ff 100644 (file)
@@ -1020,7 +1020,7 @@ static int musb_gadget_enable(struct usb_ep *ep,
                goto fail;
 
        /* REVISIT this rules out high bandwidth periodic transfers */
-       tmp = le16_to_cpu(desc->wMaxPacketSize);
+       tmp = usb_endpoint_maxp(desc);
        if (tmp & ~0x07ff) {
                int ok;
 
index 8b2473fa0f47387c9647944d6e45b362539a8ab5..60ddba8066ea201181b0b6ce3c69a847eafc618a 100644 (file)
@@ -1932,7 +1932,7 @@ static int musb_urb_enqueue(
        INIT_LIST_HEAD(&qh->ring);
        qh->is_ready = 1;
 
-       qh->maxpacket = le16_to_cpu(epd->wMaxPacketSize);
+       qh->maxpacket = usb_endpoint_maxp(epd);
        qh->type = usb_endpoint_type(epd);
 
        /* Bits 11 & 12 of wMaxPacketSize encode high bandwidth multiplier.
index b4d2c0972b3df77b67db8efb5cb0838e4bc26097..ed2b26cfe8140aecd2516f1752303e5ae9b3f0d3 100644 (file)
@@ -137,22 +137,6 @@ static inline u8 twl6030_readb(struct twl6030_usb *twl, u8 module, u8 address)
        return ret;
 }
 
-/*-------------------------------------------------------------------------*/
-static int twl6030_set_phy_clk(struct otg_transceiver *x, int on)
-{
-       struct twl6030_usb *twl;
-       struct device *dev;
-       struct twl4030_usb_data *pdata;
-
-       twl = xceiv_to_twl(x);
-       dev  = twl->dev;
-       pdata = dev->platform_data;
-
-       pdata->phy_set_clock(twl->dev, on);
-
-       return 0;
-}
-
 static int twl6030_phy_init(struct otg_transceiver *x)
 {
        struct twl6030_usb *twl;
index 1b14cae45704e545f93e1e3073cb4b56404f353e..3bbbbb403f017ec58e72e1f624912dc932a90519 100644 (file)
@@ -392,7 +392,7 @@ static u16 usbhsp_setup_pipemaxp(struct usbhs_pipe *pipe,
        /* host should set DEVSEL */
 
        /* reutn MXPS */
-       return PIPE_MAXP_MASK & le16_to_cpu(desc->wMaxPacketSize);
+       return PIPE_MAXP_MASK & usb_endpoint_maxp(desc);
 }
 
 static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe,
index b71e309116a304c37ea462762ab5bdb89a240185..677f577c0243aa1437b48e9246f357f7b721c08e 100644 (file)
@@ -252,6 +252,7 @@ config USB_SERIAL_GARMIN
 
 config USB_SERIAL_IPW
         tristate "USB IPWireless (3G UMTS TDD) Driver"
+       select USB_SERIAL_WWAN
        help
          Say Y here if you want to use a IPWireless USB modem such as
          the ones supplied by Axity3G/Sentech South Africa.
index 5fc13e717911708fa3f8b1d443b190dad2ecadaf..5cfd87eb1a8bbcb23970bcaf215baf2861a4ab24 100644 (file)
@@ -1486,7 +1486,7 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port)
        }
 
        /* set max packet size based on descriptor */
-       priv->max_packet_size = le16_to_cpu(ep_desc->wMaxPacketSize);
+       priv->max_packet_size = usb_endpoint_maxp(ep_desc);
 
        dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size);
 }
index abf095be5753419184423ad117f23cc4ea4dbf5f..2ee807523f5379741e795a09f9d03837fbf2f989 100644 (file)
@@ -3042,7 +3042,7 @@ static int edge_startup(struct usb_serial *serial)
 
                        endpoint = &serial->interface->altsetting[0].
                                                        endpoint[i].desc;
-                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+                       buffer_size = usb_endpoint_maxp(endpoint);
                        if (!interrupt_in_found &&
                            (usb_endpoint_is_int_in(endpoint))) {
                                /* we found a interrupt in endpoint */
@@ -3107,7 +3107,7 @@ static int edge_startup(struct usb_serial *serial)
                                        usb_rcvbulkpipe(dev,
                                                endpoint->bEndpointAddress),
                                        edge_serial->bulk_in_buffer,
-                                       le16_to_cpu(endpoint->wMaxPacketSize),
+                                       usb_endpoint_maxp(endpoint),
                                        edge_bulk_in_callback,
                                        edge_serial);
                                bulk_in_found = true;
index ca77e88836bd224cf82ce601d6524cba25a98a6f..5170799d6e94739cffb66f3266254d900fd322f8 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 #include <linux/uaccess.h>
+#include "usb-wwan.h"
 
 /*
  * Version Information
@@ -185,7 +186,7 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port)
 
        /*--2: Start reading from the device */
        dbg("%s: setting up bulk read callback", __func__);
-       usb_serial_generic_open(tty, port);
+       usb_wwan_open(tty, port);
 
        /*--3: Tell the modem to open the floodgates on the rx bulk channel */
        dbg("%s:asking modem for RxRead (RXBULK_ON)", __func__);
@@ -219,6 +220,29 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port)
        return 0;
 }
 
+/* fake probe - only to allocate data structures */
+static int ipw_probe(struct usb_serial *serial, const struct usb_device_id *id)
+{
+       struct usb_wwan_intf_private *data;
+
+       data = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       spin_lock_init(&data->susp_lock);
+       usb_set_serial_data(serial, data);
+       return 0;
+}
+
+static void ipw_release(struct usb_serial *serial)
+{
+       struct usb_wwan_intf_private *data = usb_get_serial_data(serial);
+
+       usb_wwan_release(serial);
+       usb_set_serial_data(serial, NULL);
+       kfree(data);
+}
+
 static void ipw_dtr_rts(struct usb_serial_port *port, int on)
 {
        struct usb_device *dev = port->serial->dev;
@@ -285,7 +309,7 @@ static void ipw_close(struct usb_serial_port *port)
                dev_err(&port->dev,
                        "Disabling bulk RxRead failed (error = %d)\n", result);
 
-       usb_serial_generic_close(port);
+       usb_wwan_close(port);
 }
 
 static struct usb_serial_driver ipw_device = {
@@ -297,9 +321,14 @@ static struct usb_serial_driver ipw_device = {
        .usb_driver =           &usb_ipw_driver,
        .id_table =             usb_ipw_ids,
        .num_ports =            1,
+       .disconnect =           usb_wwan_disconnect,
        .open =                 ipw_open,
        .close =                ipw_close,
+       .probe =                ipw_probe,
+       .attach =               usb_wwan_startup,
+       .release =              ipw_release,
        .dtr_rts =              ipw_dtr_rts,
+       .write =                usb_wwan_write,
 };
 
 
index 96423f3c8ef3d6b28b80ae15da65cf7b0bc9271a..c248a9147439ad88264bc1047cf8d703fe656685 100644 (file)
@@ -523,7 +523,7 @@ static int opticon_startup(struct usb_serial *serial)
                        goto error;
                }
 
-               priv->buffer_size = le16_to_cpu(endpoint->wMaxPacketSize) * 2;
+               priv->buffer_size = usb_endpoint_maxp(endpoint) * 2;
                priv->bulk_in_buffer = kmalloc(priv->buffer_size, GFP_KERNEL);
                if (!priv->bulk_in_buffer) {
                        dev_err(&priv->udev->dev, "out of memory\n");
index 1d33260de014f0ee3c39546567a2e61b867b7ebf..0ae840f789a45be017639dc9c539a015286d5e6c 100644 (file)
@@ -360,9 +360,6 @@ static void pl2303_set_termios(struct tty_struct *tty,
                                tmp >>= 2;
                                buf[1] <<= 1;
                        }
-                       if (tmp > 256) {
-                               tmp %= 256;
-                       }
                        buf[0] = tmp;
                }
        }
index d9457bd4fe10a925423b9f3f1d3b5670e5ac5822..7096f799b071a1813888c714746dc1623b81acb2 100644 (file)
@@ -226,7 +226,7 @@ static int symbol_startup(struct usb_serial *serial)
                        goto error;
                }
 
-               priv->buffer_size = le16_to_cpu(endpoint->wMaxPacketSize) * 2;
+               priv->buffer_size = usb_endpoint_maxp(endpoint) * 2;
                priv->int_buffer = kmalloc(priv->buffer_size, GFP_KERNEL);
                if (!priv->int_buffer) {
                        dev_err(&priv->udev->dev, "out of memory\n");
index 1c031309ab255ba83b70739566fb8e6c6b1bb58e..cc274fdf2627313aeb5a21f92d68ad4681e6e408 100644 (file)
@@ -912,7 +912,7 @@ int usb_serial_probe(struct usb_interface *interface,
                        goto probe_error;
                }
                buffer_size = max_t(int, serial->type->bulk_in_size,
-                               le16_to_cpu(endpoint->wMaxPacketSize));
+                               usb_endpoint_maxp(endpoint));
                port->bulk_in_size = buffer_size;
                port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
                port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
@@ -942,7 +942,7 @@ int usb_serial_probe(struct usb_interface *interface,
                        goto probe_error;
                buffer_size = serial->type->bulk_out_size;
                if (!buffer_size)
-                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+                       buffer_size = usb_endpoint_maxp(endpoint);
                port->bulk_out_size = buffer_size;
                port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
                port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
@@ -990,7 +990,7 @@ int usb_serial_probe(struct usb_interface *interface,
                                                "No free urbs available\n");
                                goto probe_error;
                        }
-                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+                       buffer_size = usb_endpoint_maxp(endpoint);
                        port->interrupt_in_endpointAddress =
                                                endpoint->bEndpointAddress;
                        port->interrupt_in_buffer = kmalloc(buffer_size,
@@ -1021,7 +1021,7 @@ int usb_serial_probe(struct usb_interface *interface,
                                                "No free urbs available\n");
                                goto probe_error;
                        }
-                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+                       buffer_size = usb_endpoint_maxp(endpoint);
                        port->interrupt_out_size = buffer_size;
                        port->interrupt_out_endpointAddress =
                                                endpoint->bEndpointAddress;
index 6fd13068481b7f6dab277acbd9760125b78fe42d..45e496c538ed930d910d730400465843ecc328dc 100644 (file)
@@ -319,6 +319,11 @@ static int rts51x_read_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
 {
        int retval;
        u8 cmnd[12] = { 0 };
+       u8 *buf;
+
+       buf = kmalloc(len, GFP_NOIO);
+       if (buf == NULL)
+               return USB_STOR_TRANSPORT_ERROR;
 
        US_DEBUGP("%s, addr = 0x%x, len = %d\n", __func__, addr, len);
 
@@ -330,10 +335,14 @@ static int rts51x_read_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
        cmnd[5] = (u8) len;
 
        retval = rts51x_bulk_transport(us, 0, cmnd, 12,
-                                      data, len, DMA_FROM_DEVICE, NULL);
-       if (retval != USB_STOR_TRANSPORT_GOOD)
+                                      buf, len, DMA_FROM_DEVICE, NULL);
+       if (retval != USB_STOR_TRANSPORT_GOOD) {
+               kfree(buf);
                return -EIO;
+       }
 
+       memcpy(data, buf, len);
+       kfree(buf);
        return 0;
 }
 
@@ -341,6 +350,12 @@ static int rts51x_write_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
 {
        int retval;
        u8 cmnd[12] = { 0 };
+       u8 *buf;
+
+       buf = kmalloc(len, GFP_NOIO);
+       if (buf == NULL)
+               return USB_STOR_TRANSPORT_ERROR;
+       memcpy(buf, data, len);
 
        US_DEBUGP("%s, addr = 0x%x, len = %d\n", __func__, addr, len);
 
@@ -352,7 +367,8 @@ static int rts51x_write_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
        cmnd[5] = (u8) len;
 
        retval = rts51x_bulk_transport(us, 0, cmnd, 12,
-                                      data, len, DMA_TO_DEVICE, NULL);
+                                      buf, len, DMA_TO_DEVICE, NULL);
+       kfree(buf);
        if (retval != USB_STOR_TRANSPORT_GOOD)
                return -EIO;
 
@@ -364,6 +380,11 @@ static int rts51x_read_status(struct us_data *us,
 {
        int retval;
        u8 cmnd[12] = { 0 };
+       u8 *buf;
+
+       buf = kmalloc(len, GFP_NOIO);
+       if (buf == NULL)
+               return USB_STOR_TRANSPORT_ERROR;
 
        US_DEBUGP("%s, lun = %d\n", __func__, lun);
 
@@ -371,10 +392,14 @@ static int rts51x_read_status(struct us_data *us,
        cmnd[1] = 0x09;
 
        retval = rts51x_bulk_transport(us, lun, cmnd, 12,
-                                      status, len, DMA_FROM_DEVICE, actlen);
-       if (retval != USB_STOR_TRANSPORT_GOOD)
+                                      buf, len, DMA_FROM_DEVICE, actlen);
+       if (retval != USB_STOR_TRANSPORT_GOOD) {
+               kfree(buf);
                return -EIO;
+       }
 
+       memcpy(status, buf, len);
+       kfree(buf);
        return 0;
 }
 
index 0ca095820f3e7ca10c98e27a4eaeea728e5c533e..c325e69415a14755b9f8ae9e13982ec260c40ef1 100644 (file)
@@ -831,12 +831,22 @@ static int usb_stor_scan_thread(void * __us)
 
        dev_dbg(dev, "device found\n");
 
-       set_freezable();
-       /* Wait for the timeout to expire or for a disconnect */
+       set_freezable_with_signal();
+       /*
+        * Wait for the timeout to expire or for a disconnect
+        *
+        * We can't freeze in this thread or we risk causing khubd to
+        * fail to freeze, but we can't be non-freezable either. Nor can
+        * khubd freeze while waiting for scanning to complete as it may
+        * hold the device lock, causing a hang when suspending devices.
+        * So we request a fake signal when freezing and use
+        * interruptible sleep to kick us out of our wait early when
+        * freezing happens.
+        */
        if (delay_use > 0) {
                dev_dbg(dev, "waiting for device to settle "
                                "before scanning\n");
-               wait_event_freezable_timeout(us->delay_wait,
+               wait_event_interruptible_timeout(us->delay_wait,
                                test_bit(US_FLIDX_DONT_SCAN, &us->dflags),
                                delay_use * HZ);
        }
index e24ce31230712e4ee4f4fa1f439cab445c6917c5..32d6fc9539042ad0c97b2d458ade68ce0188de9d 100644 (file)
@@ -555,7 +555,7 @@ static int skel_probe(struct usb_interface *interface,
                if (!dev->bulk_in_endpointAddr &&
                    usb_endpoint_is_bulk_in(endpoint)) {
                        /* we found a bulk in endpoint */
-                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+                       buffer_size = usb_endpoint_maxp(endpoint);
                        dev->bulk_in_size = buffer_size;
                        dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
                        dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
index 59a748a0e5dae07cbaa1ae5107654b9666712156..0d1863c9eddefedcd34fc19daa2ee45bc1dde82a 100644 (file)
@@ -43,7 +43,7 @@ int wa_create(struct wahc *wa, struct usb_interface *iface)
        /* Fill up Data Transfer EP pointers */
        wa->dti_epd = &iface->cur_altsetting->endpoint[1].desc;
        wa->dto_epd = &iface->cur_altsetting->endpoint[2].desc;
-       wa->xfer_result_size = le16_to_cpu(wa->dti_epd->wMaxPacketSize);
+       wa->xfer_result_size = usb_endpoint_maxp(wa->dti_epd);
        wa->xfer_result = kmalloc(wa->xfer_result_size, GFP_KERNEL);
        if (wa->xfer_result == NULL)
                goto error_xfer_result_alloc;
index 73c7df4896074219ad76daee5e9eb0ba6e1a1976..c19f9100c3071bd9e343eeec82de95771c137fbd 100644 (file)
@@ -1574,7 +1574,7 @@ usb_maxpacket(struct usb_device *udev, int pipe, int is_out)
                return 0;
 
        /* NOTE:  only 0x07ff bits are for packet size... */
-       return le16_to_cpu(ep->desc.wMaxPacketSize);
+       return usb_endpoint_maxp(&ep->desc);
 }
 
 /* ----------------------------------------------------------------------- */
index f302535995015dc1f4bc810129b8d5dc9c13dca3..706a421ce717d9de2363950393e8cc6a17c3a1c9 100644 (file)
@@ -34,6 +34,7 @@
 #define __LINUX_USB_CH9_H
 
 #include <linux/types.h>       /* __u8 etc */
+#include <asm/byteorder.h>     /* le16_to_cpu */
 
 /*-------------------------------------------------------------------------*/
 
 #define USB_INTRF_FUNC_SUSPEND 0       /* function suspend */
 
 #define USB_INTR_FUNC_SUSPEND_OPT_MASK 0xFF00
+/*
+ * Suspend Options, Table 9-7 USB 3.0 spec
+ */
+#define USB_INTRF_FUNC_SUSPEND_LP      (1 << (8 + 0))
+#define USB_INTRF_FUNC_SUSPEND_RW      (1 << (8 + 1))
 
 #define USB_ENDPOINT_HALT              0       /* IN/OUT will STALL */
 
@@ -575,6 +581,17 @@ static inline int usb_endpoint_is_isoc_out(
        return usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd);
 }
 
+/**
+ * usb_endpoint_maxp - get endpoint's max packet size
+ * @epd: endpoint to be checked
+ *
+ * Returns @epd's max packet
+ */
+static inline int usb_endpoint_maxp(const struct usb_endpoint_descriptor *epd)
+{
+       return le16_to_cpu(epd->wMaxPacketSize);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */