Move DWC2 driver out of staging
authorPaul Zimmerman <Paul.Zimmerman@synopsys.com>
Mon, 13 Jan 2014 21:50:09 +0000 (13:50 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 13 Jan 2014 22:44:01 +0000 (14:44 -0800)
The DWC2 driver should now be in good enough shape to move out of
staging. I have stress tested it overnight on RPI running mass
storage and Ethernet transfers in parallel, and for several days
on our proprietary PCI-based platform.

Signed-off-by: Paul Zimmerman <paulz@synopsys.com>
Cc: Felipe Balbi <balbi@ti.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
32 files changed:
MAINTAINERS
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/dwc2/Kconfig [deleted file]
drivers/staging/dwc2/Makefile [deleted file]
drivers/staging/dwc2/TODO [deleted file]
drivers/staging/dwc2/core.c [deleted file]
drivers/staging/dwc2/core.h [deleted file]
drivers/staging/dwc2/core_intr.c [deleted file]
drivers/staging/dwc2/hcd.c [deleted file]
drivers/staging/dwc2/hcd.h [deleted file]
drivers/staging/dwc2/hcd_ddma.c [deleted file]
drivers/staging/dwc2/hcd_intr.c [deleted file]
drivers/staging/dwc2/hcd_queue.c [deleted file]
drivers/staging/dwc2/hw.h [deleted file]
drivers/staging/dwc2/pci.c [deleted file]
drivers/staging/dwc2/platform.c [deleted file]
drivers/usb/Kconfig
drivers/usb/Makefile
drivers/usb/dwc2/Kconfig [new file with mode: 0644]
drivers/usb/dwc2/Makefile [new file with mode: 0644]
drivers/usb/dwc2/core.c [new file with mode: 0644]
drivers/usb/dwc2/core.h [new file with mode: 0644]
drivers/usb/dwc2/core_intr.c [new file with mode: 0644]
drivers/usb/dwc2/hcd.c [new file with mode: 0644]
drivers/usb/dwc2/hcd.h [new file with mode: 0644]
drivers/usb/dwc2/hcd_ddma.c [new file with mode: 0644]
drivers/usb/dwc2/hcd_intr.c [new file with mode: 0644]
drivers/usb/dwc2/hcd_queue.c [new file with mode: 0644]
drivers/usb/dwc2/hw.h [new file with mode: 0644]
drivers/usb/dwc2/pci.c [new file with mode: 0644]
drivers/usb/dwc2/platform.c [new file with mode: 0644]

index d5e4ff328cc7146827ac3d02cd8df189b881abc4..d3303eb1d10200af2e7c8ac49d09b312bc802fff 100644 (file)
@@ -2635,7 +2635,7 @@ DESIGNWARE USB2 DRD IP DRIVER
 M:     Paul Zimmerman <paulz@synopsys.com>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
-F:     drivers/staging/dwc2/
+F:     drivers/usb/dwc2/
 
 DESIGNWARE USB3 DRD IP DRIVER
 M:     Felipe Balbi <balbi@ti.com>
index d2beb07f24038123449911ea7bbc52ebd3c48a62..4bb6b11166b33544958634157dcabbe2f09ad0b2 100644 (file)
@@ -140,8 +140,6 @@ source "drivers/staging/netlogic/Kconfig"
 
 source "drivers/staging/mt29f_spinand/Kconfig"
 
-source "drivers/staging/dwc2/Kconfig"
-
 source "drivers/staging/lustre/Kconfig"
 
 source "drivers/staging/xillybus/Kconfig"
index bf62386d625951c8af6fbc7991a0467d8f12c3b7..9f07e5e160942bb8744b895fe08791ef3fcbe684 100644 (file)
@@ -61,7 +61,6 @@ obj-$(CONFIG_DGRP)            += dgrp/
 obj-$(CONFIG_SB105X)           += sb105x/
 obj-$(CONFIG_FIREWIRE_SERIAL)  += fwserial/
 obj-$(CONFIG_GOLDFISH)         += goldfish/
-obj-$(CONFIG_USB_DWC2)         += dwc2/
 obj-$(CONFIG_LUSTRE_FS)                += lustre/
 obj-$(CONFIG_XILLYBUS)         += xillybus/
 obj-$(CONFIG_DGNC)                     += dgnc/
diff --git a/drivers/staging/dwc2/Kconfig b/drivers/staging/dwc2/Kconfig
deleted file mode 100644 (file)
index be947d6..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-config USB_DWC2
-       tristate "DesignWare USB2 DRD Core Support"
-       depends on USB
-       help
-         Say Y or M here if your system has a Dual Role HighSpeed
-         USB controller based on the DesignWare HSOTG IP Core.
-
-         If you choose to build this driver as dynamically linked
-         modules, the core module will be called dwc2.ko, the
-         PCI bus interface module (if you have a PCI bus system)
-         will be called dwc2_pci.ko and the platform interface module
-         (for controllers directly connected to the CPU) will be called
-         dwc2_platform.ko.
-
-         NOTE: This driver at present only implements the Host mode
-         of the controller. The existing s3c-hsotg driver supports
-         Peripheral mode, but only for the Samsung S3C platforms.
-         There are plans to merge the s3c-hsotg driver with this
-         driver in the near future to create a dual-role driver.
-
-if USB_DWC2
-
-config USB_DWC2_DEBUG
-       bool "Enable Debugging Messages"
-       help
-         Say Y here to enable debugging messages in the DWC2 Driver.
-
-config USB_DWC2_VERBOSE
-       bool "Enable Verbose Debugging Messages"
-       depends on USB_DWC2_DEBUG
-       help
-         Say Y here to enable verbose debugging messages in the DWC2 Driver.
-         WARNING: Enabling this will quickly fill your message log.
-         If in doubt, say N.
-
-config USB_DWC2_TRACK_MISSED_SOFS
-       bool "Enable Missed SOF Tracking"
-       help
-         Say Y here to enable logging of missed SOF events to the dmesg log.
-         WARNING: This feature is still experimental.
-         If in doubt, say N.
-
-config USB_DWC2_DEBUG_PERIODIC
-       bool "Enable Debugging Messages For Periodic Transfers"
-       depends on USB_DWC2_DEBUG || USB_DWC2_VERBOSE
-       default y
-       help
-         Say N here to disable (verbose) debugging messages to be
-         logged for periodic transfers. This allows better debugging of
-         non-periodic transfers, but of course the debug logs will be
-         incomplete. Note that this also disables some debug messages
-         for which the transfer type cannot be deduced.
-endif
diff --git a/drivers/staging/dwc2/Makefile b/drivers/staging/dwc2/Makefile
deleted file mode 100644 (file)
index 11529d3..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-ccflags-$(CONFIG_USB_DWC2_DEBUG)       += -DDEBUG
-ccflags-$(CONFIG_USB_DWC2_VERBOSE)     += -DVERBOSE_DEBUG
-
-obj-$(CONFIG_USB_DWC2)                 += dwc2.o
-
-dwc2-y                                 += core.o core_intr.o
-
-# NOTE: This driver at present only implements the Host mode
-# of the controller. The existing s3c-hsotg driver supports
-# Peripheral mode, but only for the Samsung S3C platforms.
-# There are plans to merge the s3c-hsotg driver with this
-# driver in the near future to create a dual-role driver. Once
-# that is done, Host mode will become an optional feature that
-# is selected with a config option.
-
-dwc2-y                                 += hcd.o hcd_intr.o
-dwc2-y                                 += hcd_queue.o hcd_ddma.o
-
-ifneq ($(CONFIG_PCI),)
-       obj-$(CONFIG_USB_DWC2)          += dwc2_pci.o
-endif
-obj-$(CONFIG_USB_DWC2)                 += dwc2_platform.o
-
-dwc2_pci-y                             += pci.o
-dwc2_platform-y                                += platform.o
diff --git a/drivers/staging/dwc2/TODO b/drivers/staging/dwc2/TODO
deleted file mode 100644 (file)
index 282470d..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-TODO:
-       - Dan Carpenter would like to see some cleanups to the microframe
-         scheduler code:
-         http://www.mail-archive.com/linux-usb@vger.kernel.org/msg26650.html
-
-       - Should merge the NAK holdoff patch from Raspberry Pi
-         (http://marc.info/?l=linux-usb&m=137625067103833). But as it stands
-         that patch is incomplete, it needs more investigation to see if it
-         can be made to work for non-Raspberry Pi platforms that lack the
-         special FIQ interrupt that the Pi has. Without this patch, the driver
-         has a high interrupt rate (8K/sec).
-
-       - The Raspberry Pi platform needs to have support for its FIQ interrupt
-         added, to get the same level of functionality as the downstream
-         driver. The raspberrypi.org developers have indicated they are
-         willing to help with that.
-
-       - Some of the default driver parameters (see 'struct dwc2_core_params'
-         in core.h) won't work for many platforms. So DT attributes will need
-         to be added for some of these. But that can be done as-needed as new
-         platforms are added.
-
-       - Eventually the driver should be merged with the s3c-hsotg peripheral
-         mode driver, so that both modes of operation can be supported with a
-         single driver. But I think that can wait till after the driver has
-         been moved to mainline.
-
-       - After that, OTG support can be added. I'm not sure how much demand
-         there is for that, though, so I have that as a low priority.
-
-Please send any patches for this driver to Paul Zimmerman <paulz@synopsys.com>
-and Greg Kroah-Hartman <gregkh@linuxfoundation.org>. And please CC linux-usb
-<linux-usb@vger.kernel.org> too.
diff --git a/drivers/staging/dwc2/core.c b/drivers/staging/dwc2/core.c
deleted file mode 100644 (file)
index 8565d87..0000000
+++ /dev/null
@@ -1,2777 +0,0 @@
-/*
- * core.c - DesignWare HS OTG Controller common routines
- *
- * Copyright (C) 2004-2013 Synopsys, Inc.
- *
- * 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") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * 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.
- */
-
-/*
- * The Core code provides basic services for accessing and managing the
- * DWC_otg hardware. These services are used by both the Host Controller
- * Driver and the Peripheral Controller Driver.
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-
-#include <linux/usb/hcd.h>
-#include <linux/usb/ch11.h>
-
-#include "core.h"
-#include "hcd.h"
-
-/**
- * dwc2_enable_common_interrupts() - Initializes the commmon interrupts,
- * used in both device and host modes
- *
- * @hsotg: Programming view of the DWC_otg controller
- */
-static void dwc2_enable_common_interrupts(struct dwc2_hsotg *hsotg)
-{
-       u32 intmsk;
-
-       /* Clear any pending OTG Interrupts */
-       writel(0xffffffff, hsotg->regs + GOTGINT);
-
-       /* Clear any pending interrupts */
-       writel(0xffffffff, hsotg->regs + GINTSTS);
-
-       /* Enable the interrupts in the GINTMSK */
-       intmsk = GINTSTS_MODEMIS | GINTSTS_OTGINT;
-
-       if (hsotg->core_params->dma_enable <= 0)
-               intmsk |= GINTSTS_RXFLVL;
-
-       intmsk |= GINTSTS_CONIDSTSCHNG | GINTSTS_WKUPINT | GINTSTS_USBSUSP |
-                 GINTSTS_SESSREQINT;
-
-       writel(intmsk, hsotg->regs + GINTMSK);
-}
-
-/*
- * Initializes the FSLSPClkSel field of the HCFG register depending on the
- * PHY type
- */
-static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)
-{
-       u32 hcfg, val;
-
-       if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
-            hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
-            hsotg->core_params->ulpi_fs_ls > 0) ||
-           hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) {
-               /* Full speed PHY */
-               val = HCFG_FSLSPCLKSEL_48_MHZ;
-       } else {
-               /* High speed PHY running at full speed or high speed */
-               val = HCFG_FSLSPCLKSEL_30_60_MHZ;
-       }
-
-       dev_dbg(hsotg->dev, "Initializing HCFG.FSLSPClkSel to %08x\n", val);
-       hcfg = readl(hsotg->regs + HCFG);
-       hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
-       hcfg |= val << HCFG_FSLSPCLKSEL_SHIFT;
-       writel(hcfg, hsotg->regs + HCFG);
-}
-
-/*
- * Do core a soft reset of the core.  Be careful with this because it
- * resets all the internal state machines of the core.
- */
-static int dwc2_core_reset(struct dwc2_hsotg *hsotg)
-{
-       u32 greset;
-       int count = 0;
-
-       dev_vdbg(hsotg->dev, "%s()\n", __func__);
-
-       /* Wait for AHB master IDLE state */
-       do {
-               usleep_range(20000, 40000);
-               greset = readl(hsotg->regs + GRSTCTL);
-               if (++count > 50) {
-                       dev_warn(hsotg->dev,
-                                "%s() HANG! AHB Idle GRSTCTL=%0x\n",
-                                __func__, greset);
-                       return -EBUSY;
-               }
-       } while (!(greset & GRSTCTL_AHBIDLE));
-
-       /* Core Soft Reset */
-       count = 0;
-       greset |= GRSTCTL_CSFTRST;
-       writel(greset, hsotg->regs + GRSTCTL);
-       do {
-               usleep_range(20000, 40000);
-               greset = readl(hsotg->regs + GRSTCTL);
-               if (++count > 50) {
-                       dev_warn(hsotg->dev,
-                                "%s() HANG! Soft Reset GRSTCTL=%0x\n",
-                                __func__, greset);
-                       return -EBUSY;
-               }
-       } while (greset & GRSTCTL_CSFTRST);
-
-       /*
-        * NOTE: This long sleep is _very_ important, otherwise the core will
-        * not stay in host mode after a connector ID change!
-        */
-       usleep_range(150000, 200000);
-
-       return 0;
-}
-
-static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
-{
-       u32 usbcfg, i2cctl;
-       int retval = 0;
-
-       /*
-        * core_init() is now called on every switch so only call the
-        * following for the first time through
-        */
-       if (select_phy) {
-               dev_dbg(hsotg->dev, "FS PHY selected\n");
-               usbcfg = readl(hsotg->regs + GUSBCFG);
-               usbcfg |= GUSBCFG_PHYSEL;
-               writel(usbcfg, hsotg->regs + GUSBCFG);
-
-               /* Reset after a PHY select */
-               retval = dwc2_core_reset(hsotg);
-               if (retval) {
-                       dev_err(hsotg->dev, "%s() Reset failed, aborting",
-                                       __func__);
-                       return retval;
-               }
-       }
-
-       /*
-        * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also
-        * do this on HNP Dev/Host mode switches (done in dev_init and
-        * host_init).
-        */
-       if (dwc2_is_host_mode(hsotg))
-               dwc2_init_fs_ls_pclk_sel(hsotg);
-
-       if (hsotg->core_params->i2c_enable > 0) {
-               dev_dbg(hsotg->dev, "FS PHY enabling I2C\n");
-
-               /* Program GUSBCFG.OtgUtmiFsSel to I2C */
-               usbcfg = readl(hsotg->regs + GUSBCFG);
-               usbcfg |= GUSBCFG_OTG_UTMI_FS_SEL;
-               writel(usbcfg, hsotg->regs + GUSBCFG);
-
-               /* Program GI2CCTL.I2CEn */
-               i2cctl = readl(hsotg->regs + GI2CCTL);
-               i2cctl &= ~GI2CCTL_I2CDEVADDR_MASK;
-               i2cctl |= 1 << GI2CCTL_I2CDEVADDR_SHIFT;
-               i2cctl &= ~GI2CCTL_I2CEN;
-               writel(i2cctl, hsotg->regs + GI2CCTL);
-               i2cctl |= GI2CCTL_I2CEN;
-               writel(i2cctl, hsotg->regs + GI2CCTL);
-       }
-
-       return retval;
-}
-
-static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
-{
-       u32 usbcfg;
-       int retval = 0;
-
-       if (!select_phy)
-               return -ENODEV;
-
-       usbcfg = readl(hsotg->regs + GUSBCFG);
-
-       /*
-        * HS PHY parameters. These parameters are preserved during soft reset
-        * so only program the first time. Do a soft reset immediately after
-        * setting phyif.
-        */
-       switch (hsotg->core_params->phy_type) {
-       case DWC2_PHY_TYPE_PARAM_ULPI:
-               /* ULPI interface */
-               dev_dbg(hsotg->dev, "HS ULPI PHY selected\n");
-               usbcfg |= GUSBCFG_ULPI_UTMI_SEL;
-               usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL);
-               if (hsotg->core_params->phy_ulpi_ddr > 0)
-                       usbcfg |= GUSBCFG_DDRSEL;
-               break;
-       case DWC2_PHY_TYPE_PARAM_UTMI:
-               /* UTMI+ interface */
-               dev_dbg(hsotg->dev, "HS UTMI+ PHY selected\n");
-               usbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16);
-               if (hsotg->core_params->phy_utmi_width == 16)
-                       usbcfg |= GUSBCFG_PHYIF16;
-               break;
-       default:
-               dev_err(hsotg->dev, "FS PHY selected at HS!\n");
-               break;
-       }
-
-       writel(usbcfg, hsotg->regs + GUSBCFG);
-
-       /* Reset after setting the PHY parameters */
-       retval = dwc2_core_reset(hsotg);
-       if (retval) {
-               dev_err(hsotg->dev, "%s() Reset failed, aborting",
-                               __func__);
-               return retval;
-       }
-
-       return retval;
-}
-
-static int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
-{
-       u32 usbcfg;
-       int retval = 0;
-
-       if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL &&
-           hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) {
-               /* If FS mode with FS PHY */
-               retval = dwc2_fs_phy_init(hsotg, select_phy);
-               if (retval)
-                       return retval;
-       } else {
-               /* High speed PHY */
-               retval = dwc2_hs_phy_init(hsotg, select_phy);
-               if (retval)
-                       return retval;
-       }
-
-       if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
-           hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
-           hsotg->core_params->ulpi_fs_ls > 0) {
-               dev_dbg(hsotg->dev, "Setting ULPI FSLS\n");
-               usbcfg = readl(hsotg->regs + GUSBCFG);
-               usbcfg |= GUSBCFG_ULPI_FS_LS;
-               usbcfg |= GUSBCFG_ULPI_CLK_SUSP_M;
-               writel(usbcfg, hsotg->regs + GUSBCFG);
-       } else {
-               usbcfg = readl(hsotg->regs + GUSBCFG);
-               usbcfg &= ~GUSBCFG_ULPI_FS_LS;
-               usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M;
-               writel(usbcfg, hsotg->regs + GUSBCFG);
-       }
-
-       return retval;
-}
-
-static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg)
-{
-       u32 ahbcfg = readl(hsotg->regs + GAHBCFG);
-
-       switch (hsotg->hw_params.arch) {
-       case GHWCFG2_EXT_DMA_ARCH:
-               dev_err(hsotg->dev, "External DMA Mode not supported\n");
-               return -EINVAL;
-
-       case GHWCFG2_INT_DMA_ARCH:
-               dev_dbg(hsotg->dev, "Internal DMA Mode\n");
-               if (hsotg->core_params->ahbcfg != -1) {
-                       ahbcfg &= GAHBCFG_CTRL_MASK;
-                       ahbcfg |= hsotg->core_params->ahbcfg &
-                                 ~GAHBCFG_CTRL_MASK;
-               }
-               break;
-
-       case GHWCFG2_SLAVE_ONLY_ARCH:
-       default:
-               dev_dbg(hsotg->dev, "Slave Only Mode\n");
-               break;
-       }
-
-       dev_dbg(hsotg->dev, "dma_enable:%d dma_desc_enable:%d\n",
-               hsotg->core_params->dma_enable,
-               hsotg->core_params->dma_desc_enable);
-
-       if (hsotg->core_params->dma_enable > 0) {
-               if (hsotg->core_params->dma_desc_enable > 0)
-                       dev_dbg(hsotg->dev, "Using Descriptor DMA mode\n");
-               else
-                       dev_dbg(hsotg->dev, "Using Buffer DMA mode\n");
-       } else {
-               dev_dbg(hsotg->dev, "Using Slave mode\n");
-               hsotg->core_params->dma_desc_enable = 0;
-       }
-
-       if (hsotg->core_params->dma_enable > 0)
-               ahbcfg |= GAHBCFG_DMA_EN;
-
-       writel(ahbcfg, hsotg->regs + GAHBCFG);
-
-       return 0;
-}
-
-static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)
-{
-       u32 usbcfg;
-
-       usbcfg = readl(hsotg->regs + GUSBCFG);
-       usbcfg &= ~(GUSBCFG_HNPCAP | GUSBCFG_SRPCAP);
-
-       switch (hsotg->hw_params.op_mode) {
-       case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
-               if (hsotg->core_params->otg_cap ==
-                               DWC2_CAP_PARAM_HNP_SRP_CAPABLE)
-                       usbcfg |= GUSBCFG_HNPCAP;
-               if (hsotg->core_params->otg_cap !=
-                               DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE)
-                       usbcfg |= GUSBCFG_SRPCAP;
-               break;
-
-       case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
-       case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
-       case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
-               if (hsotg->core_params->otg_cap !=
-                               DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE)
-                       usbcfg |= GUSBCFG_SRPCAP;
-               break;
-
-       case GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE:
-       case GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE:
-       case GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST:
-       default:
-               break;
-       }
-
-       writel(usbcfg, hsotg->regs + GUSBCFG);
-}
-
-/**
- * dwc2_core_init() - Initializes the DWC_otg controller registers and
- * prepares the core for device mode or host mode operation
- *
- * @hsotg:      Programming view of the DWC_otg controller
- * @select_phy: If true then also set the Phy type
- * @irq:        If >= 0, the irq to register
- */
-int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)
-{
-       u32 usbcfg, otgctl;
-       int retval;
-
-       dev_dbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
-
-       usbcfg = readl(hsotg->regs + GUSBCFG);
-
-       /* Set ULPI External VBUS bit if needed */
-       usbcfg &= ~GUSBCFG_ULPI_EXT_VBUS_DRV;
-       if (hsotg->core_params->phy_ulpi_ext_vbus ==
-                               DWC2_PHY_ULPI_EXTERNAL_VBUS)
-               usbcfg |= GUSBCFG_ULPI_EXT_VBUS_DRV;
-
-       /* Set external TS Dline pulsing bit if needed */
-       usbcfg &= ~GUSBCFG_TERMSELDLPULSE;
-       if (hsotg->core_params->ts_dline > 0)
-               usbcfg |= GUSBCFG_TERMSELDLPULSE;
-
-       writel(usbcfg, hsotg->regs + GUSBCFG);
-
-       /* Reset the Controller */
-       retval = dwc2_core_reset(hsotg);
-       if (retval) {
-               dev_err(hsotg->dev, "%s(): Reset failed, aborting\n",
-                               __func__);
-               return retval;
-       }
-
-       /*
-        * This needs to happen in FS mode before any other programming occurs
-        */
-       retval = dwc2_phy_init(hsotg, select_phy);
-       if (retval)
-               return retval;
-
-       /* Program the GAHBCFG Register */
-       retval = dwc2_gahbcfg_init(hsotg);
-       if (retval)
-               return retval;
-
-       /* Program the GUSBCFG register */
-       dwc2_gusbcfg_init(hsotg);
-
-       /* Program the GOTGCTL register */
-       otgctl = readl(hsotg->regs + GOTGCTL);
-       otgctl &= ~GOTGCTL_OTGVER;
-       if (hsotg->core_params->otg_ver > 0)
-               otgctl |= GOTGCTL_OTGVER;
-       writel(otgctl, hsotg->regs + GOTGCTL);
-       dev_dbg(hsotg->dev, "OTG VER PARAM: %d\n", hsotg->core_params->otg_ver);
-
-       /* Clear the SRP success bit for FS-I2c */
-       hsotg->srp_success = 0;
-
-       if (irq >= 0) {
-               dev_dbg(hsotg->dev, "registering common handler for irq%d\n",
-                       irq);
-               retval = devm_request_irq(hsotg->dev, irq,
-                                         dwc2_handle_common_intr, IRQF_SHARED,
-                                         dev_name(hsotg->dev), hsotg);
-               if (retval)
-                       return retval;
-       }
-
-       /* Enable common interrupts */
-       dwc2_enable_common_interrupts(hsotg);
-
-       /*
-        * Do device or host intialization based on mode during PCD and
-        * HCD initialization
-        */
-       if (dwc2_is_host_mode(hsotg)) {
-               dev_dbg(hsotg->dev, "Host Mode\n");
-               hsotg->op_state = OTG_STATE_A_HOST;
-       } else {
-               dev_dbg(hsotg->dev, "Device Mode\n");
-               hsotg->op_state = OTG_STATE_B_PERIPHERAL;
-       }
-
-       return 0;
-}
-
-/**
- * dwc2_enable_host_interrupts() - Enables the Host mode interrupts
- *
- * @hsotg: Programming view of DWC_otg controller
- */
-void dwc2_enable_host_interrupts(struct dwc2_hsotg *hsotg)
-{
-       u32 intmsk;
-
-       dev_dbg(hsotg->dev, "%s()\n", __func__);
-
-       /* Disable all interrupts */
-       writel(0, hsotg->regs + GINTMSK);
-       writel(0, hsotg->regs + HAINTMSK);
-
-       /* Enable the common interrupts */
-       dwc2_enable_common_interrupts(hsotg);
-
-       /* Enable host mode interrupts without disturbing common interrupts */
-       intmsk = readl(hsotg->regs + GINTMSK);
-       intmsk |= GINTSTS_DISCONNINT | GINTSTS_PRTINT | GINTSTS_HCHINT;
-       writel(intmsk, hsotg->regs + GINTMSK);
-}
-
-/**
- * dwc2_disable_host_interrupts() - Disables the Host Mode interrupts
- *
- * @hsotg: Programming view of DWC_otg controller
- */
-void dwc2_disable_host_interrupts(struct dwc2_hsotg *hsotg)
-{
-       u32 intmsk = readl(hsotg->regs + GINTMSK);
-
-       /* Disable host mode interrupts without disturbing common interrupts */
-       intmsk &= ~(GINTSTS_SOF | GINTSTS_PRTINT | GINTSTS_HCHINT |
-                   GINTSTS_PTXFEMP | GINTSTS_NPTXFEMP);
-       writel(intmsk, hsotg->regs + GINTMSK);
-}
-
-static void dwc2_config_fifos(struct dwc2_hsotg *hsotg)
-{
-       struct dwc2_core_params *params = hsotg->core_params;
-       u32 nptxfsiz, hptxfsiz, dfifocfg, grxfsiz;
-
-       if (!params->enable_dynamic_fifo)
-               return;
-
-       /* Rx FIFO */
-       grxfsiz = readl(hsotg->regs + GRXFSIZ);
-       dev_dbg(hsotg->dev, "initial grxfsiz=%08x\n", grxfsiz);
-       grxfsiz &= ~GRXFSIZ_DEPTH_MASK;
-       grxfsiz |= params->host_rx_fifo_size <<
-                  GRXFSIZ_DEPTH_SHIFT & GRXFSIZ_DEPTH_MASK;
-       writel(grxfsiz, hsotg->regs + GRXFSIZ);
-       dev_dbg(hsotg->dev, "new grxfsiz=%08x\n", readl(hsotg->regs + GRXFSIZ));
-
-       /* Non-periodic Tx FIFO */
-       dev_dbg(hsotg->dev, "initial gnptxfsiz=%08x\n",
-               readl(hsotg->regs + GNPTXFSIZ));
-       nptxfsiz = params->host_nperio_tx_fifo_size <<
-                  FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
-       nptxfsiz |= params->host_rx_fifo_size <<
-                   FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
-       writel(nptxfsiz, hsotg->regs + GNPTXFSIZ);
-       dev_dbg(hsotg->dev, "new gnptxfsiz=%08x\n",
-               readl(hsotg->regs + GNPTXFSIZ));
-
-       /* Periodic Tx FIFO */
-       dev_dbg(hsotg->dev, "initial hptxfsiz=%08x\n",
-               readl(hsotg->regs + HPTXFSIZ));
-       hptxfsiz = params->host_perio_tx_fifo_size <<
-                  FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
-       hptxfsiz |= (params->host_rx_fifo_size +
-                    params->host_nperio_tx_fifo_size) <<
-                   FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
-       writel(hptxfsiz, hsotg->regs + HPTXFSIZ);
-       dev_dbg(hsotg->dev, "new hptxfsiz=%08x\n",
-               readl(hsotg->regs + HPTXFSIZ));
-
-       if (hsotg->core_params->en_multiple_tx_fifo > 0 &&
-           hsotg->hw_params.snpsid <= DWC2_CORE_REV_2_94a) {
-               /*
-                * Global DFIFOCFG calculation for Host mode -
-                * include RxFIFO, NPTXFIFO and HPTXFIFO
-                */
-               dfifocfg = readl(hsotg->regs + GDFIFOCFG);
-               dfifocfg &= ~GDFIFOCFG_EPINFOBASE_MASK;
-               dfifocfg |= (params->host_rx_fifo_size +
-                            params->host_nperio_tx_fifo_size +
-                            params->host_perio_tx_fifo_size) <<
-                           GDFIFOCFG_EPINFOBASE_SHIFT &
-                           GDFIFOCFG_EPINFOBASE_MASK;
-               writel(dfifocfg, hsotg->regs + GDFIFOCFG);
-       }
-}
-
-/**
- * dwc2_core_host_init() - Initializes the DWC_otg controller registers for
- * Host mode
- *
- * @hsotg: Programming view of DWC_otg controller
- *
- * This function flushes the Tx and Rx FIFOs and flushes any entries in the
- * request queues. Host channels are reset to ensure that they are ready for
- * performing transfers.
- */
-void dwc2_core_host_init(struct dwc2_hsotg *hsotg)
-{
-       u32 hcfg, hfir, otgctl;
-
-       dev_dbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
-
-       /* Restart the Phy Clock */
-       writel(0, hsotg->regs + PCGCTL);
-
-       /* Initialize Host Configuration Register */
-       dwc2_init_fs_ls_pclk_sel(hsotg);
-       if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL) {
-               hcfg = readl(hsotg->regs + HCFG);
-               hcfg |= HCFG_FSLSSUPP;
-               writel(hcfg, hsotg->regs + HCFG);
-       }
-
-       /*
-        * This bit allows dynamic reloading of the HFIR register during
-        * runtime. This bit needs to be programmed during initial configuration
-        * and its value must not be changed during runtime.
-        */
-       if (hsotg->core_params->reload_ctl > 0) {
-               hfir = readl(hsotg->regs + HFIR);
-               hfir |= HFIR_RLDCTRL;
-               writel(hfir, hsotg->regs + HFIR);
-       }
-
-       if (hsotg->core_params->dma_desc_enable > 0) {
-               u32 op_mode = hsotg->hw_params.op_mode;
-               if (hsotg->hw_params.snpsid < DWC2_CORE_REV_2_90a ||
-                   !hsotg->hw_params.dma_desc_enable ||
-                   op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE ||
-                   op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE ||
-                   op_mode == GHWCFG2_OP_MODE_UNDEFINED) {
-                       dev_err(hsotg->dev,
-                               "Hardware does not support descriptor DMA mode -\n");
-                       dev_err(hsotg->dev,
-                               "falling back to buffer DMA mode.\n");
-                       hsotg->core_params->dma_desc_enable = 0;
-               } else {
-                       hcfg = readl(hsotg->regs + HCFG);
-                       hcfg |= HCFG_DESCDMA;
-                       writel(hcfg, hsotg->regs + HCFG);
-               }
-       }
-
-       /* Configure data FIFO sizes */
-       dwc2_config_fifos(hsotg);
-
-       /* TODO - check this */
-       /* Clear Host Set HNP Enable in the OTG Control Register */
-       otgctl = readl(hsotg->regs + GOTGCTL);
-       otgctl &= ~GOTGCTL_HSTSETHNPEN;
-       writel(otgctl, hsotg->regs + GOTGCTL);
-
-       /* Make sure the FIFOs are flushed */
-       dwc2_flush_tx_fifo(hsotg, 0x10 /* all TX FIFOs */);
-       dwc2_flush_rx_fifo(hsotg);
-
-       /* Clear Host Set HNP Enable in the OTG Control Register */
-       otgctl = readl(hsotg->regs + GOTGCTL);
-       otgctl &= ~GOTGCTL_HSTSETHNPEN;
-       writel(otgctl, hsotg->regs + GOTGCTL);
-
-       if (hsotg->core_params->dma_desc_enable <= 0) {
-               int num_channels, i;
-               u32 hcchar;
-
-               /* Flush out any leftover queued requests */
-               num_channels = hsotg->core_params->host_channels;
-               for (i = 0; i < num_channels; i++) {
-                       hcchar = readl(hsotg->regs + HCCHAR(i));
-                       hcchar &= ~HCCHAR_CHENA;
-                       hcchar |= HCCHAR_CHDIS;
-                       hcchar &= ~HCCHAR_EPDIR;
-                       writel(hcchar, hsotg->regs + HCCHAR(i));
-               }
-
-               /* Halt all channels to put them into a known state */
-               for (i = 0; i < num_channels; i++) {
-                       int count = 0;
-
-                       hcchar = readl(hsotg->regs + HCCHAR(i));
-                       hcchar |= HCCHAR_CHENA | HCCHAR_CHDIS;
-                       hcchar &= ~HCCHAR_EPDIR;
-                       writel(hcchar, hsotg->regs + HCCHAR(i));
-                       dev_dbg(hsotg->dev, "%s: Halt channel %d\n",
-                               __func__, i);
-                       do {
-                               hcchar = readl(hsotg->regs + HCCHAR(i));
-                               if (++count > 1000) {
-                                       dev_err(hsotg->dev,
-                                               "Unable to clear enable on channel %d\n",
-                                               i);
-                                       break;
-                               }
-                               udelay(1);
-                       } while (hcchar & HCCHAR_CHENA);
-               }
-       }
-
-       /* Turn on the vbus power */
-       dev_dbg(hsotg->dev, "Init: Port Power? op_state=%d\n", hsotg->op_state);
-       if (hsotg->op_state == OTG_STATE_A_HOST) {
-               u32 hprt0 = dwc2_read_hprt0(hsotg);
-
-               dev_dbg(hsotg->dev, "Init: Power Port (%d)\n",
-                       !!(hprt0 & HPRT0_PWR));
-               if (!(hprt0 & HPRT0_PWR)) {
-                       hprt0 |= HPRT0_PWR;
-                       writel(hprt0, hsotg->regs + HPRT0);
-               }
-       }
-
-       dwc2_enable_host_interrupts(hsotg);
-}
-
-static void dwc2_hc_enable_slave_ints(struct dwc2_hsotg *hsotg,
-                                     struct dwc2_host_chan *chan)
-{
-       u32 hcintmsk = HCINTMSK_CHHLTD;
-
-       switch (chan->ep_type) {
-       case USB_ENDPOINT_XFER_CONTROL:
-       case USB_ENDPOINT_XFER_BULK:
-               dev_vdbg(hsotg->dev, "control/bulk\n");
-               hcintmsk |= HCINTMSK_XFERCOMPL;
-               hcintmsk |= HCINTMSK_STALL;
-               hcintmsk |= HCINTMSK_XACTERR;
-               hcintmsk |= HCINTMSK_DATATGLERR;
-               if (chan->ep_is_in) {
-                       hcintmsk |= HCINTMSK_BBLERR;
-               } else {
-                       hcintmsk |= HCINTMSK_NAK;
-                       hcintmsk |= HCINTMSK_NYET;
-                       if (chan->do_ping)
-                               hcintmsk |= HCINTMSK_ACK;
-               }
-
-               if (chan->do_split) {
-                       hcintmsk |= HCINTMSK_NAK;
-                       if (chan->complete_split)
-                               hcintmsk |= HCINTMSK_NYET;
-                       else
-                               hcintmsk |= HCINTMSK_ACK;
-               }
-
-               if (chan->error_state)
-                       hcintmsk |= HCINTMSK_ACK;
-               break;
-
-       case USB_ENDPOINT_XFER_INT:
-               if (dbg_perio())
-                       dev_vdbg(hsotg->dev, "intr\n");
-               hcintmsk |= HCINTMSK_XFERCOMPL;
-               hcintmsk |= HCINTMSK_NAK;
-               hcintmsk |= HCINTMSK_STALL;
-               hcintmsk |= HCINTMSK_XACTERR;
-               hcintmsk |= HCINTMSK_DATATGLERR;
-               hcintmsk |= HCINTMSK_FRMOVRUN;
-
-               if (chan->ep_is_in)
-                       hcintmsk |= HCINTMSK_BBLERR;
-               if (chan->error_state)
-                       hcintmsk |= HCINTMSK_ACK;
-               if (chan->do_split) {
-                       if (chan->complete_split)
-                               hcintmsk |= HCINTMSK_NYET;
-                       else
-                               hcintmsk |= HCINTMSK_ACK;
-               }
-               break;
-
-       case USB_ENDPOINT_XFER_ISOC:
-               if (dbg_perio())
-                       dev_vdbg(hsotg->dev, "isoc\n");
-               hcintmsk |= HCINTMSK_XFERCOMPL;
-               hcintmsk |= HCINTMSK_FRMOVRUN;
-               hcintmsk |= HCINTMSK_ACK;
-
-               if (chan->ep_is_in) {
-                       hcintmsk |= HCINTMSK_XACTERR;
-                       hcintmsk |= HCINTMSK_BBLERR;
-               }
-               break;
-       default:
-               dev_err(hsotg->dev, "## Unknown EP type ##\n");
-               break;
-       }
-
-       writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num));
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "set HCINTMSK to %08x\n", hcintmsk);
-}
-
-static void dwc2_hc_enable_dma_ints(struct dwc2_hsotg *hsotg,
-                                   struct dwc2_host_chan *chan)
-{
-       u32 hcintmsk = HCINTMSK_CHHLTD;
-
-       /*
-        * For Descriptor DMA mode core halts the channel on AHB error.
-        * Interrupt is not required.
-        */
-       if (hsotg->core_params->dma_desc_enable <= 0) {
-               if (dbg_hc(chan))
-                       dev_vdbg(hsotg->dev, "desc DMA disabled\n");
-               hcintmsk |= HCINTMSK_AHBERR;
-       } else {
-               if (dbg_hc(chan))
-                       dev_vdbg(hsotg->dev, "desc DMA enabled\n");
-               if (chan->ep_type == USB_ENDPOINT_XFER_ISOC)
-                       hcintmsk |= HCINTMSK_XFERCOMPL;
-       }
-
-       if (chan->error_state && !chan->do_split &&
-           chan->ep_type != USB_ENDPOINT_XFER_ISOC) {
-               if (dbg_hc(chan))
-                       dev_vdbg(hsotg->dev, "setting ACK\n");
-               hcintmsk |= HCINTMSK_ACK;
-               if (chan->ep_is_in) {
-                       hcintmsk |= HCINTMSK_DATATGLERR;
-                       if (chan->ep_type != USB_ENDPOINT_XFER_INT)
-                               hcintmsk |= HCINTMSK_NAK;
-               }
-       }
-
-       writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num));
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "set HCINTMSK to %08x\n", hcintmsk);
-}
-
-static void dwc2_hc_enable_ints(struct dwc2_hsotg *hsotg,
-                               struct dwc2_host_chan *chan)
-{
-       u32 intmsk;
-
-       if (hsotg->core_params->dma_enable > 0) {
-               if (dbg_hc(chan))
-                       dev_vdbg(hsotg->dev, "DMA enabled\n");
-               dwc2_hc_enable_dma_ints(hsotg, chan);
-       } else {
-               if (dbg_hc(chan))
-                       dev_vdbg(hsotg->dev, "DMA disabled\n");
-               dwc2_hc_enable_slave_ints(hsotg, chan);
-       }
-
-       /* Enable the top level host channel interrupt */
-       intmsk = readl(hsotg->regs + HAINTMSK);
-       intmsk |= 1 << chan->hc_num;
-       writel(intmsk, hsotg->regs + HAINTMSK);
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "set HAINTMSK to %08x\n", intmsk);
-
-       /* Make sure host channel interrupts are enabled */
-       intmsk = readl(hsotg->regs + GINTMSK);
-       intmsk |= GINTSTS_HCHINT;
-       writel(intmsk, hsotg->regs + GINTMSK);
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "set GINTMSK to %08x\n", intmsk);
-}
-
-/**
- * dwc2_hc_init() - Prepares a host channel for transferring packets to/from
- * a specific endpoint
- *
- * @hsotg: Programming view of DWC_otg controller
- * @chan:  Information needed to initialize the host channel
- *
- * The HCCHARn register is set up with the characteristics specified in chan.
- * Host channel interrupts that may need to be serviced while this transfer is
- * in progress are enabled.
- */
-void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
-{
-       u8 hc_num = chan->hc_num;
-       u32 hcintmsk;
-       u32 hcchar;
-       u32 hcsplt = 0;
-
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "%s()\n", __func__);
-
-       /* Clear old interrupt conditions for this host channel */
-       hcintmsk = 0xffffffff;
-       hcintmsk &= ~HCINTMSK_RESERVED14_31;
-       writel(hcintmsk, hsotg->regs + HCINT(hc_num));
-
-       /* Enable channel interrupts required for this transfer */
-       dwc2_hc_enable_ints(hsotg, chan);
-
-       /*
-        * Program the HCCHARn register with the endpoint characteristics for
-        * the current transfer
-        */
-       hcchar = chan->dev_addr << HCCHAR_DEVADDR_SHIFT & HCCHAR_DEVADDR_MASK;
-       hcchar |= chan->ep_num << HCCHAR_EPNUM_SHIFT & HCCHAR_EPNUM_MASK;
-       if (chan->ep_is_in)
-               hcchar |= HCCHAR_EPDIR;
-       if (chan->speed == USB_SPEED_LOW)
-               hcchar |= HCCHAR_LSPDDEV;
-       hcchar |= chan->ep_type << HCCHAR_EPTYPE_SHIFT & HCCHAR_EPTYPE_MASK;
-       hcchar |= chan->max_packet << HCCHAR_MPS_SHIFT & HCCHAR_MPS_MASK;
-       writel(hcchar, hsotg->regs + HCCHAR(hc_num));
-       if (dbg_hc(chan)) {
-               dev_vdbg(hsotg->dev, "set HCCHAR(%d) to %08x\n",
-                        hc_num, hcchar);
-
-               dev_vdbg(hsotg->dev, "%s: Channel %d\n",
-                        __func__, hc_num);
-               dev_vdbg(hsotg->dev, "   Dev Addr: %d\n",
-                        chan->dev_addr);
-               dev_vdbg(hsotg->dev, "   Ep Num: %d\n",
-                        chan->ep_num);
-               dev_vdbg(hsotg->dev, "   Is In: %d\n",
-                        chan->ep_is_in);
-               dev_vdbg(hsotg->dev, "   Is Low Speed: %d\n",
-                        chan->speed == USB_SPEED_LOW);
-               dev_vdbg(hsotg->dev, "   Ep Type: %d\n",
-                        chan->ep_type);
-               dev_vdbg(hsotg->dev, "   Max Pkt: %d\n",
-                        chan->max_packet);
-       }
-
-       /* Program the HCSPLT register for SPLITs */
-       if (chan->do_split) {
-               if (dbg_hc(chan))
-                       dev_vdbg(hsotg->dev,
-                                "Programming HC %d with split --> %s\n",
-                                hc_num,
-                                chan->complete_split ? "CSPLIT" : "SSPLIT");
-               if (chan->complete_split)
-                       hcsplt |= HCSPLT_COMPSPLT;
-               hcsplt |= chan->xact_pos << HCSPLT_XACTPOS_SHIFT &
-                         HCSPLT_XACTPOS_MASK;
-               hcsplt |= chan->hub_addr << HCSPLT_HUBADDR_SHIFT &
-                         HCSPLT_HUBADDR_MASK;
-               hcsplt |= chan->hub_port << HCSPLT_PRTADDR_SHIFT &
-                         HCSPLT_PRTADDR_MASK;
-               if (dbg_hc(chan)) {
-                       dev_vdbg(hsotg->dev, "    comp split %d\n",
-                                chan->complete_split);
-                       dev_vdbg(hsotg->dev, "    xact pos %d\n",
-                                chan->xact_pos);
-                       dev_vdbg(hsotg->dev, "    hub addr %d\n",
-                                chan->hub_addr);
-                       dev_vdbg(hsotg->dev, "    hub port %d\n",
-                                chan->hub_port);
-                       dev_vdbg(hsotg->dev, "    is_in %d\n",
-                                chan->ep_is_in);
-                       dev_vdbg(hsotg->dev, "    Max Pkt %d\n",
-                                chan->max_packet);
-                       dev_vdbg(hsotg->dev, "    xferlen %d\n",
-                                chan->xfer_len);
-               }
-       }
-
-       writel(hcsplt, hsotg->regs + HCSPLT(hc_num));
-}
-
-/**
- * dwc2_hc_halt() - Attempts to halt a host channel
- *
- * @hsotg:       Controller register interface
- * @chan:        Host channel to halt
- * @halt_status: Reason for halting the channel
- *
- * This function should only be called in Slave mode or to abort a transfer in
- * either Slave mode or DMA mode. Under normal circumstances in DMA mode, the
- * controller halts the channel when the transfer is complete or a condition
- * occurs that requires application intervention.
- *
- * In slave mode, checks for a free request queue entry, then sets the Channel
- * Enable and Channel Disable bits of the Host Channel Characteristics
- * register of the specified channel to intiate the halt. If there is no free
- * request queue entry, sets only the Channel Disable bit of the HCCHARn
- * register to flush requests for this channel. In the latter case, sets a
- * flag to indicate that the host channel needs to be halted when a request
- * queue slot is open.
- *
- * In DMA mode, always sets the Channel Enable and Channel Disable bits of the
- * HCCHARn register. The controller ensures there is space in the request
- * queue before submitting the halt request.
- *
- * Some time may elapse before the core flushes any posted requests for this
- * host channel and halts. The Channel Halted interrupt handler completes the
- * deactivation of the host channel.
- */
-void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
-                 enum dwc2_halt_status halt_status)
-{
-       u32 nptxsts, hptxsts, hcchar;
-
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "%s()\n", __func__);
-       if (halt_status == DWC2_HC_XFER_NO_HALT_STATUS)
-               dev_err(hsotg->dev, "!!! halt_status = %d !!!\n", halt_status);
-
-       if (halt_status == DWC2_HC_XFER_URB_DEQUEUE ||
-           halt_status == DWC2_HC_XFER_AHB_ERR) {
-               /*
-                * Disable all channel interrupts except Ch Halted. The QTD
-                * and QH state associated with this transfer has been cleared
-                * (in the case of URB_DEQUEUE), so the channel needs to be
-                * shut down carefully to prevent crashes.
-                */
-               u32 hcintmsk = HCINTMSK_CHHLTD;
-
-               dev_vdbg(hsotg->dev, "dequeue/error\n");
-               writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num));
-
-               /*
-                * Make sure no other interrupts besides halt are currently
-                * pending. Handling another interrupt could cause a crash due
-                * to the QTD and QH state.
-                */
-               writel(~hcintmsk, hsotg->regs + HCINT(chan->hc_num));
-
-               /*
-                * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
-                * even if the channel was already halted for some other
-                * reason
-                */
-               chan->halt_status = halt_status;
-
-               hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
-               if (!(hcchar & HCCHAR_CHENA)) {
-                       /*
-                        * The channel is either already halted or it hasn't
-                        * started yet. In DMA mode, the transfer may halt if
-                        * it finishes normally or a condition occurs that
-                        * requires driver intervention. Don't want to halt
-                        * the channel again. In either Slave or DMA mode,
-                        * it's possible that the transfer has been assigned
-                        * to a channel, but not started yet when an URB is
-                        * dequeued. Don't want to halt a channel that hasn't
-                        * started yet.
-                        */
-                       return;
-               }
-       }
-       if (chan->halt_pending) {
-               /*
-                * A halt has already been issued for this channel. This might
-                * happen when a transfer is aborted by a higher level in
-                * the stack.
-                */
-               dev_vdbg(hsotg->dev,
-                        "*** %s: Channel %d, chan->halt_pending already set ***\n",
-                        __func__, chan->hc_num);
-               return;
-       }
-
-       hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
-
-       /* No need to set the bit in DDMA for disabling the channel */
-       /* TODO check it everywhere channel is disabled */
-       if (hsotg->core_params->dma_desc_enable <= 0) {
-               if (dbg_hc(chan))
-                       dev_vdbg(hsotg->dev, "desc DMA disabled\n");
-               hcchar |= HCCHAR_CHENA;
-       } else {
-               if (dbg_hc(chan))
-                       dev_dbg(hsotg->dev, "desc DMA enabled\n");
-       }
-       hcchar |= HCCHAR_CHDIS;
-
-       if (hsotg->core_params->dma_enable <= 0) {
-               if (dbg_hc(chan))
-                       dev_vdbg(hsotg->dev, "DMA not enabled\n");
-               hcchar |= HCCHAR_CHENA;
-
-               /* Check for space in the request queue to issue the halt */
-               if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL ||
-                   chan->ep_type == USB_ENDPOINT_XFER_BULK) {
-                       dev_vdbg(hsotg->dev, "control/bulk\n");
-                       nptxsts = readl(hsotg->regs + GNPTXSTS);
-                       if ((nptxsts & TXSTS_QSPCAVAIL_MASK) == 0) {
-                               dev_vdbg(hsotg->dev, "Disabling channel\n");
-                               hcchar &= ~HCCHAR_CHENA;
-                       }
-               } else {
-                       if (dbg_perio())
-                               dev_vdbg(hsotg->dev, "isoc/intr\n");
-                       hptxsts = readl(hsotg->regs + HPTXSTS);
-                       if ((hptxsts & TXSTS_QSPCAVAIL_MASK) == 0 ||
-                           hsotg->queuing_high_bandwidth) {
-                               if (dbg_perio())
-                                       dev_vdbg(hsotg->dev, "Disabling channel\n");
-                               hcchar &= ~HCCHAR_CHENA;
-                       }
-               }
-       } else {
-               if (dbg_hc(chan))
-                       dev_vdbg(hsotg->dev, "DMA enabled\n");
-       }
-
-       writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
-       chan->halt_status = halt_status;
-
-       if (hcchar & HCCHAR_CHENA) {
-               if (dbg_hc(chan))
-                       dev_vdbg(hsotg->dev, "Channel enabled\n");
-               chan->halt_pending = 1;
-               chan->halt_on_queue = 0;
-       } else {
-               if (dbg_hc(chan))
-                       dev_vdbg(hsotg->dev, "Channel disabled\n");
-               chan->halt_on_queue = 1;
-       }
-
-       if (dbg_hc(chan)) {
-               dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
-                        chan->hc_num);
-               dev_vdbg(hsotg->dev, "   hcchar: 0x%08x\n",
-                        hcchar);
-               dev_vdbg(hsotg->dev, "   halt_pending: %d\n",
-                        chan->halt_pending);
-               dev_vdbg(hsotg->dev, "   halt_on_queue: %d\n",
-                        chan->halt_on_queue);
-               dev_vdbg(hsotg->dev, "   halt_status: %d\n",
-                        chan->halt_status);
-       }
-}
-
-/**
- * dwc2_hc_cleanup() - Clears the transfer state for a host channel
- *
- * @hsotg: Programming view of DWC_otg controller
- * @chan:  Identifies the host channel to clean up
- *
- * This function is normally called after a transfer is done and the host
- * channel is being released
- */
-void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
-{
-       u32 hcintmsk;
-
-       chan->xfer_started = 0;
-
-       /*
-        * Clear channel interrupt enables and any unhandled channel interrupt
-        * conditions
-        */
-       writel(0, hsotg->regs + HCINTMSK(chan->hc_num));
-       hcintmsk = 0xffffffff;
-       hcintmsk &= ~HCINTMSK_RESERVED14_31;
-       writel(hcintmsk, hsotg->regs + HCINT(chan->hc_num));
-}
-
-/**
- * dwc2_hc_set_even_odd_frame() - Sets the channel property that indicates in
- * which frame a periodic transfer should occur
- *
- * @hsotg:  Programming view of DWC_otg controller
- * @chan:   Identifies the host channel to set up and its properties
- * @hcchar: Current value of the HCCHAR register for the specified host channel
- *
- * This function has no effect on non-periodic transfers
- */
-static void dwc2_hc_set_even_odd_frame(struct dwc2_hsotg *hsotg,
-                                      struct dwc2_host_chan *chan, u32 *hcchar)
-{
-       if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
-           chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
-               /* 1 if _next_ frame is odd, 0 if it's even */
-               if (!(dwc2_hcd_get_frame_number(hsotg) & 0x1))
-                       *hcchar |= HCCHAR_ODDFRM;
-       }
-}
-
-static void dwc2_set_pid_isoc(struct dwc2_host_chan *chan)
-{
-       /* Set up the initial PID for the transfer */
-       if (chan->speed == USB_SPEED_HIGH) {
-               if (chan->ep_is_in) {
-                       if (chan->multi_count == 1)
-                               chan->data_pid_start = DWC2_HC_PID_DATA0;
-                       else if (chan->multi_count == 2)
-                               chan->data_pid_start = DWC2_HC_PID_DATA1;
-                       else
-                               chan->data_pid_start = DWC2_HC_PID_DATA2;
-               } else {
-                       if (chan->multi_count == 1)
-                               chan->data_pid_start = DWC2_HC_PID_DATA0;
-                       else
-                               chan->data_pid_start = DWC2_HC_PID_MDATA;
-               }
-       } else {
-               chan->data_pid_start = DWC2_HC_PID_DATA0;
-       }
-}
-
-/**
- * dwc2_hc_write_packet() - Writes a packet into the Tx FIFO associated with
- * the Host Channel
- *
- * @hsotg: Programming view of DWC_otg controller
- * @chan:  Information needed to initialize the host channel
- *
- * This function should only be called in Slave mode. For a channel associated
- * with a non-periodic EP, the non-periodic Tx FIFO is written. For a channel
- * associated with a periodic EP, the periodic Tx FIFO is written.
- *
- * Upon return the xfer_buf and xfer_count fields in chan are incremented by
- * the number of bytes written to the Tx FIFO.
- */
-static void dwc2_hc_write_packet(struct dwc2_hsotg *hsotg,
-                                struct dwc2_host_chan *chan)
-{
-       u32 i;
-       u32 remaining_count;
-       u32 byte_count;
-       u32 dword_count;
-       u32 __iomem *data_fifo;
-       u32 *data_buf = (u32 *)chan->xfer_buf;
-
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "%s()\n", __func__);
-
-       data_fifo = (u32 __iomem *)(hsotg->regs + HCFIFO(chan->hc_num));
-
-       remaining_count = chan->xfer_len - chan->xfer_count;
-       if (remaining_count > chan->max_packet)
-               byte_count = chan->max_packet;
-       else
-               byte_count = remaining_count;
-
-       dword_count = (byte_count + 3) / 4;
-
-       if (((unsigned long)data_buf & 0x3) == 0) {
-               /* xfer_buf is DWORD aligned */
-               for (i = 0; i < dword_count; i++, data_buf++)
-                       writel(*data_buf, data_fifo);
-       } else {
-               /* xfer_buf is not DWORD aligned */
-               for (i = 0; i < dword_count; i++, data_buf++) {
-                       u32 data = data_buf[0] | data_buf[1] << 8 |
-                                  data_buf[2] << 16 | data_buf[3] << 24;
-                       writel(data, data_fifo);
-               }
-       }
-
-       chan->xfer_count += byte_count;
-       chan->xfer_buf += byte_count;
-}
-
-/**
- * dwc2_hc_start_transfer() - Does the setup for a data transfer for a host
- * channel and starts the transfer
- *
- * @hsotg: Programming view of DWC_otg controller
- * @chan:  Information needed to initialize the host channel. The xfer_len value
- *         may be reduced to accommodate the max widths of the XferSize and
- *         PktCnt fields in the HCTSIZn register. The multi_count value may be
- *         changed to reflect the final xfer_len value.
- *
- * This function may be called in either Slave mode or DMA mode. In Slave mode,
- * the caller must ensure that there is sufficient space in the request queue
- * and Tx Data FIFO.
- *
- * For an OUT transfer in Slave mode, it loads a data packet into the
- * appropriate FIFO. If necessary, additional data packets are loaded in the
- * Host ISR.
- *
- * For an IN transfer in Slave mode, a data packet is requested. The data
- * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
- * additional data packets are requested in the Host ISR.
- *
- * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
- * register along with a packet count of 1 and the channel is enabled. This
- * causes a single PING transaction to occur. Other fields in HCTSIZ are
- * simply set to 0 since no data transfer occurs in this case.
- *
- * For a PING transfer in DMA mode, the HCTSIZ register is initialized with
- * all the information required to perform the subsequent data transfer. In
- * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
- * controller performs the entire PING protocol, then starts the data
- * transfer.
- */
-void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
-                           struct dwc2_host_chan *chan)
-{
-       u32 max_hc_xfer_size = hsotg->core_params->max_transfer_size;
-       u16 max_hc_pkt_count = hsotg->core_params->max_packet_count;
-       u32 hcchar;
-       u32 hctsiz = 0;
-       u16 num_packets;
-
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "%s()\n", __func__);
-
-       if (chan->do_ping) {
-               if (hsotg->core_params->dma_enable <= 0) {
-                       if (dbg_hc(chan))
-                               dev_vdbg(hsotg->dev, "ping, no DMA\n");
-                       dwc2_hc_do_ping(hsotg, chan);
-                       chan->xfer_started = 1;
-                       return;
-               } else {
-                       if (dbg_hc(chan))
-                               dev_vdbg(hsotg->dev, "ping, DMA\n");
-                       hctsiz |= TSIZ_DOPNG;
-               }
-       }
-
-       if (chan->do_split) {
-               if (dbg_hc(chan))
-                       dev_vdbg(hsotg->dev, "split\n");
-               num_packets = 1;
-
-               if (chan->complete_split && !chan->ep_is_in)
-                       /*
-                        * For CSPLIT OUT Transfer, set the size to 0 so the
-                        * core doesn't expect any data written to the FIFO
-                        */
-                       chan->xfer_len = 0;
-               else if (chan->ep_is_in || chan->xfer_len > chan->max_packet)
-                       chan->xfer_len = chan->max_packet;
-               else if (!chan->ep_is_in && chan->xfer_len > 188)
-                       chan->xfer_len = 188;
-
-               hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT &
-                         TSIZ_XFERSIZE_MASK;
-       } else {
-               if (dbg_hc(chan))
-                       dev_vdbg(hsotg->dev, "no split\n");
-               /*
-                * Ensure that the transfer length and packet count will fit
-                * in the widths allocated for them in the HCTSIZn register
-                */
-               if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
-                   chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
-                       /*
-                        * Make sure the transfer size is no larger than one
-                        * (micro)frame's worth of data. (A check was done
-                        * when the periodic transfer was accepted to ensure
-                        * that a (micro)frame's worth of data can be
-                        * programmed into a channel.)
-                        */
-                       u32 max_periodic_len =
-                               chan->multi_count * chan->max_packet;
-
-                       if (chan->xfer_len > max_periodic_len)
-                               chan->xfer_len = max_periodic_len;
-               } else if (chan->xfer_len > max_hc_xfer_size) {
-                       /*
-                        * Make sure that xfer_len is a multiple of max packet
-                        * size
-                        */
-                       chan->xfer_len =
-                               max_hc_xfer_size - chan->max_packet + 1;
-               }
-
-               if (chan->xfer_len > 0) {
-                       num_packets = (chan->xfer_len + chan->max_packet - 1) /
-                                       chan->max_packet;
-                       if (num_packets > max_hc_pkt_count) {
-                               num_packets = max_hc_pkt_count;
-                               chan->xfer_len = num_packets * chan->max_packet;
-                       }
-               } else {
-                       /* Need 1 packet for transfer length of 0 */
-                       num_packets = 1;
-               }
-
-               if (chan->ep_is_in)
-                       /*
-                        * Always program an integral # of max packets for IN
-                        * transfers
-                        */
-                       chan->xfer_len = num_packets * chan->max_packet;
-
-               if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
-                   chan->ep_type == USB_ENDPOINT_XFER_ISOC)
-                       /*
-                        * Make sure that the multi_count field matches the
-                        * actual transfer length
-                        */
-                       chan->multi_count = num_packets;
-
-               if (chan->ep_type == USB_ENDPOINT_XFER_ISOC)
-                       dwc2_set_pid_isoc(chan);
-
-               hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT &
-                         TSIZ_XFERSIZE_MASK;
-       }
-
-       chan->start_pkt_count = num_packets;
-       hctsiz |= num_packets << TSIZ_PKTCNT_SHIFT & TSIZ_PKTCNT_MASK;
-       hctsiz |= chan->data_pid_start << TSIZ_SC_MC_PID_SHIFT &
-                 TSIZ_SC_MC_PID_MASK;
-       writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
-       if (dbg_hc(chan)) {
-               dev_vdbg(hsotg->dev, "Wrote %08x to HCTSIZ(%d)\n",
-                        hctsiz, chan->hc_num);
-
-               dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
-                        chan->hc_num);
-               dev_vdbg(hsotg->dev, "   Xfer Size: %d\n",
-                        (hctsiz & TSIZ_XFERSIZE_MASK) >>
-                        TSIZ_XFERSIZE_SHIFT);
-               dev_vdbg(hsotg->dev, "   Num Pkts: %d\n",
-                        (hctsiz & TSIZ_PKTCNT_MASK) >>
-                        TSIZ_PKTCNT_SHIFT);
-               dev_vdbg(hsotg->dev, "   Start PID: %d\n",
-                        (hctsiz & TSIZ_SC_MC_PID_MASK) >>
-                        TSIZ_SC_MC_PID_SHIFT);
-       }
-
-       if (hsotg->core_params->dma_enable > 0) {
-               dma_addr_t dma_addr;
-
-               if (chan->align_buf) {
-                       if (dbg_hc(chan))
-                               dev_vdbg(hsotg->dev, "align_buf\n");
-                       dma_addr = chan->align_buf;
-               } else {
-                       dma_addr = chan->xfer_dma;
-               }
-               writel((u32)dma_addr, hsotg->regs + HCDMA(chan->hc_num));
-               if (dbg_hc(chan))
-                       dev_vdbg(hsotg->dev, "Wrote %08lx to HCDMA(%d)\n",
-                                (unsigned long)dma_addr, chan->hc_num);
-       }
-
-       /* Start the split */
-       if (chan->do_split) {
-               u32 hcsplt = readl(hsotg->regs + HCSPLT(chan->hc_num));
-
-               hcsplt |= HCSPLT_SPLTENA;
-               writel(hcsplt, hsotg->regs + HCSPLT(chan->hc_num));
-       }
-
-       hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
-       hcchar &= ~HCCHAR_MULTICNT_MASK;
-       hcchar |= chan->multi_count << HCCHAR_MULTICNT_SHIFT &
-                 HCCHAR_MULTICNT_MASK;
-       dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar);
-
-       if (hcchar & HCCHAR_CHDIS)
-               dev_warn(hsotg->dev,
-                        "%s: chdis set, channel %d, hcchar 0x%08x\n",
-                        __func__, chan->hc_num, hcchar);
-
-       /* Set host channel enable after all other setup is complete */
-       hcchar |= HCCHAR_CHENA;
-       hcchar &= ~HCCHAR_CHDIS;
-
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "   Multi Cnt: %d\n",
-                        (hcchar & HCCHAR_MULTICNT_MASK) >>
-                        HCCHAR_MULTICNT_SHIFT);
-
-       writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "Wrote %08x to HCCHAR(%d)\n", hcchar,
-                        chan->hc_num);
-
-       chan->xfer_started = 1;
-       chan->requests++;
-
-       if (hsotg->core_params->dma_enable <= 0 &&
-           !chan->ep_is_in && chan->xfer_len > 0)
-               /* Load OUT packet into the appropriate Tx FIFO */
-               dwc2_hc_write_packet(hsotg, chan);
-}
-
-/**
- * dwc2_hc_start_transfer_ddma() - Does the setup for a data transfer for a
- * host channel and starts the transfer in Descriptor DMA mode
- *
- * @hsotg: Programming view of DWC_otg controller
- * @chan:  Information needed to initialize the host channel
- *
- * Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set.
- * Sets PID and NTD values. For periodic transfers initializes SCHED_INFO field
- * with micro-frame bitmap.
- *
- * Initializes HCDMA register with descriptor list address and CTD value then
- * starts the transfer via enabling the channel.
- */
-void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
-                                struct dwc2_host_chan *chan)
-{
-       u32 hcchar;
-       u32 hc_dma;
-       u32 hctsiz = 0;
-
-       if (chan->do_ping)
-               hctsiz |= TSIZ_DOPNG;
-
-       if (chan->ep_type == USB_ENDPOINT_XFER_ISOC)
-               dwc2_set_pid_isoc(chan);
-
-       /* Packet Count and Xfer Size are not used in Descriptor DMA mode */
-       hctsiz |= chan->data_pid_start << TSIZ_SC_MC_PID_SHIFT &
-                 TSIZ_SC_MC_PID_MASK;
-
-       /* 0 - 1 descriptor, 1 - 2 descriptors, etc */
-       hctsiz |= (chan->ntd - 1) << TSIZ_NTD_SHIFT & TSIZ_NTD_MASK;
-
-       /* Non-zero only for high-speed interrupt endpoints */
-       hctsiz |= chan->schinfo << TSIZ_SCHINFO_SHIFT & TSIZ_SCHINFO_MASK;
-
-       if (dbg_hc(chan)) {
-               dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
-                        chan->hc_num);
-               dev_vdbg(hsotg->dev, "   Start PID: %d\n",
-                        chan->data_pid_start);
-               dev_vdbg(hsotg->dev, "   NTD: %d\n", chan->ntd - 1);
-       }
-
-       writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
-
-       hc_dma = (u32)chan->desc_list_addr & HCDMA_DMA_ADDR_MASK;
-
-       /* Always start from first descriptor */
-       hc_dma &= ~HCDMA_CTD_MASK;
-       writel(hc_dma, hsotg->regs + HCDMA(chan->hc_num));
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "Wrote %08x to HCDMA(%d)\n",
-                        hc_dma, chan->hc_num);
-
-       hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
-       hcchar &= ~HCCHAR_MULTICNT_MASK;
-       hcchar |= chan->multi_count << HCCHAR_MULTICNT_SHIFT &
-                 HCCHAR_MULTICNT_MASK;
-
-       if (hcchar & HCCHAR_CHDIS)
-               dev_warn(hsotg->dev,
-                        "%s: chdis set, channel %d, hcchar 0x%08x\n",
-                        __func__, chan->hc_num, hcchar);
-
-       /* Set host channel enable after all other setup is complete */
-       hcchar |= HCCHAR_CHENA;
-       hcchar &= ~HCCHAR_CHDIS;
-
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "   Multi Cnt: %d\n",
-                        (hcchar & HCCHAR_MULTICNT_MASK) >>
-                        HCCHAR_MULTICNT_SHIFT);
-
-       writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "Wrote %08x to HCCHAR(%d)\n", hcchar,
-                        chan->hc_num);
-
-       chan->xfer_started = 1;
-       chan->requests++;
-}
-
-/**
- * dwc2_hc_continue_transfer() - Continues a data transfer that was started by
- * a previous call to dwc2_hc_start_transfer()
- *
- * @hsotg: Programming view of DWC_otg controller
- * @chan:  Information needed to initialize the host channel
- *
- * The caller must ensure there is sufficient space in the request queue and Tx
- * Data FIFO. This function should only be called in Slave mode. In DMA mode,
- * the controller acts autonomously to complete transfers programmed to a host
- * channel.
- *
- * For an OUT transfer, a new data packet is loaded into the appropriate FIFO
- * if there is any data remaining to be queued. For an IN transfer, another
- * data packet is always requested. For the SETUP phase of a control transfer,
- * this function does nothing.
- *
- * Return: 1 if a new request is queued, 0 if no more requests are required
- * for this transfer
- */
-int dwc2_hc_continue_transfer(struct dwc2_hsotg *hsotg,
-                             struct dwc2_host_chan *chan)
-{
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
-                        chan->hc_num);
-
-       if (chan->do_split)
-               /* SPLITs always queue just once per channel */
-               return 0;
-
-       if (chan->data_pid_start == DWC2_HC_PID_SETUP)
-               /* SETUPs are queued only once since they can't be NAK'd */
-               return 0;
-
-       if (chan->ep_is_in) {
-               /*
-                * Always queue another request for other IN transfers. If
-                * back-to-back INs are issued and NAKs are received for both,
-                * the driver may still be processing the first NAK when the
-                * second NAK is received. When the interrupt handler clears
-                * the NAK interrupt for the first NAK, the second NAK will
-                * not be seen. So we can't depend on the NAK interrupt
-                * handler to requeue a NAK'd request. Instead, IN requests
-                * are issued each time this function is called. When the
-                * transfer completes, the extra requests for the channel will
-                * be flushed.
-                */
-               u32 hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
-
-               dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar);
-               hcchar |= HCCHAR_CHENA;
-               hcchar &= ~HCCHAR_CHDIS;
-               if (dbg_hc(chan))
-                       dev_vdbg(hsotg->dev, "   IN xfer: hcchar = 0x%08x\n",
-                                hcchar);
-               writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
-               chan->requests++;
-               return 1;
-       }
-
-       /* OUT transfers */
-
-       if (chan->xfer_count < chan->xfer_len) {
-               if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
-                   chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
-                       u32 hcchar = readl(hsotg->regs +
-                                          HCCHAR(chan->hc_num));
-
-                       dwc2_hc_set_even_odd_frame(hsotg, chan,
-                                                  &hcchar);
-               }
-
-               /* Load OUT packet into the appropriate Tx FIFO */
-               dwc2_hc_write_packet(hsotg, chan);
-               chan->requests++;
-               return 1;
-       }
-
-       return 0;
-}
-
-/**
- * dwc2_hc_do_ping() - Starts a PING transfer
- *
- * @hsotg: Programming view of DWC_otg controller
- * @chan:  Information needed to initialize the host channel
- *
- * This function should only be called in Slave mode. The Do Ping bit is set in
- * the HCTSIZ register, then the channel is enabled.
- */
-void dwc2_hc_do_ping(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
-{
-       u32 hcchar;
-       u32 hctsiz;
-
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
-                        chan->hc_num);
-
-
-       hctsiz = TSIZ_DOPNG;
-       hctsiz |= 1 << TSIZ_PKTCNT_SHIFT;
-       writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
-
-       hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
-       hcchar |= HCCHAR_CHENA;
-       hcchar &= ~HCCHAR_CHDIS;
-       writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
-}
-
-/**
- * dwc2_calc_frame_interval() - Calculates the correct frame Interval value for
- * the HFIR register according to PHY type and speed
- *
- * @hsotg: Programming view of DWC_otg controller
- *
- * NOTE: The caller can modify the value of the HFIR register only after the
- * Port Enable bit of the Host Port Control and Status register (HPRT.EnaPort)
- * has been set
- */
-u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg)
-{
-       u32 usbcfg;
-       u32 hprt0;
-       int clock = 60; /* default value */
-
-       usbcfg = readl(hsotg->regs + GUSBCFG);
-       hprt0 = readl(hsotg->regs + HPRT0);
-
-       if (!(usbcfg & GUSBCFG_PHYSEL) && (usbcfg & GUSBCFG_ULPI_UTMI_SEL) &&
-           !(usbcfg & GUSBCFG_PHYIF16))
-               clock = 60;
-       if ((usbcfg & GUSBCFG_PHYSEL) && hsotg->hw_params.fs_phy_type ==
-           GHWCFG2_FS_PHY_TYPE_SHARED_ULPI)
-               clock = 48;
-       if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
-           !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && (usbcfg & GUSBCFG_PHYIF16))
-               clock = 30;
-       if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
-           !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && !(usbcfg & GUSBCFG_PHYIF16))
-               clock = 60;
-       if ((usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
-           !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && (usbcfg & GUSBCFG_PHYIF16))
-               clock = 48;
-       if ((usbcfg & GUSBCFG_PHYSEL) && !(usbcfg & GUSBCFG_PHYIF16) &&
-           hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_SHARED_UTMI)
-               clock = 48;
-       if ((usbcfg & GUSBCFG_PHYSEL) &&
-           hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED)
-               clock = 48;
-
-       if ((hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT == HPRT0_SPD_HIGH_SPEED)
-               /* High speed case */
-               return 125 * clock;
-       else
-               /* FS/LS case */
-               return 1000 * clock;
-}
-
-/**
- * dwc2_read_packet() - Reads a packet from the Rx FIFO into the destination
- * buffer
- *
- * @core_if: Programming view of DWC_otg controller
- * @dest:    Destination buffer for the packet
- * @bytes:   Number of bytes to copy to the destination
- */
-void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes)
-{
-       u32 __iomem *fifo = hsotg->regs + HCFIFO(0);
-       u32 *data_buf = (u32 *)dest;
-       int word_count = (bytes + 3) / 4;
-       int i;
-
-       /*
-        * Todo: Account for the case where dest is not dword aligned. This
-        * requires reading data from the FIFO into a u32 temp buffer, then
-        * moving it into the data buffer.
-        */
-
-       dev_vdbg(hsotg->dev, "%s(%p,%p,%d)\n", __func__, hsotg, dest, bytes);
-
-       for (i = 0; i < word_count; i++, data_buf++)
-               *data_buf = readl(fifo);
-}
-
-/**
- * dwc2_dump_host_registers() - Prints the host registers
- *
- * @hsotg: Programming view of DWC_otg controller
- *
- * NOTE: This function will be removed once the peripheral controller code
- * is integrated and the driver is stable
- */
-void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg)
-{
-#ifdef DEBUG
-       u32 __iomem *addr;
-       int i;
-
-       dev_dbg(hsotg->dev, "Host Global Registers\n");
-       addr = hsotg->regs + HCFG;
-       dev_dbg(hsotg->dev, "HCFG        @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + HFIR;
-       dev_dbg(hsotg->dev, "HFIR        @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + HFNUM;
-       dev_dbg(hsotg->dev, "HFNUM       @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + HPTXSTS;
-       dev_dbg(hsotg->dev, "HPTXSTS     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + HAINT;
-       dev_dbg(hsotg->dev, "HAINT       @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + HAINTMSK;
-       dev_dbg(hsotg->dev, "HAINTMSK    @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       if (hsotg->core_params->dma_desc_enable > 0) {
-               addr = hsotg->regs + HFLBADDR;
-               dev_dbg(hsotg->dev, "HFLBADDR @0x%08lX : 0x%08X\n",
-                       (unsigned long)addr, readl(addr));
-       }
-
-       addr = hsotg->regs + HPRT0;
-       dev_dbg(hsotg->dev, "HPRT0       @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-
-       for (i = 0; i < hsotg->core_params->host_channels; i++) {
-               dev_dbg(hsotg->dev, "Host Channel %d Specific Registers\n", i);
-               addr = hsotg->regs + HCCHAR(i);
-               dev_dbg(hsotg->dev, "HCCHAR      @0x%08lX : 0x%08X\n",
-                       (unsigned long)addr, readl(addr));
-               addr = hsotg->regs + HCSPLT(i);
-               dev_dbg(hsotg->dev, "HCSPLT      @0x%08lX : 0x%08X\n",
-                       (unsigned long)addr, readl(addr));
-               addr = hsotg->regs + HCINT(i);
-               dev_dbg(hsotg->dev, "HCINT       @0x%08lX : 0x%08X\n",
-                       (unsigned long)addr, readl(addr));
-               addr = hsotg->regs + HCINTMSK(i);
-               dev_dbg(hsotg->dev, "HCINTMSK    @0x%08lX : 0x%08X\n",
-                       (unsigned long)addr, readl(addr));
-               addr = hsotg->regs + HCTSIZ(i);
-               dev_dbg(hsotg->dev, "HCTSIZ      @0x%08lX : 0x%08X\n",
-                       (unsigned long)addr, readl(addr));
-               addr = hsotg->regs + HCDMA(i);
-               dev_dbg(hsotg->dev, "HCDMA       @0x%08lX : 0x%08X\n",
-                       (unsigned long)addr, readl(addr));
-               if (hsotg->core_params->dma_desc_enable > 0) {
-                       addr = hsotg->regs + HCDMAB(i);
-                       dev_dbg(hsotg->dev, "HCDMAB      @0x%08lX : 0x%08X\n",
-                               (unsigned long)addr, readl(addr));
-               }
-       }
-#endif
-}
-
-/**
- * dwc2_dump_global_registers() - Prints the core global registers
- *
- * @hsotg: Programming view of DWC_otg controller
- *
- * NOTE: This function will be removed once the peripheral controller code
- * is integrated and the driver is stable
- */
-void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg)
-{
-#ifdef DEBUG
-       u32 __iomem *addr;
-
-       dev_dbg(hsotg->dev, "Core Global Registers\n");
-       addr = hsotg->regs + GOTGCTL;
-       dev_dbg(hsotg->dev, "GOTGCTL     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GOTGINT;
-       dev_dbg(hsotg->dev, "GOTGINT     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GAHBCFG;
-       dev_dbg(hsotg->dev, "GAHBCFG     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GUSBCFG;
-       dev_dbg(hsotg->dev, "GUSBCFG     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GRSTCTL;
-       dev_dbg(hsotg->dev, "GRSTCTL     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GINTSTS;
-       dev_dbg(hsotg->dev, "GINTSTS     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GINTMSK;
-       dev_dbg(hsotg->dev, "GINTMSK     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GRXSTSR;
-       dev_dbg(hsotg->dev, "GRXSTSR     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GRXFSIZ;
-       dev_dbg(hsotg->dev, "GRXFSIZ     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GNPTXFSIZ;
-       dev_dbg(hsotg->dev, "GNPTXFSIZ   @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GNPTXSTS;
-       dev_dbg(hsotg->dev, "GNPTXSTS    @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GI2CCTL;
-       dev_dbg(hsotg->dev, "GI2CCTL     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GPVNDCTL;
-       dev_dbg(hsotg->dev, "GPVNDCTL    @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GGPIO;
-       dev_dbg(hsotg->dev, "GGPIO       @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GUID;
-       dev_dbg(hsotg->dev, "GUID        @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GSNPSID;
-       dev_dbg(hsotg->dev, "GSNPSID     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GHWCFG1;
-       dev_dbg(hsotg->dev, "GHWCFG1     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GHWCFG2;
-       dev_dbg(hsotg->dev, "GHWCFG2     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GHWCFG3;
-       dev_dbg(hsotg->dev, "GHWCFG3     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GHWCFG4;
-       dev_dbg(hsotg->dev, "GHWCFG4     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GLPMCFG;
-       dev_dbg(hsotg->dev, "GLPMCFG     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GPWRDN;
-       dev_dbg(hsotg->dev, "GPWRDN      @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + GDFIFOCFG;
-       dev_dbg(hsotg->dev, "GDFIFOCFG   @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-       addr = hsotg->regs + HPTXFSIZ;
-       dev_dbg(hsotg->dev, "HPTXFSIZ    @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-
-       addr = hsotg->regs + PCGCTL;
-       dev_dbg(hsotg->dev, "PCGCTL      @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, readl(addr));
-#endif
-}
-
-/**
- * dwc2_flush_tx_fifo() - Flushes a Tx FIFO
- *
- * @hsotg: Programming view of DWC_otg controller
- * @num:   Tx FIFO to flush
- */
-void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num)
-{
-       u32 greset;
-       int count = 0;
-
-       dev_vdbg(hsotg->dev, "Flush Tx FIFO %d\n", num);
-
-       greset = GRSTCTL_TXFFLSH;
-       greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK;
-       writel(greset, hsotg->regs + GRSTCTL);
-
-       do {
-               greset = readl(hsotg->regs + GRSTCTL);
-               if (++count > 10000) {
-                       dev_warn(hsotg->dev,
-                                "%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
-                                __func__, greset,
-                                readl(hsotg->regs + GNPTXSTS));
-                       break;
-               }
-               udelay(1);
-       } while (greset & GRSTCTL_TXFFLSH);
-
-       /* Wait for at least 3 PHY Clocks */
-       udelay(1);
-}
-
-/**
- * dwc2_flush_rx_fifo() - Flushes the Rx FIFO
- *
- * @hsotg: Programming view of DWC_otg controller
- */
-void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg)
-{
-       u32 greset;
-       int count = 0;
-
-       dev_vdbg(hsotg->dev, "%s()\n", __func__);
-
-       greset = GRSTCTL_RXFFLSH;
-       writel(greset, hsotg->regs + GRSTCTL);
-
-       do {
-               greset = readl(hsotg->regs + GRSTCTL);
-               if (++count > 10000) {
-                       dev_warn(hsotg->dev, "%s() HANG! GRSTCTL=%0x\n",
-                                __func__, greset);
-                       break;
-               }
-               udelay(1);
-       } while (greset & GRSTCTL_RXFFLSH);
-
-       /* Wait for at least 3 PHY Clocks */
-       udelay(1);
-}
-
-#define DWC2_OUT_OF_BOUNDS(a, b, c)    ((a) < (b) || (a) > (c))
-
-/* Parameter access functions */
-void dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg, int val)
-{
-       int valid = 1;
-
-       switch (val) {
-       case DWC2_CAP_PARAM_HNP_SRP_CAPABLE:
-               if (hsotg->hw_params.op_mode != GHWCFG2_OP_MODE_HNP_SRP_CAPABLE)
-                       valid = 0;
-               break;
-       case DWC2_CAP_PARAM_SRP_ONLY_CAPABLE:
-               switch (hsotg->hw_params.op_mode) {
-               case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
-               case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
-               case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
-               case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
-                       break;
-               default:
-                       valid = 0;
-                       break;
-               }
-               break;
-       case DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE:
-               /* always valid */
-               break;
-       default:
-               valid = 0;
-               break;
-       }
-
-       if (!valid) {
-               if (val >= 0)
-                       dev_err(hsotg->dev,
-                               "%d invalid for otg_cap parameter. Check HW configuration.\n",
-                               val);
-               switch (hsotg->hw_params.op_mode) {
-               case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
-                       val = DWC2_CAP_PARAM_HNP_SRP_CAPABLE;
-                       break;
-               case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
-               case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
-               case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
-                       val = DWC2_CAP_PARAM_SRP_ONLY_CAPABLE;
-                       break;
-               default:
-                       val = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
-                       break;
-               }
-               dev_dbg(hsotg->dev, "Setting otg_cap to %d\n", val);
-       }
-
-       hsotg->core_params->otg_cap = val;
-}
-
-void dwc2_set_param_dma_enable(struct dwc2_hsotg *hsotg, int val)
-{
-       int valid = 1;
-
-       if (val > 0 && hsotg->hw_params.arch == GHWCFG2_SLAVE_ONLY_ARCH)
-               valid = 0;
-       if (val < 0)
-               valid = 0;
-
-       if (!valid) {
-               if (val >= 0)
-                       dev_err(hsotg->dev,
-                               "%d invalid for dma_enable parameter. Check HW configuration.\n",
-                               val);
-               val = hsotg->hw_params.arch != GHWCFG2_SLAVE_ONLY_ARCH;
-               dev_dbg(hsotg->dev, "Setting dma_enable to %d\n", val);
-       }
-
-       hsotg->core_params->dma_enable = val;
-}
-
-void dwc2_set_param_dma_desc_enable(struct dwc2_hsotg *hsotg, int val)
-{
-       int valid = 1;
-
-       if (val > 0 && (hsotg->core_params->dma_enable <= 0 ||
-                       !hsotg->hw_params.dma_desc_enable))
-               valid = 0;
-       if (val < 0)
-               valid = 0;
-
-       if (!valid) {
-               if (val >= 0)
-                       dev_err(hsotg->dev,
-                               "%d invalid for dma_desc_enable parameter. Check HW configuration.\n",
-                               val);
-               val = (hsotg->core_params->dma_enable > 0 &&
-                       hsotg->hw_params.dma_desc_enable);
-               dev_dbg(hsotg->dev, "Setting dma_desc_enable to %d\n", val);
-       }
-
-       hsotg->core_params->dma_desc_enable = val;
-}
-
-void dwc2_set_param_host_support_fs_ls_low_power(struct dwc2_hsotg *hsotg,
-                                                int val)
-{
-       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
-               if (val >= 0) {
-                       dev_err(hsotg->dev,
-                               "Wrong value for host_support_fs_low_power\n");
-                       dev_err(hsotg->dev,
-                               "host_support_fs_low_power must be 0 or 1\n");
-               }
-               val = 0;
-               dev_dbg(hsotg->dev,
-                       "Setting host_support_fs_low_power to %d\n", val);
-       }
-
-       hsotg->core_params->host_support_fs_ls_low_power = val;
-}
-
-void dwc2_set_param_enable_dynamic_fifo(struct dwc2_hsotg *hsotg, int val)
-{
-       int valid = 1;
-
-       if (val > 0 && !hsotg->hw_params.enable_dynamic_fifo)
-               valid = 0;
-       if (val < 0)
-               valid = 0;
-
-       if (!valid) {
-               if (val >= 0)
-                       dev_err(hsotg->dev,
-                               "%d invalid for enable_dynamic_fifo parameter. Check HW configuration.\n",
-                               val);
-               val = hsotg->hw_params.enable_dynamic_fifo;
-               dev_dbg(hsotg->dev, "Setting enable_dynamic_fifo to %d\n", val);
-       }
-
-       hsotg->core_params->enable_dynamic_fifo = val;
-}
-
-void dwc2_set_param_host_rx_fifo_size(struct dwc2_hsotg *hsotg, int val)
-{
-       int valid = 1;
-
-       if (val < 16 || val > hsotg->hw_params.host_rx_fifo_size)
-               valid = 0;
-
-       if (!valid) {
-               if (val >= 0)
-                       dev_err(hsotg->dev,
-                               "%d invalid for host_rx_fifo_size. Check HW configuration.\n",
-                               val);
-               val = hsotg->hw_params.host_rx_fifo_size;
-               dev_dbg(hsotg->dev, "Setting host_rx_fifo_size to %d\n", val);
-       }
-
-       hsotg->core_params->host_rx_fifo_size = val;
-}
-
-void dwc2_set_param_host_nperio_tx_fifo_size(struct dwc2_hsotg *hsotg, int val)
-{
-       int valid = 1;
-
-       if (val < 16 || val > hsotg->hw_params.host_nperio_tx_fifo_size)
-               valid = 0;
-
-       if (!valid) {
-               if (val >= 0)
-                       dev_err(hsotg->dev,
-                               "%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n",
-                               val);
-               val = hsotg->hw_params.host_nperio_tx_fifo_size;
-               dev_dbg(hsotg->dev, "Setting host_nperio_tx_fifo_size to %d\n",
-                       val);
-       }
-
-       hsotg->core_params->host_nperio_tx_fifo_size = val;
-}
-
-void dwc2_set_param_host_perio_tx_fifo_size(struct dwc2_hsotg *hsotg, int val)
-{
-       int valid = 1;
-
-       if (val < 16 || val > hsotg->hw_params.host_perio_tx_fifo_size)
-               valid = 0;
-
-       if (!valid) {
-               if (val >= 0)
-                       dev_err(hsotg->dev,
-                               "%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n",
-                               val);
-               val = hsotg->hw_params.host_perio_tx_fifo_size;
-               dev_dbg(hsotg->dev, "Setting host_perio_tx_fifo_size to %d\n",
-                       val);
-       }
-
-       hsotg->core_params->host_perio_tx_fifo_size = val;
-}
-
-void dwc2_set_param_max_transfer_size(struct dwc2_hsotg *hsotg, int val)
-{
-       int valid = 1;
-
-       if (val < 2047 || val > hsotg->hw_params.max_transfer_size)
-               valid = 0;
-
-       if (!valid) {
-               if (val >= 0)
-                       dev_err(hsotg->dev,
-                               "%d invalid for max_transfer_size. Check HW configuration.\n",
-                               val);
-               val = hsotg->hw_params.max_transfer_size;
-               dev_dbg(hsotg->dev, "Setting max_transfer_size to %d\n", val);
-       }
-
-       hsotg->core_params->max_transfer_size = val;
-}
-
-void dwc2_set_param_max_packet_count(struct dwc2_hsotg *hsotg, int val)
-{
-       int valid = 1;
-
-       if (val < 15 || val > hsotg->hw_params.max_packet_count)
-               valid = 0;
-
-       if (!valid) {
-               if (val >= 0)
-                       dev_err(hsotg->dev,
-                               "%d invalid for max_packet_count. Check HW configuration.\n",
-                               val);
-               val = hsotg->hw_params.max_packet_count;
-               dev_dbg(hsotg->dev, "Setting max_packet_count to %d\n", val);
-       }
-
-       hsotg->core_params->max_packet_count = val;
-}
-
-void dwc2_set_param_host_channels(struct dwc2_hsotg *hsotg, int val)
-{
-       int valid = 1;
-
-       if (val < 1 || val > hsotg->hw_params.host_channels)
-               valid = 0;
-
-       if (!valid) {
-               if (val >= 0)
-                       dev_err(hsotg->dev,
-                               "%d invalid for host_channels. Check HW configuration.\n",
-                               val);
-               val = hsotg->hw_params.host_channels;
-               dev_dbg(hsotg->dev, "Setting host_channels to %d\n", val);
-       }
-
-       hsotg->core_params->host_channels = val;
-}
-
-void dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg, int val)
-{
-       int valid = 0;
-       u32 hs_phy_type, fs_phy_type;
-
-       if (DWC2_OUT_OF_BOUNDS(val, DWC2_PHY_TYPE_PARAM_FS,
-                              DWC2_PHY_TYPE_PARAM_ULPI)) {
-               if (val >= 0) {
-                       dev_err(hsotg->dev, "Wrong value for phy_type\n");
-                       dev_err(hsotg->dev, "phy_type must be 0, 1 or 2\n");
-               }
-
-               valid = 0;
-       }
-
-       hs_phy_type = hsotg->hw_params.hs_phy_type;
-       fs_phy_type = hsotg->hw_params.fs_phy_type;
-       if (val == DWC2_PHY_TYPE_PARAM_UTMI &&
-           (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI ||
-            hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI))
-               valid = 1;
-       else if (val == DWC2_PHY_TYPE_PARAM_ULPI &&
-                (hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI ||
-                 hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI))
-               valid = 1;
-       else if (val == DWC2_PHY_TYPE_PARAM_FS &&
-                fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED)
-               valid = 1;
-
-       if (!valid) {
-               if (val >= 0)
-                       dev_err(hsotg->dev,
-                               "%d invalid for phy_type. Check HW configuration.\n",
-                               val);
-               val = DWC2_PHY_TYPE_PARAM_FS;
-               if (hs_phy_type != GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED) {
-                       if (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI ||
-                           hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI)
-                               val = DWC2_PHY_TYPE_PARAM_UTMI;
-                       else
-                               val = DWC2_PHY_TYPE_PARAM_ULPI;
-               }
-               dev_dbg(hsotg->dev, "Setting phy_type to %d\n", val);
-       }
-
-       hsotg->core_params->phy_type = val;
-}
-
-static int dwc2_get_param_phy_type(struct dwc2_hsotg *hsotg)
-{
-       return hsotg->core_params->phy_type;
-}
-
-void dwc2_set_param_speed(struct dwc2_hsotg *hsotg, int val)
-{
-       int valid = 1;
-
-       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
-               if (val >= 0) {
-                       dev_err(hsotg->dev, "Wrong value for speed parameter\n");
-                       dev_err(hsotg->dev, "max_speed parameter must be 0 or 1\n");
-               }
-               valid = 0;
-       }
-
-       if (val == DWC2_SPEED_PARAM_HIGH &&
-           dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS)
-               valid = 0;
-
-       if (!valid) {
-               if (val >= 0)
-                       dev_err(hsotg->dev,
-                               "%d invalid for speed parameter. Check HW configuration.\n",
-                               val);
-               val = dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS ?
-                               DWC2_SPEED_PARAM_FULL : DWC2_SPEED_PARAM_HIGH;
-               dev_dbg(hsotg->dev, "Setting speed to %d\n", val);
-       }
-
-       hsotg->core_params->speed = val;
-}
-
-void dwc2_set_param_host_ls_low_power_phy_clk(struct dwc2_hsotg *hsotg, int val)
-{
-       int valid = 1;
-
-       if (DWC2_OUT_OF_BOUNDS(val, DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ,
-                              DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)) {
-               if (val >= 0) {
-                       dev_err(hsotg->dev,
-                               "Wrong value for host_ls_low_power_phy_clk parameter\n");
-                       dev_err(hsotg->dev,
-                               "host_ls_low_power_phy_clk must be 0 or 1\n");
-               }
-               valid = 0;
-       }
-
-       if (val == DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ &&
-           dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS)
-               valid = 0;
-
-       if (!valid) {
-               if (val >= 0)
-                       dev_err(hsotg->dev,
-                               "%d invalid for host_ls_low_power_phy_clk. Check HW configuration.\n",
-                               val);
-               val = dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS
-                       ? DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ
-                       : DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ;
-               dev_dbg(hsotg->dev, "Setting host_ls_low_power_phy_clk to %d\n",
-                       val);
-       }
-
-       hsotg->core_params->host_ls_low_power_phy_clk = val;
-}
-
-void dwc2_set_param_phy_ulpi_ddr(struct dwc2_hsotg *hsotg, int val)
-{
-       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
-               if (val >= 0) {
-                       dev_err(hsotg->dev, "Wrong value for phy_ulpi_ddr\n");
-                       dev_err(hsotg->dev, "phy_upli_ddr must be 0 or 1\n");
-               }
-               val = 0;
-               dev_dbg(hsotg->dev, "Setting phy_upli_ddr to %d\n", val);
-       }
-
-       hsotg->core_params->phy_ulpi_ddr = val;
-}
-
-void dwc2_set_param_phy_ulpi_ext_vbus(struct dwc2_hsotg *hsotg, int val)
-{
-       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
-               if (val >= 0) {
-                       dev_err(hsotg->dev,
-                               "Wrong value for phy_ulpi_ext_vbus\n");
-                       dev_err(hsotg->dev,
-                               "phy_ulpi_ext_vbus must be 0 or 1\n");
-               }
-               val = 0;
-               dev_dbg(hsotg->dev, "Setting phy_ulpi_ext_vbus to %d\n", val);
-       }
-
-       hsotg->core_params->phy_ulpi_ext_vbus = val;
-}
-
-void dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg, int val)
-{
-       int valid = 0;
-
-       switch (hsotg->hw_params.utmi_phy_data_width) {
-       case GHWCFG4_UTMI_PHY_DATA_WIDTH_8:
-               valid = (val == 8);
-               break;
-       case GHWCFG4_UTMI_PHY_DATA_WIDTH_16:
-               valid = (val == 16);
-               break;
-       case GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16:
-               valid = (val == 8 || val == 16);
-               break;
-       }
-
-       if (!valid) {
-               if (val >= 0) {
-                       dev_err(hsotg->dev,
-                               "%d invalid for phy_utmi_width. Check HW configuration.\n",
-                               val);
-               }
-               val = (hsotg->hw_params.utmi_phy_data_width ==
-                      GHWCFG4_UTMI_PHY_DATA_WIDTH_8) ? 8 : 16;
-               dev_dbg(hsotg->dev, "Setting phy_utmi_width to %d\n", val);
-       }
-
-       hsotg->core_params->phy_utmi_width = val;
-}
-
-void dwc2_set_param_ulpi_fs_ls(struct dwc2_hsotg *hsotg, int val)
-{
-       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
-               if (val >= 0) {
-                       dev_err(hsotg->dev, "Wrong value for ulpi_fs_ls\n");
-                       dev_err(hsotg->dev, "ulpi_fs_ls must be 0 or 1\n");
-               }
-               val = 0;
-               dev_dbg(hsotg->dev, "Setting ulpi_fs_ls to %d\n", val);
-       }
-
-       hsotg->core_params->ulpi_fs_ls = val;
-}
-
-void dwc2_set_param_ts_dline(struct dwc2_hsotg *hsotg, int val)
-{
-       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
-               if (val >= 0) {
-                       dev_err(hsotg->dev, "Wrong value for ts_dline\n");
-                       dev_err(hsotg->dev, "ts_dline must be 0 or 1\n");
-               }
-               val = 0;
-               dev_dbg(hsotg->dev, "Setting ts_dline to %d\n", val);
-       }
-
-       hsotg->core_params->ts_dline = val;
-}
-
-void dwc2_set_param_i2c_enable(struct dwc2_hsotg *hsotg, int val)
-{
-       int valid = 1;
-
-       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
-               if (val >= 0) {
-                       dev_err(hsotg->dev, "Wrong value for i2c_enable\n");
-                       dev_err(hsotg->dev, "i2c_enable must be 0 or 1\n");
-               }
-
-               valid = 0;
-       }
-
-       if (val == 1 && !(hsotg->hw_params.i2c_enable))
-               valid = 0;
-
-       if (!valid) {
-               if (val >= 0)
-                       dev_err(hsotg->dev,
-                               "%d invalid for i2c_enable. Check HW configuration.\n",
-                               val);
-               val = hsotg->hw_params.i2c_enable;
-               dev_dbg(hsotg->dev, "Setting i2c_enable to %d\n", val);
-       }
-
-       hsotg->core_params->i2c_enable = val;
-}
-
-void dwc2_set_param_en_multiple_tx_fifo(struct dwc2_hsotg *hsotg, int val)
-{
-       int valid = 1;
-
-       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
-               if (val >= 0) {
-                       dev_err(hsotg->dev,
-                               "Wrong value for en_multiple_tx_fifo,\n");
-                       dev_err(hsotg->dev,
-                               "en_multiple_tx_fifo must be 0 or 1\n");
-               }
-               valid = 0;
-       }
-
-       if (val == 1 && !hsotg->hw_params.en_multiple_tx_fifo)
-               valid = 0;
-
-       if (!valid) {
-               if (val >= 0)
-                       dev_err(hsotg->dev,
-                               "%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n",
-                               val);
-               val = hsotg->hw_params.en_multiple_tx_fifo;
-               dev_dbg(hsotg->dev, "Setting en_multiple_tx_fifo to %d\n", val);
-       }
-
-       hsotg->core_params->en_multiple_tx_fifo = val;
-}
-
-void dwc2_set_param_reload_ctl(struct dwc2_hsotg *hsotg, int val)
-{
-       int valid = 1;
-
-       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
-               if (val >= 0) {
-                       dev_err(hsotg->dev,
-                               "'%d' invalid for parameter reload_ctl\n", val);
-                       dev_err(hsotg->dev, "reload_ctl must be 0 or 1\n");
-               }
-               valid = 0;
-       }
-
-       if (val == 1 && hsotg->hw_params.snpsid < DWC2_CORE_REV_2_92a)
-               valid = 0;
-
-       if (!valid) {
-               if (val >= 0)
-                       dev_err(hsotg->dev,
-                               "%d invalid for parameter reload_ctl. Check HW configuration.\n",
-                               val);
-               val = hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_92a;
-               dev_dbg(hsotg->dev, "Setting reload_ctl to %d\n", val);
-       }
-
-       hsotg->core_params->reload_ctl = val;
-}
-
-void dwc2_set_param_ahbcfg(struct dwc2_hsotg *hsotg, int val)
-{
-       if (val != -1)
-               hsotg->core_params->ahbcfg = val;
-       else
-               hsotg->core_params->ahbcfg = GAHBCFG_HBSTLEN_INCR4 <<
-                                               GAHBCFG_HBSTLEN_SHIFT;
-}
-
-void dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val)
-{
-       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
-               if (val >= 0) {
-                       dev_err(hsotg->dev,
-                               "'%d' invalid for parameter otg_ver\n", val);
-                       dev_err(hsotg->dev,
-                               "otg_ver must be 0 (for OTG 1.3 support) or 1 (for OTG 2.0 support)\n");
-               }
-               val = 0;
-               dev_dbg(hsotg->dev, "Setting otg_ver to %d\n", val);
-       }
-
-       hsotg->core_params->otg_ver = val;
-}
-
-static void dwc2_set_param_uframe_sched(struct dwc2_hsotg *hsotg, int val)
-{
-       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
-               if (val >= 0) {
-                       dev_err(hsotg->dev,
-                               "'%d' invalid for parameter uframe_sched\n",
-                               val);
-                       dev_err(hsotg->dev, "uframe_sched must be 0 or 1\n");
-               }
-               val = 1;
-               dev_dbg(hsotg->dev, "Setting uframe_sched to %d\n", val);
-       }
-
-       hsotg->core_params->uframe_sched = val;
-}
-
-/*
- * This function is called during module intialization to pass module parameters
- * for the DWC_otg core.
- */
-void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
-                        const struct dwc2_core_params *params)
-{
-       dev_dbg(hsotg->dev, "%s()\n", __func__);
-
-       dwc2_set_param_otg_cap(hsotg, params->otg_cap);
-       dwc2_set_param_dma_enable(hsotg, params->dma_enable);
-       dwc2_set_param_dma_desc_enable(hsotg, params->dma_desc_enable);
-       dwc2_set_param_host_support_fs_ls_low_power(hsotg,
-                       params->host_support_fs_ls_low_power);
-       dwc2_set_param_enable_dynamic_fifo(hsotg,
-                       params->enable_dynamic_fifo);
-       dwc2_set_param_host_rx_fifo_size(hsotg,
-                       params->host_rx_fifo_size);
-       dwc2_set_param_host_nperio_tx_fifo_size(hsotg,
-                       params->host_nperio_tx_fifo_size);
-       dwc2_set_param_host_perio_tx_fifo_size(hsotg,
-                       params->host_perio_tx_fifo_size);
-       dwc2_set_param_max_transfer_size(hsotg,
-                       params->max_transfer_size);
-       dwc2_set_param_max_packet_count(hsotg,
-                       params->max_packet_count);
-       dwc2_set_param_host_channels(hsotg, params->host_channels);
-       dwc2_set_param_phy_type(hsotg, params->phy_type);
-       dwc2_set_param_speed(hsotg, params->speed);
-       dwc2_set_param_host_ls_low_power_phy_clk(hsotg,
-                       params->host_ls_low_power_phy_clk);
-       dwc2_set_param_phy_ulpi_ddr(hsotg, params->phy_ulpi_ddr);
-       dwc2_set_param_phy_ulpi_ext_vbus(hsotg,
-                       params->phy_ulpi_ext_vbus);
-       dwc2_set_param_phy_utmi_width(hsotg, params->phy_utmi_width);
-       dwc2_set_param_ulpi_fs_ls(hsotg, params->ulpi_fs_ls);
-       dwc2_set_param_ts_dline(hsotg, params->ts_dline);
-       dwc2_set_param_i2c_enable(hsotg, params->i2c_enable);
-       dwc2_set_param_en_multiple_tx_fifo(hsotg,
-                       params->en_multiple_tx_fifo);
-       dwc2_set_param_reload_ctl(hsotg, params->reload_ctl);
-       dwc2_set_param_ahbcfg(hsotg, params->ahbcfg);
-       dwc2_set_param_otg_ver(hsotg, params->otg_ver);
-       dwc2_set_param_uframe_sched(hsotg, params->uframe_sched);
-}
-
-/**
- * During device initialization, read various hardware configuration
- * registers and interpret the contents.
- */
-int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
-{
-       struct dwc2_hw_params *hw = &hsotg->hw_params;
-       unsigned width;
-       u32 hwcfg1, hwcfg2, hwcfg3, hwcfg4;
-       u32 hptxfsiz, grxfsiz, gnptxfsiz;
-       u32 gusbcfg;
-
-       /*
-        * Attempt to ensure this device is really a DWC_otg Controller.
-        * Read and verify the GSNPSID register contents. The value should be
-        * 0x45f42xxx or 0x45f43xxx, which corresponds to either "OT2" or "OT3",
-        * as in "OTG version 2.xx" or "OTG version 3.xx".
-        */
-       hw->snpsid = readl(hsotg->regs + GSNPSID);
-       if ((hw->snpsid & 0xfffff000) != 0x4f542000 &&
-           (hw->snpsid & 0xfffff000) != 0x4f543000) {
-               dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n",
-                       hw->snpsid);
-               return -ENODEV;
-       }
-
-       dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x (snpsid=%x)\n",
-               hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
-               hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
-
-       hwcfg1 = readl(hsotg->regs + GHWCFG1);
-       hwcfg2 = readl(hsotg->regs + GHWCFG2);
-       hwcfg3 = readl(hsotg->regs + GHWCFG3);
-       hwcfg4 = readl(hsotg->regs + GHWCFG4);
-       gnptxfsiz = readl(hsotg->regs + GNPTXFSIZ);
-       grxfsiz = readl(hsotg->regs + GRXFSIZ);
-
-       dev_dbg(hsotg->dev, "hwcfg1=%08x\n", hwcfg1);
-       dev_dbg(hsotg->dev, "hwcfg2=%08x\n", hwcfg2);
-       dev_dbg(hsotg->dev, "hwcfg3=%08x\n", hwcfg3);
-       dev_dbg(hsotg->dev, "hwcfg4=%08x\n", hwcfg4);
-       dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz);
-       dev_dbg(hsotg->dev, "grxfsiz=%08x\n", grxfsiz);
-
-       /* Force host mode to get HPTXFSIZ exact power on value */
-       gusbcfg = readl(hsotg->regs + GUSBCFG);
-       gusbcfg |= GUSBCFG_FORCEHOSTMODE;
-       writel(gusbcfg, hsotg->regs + GUSBCFG);
-       usleep_range(100000, 150000);
-
-       hptxfsiz = readl(hsotg->regs + HPTXFSIZ);
-       dev_dbg(hsotg->dev, "hptxfsiz=%08x\n", hptxfsiz);
-       gusbcfg = readl(hsotg->regs + GUSBCFG);
-       gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
-       writel(gusbcfg, hsotg->regs + GUSBCFG);
-       usleep_range(100000, 150000);
-
-       /* hwcfg2 */
-       hw->op_mode = (hwcfg2 & GHWCFG2_OP_MODE_MASK) >>
-                     GHWCFG2_OP_MODE_SHIFT;
-       hw->arch = (hwcfg2 & GHWCFG2_ARCHITECTURE_MASK) >>
-                  GHWCFG2_ARCHITECTURE_SHIFT;
-       hw->enable_dynamic_fifo = !!(hwcfg2 & GHWCFG2_DYNAMIC_FIFO);
-       hw->host_channels = 1 + ((hwcfg2 & GHWCFG2_NUM_HOST_CHAN_MASK) >>
-                               GHWCFG2_NUM_HOST_CHAN_SHIFT);
-       hw->hs_phy_type = (hwcfg2 & GHWCFG2_HS_PHY_TYPE_MASK) >>
-                         GHWCFG2_HS_PHY_TYPE_SHIFT;
-       hw->fs_phy_type = (hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK) >>
-                         GHWCFG2_FS_PHY_TYPE_SHIFT;
-       hw->num_dev_ep = (hwcfg2 & GHWCFG2_NUM_DEV_EP_MASK) >>
-                        GHWCFG2_NUM_DEV_EP_SHIFT;
-       hw->nperio_tx_q_depth =
-               (hwcfg2 & GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK) >>
-               GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT << 1;
-       hw->host_perio_tx_q_depth =
-               (hwcfg2 & GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK) >>
-               GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT << 1;
-       hw->dev_token_q_depth =
-               (hwcfg2 & GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK) >>
-               GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT;
-
-       /* hwcfg3 */
-       width = (hwcfg3 & GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK) >>
-               GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT;
-       hw->max_transfer_size = (1 << (width + 11)) - 1;
-       width = (hwcfg3 & GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK) >>
-               GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT;
-       hw->max_packet_count = (1 << (width + 4)) - 1;
-       hw->i2c_enable = !!(hwcfg3 & GHWCFG3_I2C);
-       hw->total_fifo_size = (hwcfg3 & GHWCFG3_DFIFO_DEPTH_MASK) >>
-                             GHWCFG3_DFIFO_DEPTH_SHIFT;
-
-       /* hwcfg4 */
-       hw->en_multiple_tx_fifo = !!(hwcfg4 & GHWCFG4_DED_FIFO_EN);
-       hw->num_dev_perio_in_ep = (hwcfg4 & GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK) >>
-                                 GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT;
-       hw->dma_desc_enable = !!(hwcfg4 & GHWCFG4_DESC_DMA);
-       hw->power_optimized = !!(hwcfg4 & GHWCFG4_POWER_OPTIMIZ);
-       hw->utmi_phy_data_width = (hwcfg4 & GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK) >>
-                                 GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT;
-
-       /* fifo sizes */
-       hw->host_rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >>
-                               GRXFSIZ_DEPTH_SHIFT;
-       hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >>
-                                      FIFOSIZE_DEPTH_SHIFT;
-       hw->host_perio_tx_fifo_size = (hptxfsiz & FIFOSIZE_DEPTH_MASK) >>
-                                     FIFOSIZE_DEPTH_SHIFT;
-
-       dev_dbg(hsotg->dev, "Detected values from hardware:\n");
-       dev_dbg(hsotg->dev, "  op_mode=%d\n",
-               hw->op_mode);
-       dev_dbg(hsotg->dev, "  arch=%d\n",
-               hw->arch);
-       dev_dbg(hsotg->dev, "  dma_desc_enable=%d\n",
-               hw->dma_desc_enable);
-       dev_dbg(hsotg->dev, "  power_optimized=%d\n",
-               hw->power_optimized);
-       dev_dbg(hsotg->dev, "  i2c_enable=%d\n",
-               hw->i2c_enable);
-       dev_dbg(hsotg->dev, "  hs_phy_type=%d\n",
-               hw->hs_phy_type);
-       dev_dbg(hsotg->dev, "  fs_phy_type=%d\n",
-               hw->fs_phy_type);
-       dev_dbg(hsotg->dev, "  utmi_phy_data_wdith=%d\n",
-               hw->utmi_phy_data_width);
-       dev_dbg(hsotg->dev, "  num_dev_ep=%d\n",
-               hw->num_dev_ep);
-       dev_dbg(hsotg->dev, "  num_dev_perio_in_ep=%d\n",
-               hw->num_dev_perio_in_ep);
-       dev_dbg(hsotg->dev, "  host_channels=%d\n",
-               hw->host_channels);
-       dev_dbg(hsotg->dev, "  max_transfer_size=%d\n",
-               hw->max_transfer_size);
-       dev_dbg(hsotg->dev, "  max_packet_count=%d\n",
-               hw->max_packet_count);
-       dev_dbg(hsotg->dev, "  nperio_tx_q_depth=0x%0x\n",
-               hw->nperio_tx_q_depth);
-       dev_dbg(hsotg->dev, "  host_perio_tx_q_depth=0x%0x\n",
-               hw->host_perio_tx_q_depth);
-       dev_dbg(hsotg->dev, "  dev_token_q_depth=0x%0x\n",
-               hw->dev_token_q_depth);
-       dev_dbg(hsotg->dev, "  enable_dynamic_fifo=%d\n",
-               hw->enable_dynamic_fifo);
-       dev_dbg(hsotg->dev, "  en_multiple_tx_fifo=%d\n",
-               hw->en_multiple_tx_fifo);
-       dev_dbg(hsotg->dev, "  total_fifo_size=%d\n",
-               hw->total_fifo_size);
-       dev_dbg(hsotg->dev, "  host_rx_fifo_size=%d\n",
-               hw->host_rx_fifo_size);
-       dev_dbg(hsotg->dev, "  host_nperio_tx_fifo_size=%d\n",
-               hw->host_nperio_tx_fifo_size);
-       dev_dbg(hsotg->dev, "  host_perio_tx_fifo_size=%d\n",
-               hw->host_perio_tx_fifo_size);
-       dev_dbg(hsotg->dev, "\n");
-
-       return 0;
-}
-
-u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg)
-{
-       return hsotg->core_params->otg_ver == 1 ? 0x0200 : 0x0103;
-}
-
-bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg)
-{
-       if (readl(hsotg->regs + GSNPSID) == 0xffffffff)
-               return false;
-       else
-               return true;
-}
-
-/**
- * dwc2_enable_global_interrupts() - Enables the controller's Global
- * Interrupt in the AHB Config register
- *
- * @hsotg: Programming view of DWC_otg controller
- */
-void dwc2_enable_global_interrupts(struct dwc2_hsotg *hsotg)
-{
-       u32 ahbcfg = readl(hsotg->regs + GAHBCFG);
-
-       ahbcfg |= GAHBCFG_GLBL_INTR_EN;
-       writel(ahbcfg, hsotg->regs + GAHBCFG);
-}
-
-/**
- * dwc2_disable_global_interrupts() - Disables the controller's Global
- * Interrupt in the AHB Config register
- *
- * @hsotg: Programming view of DWC_otg controller
- */
-void dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg)
-{
-       u32 ahbcfg = readl(hsotg->regs + GAHBCFG);
-
-       ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
-       writel(ahbcfg, hsotg->regs + GAHBCFG);
-}
-
-MODULE_DESCRIPTION("DESIGNWARE HS OTG Core");
-MODULE_AUTHOR("Synopsys, Inc.");
-MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/staging/dwc2/core.h b/drivers/staging/dwc2/core.h
deleted file mode 100644 (file)
index 648519c..0000000
+++ /dev/null
@@ -1,768 +0,0 @@
-/*
- * core.h - DesignWare HS OTG Controller common declarations
- *
- * Copyright (C) 2004-2013 Synopsys, Inc.
- *
- * 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") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * 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 __DWC2_CORE_H__
-#define __DWC2_CORE_H__
-
-#include <linux/usb/phy.h>
-#include "hw.h"
-
-#ifdef DWC2_LOG_WRITES
-static inline void do_write(u32 value, void *addr)
-{
-       writel(value, addr);
-       pr_info("INFO:: wrote %08x to %p\n", value, addr);
-}
-
-#undef writel
-#define writel(v, a)   do_write(v, a)
-#endif
-
-/* Maximum number of Endpoints/HostChannels */
-#define MAX_EPS_CHANNELS       16
-
-struct dwc2_hsotg;
-struct dwc2_host_chan;
-
-/* Device States */
-enum dwc2_lx_state {
-       DWC2_L0,        /* On state */
-       DWC2_L1,        /* LPM sleep state */
-       DWC2_L2,        /* USB suspend state */
-       DWC2_L3,        /* Off state */
-};
-
-/**
- * struct dwc2_core_params - Parameters for configuring the core
- *
- * @otg_cap:            Specifies the OTG capabilities.
- *                       0 - HNP and SRP capable
- *                       1 - SRP Only capable
- *                       2 - No HNP/SRP capable (always available)
- *                      Defaults to best available option (0, 1, then 2)
- * @otg_ver:            OTG version supported
- *                       0 - 1.3 (default)
- *                       1 - 2.0
- * @dma_enable:         Specifies whether to use slave or DMA mode for accessing
- *                      the data FIFOs. The driver will automatically detect the
- *                      value for this parameter if none is specified.
- *                       0 - Slave (always available)
- *                       1 - DMA (default, if available)
- * @dma_desc_enable:    When DMA mode is enabled, specifies whether to use
- *                      address DMA mode or descriptor DMA mode for accessing
- *                      the data FIFOs. The driver will automatically detect the
- *                      value for this if none is specified.
- *                       0 - Address DMA
- *                       1 - Descriptor DMA (default, if available)
- * @speed:              Specifies the maximum speed of operation in host and
- *                      device mode. The actual speed depends on the speed of
- *                      the attached device and the value of phy_type.
- *                       0 - High Speed
- *                           (default when phy_type is UTMI+ or ULPI)
- *                       1 - Full Speed
- *                           (default when phy_type is Full Speed)
- * @enable_dynamic_fifo: 0 - Use coreConsultant-specified FIFO size parameters
- *                       1 - Allow dynamic FIFO sizing (default, if available)
- * @en_multiple_tx_fifo: Specifies whether dedicated per-endpoint transmit FIFOs
- *                      are enabled
- * @host_rx_fifo_size:  Number of 4-byte words in the Rx FIFO in host mode when
- *                      dynamic FIFO sizing is enabled
- *                       16 to 32768
- *                      Actual maximum value is autodetected and also
- *                      the default.
- * @host_nperio_tx_fifo_size: Number of 4-byte words in the non-periodic Tx FIFO
- *                      in host mode when dynamic FIFO sizing is enabled
- *                       16 to 32768
- *                      Actual maximum value is autodetected and also
- *                      the default.
- * @host_perio_tx_fifo_size: Number of 4-byte words in the periodic Tx FIFO in
- *                      host mode when dynamic FIFO sizing is enabled
- *                       16 to 32768
- *                      Actual maximum value is autodetected and also
- *                      the default.
- * @max_transfer_size:  The maximum transfer size supported, in bytes
- *                       2047 to 65,535
- *                      Actual maximum value is autodetected and also
- *                      the default.
- * @max_packet_count:   The maximum number of packets in a transfer
- *                       15 to 511
- *                      Actual maximum value is autodetected and also
- *                      the default.
- * @host_channels:      The number of host channel registers to use
- *                       1 to 16
- *                      Actual maximum value is autodetected and also
- *                      the default.
- * @phy_type:           Specifies the type of PHY interface to use. By default,
- *                      the driver will automatically detect the phy_type.
- *                       0 - Full Speed Phy
- *                       1 - UTMI+ Phy
- *                       2 - ULPI Phy
- *                      Defaults to best available option (2, 1, then 0)
- * @phy_utmi_width:     Specifies the UTMI+ Data Width (in bits). This parameter
- *                      is applicable for a phy_type of UTMI+ or ULPI. (For a
- *                      ULPI phy_type, this parameter indicates the data width
- *                      between the MAC and the ULPI Wrapper.) Also, this
- *                      parameter is applicable only if the OTG_HSPHY_WIDTH cC
- *                      parameter was set to "8 and 16 bits", meaning that the
- *                      core has been configured to work at either data path
- *                      width.
- *                       8 or 16 (default 16 if available)
- * @phy_ulpi_ddr:       Specifies whether the ULPI operates at double or single
- *                      data rate. This parameter is only applicable if phy_type
- *                      is ULPI.
- *                       0 - single data rate ULPI interface with 8 bit wide
- *                           data bus (default)
- *                       1 - double data rate ULPI interface with 4 bit wide
- *                           data bus
- * @phy_ulpi_ext_vbus:  For a ULPI phy, specifies whether to use the internal or
- *                      external supply to drive the VBus
- *                       0 - Internal supply (default)
- *                       1 - External supply
- * @i2c_enable:         Specifies whether to use the I2Cinterface for a full
- *                      speed PHY. This parameter is only applicable if phy_type
- *                      is FS.
- *                       0 - No (default)
- *                       1 - Yes
- * @ulpi_fs_ls:         Make ULPI phy operate in FS/LS mode only
- *                       0 - No (default)
- *                       1 - Yes
- * @host_support_fs_ls_low_power: Specifies whether low power mode is supported
- *                      when attached to a Full Speed or Low Speed device in
- *                      host mode.
- *                       0 - Don't support low power mode (default)
- *                       1 - Support low power mode
- * @host_ls_low_power_phy_clk: Specifies the PHY clock rate in low power mode
- *                      when connected to a Low Speed device in host
- *                      mode. This parameter is applicable only if
- *                      host_support_fs_ls_low_power is enabled.
- *                       0 - 48 MHz
- *                           (default when phy_type is UTMI+ or ULPI)
- *                       1 - 6 MHz
- *                           (default when phy_type is Full Speed)
- * @ts_dline:           Enable Term Select Dline pulsing
- *                       0 - No (default)
- *                       1 - Yes
- * @reload_ctl:         Allow dynamic reloading of HFIR register during runtime
- *                       0 - No (default for core < 2.92a)
- *                       1 - Yes (default for core >= 2.92a)
- * @ahbcfg:             This field allows the default value of the GAHBCFG
- *                      register to be overridden
- *                       -1         - GAHBCFG value will be set to 0x06
- *                                    (INCR4, default)
- *                       all others - GAHBCFG value will be overridden with
- *                                    this value
- *                      Not all bits can be controlled like this, the
- *                      bits defined by GAHBCFG_CTRL_MASK are controlled
- *                      by the driver and are ignored in this
- *                      configuration value.
- * @uframe_sched:       True to enable the microframe scheduler
- *
- * The following parameters may be specified when starting the module. These
- * parameters define how the DWC_otg controller should be configured. A
- * value of -1 (or any other out of range value) for any parameter means
- * to read the value from hardware (if possible) or use the builtin
- * default described above.
- */
-struct dwc2_core_params {
-       /*
-        * Don't add any non-int members here, this will break
-        * dwc2_set_all_params!
-        */
-       int otg_cap;
-       int otg_ver;
-       int dma_enable;
-       int dma_desc_enable;
-       int speed;
-       int enable_dynamic_fifo;
-       int en_multiple_tx_fifo;
-       int host_rx_fifo_size;
-       int host_nperio_tx_fifo_size;
-       int host_perio_tx_fifo_size;
-       int max_transfer_size;
-       int max_packet_count;
-       int host_channels;
-       int phy_type;
-       int phy_utmi_width;
-       int phy_ulpi_ddr;
-       int phy_ulpi_ext_vbus;
-       int i2c_enable;
-       int ulpi_fs_ls;
-       int host_support_fs_ls_low_power;
-       int host_ls_low_power_phy_clk;
-       int ts_dline;
-       int reload_ctl;
-       int ahbcfg;
-       int uframe_sched;
-};
-
-/**
- * struct dwc2_hw_params - Autodetected parameters.
- *
- * These parameters are the various parameters read from hardware
- * registers during initialization. They typically contain the best
- * supported or maximum value that can be configured in the
- * corresponding dwc2_core_params value.
- *
- * The values that are not in dwc2_core_params are documented below.
- *
- * @op_mode             Mode of Operation
- *                       0 - HNP- and SRP-Capable OTG (Host & Device)
- *                       1 - SRP-Capable OTG (Host & Device)
- *                       2 - Non-HNP and Non-SRP Capable OTG (Host & Device)
- *                       3 - SRP-Capable Device
- *                       4 - Non-OTG Device
- *                       5 - SRP-Capable Host
- *                       6 - Non-OTG Host
- * @arch                Architecture
- *                       0 - Slave only
- *                       1 - External DMA
- *                       2 - Internal DMA
- * @power_optimized     Are power optimizations enabled?
- * @num_dev_ep          Number of device endpoints available
- * @num_dev_perio_in_ep Number of device periodic IN endpoints
- *                      avaialable
- * @dev_token_q_depth   Device Mode IN Token Sequence Learning Queue
- *                      Depth
- *                       0 to 30
- * @host_perio_tx_q_depth
- *                      Host Mode Periodic Request Queue Depth
- *                       2, 4 or 8
- * @nperio_tx_q_depth
- *                      Non-Periodic Request Queue Depth
- *                       2, 4 or 8
- * @hs_phy_type         High-speed PHY interface type
- *                       0 - High-speed interface not supported
- *                       1 - UTMI+
- *                       2 - ULPI
- *                       3 - UTMI+ and ULPI
- * @fs_phy_type         Full-speed PHY interface type
- *                       0 - Full speed interface not supported
- *                       1 - Dedicated full speed interface
- *                       2 - FS pins shared with UTMI+ pins
- *                       3 - FS pins shared with ULPI pins
- * @total_fifo_size:    Total internal RAM for FIFOs (bytes)
- * @utmi_phy_data_width UTMI+ PHY data width
- *                       0 - 8 bits
- *                       1 - 16 bits
- *                       2 - 8 or 16 bits
- * @snpsid:             Value from SNPSID register
- */
-struct dwc2_hw_params {
-       unsigned op_mode:3;
-       unsigned arch:2;
-       unsigned dma_desc_enable:1;
-       unsigned enable_dynamic_fifo:1;
-       unsigned en_multiple_tx_fifo:1;
-       unsigned host_rx_fifo_size:16;
-       unsigned host_nperio_tx_fifo_size:16;
-       unsigned host_perio_tx_fifo_size:16;
-       unsigned nperio_tx_q_depth:3;
-       unsigned host_perio_tx_q_depth:3;
-       unsigned dev_token_q_depth:5;
-       unsigned max_transfer_size:26;
-       unsigned max_packet_count:11;
-       unsigned host_channels:5;
-       unsigned hs_phy_type:2;
-       unsigned fs_phy_type:2;
-       unsigned i2c_enable:1;
-       unsigned num_dev_ep:4;
-       unsigned num_dev_perio_in_ep:4;
-       unsigned total_fifo_size:16;
-       unsigned power_optimized:1;
-       unsigned utmi_phy_data_width:2;
-       u32 snpsid;
-};
-
-/**
- * struct dwc2_hsotg - Holds the state of the driver, including the non-periodic
- * and periodic schedules
- *
- * @dev:                The struct device pointer
- * @regs:              Pointer to controller regs
- * @core_params:        Parameters that define how the core should be configured
- * @hw_params:          Parameters that were autodetected from the
- *                      hardware registers
- * @op_state:           The operational State, during transitions (a_host=>
- *                      a_peripheral and b_device=>b_host) this may not match
- *                      the core, but allows the software to determine
- *                      transitions
- * @queuing_high_bandwidth: True if multiple packets of a high-bandwidth
- *                      transfer are in process of being queued
- * @srp_success:        Stores status of SRP request in the case of a FS PHY
- *                      with an I2C interface
- * @wq_otg:             Workqueue object used for handling of some interrupts
- * @wf_otg:             Work object for handling Connector ID Status Change
- *                      interrupt
- * @wkp_timer:          Timer object for handling Wakeup Detected interrupt
- * @lx_state:           Lx state of connected device
- * @flags:              Flags for handling root port state changes
- * @non_periodic_sched_inactive: Inactive QHs in the non-periodic schedule.
- *                      Transfers associated with these QHs are not currently
- *                      assigned to a host channel.
- * @non_periodic_sched_active: Active QHs in the non-periodic schedule.
- *                      Transfers associated with these QHs are currently
- *                      assigned to a host channel.
- * @non_periodic_qh_ptr: Pointer to next QH to process in the active
- *                      non-periodic schedule
- * @periodic_sched_inactive: Inactive QHs in the periodic schedule. This is a
- *                      list of QHs for periodic transfers that are _not_
- *                      scheduled for the next frame. Each QH in the list has an
- *                      interval counter that determines when it needs to be
- *                      scheduled for execution. This scheduling mechanism
- *                      allows only a simple calculation for periodic bandwidth
- *                      used (i.e. must assume that all periodic transfers may
- *                      need to execute in the same frame). However, it greatly
- *                      simplifies scheduling and should be sufficient for the
- *                      vast majority of OTG hosts, which need to connect to a
- *                      small number of peripherals at one time. Items move from
- *                      this list to periodic_sched_ready when the QH interval
- *                      counter is 0 at SOF.
- * @periodic_sched_ready:  List of periodic QHs that are ready for execution in
- *                      the next frame, but have not yet been assigned to host
- *                      channels. Items move from this list to
- *                      periodic_sched_assigned as host channels become
- *                      available during the current frame.
- * @periodic_sched_assigned: List of periodic QHs to be executed in the next
- *                      frame that are assigned to host channels. Items move
- *                      from this list to periodic_sched_queued as the
- *                      transactions for the QH are queued to the DWC_otg
- *                      controller.
- * @periodic_sched_queued: List of periodic QHs that have been queued for
- *                      execution. Items move from this list to either
- *                      periodic_sched_inactive or periodic_sched_ready when the
- *                      channel associated with the transfer is released. If the
- *                      interval for the QH is 1, the item moves to
- *                      periodic_sched_ready because it must be rescheduled for
- *                      the next frame. Otherwise, the item moves to
- *                      periodic_sched_inactive.
- * @periodic_usecs:     Total bandwidth claimed so far for periodic transfers.
- *                      This value is in microseconds per (micro)frame. The
- *                      assumption is that all periodic transfers may occur in
- *                      the same (micro)frame.
- * @frame_usecs:        Internal variable used by the microframe scheduler
- * @frame_number:       Frame number read from the core at SOF. The value ranges
- *                      from 0 to HFNUM_MAX_FRNUM.
- * @periodic_qh_count:  Count of periodic QHs, if using several eps. Used for
- *                      SOF enable/disable.
- * @free_hc_list:       Free host channels in the controller. This is a list of
- *                      struct dwc2_host_chan items.
- * @periodic_channels:  Number of host channels assigned to periodic transfers.
- *                      Currently assuming that there is a dedicated host
- *                      channel for each periodic transaction and at least one
- *                      host channel is available for non-periodic transactions.
- * @non_periodic_channels: Number of host channels assigned to non-periodic
- *                      transfers
- * @available_host_channels Number of host channels available for the microframe
- *                      scheduler to use
- * @hc_ptr_array:       Array of pointers to the host channel descriptors.
- *                      Allows accessing a host channel descriptor given the
- *                      host channel number. This is useful in interrupt
- *                      handlers.
- * @status_buf:         Buffer used for data received during the status phase of
- *                      a control transfer.
- * @status_buf_dma:     DMA address for status_buf
- * @start_work:         Delayed work for handling host A-cable connection
- * @reset_work:         Delayed work for handling a port reset
- * @lock:               Spinlock that protects all the driver data structures
- * @priv:               Stores a pointer to the struct usb_hcd
- * @otg_port:           OTG port number
- * @frame_list:         Frame list
- * @frame_list_dma:     Frame list DMA address
- */
-struct dwc2_hsotg {
-       struct device *dev;
-       void __iomem *regs;
-       /** Params detected from hardware */
-       struct dwc2_hw_params hw_params;
-       /** Params to actually use */
-       struct dwc2_core_params *core_params;
-       enum usb_otg_state op_state;
-
-       unsigned int queuing_high_bandwidth:1;
-       unsigned int srp_success:1;
-
-       struct workqueue_struct *wq_otg;
-       struct work_struct wf_otg;
-       struct timer_list wkp_timer;
-       enum dwc2_lx_state lx_state;
-
-       union dwc2_hcd_internal_flags {
-               u32 d32;
-               struct {
-                       unsigned port_connect_status_change:1;
-                       unsigned port_connect_status:1;
-                       unsigned port_reset_change:1;
-                       unsigned port_enable_change:1;
-                       unsigned port_suspend_change:1;
-                       unsigned port_over_current_change:1;
-                       unsigned port_l1_change:1;
-                       unsigned reserved:26;
-               } b;
-       } flags;
-
-       struct list_head non_periodic_sched_inactive;
-       struct list_head non_periodic_sched_active;
-       struct list_head *non_periodic_qh_ptr;
-       struct list_head periodic_sched_inactive;
-       struct list_head periodic_sched_ready;
-       struct list_head periodic_sched_assigned;
-       struct list_head periodic_sched_queued;
-       u16 periodic_usecs;
-       u16 frame_usecs[8];
-       u16 frame_number;
-       u16 periodic_qh_count;
-
-#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
-#define FRAME_NUM_ARRAY_SIZE 1000
-       u16 last_frame_num;
-       u16 *frame_num_array;
-       u16 *last_frame_num_array;
-       int frame_num_idx;
-       int dumped_frame_num_array;
-#endif
-
-       struct list_head free_hc_list;
-       int periodic_channels;
-       int non_periodic_channels;
-       int available_host_channels;
-       struct dwc2_host_chan *hc_ptr_array[MAX_EPS_CHANNELS];
-       u8 *status_buf;
-       dma_addr_t status_buf_dma;
-#define DWC2_HCD_STATUS_BUF_SIZE 64
-
-       struct delayed_work start_work;
-       struct delayed_work reset_work;
-       spinlock_t lock;
-       void *priv;
-       u8 otg_port;
-       u32 *frame_list;
-       dma_addr_t frame_list_dma;
-
-       /* DWC OTG HW Release versions */
-#define DWC2_CORE_REV_2_71a    0x4f54271a
-#define DWC2_CORE_REV_2_90a    0x4f54290a
-#define DWC2_CORE_REV_2_92a    0x4f54292a
-#define DWC2_CORE_REV_2_94a    0x4f54294a
-#define DWC2_CORE_REV_3_00a    0x4f54300a
-
-#ifdef DEBUG
-       u32 frrem_samples;
-       u64 frrem_accum;
-
-       u32 hfnum_7_samples_a;
-       u64 hfnum_7_frrem_accum_a;
-       u32 hfnum_0_samples_a;
-       u64 hfnum_0_frrem_accum_a;
-       u32 hfnum_other_samples_a;
-       u64 hfnum_other_frrem_accum_a;
-
-       u32 hfnum_7_samples_b;
-       u64 hfnum_7_frrem_accum_b;
-       u32 hfnum_0_samples_b;
-       u64 hfnum_0_frrem_accum_b;
-       u32 hfnum_other_samples_b;
-       u64 hfnum_other_frrem_accum_b;
-#endif
-};
-
-/* Reasons for halting a host channel */
-enum dwc2_halt_status {
-       DWC2_HC_XFER_NO_HALT_STATUS,
-       DWC2_HC_XFER_COMPLETE,
-       DWC2_HC_XFER_URB_COMPLETE,
-       DWC2_HC_XFER_ACK,
-       DWC2_HC_XFER_NAK,
-       DWC2_HC_XFER_NYET,
-       DWC2_HC_XFER_STALL,
-       DWC2_HC_XFER_XACT_ERR,
-       DWC2_HC_XFER_FRAME_OVERRUN,
-       DWC2_HC_XFER_BABBLE_ERR,
-       DWC2_HC_XFER_DATA_TOGGLE_ERR,
-       DWC2_HC_XFER_AHB_ERR,
-       DWC2_HC_XFER_PERIODIC_INCOMPLETE,
-       DWC2_HC_XFER_URB_DEQUEUE,
-};
-
-/*
- * The following functions support initialization of the core driver component
- * and the DWC_otg controller
- */
-extern void dwc2_core_host_init(struct dwc2_hsotg *hsotg);
-
-/*
- * Host core Functions.
- * The following functions support managing the DWC_otg controller in host
- * mode.
- */
-extern void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan);
-extern void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
-                        enum dwc2_halt_status halt_status);
-extern void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg,
-                           struct dwc2_host_chan *chan);
-extern void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
-                                  struct dwc2_host_chan *chan);
-extern void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
-                                       struct dwc2_host_chan *chan);
-extern int dwc2_hc_continue_transfer(struct dwc2_hsotg *hsotg,
-                                    struct dwc2_host_chan *chan);
-extern void dwc2_hc_do_ping(struct dwc2_hsotg *hsotg,
-                           struct dwc2_host_chan *chan);
-extern void dwc2_enable_host_interrupts(struct dwc2_hsotg *hsotg);
-extern void dwc2_disable_host_interrupts(struct dwc2_hsotg *hsotg);
-
-extern u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg);
-extern bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg);
-
-/*
- * Common core Functions.
- * The following functions support managing the DWC_otg controller in either
- * device or host mode.
- */
-extern void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes);
-extern void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num);
-extern void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg);
-
-extern int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq);
-extern void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd);
-extern void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd);
-
-/* This function should be called on every hardware interrupt. */
-extern irqreturn_t dwc2_handle_common_intr(int irq, void *dev);
-
-/* OTG Core Parameters */
-
-/*
- * Specifies the OTG capabilities. The driver will automatically
- * detect the value for this parameter if none is specified.
- * 0 - HNP and SRP capable (default)
- * 1 - SRP Only capable
- * 2 - No HNP/SRP capable
- */
-extern void dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg, int val);
-#define DWC2_CAP_PARAM_HNP_SRP_CAPABLE         0
-#define DWC2_CAP_PARAM_SRP_ONLY_CAPABLE                1
-#define DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE      2
-
-/*
- * Specifies whether to use slave or DMA mode for accessing the data
- * FIFOs. The driver will automatically detect the value for this
- * parameter if none is specified.
- * 0 - Slave
- * 1 - DMA (default, if available)
- */
-extern void dwc2_set_param_dma_enable(struct dwc2_hsotg *hsotg, int val);
-
-/*
- * When DMA mode is enabled specifies whether to use
- * address DMA or DMA Descritor mode for accessing the data
- * FIFOs in device mode. The driver will automatically detect
- * the value for this parameter if none is specified.
- * 0 - address DMA
- * 1 - DMA Descriptor(default, if available)
- */
-extern void dwc2_set_param_dma_desc_enable(struct dwc2_hsotg *hsotg, int val);
-
-/*
- * Specifies the maximum speed of operation in host and device mode.
- * The actual speed depends on the speed of the attached device and
- * the value of phy_type. The actual speed depends on the speed of the
- * attached device.
- * 0 - High Speed (default)
- * 1 - Full Speed
- */
-extern void dwc2_set_param_speed(struct dwc2_hsotg *hsotg, int val);
-#define DWC2_SPEED_PARAM_HIGH  0
-#define DWC2_SPEED_PARAM_FULL  1
-
-/*
- * Specifies whether low power mode is supported when attached
- * to a Full Speed or Low Speed device in host mode.
- *
- * 0 - Don't support low power mode (default)
- * 1 - Support low power mode
- */
-extern void dwc2_set_param_host_support_fs_ls_low_power(
-               struct dwc2_hsotg *hsotg, int val);
-
-/*
- * Specifies the PHY clock rate in low power mode when connected to a
- * Low Speed device in host mode. This parameter is applicable only if
- * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
- * then defaults to 6 MHZ otherwise 48 MHZ.
- *
- * 0 - 48 MHz
- * 1 - 6 MHz
- */
-extern void dwc2_set_param_host_ls_low_power_phy_clk(struct dwc2_hsotg *hsotg,
-                                                    int val);
-#define DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ     0
-#define DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ      1
-
-/*
- * 0 - Use cC FIFO size parameters
- * 1 - Allow dynamic FIFO sizing (default)
- */
-extern void dwc2_set_param_enable_dynamic_fifo(struct dwc2_hsotg *hsotg,
-                                              int val);
-
-/*
- * Number of 4-byte words in the Rx FIFO in host mode when dynamic
- * FIFO sizing is enabled.
- * 16 to 32768 (default 1024)
- */
-extern void dwc2_set_param_host_rx_fifo_size(struct dwc2_hsotg *hsotg, int val);
-
-/*
- * Number of 4-byte words in the non-periodic Tx FIFO in host mode
- * when Dynamic FIFO sizing is enabled in the core.
- * 16 to 32768 (default 256)
- */
-extern void dwc2_set_param_host_nperio_tx_fifo_size(struct dwc2_hsotg *hsotg,
-                                                   int val);
-
-/*
- * Number of 4-byte words in the host periodic Tx FIFO when dynamic
- * FIFO sizing is enabled.
- * 16 to 32768 (default 256)
- */
-extern void dwc2_set_param_host_perio_tx_fifo_size(struct dwc2_hsotg *hsotg,
-                                                  int val);
-
-/*
- * The maximum transfer size supported in bytes.
- * 2047 to 65,535  (default 65,535)
- */
-extern void dwc2_set_param_max_transfer_size(struct dwc2_hsotg *hsotg, int val);
-
-/*
- * The maximum number of packets in a transfer.
- * 15 to 511  (default 511)
- */
-extern void dwc2_set_param_max_packet_count(struct dwc2_hsotg *hsotg, int val);
-
-/*
- * The number of host channel registers to use.
- * 1 to 16 (default 11)
- * Note: The FPGA configuration supports a maximum of 11 host channels.
- */
-extern void dwc2_set_param_host_channels(struct dwc2_hsotg *hsotg, int val);
-
-/*
- * Specifies the type of PHY interface to use. By default, the driver
- * will automatically detect the phy_type.
- *
- * 0 - Full Speed PHY
- * 1 - UTMI+ (default)
- * 2 - ULPI
- */
-extern void dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg, int val);
-#define DWC2_PHY_TYPE_PARAM_FS         0
-#define DWC2_PHY_TYPE_PARAM_UTMI       1
-#define DWC2_PHY_TYPE_PARAM_ULPI       2
-
-/*
- * Specifies the UTMI+ Data Width. This parameter is
- * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
- * PHY_TYPE, this parameter indicates the data width between
- * the MAC and the ULPI Wrapper.) Also, this parameter is
- * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
- * to "8 and 16 bits", meaning that the core has been
- * configured to work at either data path width.
- *
- * 8 or 16 bits (default 16)
- */
-extern void dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg, int val);
-
-/*
- * Specifies whether the ULPI operates at double or single
- * data rate. This parameter is only applicable if PHY_TYPE is
- * ULPI.
- *
- * 0 - single data rate ULPI interface with 8 bit wide data
- * bus (default)
- * 1 - double data rate ULPI interface with 4 bit wide data
- * bus
- */
-extern void dwc2_set_param_phy_ulpi_ddr(struct dwc2_hsotg *hsotg, int val);
-
-/*
- * Specifies whether to use the internal or external supply to
- * drive the vbus with a ULPI phy.
- */
-extern void dwc2_set_param_phy_ulpi_ext_vbus(struct dwc2_hsotg *hsotg, int val);
-#define DWC2_PHY_ULPI_INTERNAL_VBUS    0
-#define DWC2_PHY_ULPI_EXTERNAL_VBUS    1
-
-/*
- * Specifies whether to use the I2Cinterface for full speed PHY. This
- * parameter is only applicable if PHY_TYPE is FS.
- * 0 - No (default)
- * 1 - Yes
- */
-extern void dwc2_set_param_i2c_enable(struct dwc2_hsotg *hsotg, int val);
-
-extern void dwc2_set_param_ulpi_fs_ls(struct dwc2_hsotg *hsotg, int val);
-
-extern void dwc2_set_param_ts_dline(struct dwc2_hsotg *hsotg, int val);
-
-/*
- * Specifies whether dedicated transmit FIFOs are
- * enabled for non periodic IN endpoints in device mode
- * 0 - No
- * 1 - Yes
- */
-extern void dwc2_set_param_en_multiple_tx_fifo(struct dwc2_hsotg *hsotg,
-                                              int val);
-
-extern void dwc2_set_param_reload_ctl(struct dwc2_hsotg *hsotg, int val);
-
-extern void dwc2_set_param_ahbcfg(struct dwc2_hsotg *hsotg, int val);
-
-extern void dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val);
-
-/*
- * Dump core registers and SPRAM
- */
-extern void dwc2_dump_dev_registers(struct dwc2_hsotg *hsotg);
-extern void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg);
-extern void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg);
-
-/*
- * Return OTG version - either 1.3 or 2.0
- */
-extern u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg);
-
-#endif /* __DWC2_CORE_H__ */
diff --git a/drivers/staging/dwc2/core_intr.c b/drivers/staging/dwc2/core_intr.c
deleted file mode 100644 (file)
index 8205799..0000000
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * core_intr.c - DesignWare HS OTG Controller common interrupt handling
- *
- * Copyright (C) 2004-2013 Synopsys, Inc.
- *
- * 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") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * 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.
- */
-
-/*
- * This file contains the common interrupt handlers
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-
-#include <linux/usb/hcd.h>
-#include <linux/usb/ch11.h>
-
-#include "core.h"
-#include "hcd.h"
-
-static const char *dwc2_op_state_str(struct dwc2_hsotg *hsotg)
-{
-       switch (hsotg->op_state) {
-       case OTG_STATE_A_HOST:
-               return "a_host";
-       case OTG_STATE_A_SUSPEND:
-               return "a_suspend";
-       case OTG_STATE_A_PERIPHERAL:
-               return "a_peripheral";
-       case OTG_STATE_B_PERIPHERAL:
-               return "b_peripheral";
-       case OTG_STATE_B_HOST:
-               return "b_host";
-       default:
-               return "unknown";
-       }
-}
-
-/**
- * dwc2_handle_mode_mismatch_intr() - Logs a mode mismatch warning message
- *
- * @hsotg: Programming view of DWC_otg controller
- */
-static void dwc2_handle_mode_mismatch_intr(struct dwc2_hsotg *hsotg)
-{
-       dev_warn(hsotg->dev, "Mode Mismatch Interrupt: currently in %s mode\n",
-                dwc2_is_host_mode(hsotg) ? "Host" : "Device");
-
-       /* Clear interrupt */
-       writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS);
-}
-
-/**
- * dwc2_handle_otg_intr() - Handles the OTG Interrupts. It reads the OTG
- * Interrupt Register (GOTGINT) to determine what interrupt has occurred.
- *
- * @hsotg: Programming view of DWC_otg controller
- */
-static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
-{
-       u32 gotgint;
-       u32 gotgctl;
-       u32 gintmsk;
-
-       gotgint = readl(hsotg->regs + GOTGINT);
-       gotgctl = readl(hsotg->regs + GOTGCTL);
-       dev_dbg(hsotg->dev, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint,
-               dwc2_op_state_str(hsotg));
-
-       if (gotgint & GOTGINT_SES_END_DET) {
-               dev_dbg(hsotg->dev,
-                       " ++OTG Interrupt: Session End Detected++ (%s)\n",
-                       dwc2_op_state_str(hsotg));
-               gotgctl = readl(hsotg->regs + GOTGCTL);
-
-               if (hsotg->op_state == OTG_STATE_B_HOST) {
-                       hsotg->op_state = OTG_STATE_B_PERIPHERAL;
-               } else {
-                       /*
-                        * If not B_HOST and Device HNP still set, HNP did
-                        * not succeed!
-                        */
-                       if (gotgctl & GOTGCTL_DEVHNPEN) {
-                               dev_dbg(hsotg->dev, "Session End Detected\n");
-                               dev_err(hsotg->dev,
-                                       "Device Not Connected/Responding!\n");
-                       }
-
-                       /*
-                        * If Session End Detected the B-Cable has been
-                        * disconnected
-                        */
-                       /* Reset to a clean state */
-                       hsotg->lx_state = DWC2_L0;
-               }
-
-               gotgctl = readl(hsotg->regs + GOTGCTL);
-               gotgctl &= ~GOTGCTL_DEVHNPEN;
-               writel(gotgctl, hsotg->regs + GOTGCTL);
-       }
-
-       if (gotgint & GOTGINT_SES_REQ_SUC_STS_CHNG) {
-               dev_dbg(hsotg->dev,
-                       " ++OTG Interrupt: Session Request Success Status Change++\n");
-               gotgctl = readl(hsotg->regs + GOTGCTL);
-               if (gotgctl & GOTGCTL_SESREQSCS) {
-                       if (hsotg->core_params->phy_type ==
-                                       DWC2_PHY_TYPE_PARAM_FS
-                           && hsotg->core_params->i2c_enable > 0) {
-                               hsotg->srp_success = 1;
-                       } else {
-                               /* Clear Session Request */
-                               gotgctl = readl(hsotg->regs + GOTGCTL);
-                               gotgctl &= ~GOTGCTL_SESREQ;
-                               writel(gotgctl, hsotg->regs + GOTGCTL);
-                       }
-               }
-       }
-
-       if (gotgint & GOTGINT_HST_NEG_SUC_STS_CHNG) {
-               /*
-                * Print statements during the HNP interrupt handling
-                * can cause it to fail
-                */
-               gotgctl = readl(hsotg->regs + GOTGCTL);
-               /*
-                * WA for 3.00a- HW is not setting cur_mode, even sometimes
-                * this does not help
-                */
-               if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a)
-                       udelay(100);
-               if (gotgctl & GOTGCTL_HSTNEGSCS) {
-                       if (dwc2_is_host_mode(hsotg)) {
-                               hsotg->op_state = OTG_STATE_B_HOST;
-                               /*
-                                * Need to disable SOF interrupt immediately.
-                                * When switching from device to host, the PCD
-                                * interrupt handler won't handle the interrupt
-                                * if host mode is already set. The HCD
-                                * interrupt handler won't get called if the
-                                * HCD state is HALT. This means that the
-                                * interrupt does not get handled and Linux
-                                * complains loudly.
-                                */
-                               gintmsk = readl(hsotg->regs + GINTMSK);
-                               gintmsk &= ~GINTSTS_SOF;
-                               writel(gintmsk, hsotg->regs + GINTMSK);
-
-                               /*
-                                * Call callback function with spin lock
-                                * released
-                                */
-                               spin_unlock(&hsotg->lock);
-
-                               /* Initialize the Core for Host mode */
-                               dwc2_hcd_start(hsotg);
-                               spin_lock(&hsotg->lock);
-                               hsotg->op_state = OTG_STATE_B_HOST;
-                       }
-               } else {
-                       gotgctl = readl(hsotg->regs + GOTGCTL);
-                       gotgctl &= ~(GOTGCTL_HNPREQ | GOTGCTL_DEVHNPEN);
-                       writel(gotgctl, hsotg->regs + GOTGCTL);
-                       dev_dbg(hsotg->dev, "HNP Failed\n");
-                       dev_err(hsotg->dev,
-                               "Device Not Connected/Responding\n");
-               }
-       }
-
-       if (gotgint & GOTGINT_HST_NEG_DET) {
-               /*
-                * The disconnect interrupt is set at the same time as
-                * Host Negotiation Detected. During the mode switch all
-                * interrupts are cleared so the disconnect interrupt
-                * handler will not get executed.
-                */
-               dev_dbg(hsotg->dev,
-                       " ++OTG Interrupt: Host Negotiation Detected++ (%s)\n",
-                       (dwc2_is_host_mode(hsotg) ? "Host" : "Device"));
-               if (dwc2_is_device_mode(hsotg)) {
-                       dev_dbg(hsotg->dev, "a_suspend->a_peripheral (%d)\n",
-                               hsotg->op_state);
-                       spin_unlock(&hsotg->lock);
-                       dwc2_hcd_disconnect(hsotg);
-                       spin_lock(&hsotg->lock);
-                       hsotg->op_state = OTG_STATE_A_PERIPHERAL;
-               } else {
-                       /* Need to disable SOF interrupt immediately */
-                       gintmsk = readl(hsotg->regs + GINTMSK);
-                       gintmsk &= ~GINTSTS_SOF;
-                       writel(gintmsk, hsotg->regs + GINTMSK);
-                       spin_unlock(&hsotg->lock);
-                       dwc2_hcd_start(hsotg);
-                       spin_lock(&hsotg->lock);
-                       hsotg->op_state = OTG_STATE_A_HOST;
-               }
-       }
-
-       if (gotgint & GOTGINT_A_DEV_TOUT_CHG)
-               dev_dbg(hsotg->dev,
-                       " ++OTG Interrupt: A-Device Timeout Change++\n");
-       if (gotgint & GOTGINT_DBNCE_DONE)
-               dev_dbg(hsotg->dev, " ++OTG Interrupt: Debounce Done++\n");
-
-       /* Clear GOTGINT */
-       writel(gotgint, hsotg->regs + GOTGINT);
-}
-
-/**
- * dwc2_handle_conn_id_status_change_intr() - Handles the Connector ID Status
- * Change Interrupt
- *
- * @hsotg: Programming view of DWC_otg controller
- *
- * Reads the OTG Interrupt Register (GOTCTL) to determine whether this is a
- * Device to Host Mode transition or a Host to Device Mode transition. This only
- * occurs when the cable is connected/removed from the PHY connector.
- */
-static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
-{
-       u32 gintmsk = readl(hsotg->regs + GINTMSK);
-
-       /* Need to disable SOF interrupt immediately */
-       gintmsk &= ~GINTSTS_SOF;
-       writel(gintmsk, hsotg->regs + GINTMSK);
-
-       dev_dbg(hsotg->dev, " ++Connector ID Status Change Interrupt++  (%s)\n",
-               dwc2_is_host_mode(hsotg) ? "Host" : "Device");
-
-       /*
-        * Need to schedule a work, as there are possible DELAY function calls.
-        * Release lock before scheduling workq as it holds spinlock during
-        * scheduling.
-        */
-       spin_unlock(&hsotg->lock);
-       queue_work(hsotg->wq_otg, &hsotg->wf_otg);
-       spin_lock(&hsotg->lock);
-
-       /* Clear interrupt */
-       writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS);
-}
-
-/**
- * dwc2_handle_session_req_intr() - This interrupt indicates that a device is
- * initiating the Session Request Protocol to request the host to turn on bus
- * power so a new session can begin
- *
- * @hsotg: Programming view of DWC_otg controller
- *
- * This handler responds by turning on bus power. If the DWC_otg controller is
- * in low power mode, this handler brings the controller out of low power mode
- * before turning on bus power.
- */
-static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
-{
-       dev_dbg(hsotg->dev, "++Session Request Interrupt++\n");
-
-       /* Clear interrupt */
-       writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
-}
-
-/*
- * This interrupt indicates that the DWC_otg controller has detected a
- * resume or remote wakeup sequence. If the DWC_otg controller is in
- * low power mode, the handler must brings the controller out of low
- * power mode. The controller automatically begins resume signaling.
- * The handler schedules a time to stop resume signaling.
- */
-static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
-{
-       dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
-       dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
-
-       if (dwc2_is_device_mode(hsotg)) {
-               dev_dbg(hsotg->dev, "DSTS=0x%0x\n", readl(hsotg->regs + DSTS));
-               if (hsotg->lx_state == DWC2_L2) {
-                       u32 dctl = readl(hsotg->regs + DCTL);
-
-                       /* Clear Remote Wakeup Signaling */
-                       dctl &= ~DCTL_RMTWKUPSIG;
-                       writel(dctl, hsotg->regs + DCTL);
-               }
-               /* Change to L0 state */
-               hsotg->lx_state = DWC2_L0;
-       } else {
-               if (hsotg->lx_state != DWC2_L1) {
-                       u32 pcgcctl = readl(hsotg->regs + PCGCTL);
-
-                       /* Restart the Phy Clock */
-                       pcgcctl &= ~PCGCTL_STOPPCLK;
-                       writel(pcgcctl, hsotg->regs + PCGCTL);
-                       mod_timer(&hsotg->wkp_timer,
-                                 jiffies + msecs_to_jiffies(71));
-               } else {
-                       /* Change to L0 state */
-                       hsotg->lx_state = DWC2_L0;
-               }
-       }
-
-       /* Clear interrupt */
-       writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
-}
-
-/*
- * This interrupt indicates that a device has been disconnected from the
- * root port
- */
-static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
-{
-       dev_dbg(hsotg->dev, "++Disconnect Detected Interrupt++ (%s) %s\n",
-               dwc2_is_host_mode(hsotg) ? "Host" : "Device",
-               dwc2_op_state_str(hsotg));
-
-       /* Change to L3 (OFF) state */
-       hsotg->lx_state = DWC2_L3;
-
-       writel(GINTSTS_DISCONNINT, hsotg->regs + GINTSTS);
-}
-
-/*
- * This interrupt indicates that SUSPEND state has been detected on the USB.
- *
- * For HNP the USB Suspend interrupt signals the change from "a_peripheral"
- * to "a_host".
- *
- * When power management is enabled the core will be put in low power mode.
- */
-static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
-{
-       u32 dsts;
-
-       dev_dbg(hsotg->dev, "USB SUSPEND\n");
-
-       if (dwc2_is_device_mode(hsotg)) {
-               /*
-                * Check the Device status register to determine if the Suspend
-                * state is active
-                */
-               dsts = readl(hsotg->regs + DSTS);
-               dev_dbg(hsotg->dev, "DSTS=0x%0x\n", dsts);
-               dev_dbg(hsotg->dev,
-                       "DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
-                       !!(dsts & DSTS_SUSPSTS),
-                       hsotg->hw_params.power_optimized);
-       } else {
-               if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
-                       dev_dbg(hsotg->dev, "a_peripheral->a_host\n");
-
-                       /* Clear the a_peripheral flag, back to a_host */
-                       spin_unlock(&hsotg->lock);
-                       dwc2_hcd_start(hsotg);
-                       spin_lock(&hsotg->lock);
-                       hsotg->op_state = OTG_STATE_A_HOST;
-               }
-       }
-
-       /* Change to L2 (suspend) state */
-       hsotg->lx_state = DWC2_L2;
-
-       /* Clear interrupt */
-       writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
-}
-
-#define GINTMSK_COMMON (GINTSTS_WKUPINT | GINTSTS_SESSREQINT |         \
-                        GINTSTS_CONIDSTSCHNG | GINTSTS_OTGINT |        \
-                        GINTSTS_MODEMIS | GINTSTS_DISCONNINT |         \
-                        GINTSTS_USBSUSP | GINTSTS_PRTINT)
-
-/*
- * This function returns the Core Interrupt register
- */
-static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg)
-{
-       u32 gintsts;
-       u32 gintmsk;
-       u32 gahbcfg;
-       u32 gintmsk_common = GINTMSK_COMMON;
-
-       gintsts = readl(hsotg->regs + GINTSTS);
-       gintmsk = readl(hsotg->regs + GINTMSK);
-       gahbcfg = readl(hsotg->regs + GAHBCFG);
-
-       /* If any common interrupts set */
-       if (gintsts & gintmsk_common)
-               dev_dbg(hsotg->dev, "gintsts=%08x  gintmsk=%08x\n",
-                       gintsts, gintmsk);
-
-       if (gahbcfg & GAHBCFG_GLBL_INTR_EN)
-               return gintsts & gintmsk & gintmsk_common;
-       else
-               return 0;
-}
-
-/*
- * Common interrupt handler
- *
- * The common interrupts are those that occur in both Host and Device mode.
- * This handler handles the following interrupts:
- * - Mode Mismatch Interrupt
- * - OTG Interrupt
- * - Connector ID Status Change Interrupt
- * - Disconnect Interrupt
- * - Session Request Interrupt
- * - Resume / Remote Wakeup Detected Interrupt
- * - Suspend Interrupt
- */
-irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
-{
-       struct dwc2_hsotg *hsotg = dev;
-       u32 gintsts;
-       irqreturn_t retval = IRQ_NONE;
-
-       if (!dwc2_is_controller_alive(hsotg)) {
-               dev_warn(hsotg->dev, "Controller is dead\n");
-               goto out;
-       }
-
-       spin_lock(&hsotg->lock);
-
-       gintsts = dwc2_read_common_intr(hsotg);
-       if (gintsts & ~GINTSTS_PRTINT)
-               retval = IRQ_HANDLED;
-
-       if (gintsts & GINTSTS_MODEMIS)
-               dwc2_handle_mode_mismatch_intr(hsotg);
-       if (gintsts & GINTSTS_OTGINT)
-               dwc2_handle_otg_intr(hsotg);
-       if (gintsts & GINTSTS_CONIDSTSCHNG)
-               dwc2_handle_conn_id_status_change_intr(hsotg);
-       if (gintsts & GINTSTS_DISCONNINT)
-               dwc2_handle_disconnect_intr(hsotg);
-       if (gintsts & GINTSTS_SESSREQINT)
-               dwc2_handle_session_req_intr(hsotg);
-       if (gintsts & GINTSTS_WKUPINT)
-               dwc2_handle_wakeup_detected_intr(hsotg);
-       if (gintsts & GINTSTS_USBSUSP)
-               dwc2_handle_usb_suspend_intr(hsotg);
-
-       if (gintsts & GINTSTS_PRTINT) {
-               /*
-                * The port interrupt occurs while in device mode with HPRT0
-                * Port Enable/Disable
-                */
-               if (dwc2_is_device_mode(hsotg)) {
-                       dev_dbg(hsotg->dev,
-                               " --Port interrupt received in Device mode--\n");
-                       gintsts = GINTSTS_PRTINT;
-                       writel(gintsts, hsotg->regs + GINTSTS);
-                       retval = 1;
-               }
-       }
-
-       spin_unlock(&hsotg->lock);
-out:
-       return retval;
-}
-EXPORT_SYMBOL_GPL(dwc2_handle_common_intr);
diff --git a/drivers/staging/dwc2/hcd.c b/drivers/staging/dwc2/hcd.c
deleted file mode 100644 (file)
index 07dfe85..0000000
+++ /dev/null
@@ -1,2990 +0,0 @@
-/*
- * hcd.c - DesignWare HS OTG Controller host-mode routines
- *
- * Copyright (C) 2004-2013 Synopsys, Inc.
- *
- * 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") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * 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.
- */
-
-/*
- * This file contains the core HCD code, and implements the Linux hc_driver
- * API
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-
-#include <linux/usb/hcd.h>
-#include <linux/usb/ch11.h>
-
-#include "core.h"
-#include "hcd.h"
-
-/**
- * dwc2_dump_channel_info() - Prints the state of a host channel
- *
- * @hsotg: Programming view of DWC_otg controller
- * @chan:  Pointer to the channel to dump
- *
- * Must be called with interrupt disabled and spinlock held
- *
- * NOTE: This function will be removed once the peripheral controller code
- * is integrated and the driver is stable
- */
-static void dwc2_dump_channel_info(struct dwc2_hsotg *hsotg,
-                                  struct dwc2_host_chan *chan)
-{
-#ifdef VERBOSE_DEBUG
-       int num_channels = hsotg->core_params->host_channels;
-       struct dwc2_qh *qh;
-       u32 hcchar;
-       u32 hcsplt;
-       u32 hctsiz;
-       u32 hc_dma;
-       int i;
-
-       if (chan == NULL)
-               return;
-
-       hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
-       hcsplt = readl(hsotg->regs + HCSPLT(chan->hc_num));
-       hctsiz = readl(hsotg->regs + HCTSIZ(chan->hc_num));
-       hc_dma = readl(hsotg->regs + HCDMA(chan->hc_num));
-
-       dev_dbg(hsotg->dev, "  Assigned to channel %p:\n", chan);
-       dev_dbg(hsotg->dev, "    hcchar 0x%08x, hcsplt 0x%08x\n",
-               hcchar, hcsplt);
-       dev_dbg(hsotg->dev, "    hctsiz 0x%08x, hc_dma 0x%08x\n",
-               hctsiz, hc_dma);
-       dev_dbg(hsotg->dev, "    dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
-               chan->dev_addr, chan->ep_num, chan->ep_is_in);
-       dev_dbg(hsotg->dev, "    ep_type: %d\n", chan->ep_type);
-       dev_dbg(hsotg->dev, "    max_packet: %d\n", chan->max_packet);
-       dev_dbg(hsotg->dev, "    data_pid_start: %d\n", chan->data_pid_start);
-       dev_dbg(hsotg->dev, "    xfer_started: %d\n", chan->xfer_started);
-       dev_dbg(hsotg->dev, "    halt_status: %d\n", chan->halt_status);
-       dev_dbg(hsotg->dev, "    xfer_buf: %p\n", chan->xfer_buf);
-       dev_dbg(hsotg->dev, "    xfer_dma: %08lx\n",
-               (unsigned long)chan->xfer_dma);
-       dev_dbg(hsotg->dev, "    xfer_len: %d\n", chan->xfer_len);
-       dev_dbg(hsotg->dev, "    qh: %p\n", chan->qh);
-       dev_dbg(hsotg->dev, "  NP inactive sched:\n");
-       list_for_each_entry(qh, &hsotg->non_periodic_sched_inactive,
-                           qh_list_entry)
-               dev_dbg(hsotg->dev, "    %p\n", qh);
-       dev_dbg(hsotg->dev, "  NP active sched:\n");
-       list_for_each_entry(qh, &hsotg->non_periodic_sched_active,
-                           qh_list_entry)
-               dev_dbg(hsotg->dev, "    %p\n", qh);
-       dev_dbg(hsotg->dev, "  Channels:\n");
-       for (i = 0; i < num_channels; i++) {
-               struct dwc2_host_chan *chan = hsotg->hc_ptr_array[i];
-
-               dev_dbg(hsotg->dev, "    %2d: %p\n", i, chan);
-       }
-#endif /* VERBOSE_DEBUG */
-}
-
-/*
- * Processes all the URBs in a single list of QHs. Completes them with
- * -ETIMEDOUT and frees the QTD.
- *
- * Must be called with interrupt disabled and spinlock held
- */
-static void dwc2_kill_urbs_in_qh_list(struct dwc2_hsotg *hsotg,
-                                     struct list_head *qh_list)
-{
-       struct dwc2_qh *qh, *qh_tmp;
-       struct dwc2_qtd *qtd, *qtd_tmp;
-
-       list_for_each_entry_safe(qh, qh_tmp, qh_list, qh_list_entry) {
-               list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
-                                        qtd_list_entry) {
-                       dwc2_host_complete(hsotg, qtd, -ETIMEDOUT);
-                       dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
-               }
-       }
-}
-
-static void dwc2_qh_list_free(struct dwc2_hsotg *hsotg,
-                             struct list_head *qh_list)
-{
-       struct dwc2_qtd *qtd, *qtd_tmp;
-       struct dwc2_qh *qh, *qh_tmp;
-       unsigned long flags;
-
-       if (!qh_list->next)
-               /* The list hasn't been initialized yet */
-               return;
-
-       spin_lock_irqsave(&hsotg->lock, flags);
-
-       /* Ensure there are no QTDs or URBs left */
-       dwc2_kill_urbs_in_qh_list(hsotg, qh_list);
-
-       list_for_each_entry_safe(qh, qh_tmp, qh_list, qh_list_entry) {
-               dwc2_hcd_qh_unlink(hsotg, qh);
-
-               /* Free each QTD in the QH's QTD list */
-               list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
-                                        qtd_list_entry)
-                       dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
-
-               spin_unlock_irqrestore(&hsotg->lock, flags);
-               dwc2_hcd_qh_free(hsotg, qh);
-               spin_lock_irqsave(&hsotg->lock, flags);
-       }
-
-       spin_unlock_irqrestore(&hsotg->lock, flags);
-}
-
-/*
- * Responds with an error status of -ETIMEDOUT to all URBs in the non-periodic
- * and periodic schedules. The QTD associated with each URB is removed from
- * the schedule and freed. This function may be called when a disconnect is
- * detected or when the HCD is being stopped.
- *
- * Must be called with interrupt disabled and spinlock held
- */
-static void dwc2_kill_all_urbs(struct dwc2_hsotg *hsotg)
-{
-       dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_inactive);
-       dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_active);
-       dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_inactive);
-       dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_ready);
-       dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_assigned);
-       dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_queued);
-}
-
-/**
- * dwc2_hcd_start() - Starts the HCD when switching to Host mode
- *
- * @hsotg: Pointer to struct dwc2_hsotg
- */
-void dwc2_hcd_start(struct dwc2_hsotg *hsotg)
-{
-       u32 hprt0;
-
-       if (hsotg->op_state == OTG_STATE_B_HOST) {
-               /*
-                * Reset the port. During a HNP mode switch the reset
-                * needs to occur within 1ms and have a duration of at
-                * least 50ms.
-                */
-               hprt0 = dwc2_read_hprt0(hsotg);
-               hprt0 |= HPRT0_RST;
-               writel(hprt0, hsotg->regs + HPRT0);
-       }
-
-       queue_delayed_work(hsotg->wq_otg, &hsotg->start_work,
-                          msecs_to_jiffies(50));
-}
-
-/* Must be called with interrupt disabled and spinlock held */
-static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg)
-{
-       int num_channels = hsotg->core_params->host_channels;
-       struct dwc2_host_chan *channel;
-       u32 hcchar;
-       int i;
-
-       if (hsotg->core_params->dma_enable <= 0) {
-               /* Flush out any channel requests in slave mode */
-               for (i = 0; i < num_channels; i++) {
-                       channel = hsotg->hc_ptr_array[i];
-                       if (!list_empty(&channel->hc_list_entry))
-                               continue;
-                       hcchar = readl(hsotg->regs + HCCHAR(i));
-                       if (hcchar & HCCHAR_CHENA) {
-                               hcchar &= ~(HCCHAR_CHENA | HCCHAR_EPDIR);
-                               hcchar |= HCCHAR_CHDIS;
-                               writel(hcchar, hsotg->regs + HCCHAR(i));
-                       }
-               }
-       }
-
-       for (i = 0; i < num_channels; i++) {
-               channel = hsotg->hc_ptr_array[i];
-               if (!list_empty(&channel->hc_list_entry))
-                       continue;
-               hcchar = readl(hsotg->regs + HCCHAR(i));
-               if (hcchar & HCCHAR_CHENA) {
-                       /* Halt the channel */
-                       hcchar |= HCCHAR_CHDIS;
-                       writel(hcchar, hsotg->regs + HCCHAR(i));
-               }
-
-               dwc2_hc_cleanup(hsotg, channel);
-               list_add_tail(&channel->hc_list_entry, &hsotg->free_hc_list);
-               /*
-                * Added for Descriptor DMA to prevent channel double cleanup in
-                * release_channel_ddma(), which is called from ep_disable when
-                * device disconnects
-                */
-               channel->qh = NULL;
-       }
-}
-
-/**
- * dwc2_hcd_disconnect() - Handles disconnect of the HCD
- *
- * @hsotg: Pointer to struct dwc2_hsotg
- *
- * Must be called with interrupt disabled and spinlock held
- */
-void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
-{
-       u32 intr;
-
-       /* Set status flags for the hub driver */
-       hsotg->flags.b.port_connect_status_change = 1;
-       hsotg->flags.b.port_connect_status = 0;
-
-       /*
-        * Shutdown any transfers in process by clearing the Tx FIFO Empty
-        * interrupt mask and status bits and disabling subsequent host
-        * channel interrupts.
-        */
-       intr = readl(hsotg->regs + GINTMSK);
-       intr &= ~(GINTSTS_NPTXFEMP | GINTSTS_PTXFEMP | GINTSTS_HCHINT);
-       writel(intr, hsotg->regs + GINTMSK);
-       intr = GINTSTS_NPTXFEMP | GINTSTS_PTXFEMP | GINTSTS_HCHINT;
-       writel(intr, hsotg->regs + GINTSTS);
-
-       /*
-        * Turn off the vbus power only if the core has transitioned to device
-        * mode. If still in host mode, need to keep power on to detect a
-        * reconnection.
-        */
-       if (dwc2_is_device_mode(hsotg)) {
-               if (hsotg->op_state != OTG_STATE_A_SUSPEND) {
-                       dev_dbg(hsotg->dev, "Disconnect: PortPower off\n");
-                       writel(0, hsotg->regs + HPRT0);
-               }
-
-               dwc2_disable_host_interrupts(hsotg);
-       }
-
-       /* Respond with an error status to all URBs in the schedule */
-       dwc2_kill_all_urbs(hsotg);
-
-       if (dwc2_is_host_mode(hsotg))
-               /* Clean up any host channels that were in use */
-               dwc2_hcd_cleanup_channels(hsotg);
-
-       dwc2_host_disconnect(hsotg);
-}
-
-/**
- * dwc2_hcd_rem_wakeup() - Handles Remote Wakeup
- *
- * @hsotg: Pointer to struct dwc2_hsotg
- */
-static void dwc2_hcd_rem_wakeup(struct dwc2_hsotg *hsotg)
-{
-       if (hsotg->lx_state == DWC2_L2)
-               hsotg->flags.b.port_suspend_change = 1;
-       else
-               hsotg->flags.b.port_l1_change = 1;
-}
-
-/**
- * dwc2_hcd_stop() - Halts the DWC_otg host mode operations in a clean manner
- *
- * @hsotg: Pointer to struct dwc2_hsotg
- *
- * Must be called with interrupt disabled and spinlock held
- */
-void dwc2_hcd_stop(struct dwc2_hsotg *hsotg)
-{
-       dev_dbg(hsotg->dev, "DWC OTG HCD STOP\n");
-
-       /*
-        * The root hub should be disconnected before this function is called.
-        * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
-        * and the QH lists (via ..._hcd_endpoint_disable).
-        */
-
-       /* Turn off all host-specific interrupts */
-       dwc2_disable_host_interrupts(hsotg);
-
-       /* Turn off the vbus power */
-       dev_dbg(hsotg->dev, "PortPower off\n");
-       writel(0, hsotg->regs + HPRT0);
-}
-
-static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
-                               struct dwc2_hcd_urb *urb, void **ep_handle,
-                               gfp_t mem_flags)
-{
-       struct dwc2_qtd *qtd;
-       unsigned long flags;
-       u32 intr_mask;
-       int retval;
-       int dev_speed;
-
-       if (!hsotg->flags.b.port_connect_status) {
-               /* No longer connected */
-               dev_err(hsotg->dev, "Not connected\n");
-               return -ENODEV;
-       }
-
-       dev_speed = dwc2_host_get_speed(hsotg, urb->priv);
-
-       /* Some configurations cannot support LS traffic on a FS root port */
-       if ((dev_speed == USB_SPEED_LOW) &&
-           (hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED) &&
-           (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI)) {
-               u32 hprt0 = readl(hsotg->regs + HPRT0);
-               u32 prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
-
-               if (prtspd == HPRT0_SPD_FULL_SPEED)
-                       return -ENODEV;
-       }
-
-       qtd = kzalloc(sizeof(*qtd), mem_flags);
-       if (!qtd)
-               return -ENOMEM;
-
-       dwc2_hcd_qtd_init(qtd, urb);
-       retval = dwc2_hcd_qtd_add(hsotg, qtd, (struct dwc2_qh **)ep_handle,
-                                 mem_flags);
-       if (retval) {
-               dev_err(hsotg->dev,
-                       "DWC OTG HCD URB Enqueue failed adding QTD. Error status %d\n",
-                       retval);
-               kfree(qtd);
-               return retval;
-       }
-
-       intr_mask = readl(hsotg->regs + GINTMSK);
-       if (!(intr_mask & GINTSTS_SOF)) {
-               enum dwc2_transaction_type tr_type;
-
-               if (qtd->qh->ep_type == USB_ENDPOINT_XFER_BULK &&
-                   !(qtd->urb->flags & URB_GIVEBACK_ASAP))
-                       /*
-                        * Do not schedule SG transactions until qtd has
-                        * URB_GIVEBACK_ASAP set
-                        */
-                       return 0;
-
-               spin_lock_irqsave(&hsotg->lock, flags);
-               tr_type = dwc2_hcd_select_transactions(hsotg);
-               if (tr_type != DWC2_TRANSACTION_NONE)
-                       dwc2_hcd_queue_transactions(hsotg, tr_type);
-               spin_unlock_irqrestore(&hsotg->lock, flags);
-       }
-
-       return 0;
-}
-
-/* Must be called with interrupt disabled and spinlock held */
-static int dwc2_hcd_urb_dequeue(struct dwc2_hsotg *hsotg,
-                               struct dwc2_hcd_urb *urb)
-{
-       struct dwc2_qh *qh;
-       struct dwc2_qtd *urb_qtd;
-
-       urb_qtd = urb->qtd;
-       if (!urb_qtd) {
-               dev_dbg(hsotg->dev, "## Urb QTD is NULL ##\n");
-               return -EINVAL;
-       }
-
-       qh = urb_qtd->qh;
-       if (!qh) {
-               dev_dbg(hsotg->dev, "## Urb QTD QH is NULL ##\n");
-               return -EINVAL;
-       }
-
-       urb->priv = NULL;
-
-       if (urb_qtd->in_process && qh->channel) {
-               dwc2_dump_channel_info(hsotg, qh->channel);
-
-               /* The QTD is in process (it has been assigned to a channel) */
-               if (hsotg->flags.b.port_connect_status)
-                       /*
-                        * If still connected (i.e. in host mode), halt the
-                        * channel so it can be used for other transfers. If
-                        * no longer connected, the host registers can't be
-                        * written to halt the channel since the core is in
-                        * device mode.
-                        */
-                       dwc2_hc_halt(hsotg, qh->channel,
-                                    DWC2_HC_XFER_URB_DEQUEUE);
-       }
-
-       /*
-        * Free the QTD and clean up the associated QH. Leave the QH in the
-        * schedule if it has any remaining QTDs.
-        */
-       if (hsotg->core_params->dma_desc_enable <= 0) {
-               u8 in_process = urb_qtd->in_process;
-
-               dwc2_hcd_qtd_unlink_and_free(hsotg, urb_qtd, qh);
-               if (in_process) {
-                       dwc2_hcd_qh_deactivate(hsotg, qh, 0);
-                       qh->channel = NULL;
-               } else if (list_empty(&qh->qtd_list)) {
-                       dwc2_hcd_qh_unlink(hsotg, qh);
-               }
-       } else {
-               dwc2_hcd_qtd_unlink_and_free(hsotg, urb_qtd, qh);
-       }
-
-       return 0;
-}
-
-/* Must NOT be called with interrupt disabled or spinlock held */
-static int dwc2_hcd_endpoint_disable(struct dwc2_hsotg *hsotg,
-                                    struct usb_host_endpoint *ep, int retry)
-{
-       struct dwc2_qtd *qtd, *qtd_tmp;
-       struct dwc2_qh *qh;
-       unsigned long flags;
-       int rc;
-
-       spin_lock_irqsave(&hsotg->lock, flags);
-
-       qh = ep->hcpriv;
-       if (!qh) {
-               rc = -EINVAL;
-               goto err;
-       }
-
-       while (!list_empty(&qh->qtd_list) && retry--) {
-               if (retry == 0) {
-                       dev_err(hsotg->dev,
-                               "## timeout in dwc2_hcd_endpoint_disable() ##\n");
-                       rc = -EBUSY;
-                       goto err;
-               }
-
-               spin_unlock_irqrestore(&hsotg->lock, flags);
-               usleep_range(20000, 40000);
-               spin_lock_irqsave(&hsotg->lock, flags);
-               qh = ep->hcpriv;
-               if (!qh) {
-                       rc = -EINVAL;
-                       goto err;
-               }
-       }
-
-       dwc2_hcd_qh_unlink(hsotg, qh);
-
-       /* Free each QTD in the QH's QTD list */
-       list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry)
-               dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
-
-       ep->hcpriv = NULL;
-       spin_unlock_irqrestore(&hsotg->lock, flags);
-       dwc2_hcd_qh_free(hsotg, qh);
-
-       return 0;
-
-err:
-       ep->hcpriv = NULL;
-       spin_unlock_irqrestore(&hsotg->lock, flags);
-
-       return rc;
-}
-
-/* Must be called with interrupt disabled and spinlock held */
-static int dwc2_hcd_endpoint_reset(struct dwc2_hsotg *hsotg,
-                                  struct usb_host_endpoint *ep)
-{
-       struct dwc2_qh *qh = ep->hcpriv;
-
-       if (!qh)
-               return -EINVAL;
-
-       qh->data_toggle = DWC2_HC_PID_DATA0;
-
-       return 0;
-}
-
-/*
- * Initializes dynamic portions of the DWC_otg HCD state
- *
- * Must be called with interrupt disabled and spinlock held
- */
-static void dwc2_hcd_reinit(struct dwc2_hsotg *hsotg)
-{
-       struct dwc2_host_chan *chan, *chan_tmp;
-       int num_channels;
-       int i;
-
-       hsotg->flags.d32 = 0;
-       hsotg->non_periodic_qh_ptr = &hsotg->non_periodic_sched_active;
-
-       if (hsotg->core_params->uframe_sched > 0) {
-               hsotg->available_host_channels =
-                       hsotg->core_params->host_channels;
-       } else {
-               hsotg->non_periodic_channels = 0;
-               hsotg->periodic_channels = 0;
-       }
-
-       /*
-        * Put all channels in the free channel list and clean up channel
-        * states
-        */
-       list_for_each_entry_safe(chan, chan_tmp, &hsotg->free_hc_list,
-                                hc_list_entry)
-               list_del_init(&chan->hc_list_entry);
-
-       num_channels = hsotg->core_params->host_channels;
-       for (i = 0; i < num_channels; i++) {
-               chan = hsotg->hc_ptr_array[i];
-               list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list);
-               dwc2_hc_cleanup(hsotg, chan);
-       }
-
-       /* Initialize the DWC core for host mode operation */
-       dwc2_core_host_init(hsotg);
-}
-
-static void dwc2_hc_init_split(struct dwc2_hsotg *hsotg,
-                              struct dwc2_host_chan *chan,
-                              struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb)
-{
-       int hub_addr, hub_port;
-
-       chan->do_split = 1;
-       chan->xact_pos = qtd->isoc_split_pos;
-       chan->complete_split = qtd->complete_split;
-       dwc2_host_hub_info(hsotg, urb->priv, &hub_addr, &hub_port);
-       chan->hub_addr = (u8)hub_addr;
-       chan->hub_port = (u8)hub_port;
-}
-
-static void *dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg,
-                              struct dwc2_host_chan *chan,
-                              struct dwc2_qtd *qtd, void *bufptr)
-{
-       struct dwc2_hcd_urb *urb = qtd->urb;
-       struct dwc2_hcd_iso_packet_desc *frame_desc;
-
-       switch (dwc2_hcd_get_pipe_type(&urb->pipe_info)) {
-       case USB_ENDPOINT_XFER_CONTROL:
-               chan->ep_type = USB_ENDPOINT_XFER_CONTROL;
-
-               switch (qtd->control_phase) {
-               case DWC2_CONTROL_SETUP:
-                       dev_vdbg(hsotg->dev, "  Control setup transaction\n");
-                       chan->do_ping = 0;
-                       chan->ep_is_in = 0;
-                       chan->data_pid_start = DWC2_HC_PID_SETUP;
-                       if (hsotg->core_params->dma_enable > 0)
-                               chan->xfer_dma = urb->setup_dma;
-                       else
-                               chan->xfer_buf = urb->setup_packet;
-                       chan->xfer_len = 8;
-                       bufptr = NULL;
-                       break;
-
-               case DWC2_CONTROL_DATA:
-                       dev_vdbg(hsotg->dev, "  Control data transaction\n");
-                       chan->data_pid_start = qtd->data_toggle;
-                       break;
-
-               case DWC2_CONTROL_STATUS:
-                       /*
-                        * Direction is opposite of data direction or IN if no
-                        * data
-                        */
-                       dev_vdbg(hsotg->dev, "  Control status transaction\n");
-                       if (urb->length == 0)
-                               chan->ep_is_in = 1;
-                       else
-                               chan->ep_is_in =
-                                       dwc2_hcd_is_pipe_out(&urb->pipe_info);
-                       if (chan->ep_is_in)
-                               chan->do_ping = 0;
-                       chan->data_pid_start = DWC2_HC_PID_DATA1;
-                       chan->xfer_len = 0;
-                       if (hsotg->core_params->dma_enable > 0)
-                               chan->xfer_dma = hsotg->status_buf_dma;
-                       else
-                               chan->xfer_buf = hsotg->status_buf;
-                       bufptr = NULL;
-                       break;
-               }
-               break;
-
-       case USB_ENDPOINT_XFER_BULK:
-               chan->ep_type = USB_ENDPOINT_XFER_BULK;
-               break;
-
-       case USB_ENDPOINT_XFER_INT:
-               chan->ep_type = USB_ENDPOINT_XFER_INT;
-               break;
-
-       case USB_ENDPOINT_XFER_ISOC:
-               chan->ep_type = USB_ENDPOINT_XFER_ISOC;
-               if (hsotg->core_params->dma_desc_enable > 0)
-                       break;
-
-               frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
-               frame_desc->status = 0;
-
-               if (hsotg->core_params->dma_enable > 0) {
-                       chan->xfer_dma = urb->dma;
-                       chan->xfer_dma += frame_desc->offset +
-                                       qtd->isoc_split_offset;
-               } else {
-                       chan->xfer_buf = urb->buf;
-                       chan->xfer_buf += frame_desc->offset +
-                                       qtd->isoc_split_offset;
-               }
-
-               chan->xfer_len = frame_desc->length - qtd->isoc_split_offset;
-
-               /* For non-dword aligned buffers */
-               if (hsotg->core_params->dma_enable > 0 &&
-                   (chan->xfer_dma & 0x3))
-                       bufptr = (u8 *)urb->buf + frame_desc->offset +
-                                       qtd->isoc_split_offset;
-               else
-                       bufptr = NULL;
-
-               if (chan->xact_pos == DWC2_HCSPLT_XACTPOS_ALL) {
-                       if (chan->xfer_len <= 188)
-                               chan->xact_pos = DWC2_HCSPLT_XACTPOS_ALL;
-                       else
-                               chan->xact_pos = DWC2_HCSPLT_XACTPOS_BEGIN;
-               }
-               break;
-       }
-
-       return bufptr;
-}
-
-static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
-                                  struct dwc2_host_chan *chan, void *bufptr)
-{
-       u32 buf_size;
-
-       if (chan->ep_type != USB_ENDPOINT_XFER_ISOC)
-               buf_size = hsotg->core_params->max_transfer_size;
-       else
-               buf_size = 4096;
-
-       if (!qh->dw_align_buf) {
-               qh->dw_align_buf = dma_alloc_coherent(hsotg->dev, buf_size,
-                                                     &qh->dw_align_buf_dma,
-                                                     GFP_ATOMIC);
-               if (!qh->dw_align_buf)
-                       return -ENOMEM;
-       }
-
-       if (!chan->ep_is_in && chan->xfer_len) {
-               dma_sync_single_for_cpu(hsotg->dev, chan->xfer_dma, buf_size,
-                                       DMA_TO_DEVICE);
-               memcpy(qh->dw_align_buf, bufptr, chan->xfer_len);
-               dma_sync_single_for_device(hsotg->dev, chan->xfer_dma, buf_size,
-                                          DMA_TO_DEVICE);
-       }
-
-       chan->align_buf = qh->dw_align_buf_dma;
-       return 0;
-}
-
-/**
- * dwc2_assign_and_init_hc() - Assigns transactions from a QTD to a free host
- * channel and initializes the host channel to perform the transactions. The
- * host channel is removed from the free list.
- *
- * @hsotg: The HCD state structure
- * @qh:    Transactions from the first QTD for this QH are selected and assigned
- *         to a free host channel
- */
-static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
-{
-       struct dwc2_host_chan *chan;
-       struct dwc2_hcd_urb *urb;
-       struct dwc2_qtd *qtd;
-       void *bufptr = NULL;
-
-       if (dbg_qh(qh))
-               dev_vdbg(hsotg->dev, "%s(%p,%p)\n", __func__, hsotg, qh);
-
-       if (list_empty(&qh->qtd_list)) {
-               dev_dbg(hsotg->dev, "No QTDs in QH list\n");
-               return -ENOMEM;
-       }
-
-       if (list_empty(&hsotg->free_hc_list)) {
-               dev_dbg(hsotg->dev, "No free channel to assign\n");
-               return -ENOMEM;
-       }
-
-       chan = list_first_entry(&hsotg->free_hc_list, struct dwc2_host_chan,
-                               hc_list_entry);
-
-       /* Remove host channel from free list */
-       list_del_init(&chan->hc_list_entry);
-
-       qtd = list_first_entry(&qh->qtd_list, struct dwc2_qtd, qtd_list_entry);
-       urb = qtd->urb;
-       qh->channel = chan;
-       qtd->in_process = 1;
-
-       /*
-        * Use usb_pipedevice to determine device address. This address is
-        * 0 before the SET_ADDRESS command and the correct address afterward.
-        */
-       chan->dev_addr = dwc2_hcd_get_dev_addr(&urb->pipe_info);
-       chan->ep_num = dwc2_hcd_get_ep_num(&urb->pipe_info);
-       chan->speed = qh->dev_speed;
-       chan->max_packet = dwc2_max_packet(qh->maxp);
-
-       chan->xfer_started = 0;
-       chan->halt_status = DWC2_HC_XFER_NO_HALT_STATUS;
-       chan->error_state = (qtd->error_count > 0);
-       chan->halt_on_queue = 0;
-       chan->halt_pending = 0;
-       chan->requests = 0;
-
-       /*
-        * The following values may be modified in the transfer type section
-        * below. The xfer_len value may be reduced when the transfer is
-        * started to accommodate the max widths of the XferSize and PktCnt
-        * fields in the HCTSIZn register.
-        */
-
-       chan->ep_is_in = (dwc2_hcd_is_pipe_in(&urb->pipe_info) != 0);
-       if (chan->ep_is_in)
-               chan->do_ping = 0;
-       else
-               chan->do_ping = qh->ping_state;
-
-       chan->data_pid_start = qh->data_toggle;
-       chan->multi_count = 1;
-
-       if (urb->actual_length > urb->length &&
-               !dwc2_hcd_is_pipe_in(&urb->pipe_info))
-               urb->actual_length = urb->length;
-
-       if (hsotg->core_params->dma_enable > 0) {
-               chan->xfer_dma = urb->dma + urb->actual_length;
-
-               /* For non-dword aligned case */
-               if (hsotg->core_params->dma_desc_enable <= 0 &&
-                   (chan->xfer_dma & 0x3))
-                       bufptr = (u8 *)urb->buf + urb->actual_length;
-       } else {
-               chan->xfer_buf = (u8 *)urb->buf + urb->actual_length;
-       }
-
-       chan->xfer_len = urb->length - urb->actual_length;
-       chan->xfer_count = 0;
-
-       /* Set the split attributes if required */
-       if (qh->do_split)
-               dwc2_hc_init_split(hsotg, chan, qtd, urb);
-       else
-               chan->do_split = 0;
-
-       /* Set the transfer attributes */
-       bufptr = dwc2_hc_init_xfer(hsotg, chan, qtd, bufptr);
-
-       /* Non DWORD-aligned buffer case */
-       if (bufptr) {
-               dev_vdbg(hsotg->dev, "Non-aligned buffer\n");
-               if (dwc2_hc_setup_align_buf(hsotg, qh, chan, bufptr)) {
-                       dev_err(hsotg->dev,
-                               "%s: Failed to allocate memory to handle non-dword aligned buffer\n",
-                               __func__);
-                       /* Add channel back to free list */
-                       chan->align_buf = 0;
-                       chan->multi_count = 0;
-                       list_add_tail(&chan->hc_list_entry,
-                                     &hsotg->free_hc_list);
-                       qtd->in_process = 0;
-                       qh->channel = NULL;
-                       return -ENOMEM;
-               }
-       } else {
-               chan->align_buf = 0;
-       }
-
-       if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
-           chan->ep_type == USB_ENDPOINT_XFER_ISOC)
-               /*
-                * This value may be modified when the transfer is started
-                * to reflect the actual transfer length
-                */
-               chan->multi_count = dwc2_hb_mult(qh->maxp);
-
-       if (hsotg->core_params->dma_desc_enable > 0)
-               chan->desc_list_addr = qh->desc_list_dma;
-
-       dwc2_hc_init(hsotg, chan);
-       chan->qh = qh;
-
-       return 0;
-}
-
-/**
- * dwc2_hcd_select_transactions() - Selects transactions from the HCD transfer
- * schedule and assigns them to available host channels. Called from the HCD
- * interrupt handler functions.
- *
- * @hsotg: The HCD state structure
- *
- * Return: The types of new transactions that were assigned to host channels
- */
-enum dwc2_transaction_type dwc2_hcd_select_transactions(
-               struct dwc2_hsotg *hsotg)
-{
-       enum dwc2_transaction_type ret_val = DWC2_TRANSACTION_NONE;
-       struct list_head *qh_ptr;
-       struct dwc2_qh *qh;
-       int num_channels;
-
-#ifdef DWC2_DEBUG_SOF
-       dev_vdbg(hsotg->dev, "  Select Transactions\n");
-#endif
-
-       /* Process entries in the periodic ready list */
-       qh_ptr = hsotg->periodic_sched_ready.next;
-       while (qh_ptr != &hsotg->periodic_sched_ready) {
-               if (list_empty(&hsotg->free_hc_list))
-                       break;
-               if (hsotg->core_params->uframe_sched > 0) {
-                       if (hsotg->available_host_channels <= 1)
-                               break;
-                       hsotg->available_host_channels--;
-               }
-               qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry);
-               if (dwc2_assign_and_init_hc(hsotg, qh))
-                       break;
-
-               /*
-                * Move the QH from the periodic ready schedule to the
-                * periodic assigned schedule
-                */
-               qh_ptr = qh_ptr->next;
-               list_move(&qh->qh_list_entry, &hsotg->periodic_sched_assigned);
-               ret_val = DWC2_TRANSACTION_PERIODIC;
-       }
-
-       /*
-        * Process entries in the inactive portion of the non-periodic
-        * schedule. Some free host channels may not be used if they are
-        * reserved for periodic transfers.
-        */
-       num_channels = hsotg->core_params->host_channels;
-       qh_ptr = hsotg->non_periodic_sched_inactive.next;
-       while (qh_ptr != &hsotg->non_periodic_sched_inactive) {
-               if (hsotg->core_params->uframe_sched <= 0 &&
-                   hsotg->non_periodic_channels >= num_channels -
-                                               hsotg->periodic_channels)
-                       break;
-               if (list_empty(&hsotg->free_hc_list))
-                       break;
-               qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry);
-               if (hsotg->core_params->uframe_sched > 0) {
-                       if (hsotg->available_host_channels < 1)
-                               break;
-                       hsotg->available_host_channels--;
-               }
-
-               if (dwc2_assign_and_init_hc(hsotg, qh))
-                       break;
-
-               /*
-                * Move the QH from the non-periodic inactive schedule to the
-                * non-periodic active schedule
-                */
-               qh_ptr = qh_ptr->next;
-               list_move(&qh->qh_list_entry,
-                         &hsotg->non_periodic_sched_active);
-
-               if (ret_val == DWC2_TRANSACTION_NONE)
-                       ret_val = DWC2_TRANSACTION_NON_PERIODIC;
-               else
-                       ret_val = DWC2_TRANSACTION_ALL;
-
-               if (hsotg->core_params->uframe_sched <= 0)
-                       hsotg->non_periodic_channels++;
-       }
-
-       return ret_val;
-}
-
-/**
- * dwc2_queue_transaction() - Attempts to queue a single transaction request for
- * a host channel associated with either a periodic or non-periodic transfer
- *
- * @hsotg: The HCD state structure
- * @chan:  Host channel descriptor associated with either a periodic or
- *         non-periodic transfer
- * @fifo_dwords_avail: Number of DWORDs available in the periodic Tx FIFO
- *                     for periodic transfers or the non-periodic Tx FIFO
- *                     for non-periodic transfers
- *
- * Return: 1 if a request is queued and more requests may be needed to
- * complete the transfer, 0 if no more requests are required for this
- * transfer, -1 if there is insufficient space in the Tx FIFO
- *
- * This function assumes that there is space available in the appropriate
- * request queue. For an OUT transfer or SETUP transaction in Slave mode,
- * it checks whether space is available in the appropriate Tx FIFO.
- *
- * Must be called with interrupt disabled and spinlock held
- */
-static int dwc2_queue_transaction(struct dwc2_hsotg *hsotg,
-                                 struct dwc2_host_chan *chan,
-                                 u16 fifo_dwords_avail)
-{
-       int retval = 0;
-
-       if (hsotg->core_params->dma_enable > 0) {
-               if (hsotg->core_params->dma_desc_enable > 0) {
-                       if (!chan->xfer_started ||
-                           chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
-                               dwc2_hcd_start_xfer_ddma(hsotg, chan->qh);
-                               chan->qh->ping_state = 0;
-                       }
-               } else if (!chan->xfer_started) {
-                       dwc2_hc_start_transfer(hsotg, chan);
-                       chan->qh->ping_state = 0;
-               }
-       } else if (chan->halt_pending) {
-               /* Don't queue a request if the channel has been halted */
-       } else if (chan->halt_on_queue) {
-               dwc2_hc_halt(hsotg, chan, chan->halt_status);
-       } else if (chan->do_ping) {
-               if (!chan->xfer_started)
-                       dwc2_hc_start_transfer(hsotg, chan);
-       } else if (!chan->ep_is_in ||
-                  chan->data_pid_start == DWC2_HC_PID_SETUP) {
-               if ((fifo_dwords_avail * 4) >= chan->max_packet) {
-                       if (!chan->xfer_started) {
-                               dwc2_hc_start_transfer(hsotg, chan);
-                               retval = 1;
-                       } else {
-                               retval = dwc2_hc_continue_transfer(hsotg, chan);
-                       }
-               } else {
-                       retval = -1;
-               }
-       } else {
-               if (!chan->xfer_started) {
-                       dwc2_hc_start_transfer(hsotg, chan);
-                       retval = 1;
-               } else {
-                       retval = dwc2_hc_continue_transfer(hsotg, chan);
-               }
-       }
-
-       return retval;
-}
-
-/*
- * Processes periodic channels for the next frame and queues transactions for
- * these channels to the DWC_otg controller. After queueing transactions, the
- * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions
- * to queue as Periodic Tx FIFO or request queue space becomes available.
- * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled.
- *
- * Must be called with interrupt disabled and spinlock held
- */
-static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
-{
-       struct list_head *qh_ptr;
-       struct dwc2_qh *qh;
-       u32 tx_status;
-       u32 fspcavail;
-       u32 gintmsk;
-       int status;
-       int no_queue_space = 0;
-       int no_fifo_space = 0;
-       u32 qspcavail;
-
-       if (dbg_perio())
-               dev_vdbg(hsotg->dev, "Queue periodic transactions\n");
-
-       tx_status = readl(hsotg->regs + HPTXSTS);
-       qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
-                   TXSTS_QSPCAVAIL_SHIFT;
-       fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
-                   TXSTS_FSPCAVAIL_SHIFT;
-
-       if (dbg_perio()) {
-               dev_vdbg(hsotg->dev, "  P Tx Req Queue Space Avail (before queue): %d\n",
-                        qspcavail);
-               dev_vdbg(hsotg->dev, "  P Tx FIFO Space Avail (before queue): %d\n",
-                        fspcavail);
-       }
-
-       qh_ptr = hsotg->periodic_sched_assigned.next;
-       while (qh_ptr != &hsotg->periodic_sched_assigned) {
-               tx_status = readl(hsotg->regs + HPTXSTS);
-               qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
-                           TXSTS_QSPCAVAIL_SHIFT;
-               if (qspcavail == 0) {
-                       no_queue_space = 1;
-                       break;
-               }
-
-               qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry);
-               if (!qh->channel) {
-                       qh_ptr = qh_ptr->next;
-                       continue;
-               }
-
-               /* Make sure EP's TT buffer is clean before queueing qtds */
-               if (qh->tt_buffer_dirty) {
-                       qh_ptr = qh_ptr->next;
-                       continue;
-               }
-
-               /*
-                * Set a flag if we're queuing high-bandwidth in slave mode.
-                * The flag prevents any halts to get into the request queue in
-                * the middle of multiple high-bandwidth packets getting queued.
-                */
-               if (hsotg->core_params->dma_enable <= 0 &&
-                               qh->channel->multi_count > 1)
-                       hsotg->queuing_high_bandwidth = 1;
-
-               fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
-                           TXSTS_FSPCAVAIL_SHIFT;
-               status = dwc2_queue_transaction(hsotg, qh->channel, fspcavail);
-               if (status < 0) {
-                       no_fifo_space = 1;
-                       break;
-               }
-
-               /*
-                * In Slave mode, stay on the current transfer until there is
-                * nothing more to do or the high-bandwidth request count is
-                * reached. In DMA mode, only need to queue one request. The
-                * controller automatically handles multiple packets for
-                * high-bandwidth transfers.
-                */
-               if (hsotg->core_params->dma_enable > 0 || status == 0 ||
-                   qh->channel->requests == qh->channel->multi_count) {
-                       qh_ptr = qh_ptr->next;
-                       /*
-                        * Move the QH from the periodic assigned schedule to
-                        * the periodic queued schedule
-                        */
-                       list_move(&qh->qh_list_entry,
-                                 &hsotg->periodic_sched_queued);
-
-                       /* done queuing high bandwidth */
-                       hsotg->queuing_high_bandwidth = 0;
-               }
-       }
-
-       if (hsotg->core_params->dma_enable <= 0) {
-               tx_status = readl(hsotg->regs + HPTXSTS);
-               qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
-                           TXSTS_QSPCAVAIL_SHIFT;
-               fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
-                           TXSTS_FSPCAVAIL_SHIFT;
-               if (dbg_perio()) {
-                       dev_vdbg(hsotg->dev,
-                                "  P Tx Req Queue Space Avail (after queue): %d\n",
-                                qspcavail);
-                       dev_vdbg(hsotg->dev,
-                                "  P Tx FIFO Space Avail (after queue): %d\n",
-                                fspcavail);
-               }
-
-               if (!list_empty(&hsotg->periodic_sched_assigned) ||
-                   no_queue_space || no_fifo_space) {
-                       /*
-                        * May need to queue more transactions as the request
-                        * queue or Tx FIFO empties. Enable the periodic Tx
-                        * FIFO empty interrupt. (Always use the half-empty
-                        * level to ensure that new requests are loaded as
-                        * soon as possible.)
-                        */
-                       gintmsk = readl(hsotg->regs + GINTMSK);
-                       gintmsk |= GINTSTS_PTXFEMP;
-                       writel(gintmsk, hsotg->regs + GINTMSK);
-               } else {
-                       /*
-                        * Disable the Tx FIFO empty interrupt since there are
-                        * no more transactions that need to be queued right
-                        * now. This function is called from interrupt
-                        * handlers to queue more transactions as transfer
-                        * states change.
-                        */
-                       gintmsk = readl(hsotg->regs + GINTMSK);
-                       gintmsk &= ~GINTSTS_PTXFEMP;
-                       writel(gintmsk, hsotg->regs + GINTMSK);
-               }
-       }
-}
-
-/*
- * Processes active non-periodic channels and queues transactions for these
- * channels to the DWC_otg controller. After queueing transactions, the NP Tx
- * FIFO Empty interrupt is enabled if there are more transactions to queue as
- * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx
- * FIFO Empty interrupt is disabled.
- *
- * Must be called with interrupt disabled and spinlock held
- */
-static void dwc2_process_non_periodic_channels(struct dwc2_hsotg *hsotg)
-{
-       struct list_head *orig_qh_ptr;
-       struct dwc2_qh *qh;
-       u32 tx_status;
-       u32 qspcavail;
-       u32 fspcavail;
-       u32 gintmsk;
-       int status;
-       int no_queue_space = 0;
-       int no_fifo_space = 0;
-       int more_to_do = 0;
-
-       dev_vdbg(hsotg->dev, "Queue non-periodic transactions\n");
-
-       tx_status = readl(hsotg->regs + GNPTXSTS);
-       qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
-                   TXSTS_QSPCAVAIL_SHIFT;
-       fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
-                   TXSTS_FSPCAVAIL_SHIFT;
-       dev_vdbg(hsotg->dev, "  NP Tx Req Queue Space Avail (before queue): %d\n",
-                qspcavail);
-       dev_vdbg(hsotg->dev, "  NP Tx FIFO Space Avail (before queue): %d\n",
-                fspcavail);
-
-       /*
-        * Keep track of the starting point. Skip over the start-of-list
-        * entry.
-        */
-       if (hsotg->non_periodic_qh_ptr == &hsotg->non_periodic_sched_active)
-               hsotg->non_periodic_qh_ptr = hsotg->non_periodic_qh_ptr->next;
-       orig_qh_ptr = hsotg->non_periodic_qh_ptr;
-
-       /*
-        * Process once through the active list or until no more space is
-        * available in the request queue or the Tx FIFO
-        */
-       do {
-               tx_status = readl(hsotg->regs + GNPTXSTS);
-               qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
-                           TXSTS_QSPCAVAIL_SHIFT;
-               if (hsotg->core_params->dma_enable <= 0 && qspcavail == 0) {
-                       no_queue_space = 1;
-                       break;
-               }
-
-               qh = list_entry(hsotg->non_periodic_qh_ptr, struct dwc2_qh,
-                               qh_list_entry);
-               if (!qh->channel)
-                       goto next;
-
-               /* Make sure EP's TT buffer is clean before queueing qtds */
-               if (qh->tt_buffer_dirty)
-                       goto next;
-
-               fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
-                           TXSTS_FSPCAVAIL_SHIFT;
-               status = dwc2_queue_transaction(hsotg, qh->channel, fspcavail);
-
-               if (status > 0) {
-                       more_to_do = 1;
-               } else if (status < 0) {
-                       no_fifo_space = 1;
-                       break;
-               }
-next:
-               /* Advance to next QH, skipping start-of-list entry */
-               hsotg->non_periodic_qh_ptr = hsotg->non_periodic_qh_ptr->next;
-               if (hsotg->non_periodic_qh_ptr ==
-                               &hsotg->non_periodic_sched_active)
-                       hsotg->non_periodic_qh_ptr =
-                                       hsotg->non_periodic_qh_ptr->next;
-       } while (hsotg->non_periodic_qh_ptr != orig_qh_ptr);
-
-       if (hsotg->core_params->dma_enable <= 0) {
-               tx_status = readl(hsotg->regs + GNPTXSTS);
-               qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
-                           TXSTS_QSPCAVAIL_SHIFT;
-               fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
-                           TXSTS_FSPCAVAIL_SHIFT;
-               dev_vdbg(hsotg->dev,
-                        "  NP Tx Req Queue Space Avail (after queue): %d\n",
-                        qspcavail);
-               dev_vdbg(hsotg->dev,
-                        "  NP Tx FIFO Space Avail (after queue): %d\n",
-                        fspcavail);
-
-               if (more_to_do || no_queue_space || no_fifo_space) {
-                       /*
-                        * May need to queue more transactions as the request
-                        * queue or Tx FIFO empties. Enable the non-periodic
-                        * Tx FIFO empty interrupt. (Always use the half-empty
-                        * level to ensure that new requests are loaded as
-                        * soon as possible.)
-                        */
-                       gintmsk = readl(hsotg->regs + GINTMSK);
-                       gintmsk |= GINTSTS_NPTXFEMP;
-                       writel(gintmsk, hsotg->regs + GINTMSK);
-               } else {
-                       /*
-                        * Disable the Tx FIFO empty interrupt since there are
-                        * no more transactions that need to be queued right
-                        * now. This function is called from interrupt
-                        * handlers to queue more transactions as transfer
-                        * states change.
-                        */
-                       gintmsk = readl(hsotg->regs + GINTMSK);
-                       gintmsk &= ~GINTSTS_NPTXFEMP;
-                       writel(gintmsk, hsotg->regs + GINTMSK);
-               }
-       }
-}
-
-/**
- * dwc2_hcd_queue_transactions() - Processes the currently active host channels
- * and queues transactions for these channels to the DWC_otg controller. Called
- * from the HCD interrupt handler functions.
- *
- * @hsotg:   The HCD state structure
- * @tr_type: The type(s) of transactions to queue (non-periodic, periodic,
- *           or both)
- *
- * Must be called with interrupt disabled and spinlock held
- */
-void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
-                                enum dwc2_transaction_type tr_type)
-{
-#ifdef DWC2_DEBUG_SOF
-       dev_vdbg(hsotg->dev, "Queue Transactions\n");
-#endif
-       /* Process host channels associated with periodic transfers */
-       if ((tr_type == DWC2_TRANSACTION_PERIODIC ||
-            tr_type == DWC2_TRANSACTION_ALL) &&
-           !list_empty(&hsotg->periodic_sched_assigned))
-               dwc2_process_periodic_channels(hsotg);
-
-       /* Process host channels associated with non-periodic transfers */
-       if (tr_type == DWC2_TRANSACTION_NON_PERIODIC ||
-           tr_type == DWC2_TRANSACTION_ALL) {
-               if (!list_empty(&hsotg->non_periodic_sched_active)) {
-                       dwc2_process_non_periodic_channels(hsotg);
-               } else {
-                       /*
-                        * Ensure NP Tx FIFO empty interrupt is disabled when
-                        * there are no non-periodic transfers to process
-                        */
-                       u32 gintmsk = readl(hsotg->regs + GINTMSK);
-
-                       gintmsk &= ~GINTSTS_NPTXFEMP;
-                       writel(gintmsk, hsotg->regs + GINTMSK);
-               }
-       }
-}
-
-static void dwc2_conn_id_status_change(struct work_struct *work)
-{
-       struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg,
-                                               wf_otg);
-       u32 count = 0;
-       u32 gotgctl;
-
-       dev_dbg(hsotg->dev, "%s()\n", __func__);
-
-       gotgctl = readl(hsotg->regs + GOTGCTL);
-       dev_dbg(hsotg->dev, "gotgctl=%0x\n", gotgctl);
-       dev_dbg(hsotg->dev, "gotgctl.b.conidsts=%d\n",
-               !!(gotgctl & GOTGCTL_CONID_B));
-
-       /* B-Device connector (Device Mode) */
-       if (gotgctl & GOTGCTL_CONID_B) {
-               /* Wait for switch to device mode */
-               dev_dbg(hsotg->dev, "connId B\n");
-               while (!dwc2_is_device_mode(hsotg)) {
-                       dev_info(hsotg->dev,
-                                "Waiting for Peripheral Mode, Mode=%s\n",
-                                dwc2_is_host_mode(hsotg) ? "Host" :
-                                "Peripheral");
-                       usleep_range(20000, 40000);
-                       if (++count > 250)
-                               break;
-               }
-               if (count > 250)
-                       dev_err(hsotg->dev,
-                               "Connection id status change timed out\n");
-               hsotg->op_state = OTG_STATE_B_PERIPHERAL;
-               dwc2_core_init(hsotg, false, -1);
-               dwc2_enable_global_interrupts(hsotg);
-       } else {
-               /* A-Device connector (Host Mode) */
-               dev_dbg(hsotg->dev, "connId A\n");
-               while (!dwc2_is_host_mode(hsotg)) {
-                       dev_info(hsotg->dev, "Waiting for Host Mode, Mode=%s\n",
-                                dwc2_is_host_mode(hsotg) ?
-                                "Host" : "Peripheral");
-                       usleep_range(20000, 40000);
-                       if (++count > 250)
-                               break;
-               }
-               if (count > 250)
-                       dev_err(hsotg->dev,
-                               "Connection id status change timed out\n");
-               hsotg->op_state = OTG_STATE_A_HOST;
-
-               /* Initialize the Core for Host mode */
-               dwc2_core_init(hsotg, false, -1);
-               dwc2_enable_global_interrupts(hsotg);
-               dwc2_hcd_start(hsotg);
-       }
-}
-
-static void dwc2_wakeup_detected(unsigned long data)
-{
-       struct dwc2_hsotg *hsotg = (struct dwc2_hsotg *)data;
-       u32 hprt0;
-
-       dev_dbg(hsotg->dev, "%s()\n", __func__);
-
-       /*
-        * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
-        * so that OPT tests pass with all PHYs.)
-        */
-       hprt0 = dwc2_read_hprt0(hsotg);
-       dev_dbg(hsotg->dev, "Resume: HPRT0=%0x\n", hprt0);
-       hprt0 &= ~HPRT0_RES;
-       writel(hprt0, hsotg->regs + HPRT0);
-       dev_dbg(hsotg->dev, "Clear Resume: HPRT0=%0x\n",
-               readl(hsotg->regs + HPRT0));
-
-       dwc2_hcd_rem_wakeup(hsotg);
-
-       /* Change to L0 state */
-       hsotg->lx_state = DWC2_L0;
-}
-
-static int dwc2_host_is_b_hnp_enabled(struct dwc2_hsotg *hsotg)
-{
-       struct usb_hcd *hcd = dwc2_hsotg_to_hcd(hsotg);
-
-       return hcd->self.b_hnp_enable;
-}
-
-/* Must NOT be called with interrupt disabled or spinlock held */
-static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
-{
-       unsigned long flags;
-       u32 hprt0;
-       u32 pcgctl;
-       u32 gotgctl;
-
-       dev_dbg(hsotg->dev, "%s()\n", __func__);
-
-       spin_lock_irqsave(&hsotg->lock, flags);
-
-       if (windex == hsotg->otg_port && dwc2_host_is_b_hnp_enabled(hsotg)) {
-               gotgctl = readl(hsotg->regs + GOTGCTL);
-               gotgctl |= GOTGCTL_HSTSETHNPEN;
-               writel(gotgctl, hsotg->regs + GOTGCTL);
-               hsotg->op_state = OTG_STATE_A_SUSPEND;
-       }
-
-       hprt0 = dwc2_read_hprt0(hsotg);
-       hprt0 |= HPRT0_SUSP;
-       writel(hprt0, hsotg->regs + HPRT0);
-
-       /* Update lx_state */
-       hsotg->lx_state = DWC2_L2;
-
-       /* Suspend the Phy Clock */
-       pcgctl = readl(hsotg->regs + PCGCTL);
-       pcgctl |= PCGCTL_STOPPCLK;
-       writel(pcgctl, hsotg->regs + PCGCTL);
-       udelay(10);
-
-       /* For HNP the bus must be suspended for at least 200ms */
-       if (dwc2_host_is_b_hnp_enabled(hsotg)) {
-               pcgctl = readl(hsotg->regs + PCGCTL);
-               pcgctl &= ~PCGCTL_STOPPCLK;
-               writel(pcgctl, hsotg->regs + PCGCTL);
-
-               spin_unlock_irqrestore(&hsotg->lock, flags);
-
-               usleep_range(200000, 250000);
-       } else {
-               spin_unlock_irqrestore(&hsotg->lock, flags);
-       }
-}
-
-/* Handles hub class-specific requests */
-static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
-                               u16 wvalue, u16 windex, char *buf, u16 wlength)
-{
-       struct usb_hub_descriptor *hub_desc;
-       int retval = 0;
-       u32 hprt0;
-       u32 port_status;
-       u32 speed;
-       u32 pcgctl;
-
-       switch (typereq) {
-       case ClearHubFeature:
-               dev_dbg(hsotg->dev, "ClearHubFeature %1xh\n", wvalue);
-
-               switch (wvalue) {
-               case C_HUB_LOCAL_POWER:
-               case C_HUB_OVER_CURRENT:
-                       /* Nothing required here */
-                       break;
-
-               default:
-                       retval = -EINVAL;
-                       dev_err(hsotg->dev,
-                               "ClearHubFeature request %1xh unknown\n",
-                               wvalue);
-               }
-               break;
-
-       case ClearPortFeature:
-               if (wvalue != USB_PORT_FEAT_L1)
-                       if (!windex || windex > 1)
-                               goto error;
-               switch (wvalue) {
-               case USB_PORT_FEAT_ENABLE:
-                       dev_dbg(hsotg->dev,
-                               "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
-                       hprt0 = dwc2_read_hprt0(hsotg);
-                       hprt0 |= HPRT0_ENA;
-                       writel(hprt0, hsotg->regs + HPRT0);
-                       break;
-
-               case USB_PORT_FEAT_SUSPEND:
-                       dev_dbg(hsotg->dev,
-                               "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
-                       writel(0, hsotg->regs + PCGCTL);
-                       usleep_range(20000, 40000);
-
-                       hprt0 = dwc2_read_hprt0(hsotg);
-                       hprt0 |= HPRT0_RES;
-                       writel(hprt0, hsotg->regs + HPRT0);
-                       hprt0 &= ~HPRT0_SUSP;
-                       usleep_range(100000, 150000);
-
-                       hprt0 &= ~HPRT0_RES;
-                       writel(hprt0, hsotg->regs + HPRT0);
-                       break;
-
-               case USB_PORT_FEAT_POWER:
-                       dev_dbg(hsotg->dev,
-                               "ClearPortFeature USB_PORT_FEAT_POWER\n");
-                       hprt0 = dwc2_read_hprt0(hsotg);
-                       hprt0 &= ~HPRT0_PWR;
-                       writel(hprt0, hsotg->regs + HPRT0);
-                       break;
-
-               case USB_PORT_FEAT_INDICATOR:
-                       dev_dbg(hsotg->dev,
-                               "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
-                       /* Port indicator not supported */
-                       break;
-
-               case USB_PORT_FEAT_C_CONNECTION:
-                       /*
-                        * Clears driver's internal Connect Status Change flag
-                        */
-                       dev_dbg(hsotg->dev,
-                               "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
-                       hsotg->flags.b.port_connect_status_change = 0;
-                       break;
-
-               case USB_PORT_FEAT_C_RESET:
-                       /* Clears driver's internal Port Reset Change flag */
-                       dev_dbg(hsotg->dev,
-                               "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
-                       hsotg->flags.b.port_reset_change = 0;
-                       break;
-
-               case USB_PORT_FEAT_C_ENABLE:
-                       /*
-                        * Clears the driver's internal Port Enable/Disable
-                        * Change flag
-                        */
-                       dev_dbg(hsotg->dev,
-                               "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
-                       hsotg->flags.b.port_enable_change = 0;
-                       break;
-
-               case USB_PORT_FEAT_C_SUSPEND:
-                       /*
-                        * Clears the driver's internal Port Suspend Change
-                        * flag, which is set when resume signaling on the host
-                        * port is complete
-                        */
-                       dev_dbg(hsotg->dev,
-                               "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
-                       hsotg->flags.b.port_suspend_change = 0;
-                       break;
-
-               case USB_PORT_FEAT_C_PORT_L1:
-                       dev_dbg(hsotg->dev,
-                               "ClearPortFeature USB_PORT_FEAT_C_PORT_L1\n");
-                       hsotg->flags.b.port_l1_change = 0;
-                       break;
-
-               case USB_PORT_FEAT_C_OVER_CURRENT:
-                       dev_dbg(hsotg->dev,
-                               "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
-                       hsotg->flags.b.port_over_current_change = 0;
-                       break;
-
-               default:
-                       retval = -EINVAL;
-                       dev_err(hsotg->dev,
-                               "ClearPortFeature request %1xh unknown or unsupported\n",
-                               wvalue);
-               }
-               break;
-
-       case GetHubDescriptor:
-               dev_dbg(hsotg->dev, "GetHubDescriptor\n");
-               hub_desc = (struct usb_hub_descriptor *)buf;
-               hub_desc->bDescLength = 9;
-               hub_desc->bDescriptorType = 0x29;
-               hub_desc->bNbrPorts = 1;
-               hub_desc->wHubCharacteristics = cpu_to_le16(0x08);
-               hub_desc->bPwrOn2PwrGood = 1;
-               hub_desc->bHubContrCurrent = 0;
-               hub_desc->u.hs.DeviceRemovable[0] = 0;
-               hub_desc->u.hs.DeviceRemovable[1] = 0xff;
-               break;
-
-       case GetHubStatus:
-               dev_dbg(hsotg->dev, "GetHubStatus\n");
-               memset(buf, 0, 4);
-               break;
-
-       case GetPortStatus:
-               dev_vdbg(hsotg->dev,
-                        "GetPortStatus wIndex=0x%04x flags=0x%08x\n", windex,
-                        hsotg->flags.d32);
-               if (!windex || windex > 1)
-                       goto error;
-
-               port_status = 0;
-               if (hsotg->flags.b.port_connect_status_change)
-                       port_status |= USB_PORT_STAT_C_CONNECTION << 16;
-               if (hsotg->flags.b.port_enable_change)
-                       port_status |= USB_PORT_STAT_C_ENABLE << 16;
-               if (hsotg->flags.b.port_suspend_change)
-                       port_status |= USB_PORT_STAT_C_SUSPEND << 16;
-               if (hsotg->flags.b.port_l1_change)
-                       port_status |= USB_PORT_STAT_C_L1 << 16;
-               if (hsotg->flags.b.port_reset_change)
-                       port_status |= USB_PORT_STAT_C_RESET << 16;
-               if (hsotg->flags.b.port_over_current_change) {
-                       dev_warn(hsotg->dev, "Overcurrent change detected\n");
-                       port_status |= USB_PORT_STAT_C_OVERCURRENT << 16;
-               }
-
-               if (!hsotg->flags.b.port_connect_status) {
-                       /*
-                        * The port is disconnected, which means the core is
-                        * either in device mode or it soon will be. Just
-                        * return 0's for the remainder of the port status
-                        * since the port register can't be read if the core
-                        * is in device mode.
-                        */
-                       *(__le32 *)buf = cpu_to_le32(port_status);
-                       break;
-               }
-
-               hprt0 = readl(hsotg->regs + HPRT0);
-               dev_vdbg(hsotg->dev, "  HPRT0: 0x%08x\n", hprt0);
-
-               if (hprt0 & HPRT0_CONNSTS)
-                       port_status |= USB_PORT_STAT_CONNECTION;
-               if (hprt0 & HPRT0_ENA)
-                       port_status |= USB_PORT_STAT_ENABLE;
-               if (hprt0 & HPRT0_SUSP)
-                       port_status |= USB_PORT_STAT_SUSPEND;
-               if (hprt0 & HPRT0_OVRCURRACT)
-                       port_status |= USB_PORT_STAT_OVERCURRENT;
-               if (hprt0 & HPRT0_RST)
-                       port_status |= USB_PORT_STAT_RESET;
-               if (hprt0 & HPRT0_PWR)
-                       port_status |= USB_PORT_STAT_POWER;
-
-               speed = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
-               if (speed == HPRT0_SPD_HIGH_SPEED)
-                       port_status |= USB_PORT_STAT_HIGH_SPEED;
-               else if (speed == HPRT0_SPD_LOW_SPEED)
-                       port_status |= USB_PORT_STAT_LOW_SPEED;
-
-               if (hprt0 & HPRT0_TSTCTL_MASK)
-                       port_status |= USB_PORT_STAT_TEST;
-               /* USB_PORT_FEAT_INDICATOR unsupported always 0 */
-
-               dev_vdbg(hsotg->dev, "port_status=%08x\n", port_status);
-               *(__le32 *)buf = cpu_to_le32(port_status);
-               break;
-
-       case SetHubFeature:
-               dev_dbg(hsotg->dev, "SetHubFeature\n");
-               /* No HUB features supported */
-               break;
-
-       case SetPortFeature:
-               dev_dbg(hsotg->dev, "SetPortFeature\n");
-               if (wvalue != USB_PORT_FEAT_TEST && (!windex || windex > 1))
-                       goto error;
-
-               if (!hsotg->flags.b.port_connect_status) {
-                       /*
-                        * The port is disconnected, which means the core is
-                        * either in device mode or it soon will be. Just
-                        * return without doing anything since the port
-                        * register can't be written if the core is in device
-                        * mode.
-                        */
-                       break;
-               }
-
-               switch (wvalue) {
-               case USB_PORT_FEAT_SUSPEND:
-                       dev_dbg(hsotg->dev,
-                               "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
-                       if (windex != hsotg->otg_port)
-                               goto error;
-                       dwc2_port_suspend(hsotg, windex);
-                       break;
-
-               case USB_PORT_FEAT_POWER:
-                       dev_dbg(hsotg->dev,
-                               "SetPortFeature - USB_PORT_FEAT_POWER\n");
-                       hprt0 = dwc2_read_hprt0(hsotg);
-                       hprt0 |= HPRT0_PWR;
-                       writel(hprt0, hsotg->regs + HPRT0);
-                       break;
-
-               case USB_PORT_FEAT_RESET:
-                       hprt0 = dwc2_read_hprt0(hsotg);
-                       dev_dbg(hsotg->dev,
-                               "SetPortFeature - USB_PORT_FEAT_RESET\n");
-                       pcgctl = readl(hsotg->regs + PCGCTL);
-                       pcgctl &= ~(PCGCTL_ENBL_SLEEP_GATING | PCGCTL_STOPPCLK);
-                       writel(pcgctl, hsotg->regs + PCGCTL);
-                       /* ??? Original driver does this */
-                       writel(0, hsotg->regs + PCGCTL);
-
-                       hprt0 = dwc2_read_hprt0(hsotg);
-                       /* Clear suspend bit if resetting from suspend state */
-                       hprt0 &= ~HPRT0_SUSP;
-
-                       /*
-                        * When B-Host the Port reset bit is set in the Start
-                        * HCD Callback function, so that the reset is started
-                        * within 1ms of the HNP success interrupt
-                        */
-                       if (!dwc2_hcd_is_b_host(hsotg)) {
-                               hprt0 |= HPRT0_PWR | HPRT0_RST;
-                               dev_dbg(hsotg->dev,
-                                       "In host mode, hprt0=%08x\n", hprt0);
-                               writel(hprt0, hsotg->regs + HPRT0);
-                       }
-
-                       /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
-                       usleep_range(50000, 70000);
-                       hprt0 &= ~HPRT0_RST;
-                       writel(hprt0, hsotg->regs + HPRT0);
-                       hsotg->lx_state = DWC2_L0; /* Now back to On state */
-                       break;
-
-               case USB_PORT_FEAT_INDICATOR:
-                       dev_dbg(hsotg->dev,
-                               "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
-                       /* Not supported */
-                       break;
-
-               default:
-                       retval = -EINVAL;
-                       dev_err(hsotg->dev,
-                               "SetPortFeature %1xh unknown or unsupported\n",
-                               wvalue);
-                       break;
-               }
-               break;
-
-       default:
-error:
-               retval = -EINVAL;
-               dev_dbg(hsotg->dev,
-                       "Unknown hub control request: %1xh wIndex: %1xh wValue: %1xh\n",
-                       typereq, windex, wvalue);
-               break;
-       }
-
-       return retval;
-}
-
-static int dwc2_hcd_is_status_changed(struct dwc2_hsotg *hsotg, int port)
-{
-       int retval;
-
-       if (port != 1)
-               return -EINVAL;
-
-       retval = (hsotg->flags.b.port_connect_status_change ||
-                 hsotg->flags.b.port_reset_change ||
-                 hsotg->flags.b.port_enable_change ||
-                 hsotg->flags.b.port_suspend_change ||
-                 hsotg->flags.b.port_over_current_change);
-
-       if (retval) {
-               dev_dbg(hsotg->dev,
-                       "DWC OTG HCD HUB STATUS DATA: Root port status changed\n");
-               dev_dbg(hsotg->dev, "  port_connect_status_change: %d\n",
-                       hsotg->flags.b.port_connect_status_change);
-               dev_dbg(hsotg->dev, "  port_reset_change: %d\n",
-                       hsotg->flags.b.port_reset_change);
-               dev_dbg(hsotg->dev, "  port_enable_change: %d\n",
-                       hsotg->flags.b.port_enable_change);
-               dev_dbg(hsotg->dev, "  port_suspend_change: %d\n",
-                       hsotg->flags.b.port_suspend_change);
-               dev_dbg(hsotg->dev, "  port_over_current_change: %d\n",
-                       hsotg->flags.b.port_over_current_change);
-       }
-
-       return retval;
-}
-
-int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
-{
-       u32 hfnum = readl(hsotg->regs + HFNUM);
-
-#ifdef DWC2_DEBUG_SOF
-       dev_vdbg(hsotg->dev, "DWC OTG HCD GET FRAME NUMBER %d\n",
-                (hfnum & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT);
-#endif
-       return (hfnum & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT;
-}
-
-int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg)
-{
-       return hsotg->op_state == OTG_STATE_B_HOST;
-}
-
-static struct dwc2_hcd_urb *dwc2_hcd_urb_alloc(struct dwc2_hsotg *hsotg,
-                                              int iso_desc_count,
-                                              gfp_t mem_flags)
-{
-       struct dwc2_hcd_urb *urb;
-       u32 size = sizeof(*urb) + iso_desc_count *
-                  sizeof(struct dwc2_hcd_iso_packet_desc);
-
-       urb = kzalloc(size, mem_flags);
-       if (urb)
-               urb->packet_count = iso_desc_count;
-       return urb;
-}
-
-static void dwc2_hcd_urb_set_pipeinfo(struct dwc2_hsotg *hsotg,
-                                     struct dwc2_hcd_urb *urb, u8 dev_addr,
-                                     u8 ep_num, u8 ep_type, u8 ep_dir, u16 mps)
-{
-       if (dbg_perio() ||
-           ep_type == USB_ENDPOINT_XFER_BULK ||
-           ep_type == USB_ENDPOINT_XFER_CONTROL)
-               dev_vdbg(hsotg->dev,
-                        "addr=%d, ep_num=%d, ep_dir=%1x, ep_type=%1x, mps=%d\n",
-                        dev_addr, ep_num, ep_dir, ep_type, mps);
-       urb->pipe_info.dev_addr = dev_addr;
-       urb->pipe_info.ep_num = ep_num;
-       urb->pipe_info.pipe_type = ep_type;
-       urb->pipe_info.pipe_dir = ep_dir;
-       urb->pipe_info.mps = mps;
-}
-
-/*
- * NOTE: This function will be removed once the peripheral controller code
- * is integrated and the driver is stable
- */
-void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg)
-{
-#ifdef DEBUG
-       struct dwc2_host_chan *chan;
-       struct dwc2_hcd_urb *urb;
-       struct dwc2_qtd *qtd;
-       int num_channels;
-       u32 np_tx_status;
-       u32 p_tx_status;
-       int i;
-
-       num_channels = hsotg->core_params->host_channels;
-       dev_dbg(hsotg->dev, "\n");
-       dev_dbg(hsotg->dev,
-               "************************************************************\n");
-       dev_dbg(hsotg->dev, "HCD State:\n");
-       dev_dbg(hsotg->dev, "  Num channels: %d\n", num_channels);
-
-       for (i = 0; i < num_channels; i++) {
-               chan = hsotg->hc_ptr_array[i];
-               dev_dbg(hsotg->dev, "  Channel %d:\n", i);
-               dev_dbg(hsotg->dev,
-                       "    dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
-                       chan->dev_addr, chan->ep_num, chan->ep_is_in);
-               dev_dbg(hsotg->dev, "    speed: %d\n", chan->speed);
-               dev_dbg(hsotg->dev, "    ep_type: %d\n", chan->ep_type);
-               dev_dbg(hsotg->dev, "    max_packet: %d\n", chan->max_packet);
-               dev_dbg(hsotg->dev, "    data_pid_start: %d\n",
-                       chan->data_pid_start);
-               dev_dbg(hsotg->dev, "    multi_count: %d\n", chan->multi_count);
-               dev_dbg(hsotg->dev, "    xfer_started: %d\n",
-                       chan->xfer_started);
-               dev_dbg(hsotg->dev, "    xfer_buf: %p\n", chan->xfer_buf);
-               dev_dbg(hsotg->dev, "    xfer_dma: %08lx\n",
-                       (unsigned long)chan->xfer_dma);
-               dev_dbg(hsotg->dev, "    xfer_len: %d\n", chan->xfer_len);
-               dev_dbg(hsotg->dev, "    xfer_count: %d\n", chan->xfer_count);
-               dev_dbg(hsotg->dev, "    halt_on_queue: %d\n",
-                       chan->halt_on_queue);
-               dev_dbg(hsotg->dev, "    halt_pending: %d\n",
-                       chan->halt_pending);
-               dev_dbg(hsotg->dev, "    halt_status: %d\n", chan->halt_status);
-               dev_dbg(hsotg->dev, "    do_split: %d\n", chan->do_split);
-               dev_dbg(hsotg->dev, "    complete_split: %d\n",
-                       chan->complete_split);
-               dev_dbg(hsotg->dev, "    hub_addr: %d\n", chan->hub_addr);
-               dev_dbg(hsotg->dev, "    hub_port: %d\n", chan->hub_port);
-               dev_dbg(hsotg->dev, "    xact_pos: %d\n", chan->xact_pos);
-               dev_dbg(hsotg->dev, "    requests: %d\n", chan->requests);
-               dev_dbg(hsotg->dev, "    qh: %p\n", chan->qh);
-
-               if (chan->xfer_started) {
-                       u32 hfnum, hcchar, hctsiz, hcint, hcintmsk;
-
-                       hfnum = readl(hsotg->regs + HFNUM);
-                       hcchar = readl(hsotg->regs + HCCHAR(i));
-                       hctsiz = readl(hsotg->regs + HCTSIZ(i));
-                       hcint = readl(hsotg->regs + HCINT(i));
-                       hcintmsk = readl(hsotg->regs + HCINTMSK(i));
-                       dev_dbg(hsotg->dev, "    hfnum: 0x%08x\n", hfnum);
-                       dev_dbg(hsotg->dev, "    hcchar: 0x%08x\n", hcchar);
-                       dev_dbg(hsotg->dev, "    hctsiz: 0x%08x\n", hctsiz);
-                       dev_dbg(hsotg->dev, "    hcint: 0x%08x\n", hcint);
-                       dev_dbg(hsotg->dev, "    hcintmsk: 0x%08x\n", hcintmsk);
-               }
-
-               if (!(chan->xfer_started && chan->qh))
-                       continue;
-
-               list_for_each_entry(qtd, &chan->qh->qtd_list, qtd_list_entry) {
-                       if (!qtd->in_process)
-                               break;
-                       urb = qtd->urb;
-                       dev_dbg(hsotg->dev, "    URB Info:\n");
-                       dev_dbg(hsotg->dev, "      qtd: %p, urb: %p\n",
-                               qtd, urb);
-                       if (urb) {
-                               dev_dbg(hsotg->dev,
-                                       "      Dev: %d, EP: %d %s\n",
-                                       dwc2_hcd_get_dev_addr(&urb->pipe_info),
-                                       dwc2_hcd_get_ep_num(&urb->pipe_info),
-                                       dwc2_hcd_is_pipe_in(&urb->pipe_info) ?
-                                       "IN" : "OUT");
-                               dev_dbg(hsotg->dev,
-                                       "      Max packet size: %d\n",
-                                       dwc2_hcd_get_mps(&urb->pipe_info));
-                               dev_dbg(hsotg->dev,
-                                       "      transfer_buffer: %p\n",
-                                       urb->buf);
-                               dev_dbg(hsotg->dev,
-                                       "      transfer_dma: %08lx\n",
-                                       (unsigned long)urb->dma);
-                               dev_dbg(hsotg->dev,
-                                       "      transfer_buffer_length: %d\n",
-                                       urb->length);
-                               dev_dbg(hsotg->dev, "      actual_length: %d\n",
-                                       urb->actual_length);
-                       }
-               }
-       }
-
-       dev_dbg(hsotg->dev, "  non_periodic_channels: %d\n",
-               hsotg->non_periodic_channels);
-       dev_dbg(hsotg->dev, "  periodic_channels: %d\n",
-               hsotg->periodic_channels);
-       dev_dbg(hsotg->dev, "  periodic_usecs: %d\n", hsotg->periodic_usecs);
-       np_tx_status = readl(hsotg->regs + GNPTXSTS);
-       dev_dbg(hsotg->dev, "  NP Tx Req Queue Space Avail: %d\n",
-               (np_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT);
-       dev_dbg(hsotg->dev, "  NP Tx FIFO Space Avail: %d\n",
-               (np_tx_status & TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT);
-       p_tx_status = readl(hsotg->regs + HPTXSTS);
-       dev_dbg(hsotg->dev, "  P Tx Req Queue Space Avail: %d\n",
-               (p_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT);
-       dev_dbg(hsotg->dev, "  P Tx FIFO Space Avail: %d\n",
-               (p_tx_status & TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT);
-       dwc2_hcd_dump_frrem(hsotg);
-       dwc2_dump_global_registers(hsotg);
-       dwc2_dump_host_registers(hsotg);
-       dev_dbg(hsotg->dev,
-               "************************************************************\n");
-       dev_dbg(hsotg->dev, "\n");
-#endif
-}
-
-/*
- * NOTE: This function will be removed once the peripheral controller code
- * is integrated and the driver is stable
- */
-void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg)
-{
-#ifdef DWC2_DUMP_FRREM
-       dev_dbg(hsotg->dev, "Frame remaining at SOF:\n");
-       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
-               hsotg->frrem_samples, hsotg->frrem_accum,
-               hsotg->frrem_samples > 0 ?
-               hsotg->frrem_accum / hsotg->frrem_samples : 0);
-       dev_dbg(hsotg->dev, "\n");
-       dev_dbg(hsotg->dev, "Frame remaining at start_transfer (uframe 7):\n");
-       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
-               hsotg->hfnum_7_samples,
-               hsotg->hfnum_7_frrem_accum,
-               hsotg->hfnum_7_samples > 0 ?
-               hsotg->hfnum_7_frrem_accum / hsotg->hfnum_7_samples : 0);
-       dev_dbg(hsotg->dev, "Frame remaining at start_transfer (uframe 0):\n");
-       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
-               hsotg->hfnum_0_samples,
-               hsotg->hfnum_0_frrem_accum,
-               hsotg->hfnum_0_samples > 0 ?
-               hsotg->hfnum_0_frrem_accum / hsotg->hfnum_0_samples : 0);
-       dev_dbg(hsotg->dev, "Frame remaining at start_transfer (uframe 1-6):\n");
-       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
-               hsotg->hfnum_other_samples,
-               hsotg->hfnum_other_frrem_accum,
-               hsotg->hfnum_other_samples > 0 ?
-               hsotg->hfnum_other_frrem_accum / hsotg->hfnum_other_samples :
-               0);
-       dev_dbg(hsotg->dev, "\n");
-       dev_dbg(hsotg->dev, "Frame remaining at sample point A (uframe 7):\n");
-       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
-               hsotg->hfnum_7_samples_a, hsotg->hfnum_7_frrem_accum_a,
-               hsotg->hfnum_7_samples_a > 0 ?
-               hsotg->hfnum_7_frrem_accum_a / hsotg->hfnum_7_samples_a : 0);
-       dev_dbg(hsotg->dev, "Frame remaining at sample point A (uframe 0):\n");
-       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
-               hsotg->hfnum_0_samples_a, hsotg->hfnum_0_frrem_accum_a,
-               hsotg->hfnum_0_samples_a > 0 ?
-               hsotg->hfnum_0_frrem_accum_a / hsotg->hfnum_0_samples_a : 0);
-       dev_dbg(hsotg->dev, "Frame remaining at sample point A (uframe 1-6):\n");
-       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
-               hsotg->hfnum_other_samples_a, hsotg->hfnum_other_frrem_accum_a,
-               hsotg->hfnum_other_samples_a > 0 ?
-               hsotg->hfnum_other_frrem_accum_a / hsotg->hfnum_other_samples_a
-               : 0);
-       dev_dbg(hsotg->dev, "\n");
-       dev_dbg(hsotg->dev, "Frame remaining at sample point B (uframe 7):\n");
-       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
-               hsotg->hfnum_7_samples_b, hsotg->hfnum_7_frrem_accum_b,
-               hsotg->hfnum_7_samples_b > 0 ?
-               hsotg->hfnum_7_frrem_accum_b / hsotg->hfnum_7_samples_b : 0);
-       dev_dbg(hsotg->dev, "Frame remaining at sample point B (uframe 0):\n");
-       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
-               hsotg->hfnum_0_samples_b, hsotg->hfnum_0_frrem_accum_b,
-               (hsotg->hfnum_0_samples_b > 0) ?
-               hsotg->hfnum_0_frrem_accum_b / hsotg->hfnum_0_samples_b : 0);
-       dev_dbg(hsotg->dev, "Frame remaining at sample point B (uframe 1-6):\n");
-       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
-               hsotg->hfnum_other_samples_b, hsotg->hfnum_other_frrem_accum_b,
-               (hsotg->hfnum_other_samples_b > 0) ?
-               hsotg->hfnum_other_frrem_accum_b / hsotg->hfnum_other_samples_b
-               : 0);
-#endif
-}
-
-struct wrapper_priv_data {
-       struct dwc2_hsotg *hsotg;
-};
-
-/* Gets the dwc2_hsotg from a usb_hcd */
-static struct dwc2_hsotg *dwc2_hcd_to_hsotg(struct usb_hcd *hcd)
-{
-       struct wrapper_priv_data *p;
-
-       p = (struct wrapper_priv_data *) &hcd->hcd_priv;
-       return p->hsotg;
-}
-
-static int _dwc2_hcd_start(struct usb_hcd *hcd);
-
-void dwc2_host_start(struct dwc2_hsotg *hsotg)
-{
-       struct usb_hcd *hcd = dwc2_hsotg_to_hcd(hsotg);
-
-       hcd->self.is_b_host = dwc2_hcd_is_b_host(hsotg);
-       _dwc2_hcd_start(hcd);
-}
-
-void dwc2_host_disconnect(struct dwc2_hsotg *hsotg)
-{
-       struct usb_hcd *hcd = dwc2_hsotg_to_hcd(hsotg);
-
-       hcd->self.is_b_host = 0;
-}
-
-void dwc2_host_hub_info(struct dwc2_hsotg *hsotg, void *context, int *hub_addr,
-                       int *hub_port)
-{
-       struct urb *urb = context;
-
-       if (urb->dev->tt)
-               *hub_addr = urb->dev->tt->hub->devnum;
-       else
-               *hub_addr = 0;
-       *hub_port = urb->dev->ttport;
-}
-
-int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context)
-{
-       struct urb *urb = context;
-
-       return urb->dev->speed;
-}
-
-static void dwc2_allocate_bus_bandwidth(struct usb_hcd *hcd, u16 bw,
-                                       struct urb *urb)
-{
-       struct usb_bus *bus = hcd_to_bus(hcd);
-
-       if (urb->interval)
-               bus->bandwidth_allocated += bw / urb->interval;
-       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
-               bus->bandwidth_isoc_reqs++;
-       else
-               bus->bandwidth_int_reqs++;
-}
-
-static void dwc2_free_bus_bandwidth(struct usb_hcd *hcd, u16 bw,
-                                   struct urb *urb)
-{
-       struct usb_bus *bus = hcd_to_bus(hcd);
-
-       if (urb->interval)
-               bus->bandwidth_allocated -= bw / urb->interval;
-       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
-               bus->bandwidth_isoc_reqs--;
-       else
-               bus->bandwidth_int_reqs--;
-}
-
-/*
- * Sets the final status of an URB and returns it to the upper layer. Any
- * required cleanup of the URB is performed.
- *
- * Must be called with interrupt disabled and spinlock held
- */
-void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
-                       int status)
-{
-       struct urb *urb;
-       int i;
-
-       if (!qtd) {
-               dev_dbg(hsotg->dev, "## %s: qtd is NULL ##\n", __func__);
-               return;
-       }
-
-       if (!qtd->urb) {
-               dev_dbg(hsotg->dev, "## %s: qtd->urb is NULL ##\n", __func__);
-               return;
-       }
-
-       urb = qtd->urb->priv;
-       if (!urb) {
-               dev_dbg(hsotg->dev, "## %s: urb->priv is NULL ##\n", __func__);
-               return;
-       }
-
-       urb->actual_length = dwc2_hcd_urb_get_actual_length(qtd->urb);
-
-       if (dbg_urb(urb))
-               dev_vdbg(hsotg->dev,
-                        "%s: urb %p device %d ep %d-%s status %d actual %d\n",
-                        __func__, urb, usb_pipedevice(urb->pipe),
-                        usb_pipeendpoint(urb->pipe),
-                        usb_pipein(urb->pipe) ? "IN" : "OUT", status,
-                        urb->actual_length);
-
-       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS && dbg_perio()) {
-               for (i = 0; i < urb->number_of_packets; i++)
-                       dev_vdbg(hsotg->dev, " ISO Desc %d status %d\n",
-                                i, urb->iso_frame_desc[i].status);
-       }
-
-       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-               urb->error_count = dwc2_hcd_urb_get_error_count(qtd->urb);
-               for (i = 0; i < urb->number_of_packets; ++i) {
-                       urb->iso_frame_desc[i].actual_length =
-                               dwc2_hcd_urb_get_iso_desc_actual_length(
-                                               qtd->urb, i);
-                       urb->iso_frame_desc[i].status =
-                               dwc2_hcd_urb_get_iso_desc_status(qtd->urb, i);
-               }
-       }
-
-       urb->status = status;
-       if (!status) {
-               if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
-                   urb->actual_length < urb->transfer_buffer_length)
-                       urb->status = -EREMOTEIO;
-       }
-
-       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS ||
-           usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
-               struct usb_host_endpoint *ep = urb->ep;
-
-               if (ep)
-                       dwc2_free_bus_bandwidth(dwc2_hsotg_to_hcd(hsotg),
-                                       dwc2_hcd_get_ep_bandwidth(hsotg, ep),
-                                       urb);
-       }
-
-       usb_hcd_unlink_urb_from_ep(dwc2_hsotg_to_hcd(hsotg), urb);
-       urb->hcpriv = NULL;
-       kfree(qtd->urb);
-       qtd->urb = NULL;
-
-       spin_unlock(&hsotg->lock);
-       usb_hcd_giveback_urb(dwc2_hsotg_to_hcd(hsotg), urb, status);
-       spin_lock(&hsotg->lock);
-}
-
-/*
- * Work queue function for starting the HCD when A-Cable is connected
- */
-static void dwc2_hcd_start_func(struct work_struct *work)
-{
-       struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg,
-                                               start_work.work);
-
-       dev_dbg(hsotg->dev, "%s() %p\n", __func__, hsotg);
-       dwc2_host_start(hsotg);
-}
-
-/*
- * Reset work queue function
- */
-static void dwc2_hcd_reset_func(struct work_struct *work)
-{
-       struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg,
-                                               reset_work.work);
-       u32 hprt0;
-
-       dev_dbg(hsotg->dev, "USB RESET function called\n");
-       hprt0 = dwc2_read_hprt0(hsotg);
-       hprt0 &= ~HPRT0_RST;
-       writel(hprt0, hsotg->regs + HPRT0);
-       hsotg->flags.b.port_reset_change = 1;
-}
-
-/*
- * =========================================================================
- *  Linux HC Driver Functions
- * =========================================================================
- */
-
-/*
- * Initializes the DWC_otg controller and its root hub and prepares it for host
- * mode operation. Activates the root port. Returns 0 on success and a negative
- * error code on failure.
- */
-static int _dwc2_hcd_start(struct usb_hcd *hcd)
-{
-       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
-       struct usb_bus *bus = hcd_to_bus(hcd);
-       unsigned long flags;
-
-       dev_dbg(hsotg->dev, "DWC OTG HCD START\n");
-
-       spin_lock_irqsave(&hsotg->lock, flags);
-
-       hcd->state = HC_STATE_RUNNING;
-
-       if (dwc2_is_device_mode(hsotg)) {
-               spin_unlock_irqrestore(&hsotg->lock, flags);
-               return 0;       /* why 0 ?? */
-       }
-
-       dwc2_hcd_reinit(hsotg);
-
-       /* Initialize and connect root hub if one is not already attached */
-       if (bus->root_hub) {
-               dev_dbg(hsotg->dev, "DWC OTG HCD Has Root Hub\n");
-               /* Inform the HUB driver to resume */
-               usb_hcd_resume_root_hub(hcd);
-       }
-
-       spin_unlock_irqrestore(&hsotg->lock, flags);
-       return 0;
-}
-
-/*
- * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
- * stopped.
- */
-static void _dwc2_hcd_stop(struct usb_hcd *hcd)
-{
-       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
-       unsigned long flags;
-
-       spin_lock_irqsave(&hsotg->lock, flags);
-       dwc2_hcd_stop(hsotg);
-       spin_unlock_irqrestore(&hsotg->lock, flags);
-
-       usleep_range(1000, 3000);
-}
-
-/* Returns the current frame number */
-static int _dwc2_hcd_get_frame_number(struct usb_hcd *hcd)
-{
-       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
-
-       return dwc2_hcd_get_frame_number(hsotg);
-}
-
-static void dwc2_dump_urb_info(struct usb_hcd *hcd, struct urb *urb,
-                              char *fn_name)
-{
-#ifdef VERBOSE_DEBUG
-       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
-       char *pipetype;
-       char *speed;
-
-       dev_vdbg(hsotg->dev, "%s, urb %p\n", fn_name, urb);
-       dev_vdbg(hsotg->dev, "  Device address: %d\n",
-                usb_pipedevice(urb->pipe));
-       dev_vdbg(hsotg->dev, "  Endpoint: %d, %s\n",
-                usb_pipeendpoint(urb->pipe),
-                usb_pipein(urb->pipe) ? "IN" : "OUT");
-
-       switch (usb_pipetype(urb->pipe)) {
-       case PIPE_CONTROL:
-               pipetype = "CONTROL";
-               break;
-       case PIPE_BULK:
-               pipetype = "BULK";
-               break;
-       case PIPE_INTERRUPT:
-               pipetype = "INTERRUPT";
-               break;
-       case PIPE_ISOCHRONOUS:
-               pipetype = "ISOCHRONOUS";
-               break;
-       default:
-               pipetype = "UNKNOWN";
-               break;
-       }
-
-       dev_vdbg(hsotg->dev, "  Endpoint type: %s %s (%s)\n", pipetype,
-                usb_urb_dir_in(urb) ? "IN" : "OUT", usb_pipein(urb->pipe) ?
-                "IN" : "OUT");
-
-       switch (urb->dev->speed) {
-       case USB_SPEED_HIGH:
-               speed = "HIGH";
-               break;
-       case USB_SPEED_FULL:
-               speed = "FULL";
-               break;
-       case USB_SPEED_LOW:
-               speed = "LOW";
-               break;
-       default:
-               speed = "UNKNOWN";
-               break;
-       }
-
-       dev_vdbg(hsotg->dev, "  Speed: %s\n", speed);
-       dev_vdbg(hsotg->dev, "  Max packet size: %d\n",
-                usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
-       dev_vdbg(hsotg->dev, "  Data buffer length: %d\n",
-                urb->transfer_buffer_length);
-       dev_vdbg(hsotg->dev, "  Transfer buffer: %p, Transfer DMA: %08lx\n",
-                urb->transfer_buffer, (unsigned long)urb->transfer_dma);
-       dev_vdbg(hsotg->dev, "  Setup buffer: %p, Setup DMA: %08lx\n",
-                urb->setup_packet, (unsigned long)urb->setup_dma);
-       dev_vdbg(hsotg->dev, "  Interval: %d\n", urb->interval);
-
-       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-               int i;
-
-               for (i = 0; i < urb->number_of_packets; i++) {
-                       dev_vdbg(hsotg->dev, "  ISO Desc %d:\n", i);
-                       dev_vdbg(hsotg->dev, "    offset: %d, length %d\n",
-                                urb->iso_frame_desc[i].offset,
-                                urb->iso_frame_desc[i].length);
-               }
-       }
-#endif
-}
-
-/*
- * Starts processing a USB transfer request specified by a USB Request Block
- * (URB). mem_flags indicates the type of memory allocation to use while
- * processing this URB.
- */
-static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
-                                gfp_t mem_flags)
-{
-       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
-       struct usb_host_endpoint *ep = urb->ep;
-       struct dwc2_hcd_urb *dwc2_urb;
-       int i;
-       int retval;
-       int alloc_bandwidth = 0;
-       u8 ep_type = 0;
-       u32 tflags = 0;
-       void *buf;
-       unsigned long flags;
-
-       if (dbg_urb(urb)) {
-               dev_vdbg(hsotg->dev, "DWC OTG HCD URB Enqueue\n");
-               dwc2_dump_urb_info(hcd, urb, "urb_enqueue");
-       }
-
-       if (ep == NULL)
-               return -EINVAL;
-
-       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS ||
-           usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
-               spin_lock_irqsave(&hsotg->lock, flags);
-               if (!dwc2_hcd_is_bandwidth_allocated(hsotg, ep))
-                       alloc_bandwidth = 1;
-               spin_unlock_irqrestore(&hsotg->lock, flags);
-       }
-
-       switch (usb_pipetype(urb->pipe)) {
-       case PIPE_CONTROL:
-               ep_type = USB_ENDPOINT_XFER_CONTROL;
-               break;
-       case PIPE_ISOCHRONOUS:
-               ep_type = USB_ENDPOINT_XFER_ISOC;
-               break;
-       case PIPE_BULK:
-               ep_type = USB_ENDPOINT_XFER_BULK;
-               break;
-       case PIPE_INTERRUPT:
-               ep_type = USB_ENDPOINT_XFER_INT;
-               break;
-       default:
-               dev_warn(hsotg->dev, "Wrong ep type\n");
-       }
-
-       dwc2_urb = dwc2_hcd_urb_alloc(hsotg, urb->number_of_packets,
-                                     mem_flags);
-       if (!dwc2_urb)
-               return -ENOMEM;
-
-       dwc2_hcd_urb_set_pipeinfo(hsotg, dwc2_urb, usb_pipedevice(urb->pipe),
-                                 usb_pipeendpoint(urb->pipe), ep_type,
-                                 usb_pipein(urb->pipe),
-                                 usb_maxpacket(urb->dev, urb->pipe,
-                                               !(usb_pipein(urb->pipe))));
-
-       buf = urb->transfer_buffer;
-
-       if (hcd->self.uses_dma) {
-               if (!buf && (urb->transfer_dma & 3)) {
-                       dev_err(hsotg->dev,
-                               "%s: unaligned transfer with no transfer_buffer",
-                               __func__);
-                       retval = -EINVAL;
-                       goto fail1;
-               }
-       }
-
-       if (!(urb->transfer_flags & URB_NO_INTERRUPT))
-               tflags |= URB_GIVEBACK_ASAP;
-       if (urb->transfer_flags & URB_ZERO_PACKET)
-               tflags |= URB_SEND_ZERO_PACKET;
-
-       dwc2_urb->priv = urb;
-       dwc2_urb->buf = buf;
-       dwc2_urb->dma = urb->transfer_dma;
-       dwc2_urb->length = urb->transfer_buffer_length;
-       dwc2_urb->setup_packet = urb->setup_packet;
-       dwc2_urb->setup_dma = urb->setup_dma;
-       dwc2_urb->flags = tflags;
-       dwc2_urb->interval = urb->interval;
-       dwc2_urb->status = -EINPROGRESS;
-
-       for (i = 0; i < urb->number_of_packets; ++i)
-               dwc2_hcd_urb_set_iso_desc_params(dwc2_urb, i,
-                                                urb->iso_frame_desc[i].offset,
-                                                urb->iso_frame_desc[i].length);
-
-       urb->hcpriv = dwc2_urb;
-
-       spin_lock_irqsave(&hsotg->lock, flags);
-       retval = usb_hcd_link_urb_to_ep(hcd, urb);
-       spin_unlock_irqrestore(&hsotg->lock, flags);
-       if (retval)
-               goto fail1;
-
-       retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, &ep->hcpriv, mem_flags);
-       if (retval)
-               goto fail2;
-
-       if (alloc_bandwidth) {
-               spin_lock_irqsave(&hsotg->lock, flags);
-               dwc2_allocate_bus_bandwidth(hcd,
-                               dwc2_hcd_get_ep_bandwidth(hsotg, ep),
-                               urb);
-               spin_unlock_irqrestore(&hsotg->lock, flags);
-       }
-
-       return 0;
-
-fail2:
-       spin_lock_irqsave(&hsotg->lock, flags);
-       dwc2_urb->priv = NULL;
-       usb_hcd_unlink_urb_from_ep(hcd, urb);
-       spin_unlock_irqrestore(&hsotg->lock, flags);
-fail1:
-       urb->hcpriv = NULL;
-       kfree(dwc2_urb);
-
-       return retval;
-}
-
-/*
- * Aborts/cancels a USB transfer request. Always returns 0 to indicate success.
- */
-static int _dwc2_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
-                                int status)
-{
-       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
-       int rc;
-       unsigned long flags;
-
-       dev_dbg(hsotg->dev, "DWC OTG HCD URB Dequeue\n");
-       dwc2_dump_urb_info(hcd, urb, "urb_dequeue");
-
-       spin_lock_irqsave(&hsotg->lock, flags);
-
-       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
-       if (rc)
-               goto out;
-
-       if (!urb->hcpriv) {
-               dev_dbg(hsotg->dev, "## urb->hcpriv is NULL ##\n");
-               goto out;
-       }
-
-       rc = dwc2_hcd_urb_dequeue(hsotg, urb->hcpriv);
-
-       usb_hcd_unlink_urb_from_ep(hcd, urb);
-
-       kfree(urb->hcpriv);
-       urb->hcpriv = NULL;
-
-       /* Higher layer software sets URB status */
-       spin_unlock(&hsotg->lock);
-       usb_hcd_giveback_urb(hcd, urb, status);
-       spin_lock(&hsotg->lock);
-
-       dev_dbg(hsotg->dev, "Called usb_hcd_giveback_urb()\n");
-       dev_dbg(hsotg->dev, "  urb->status = %d\n", urb->status);
-out:
-       spin_unlock_irqrestore(&hsotg->lock, flags);
-
-       return rc;
-}
-
-/*
- * Frees resources in the DWC_otg controller related to a given endpoint. Also
- * clears state in the HCD related to the endpoint. Any URBs for the endpoint
- * must already be dequeued.
- */
-static void _dwc2_hcd_endpoint_disable(struct usb_hcd *hcd,
-                                      struct usb_host_endpoint *ep)
-{
-       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
-
-       dev_dbg(hsotg->dev,
-               "DWC OTG HCD EP DISABLE: bEndpointAddress=0x%02x, ep->hcpriv=%p\n",
-               ep->desc.bEndpointAddress, ep->hcpriv);
-       dwc2_hcd_endpoint_disable(hsotg, ep, 250);
-}
-
-/*
- * Resets endpoint specific parameter values, in current version used to reset
- * the data toggle (as a WA). This function can be called from usb_clear_halt
- * routine.
- */
-static void _dwc2_hcd_endpoint_reset(struct usb_hcd *hcd,
-                                    struct usb_host_endpoint *ep)
-{
-       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
-       int is_control = usb_endpoint_xfer_control(&ep->desc);
-       int is_out = usb_endpoint_dir_out(&ep->desc);
-       int epnum = usb_endpoint_num(&ep->desc);
-       struct usb_device *udev;
-       unsigned long flags;
-
-       dev_dbg(hsotg->dev,
-               "DWC OTG HCD EP RESET: bEndpointAddress=0x%02x\n",
-               ep->desc.bEndpointAddress);
-
-       udev = to_usb_device(hsotg->dev);
-
-       spin_lock_irqsave(&hsotg->lock, flags);
-
-       usb_settoggle(udev, epnum, is_out, 0);
-       if (is_control)
-               usb_settoggle(udev, epnum, !is_out, 0);
-       dwc2_hcd_endpoint_reset(hsotg, ep);
-
-       spin_unlock_irqrestore(&hsotg->lock, flags);
-}
-
-/*
- * Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if
- * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid
- * interrupt.
- *
- * This function is called by the USB core when an interrupt occurs
- */
-static irqreturn_t _dwc2_hcd_irq(struct usb_hcd *hcd)
-{
-       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
-
-       return dwc2_handle_hcd_intr(hsotg);
-}
-
-/*
- * Creates Status Change bitmap for the root hub and root port. The bitmap is
- * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1
- * is the status change indicator for the single root port. Returns 1 if either
- * change indicator is 1, otherwise returns 0.
- */
-static int _dwc2_hcd_hub_status_data(struct usb_hcd *hcd, char *buf)
-{
-       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
-
-       buf[0] = dwc2_hcd_is_status_changed(hsotg, 1) << 1;
-       return buf[0] != 0;
-}
-
-/* Handles hub class-specific requests */
-static int _dwc2_hcd_hub_control(struct usb_hcd *hcd, u16 typereq, u16 wvalue,
-                                u16 windex, char *buf, u16 wlength)
-{
-       int retval = dwc2_hcd_hub_control(dwc2_hcd_to_hsotg(hcd), typereq,
-                                         wvalue, windex, buf, wlength);
-       return retval;
-}
-
-/* Handles hub TT buffer clear completions */
-static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd,
-                                              struct usb_host_endpoint *ep)
-{
-       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
-       struct dwc2_qh *qh;
-       unsigned long flags;
-
-       qh = ep->hcpriv;
-       if (!qh)
-               return;
-
-       spin_lock_irqsave(&hsotg->lock, flags);
-       qh->tt_buffer_dirty = 0;
-
-       if (hsotg->flags.b.port_connect_status)
-               dwc2_hcd_queue_transactions(hsotg, DWC2_TRANSACTION_ALL);
-
-       spin_unlock_irqrestore(&hsotg->lock, flags);
-}
-
-static struct hc_driver dwc2_hc_driver = {
-       .description = "dwc2_hsotg",
-       .product_desc = "DWC OTG Controller",
-       .hcd_priv_size = sizeof(struct wrapper_priv_data),
-
-       .irq = _dwc2_hcd_irq,
-       .flags = HCD_MEMORY | HCD_USB2,
-
-       .start = _dwc2_hcd_start,
-       .stop = _dwc2_hcd_stop,
-       .urb_enqueue = _dwc2_hcd_urb_enqueue,
-       .urb_dequeue = _dwc2_hcd_urb_dequeue,
-       .endpoint_disable = _dwc2_hcd_endpoint_disable,
-       .endpoint_reset = _dwc2_hcd_endpoint_reset,
-       .get_frame_number = _dwc2_hcd_get_frame_number,
-
-       .hub_status_data = _dwc2_hcd_hub_status_data,
-       .hub_control = _dwc2_hcd_hub_control,
-       .clear_tt_buffer_complete = _dwc2_hcd_clear_tt_buffer_complete,
-};
-
-/*
- * Frees secondary storage associated with the dwc2_hsotg structure contained
- * in the struct usb_hcd field
- */
-static void dwc2_hcd_free(struct dwc2_hsotg *hsotg)
-{
-       u32 ahbcfg;
-       u32 dctl;
-       int i;
-
-       dev_dbg(hsotg->dev, "DWC OTG HCD FREE\n");
-
-       /* Free memory for QH/QTD lists */
-       dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_inactive);
-       dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_active);
-       dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_inactive);
-       dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_ready);
-       dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_assigned);
-       dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_queued);
-
-       /* Free memory for the host channels */
-       for (i = 0; i < MAX_EPS_CHANNELS; i++) {
-               struct dwc2_host_chan *chan = hsotg->hc_ptr_array[i];
-
-               if (chan != NULL) {
-                       dev_dbg(hsotg->dev, "HCD Free channel #%i, chan=%p\n",
-                               i, chan);
-                       hsotg->hc_ptr_array[i] = NULL;
-                       kfree(chan);
-               }
-       }
-
-       if (hsotg->core_params->dma_enable > 0) {
-               if (hsotg->status_buf) {
-                       dma_free_coherent(hsotg->dev, DWC2_HCD_STATUS_BUF_SIZE,
-                                         hsotg->status_buf,
-                                         hsotg->status_buf_dma);
-                       hsotg->status_buf = NULL;
-               }
-       } else {
-               kfree(hsotg->status_buf);
-               hsotg->status_buf = NULL;
-       }
-
-       ahbcfg = readl(hsotg->regs + GAHBCFG);
-
-       /* Disable all interrupts */
-       ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
-       writel(ahbcfg, hsotg->regs + GAHBCFG);
-       writel(0, hsotg->regs + GINTMSK);
-
-       if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a) {
-               dctl = readl(hsotg->regs + DCTL);
-               dctl |= DCTL_SFTDISCON;
-               writel(dctl, hsotg->regs + DCTL);
-       }
-
-       if (hsotg->wq_otg) {
-               if (!cancel_work_sync(&hsotg->wf_otg))
-                       flush_workqueue(hsotg->wq_otg);
-               destroy_workqueue(hsotg->wq_otg);
-       }
-
-       kfree(hsotg->core_params);
-       hsotg->core_params = NULL;
-       del_timer(&hsotg->wkp_timer);
-}
-
-static void dwc2_hcd_release(struct dwc2_hsotg *hsotg)
-{
-       /* Turn off all host-specific interrupts */
-       dwc2_disable_host_interrupts(hsotg);
-
-       dwc2_hcd_free(hsotg);
-}
-
-/*
- * Sets all parameters to the given value.
- *
- * Assumes that the dwc2_core_params struct contains only integers.
- */
-void dwc2_set_all_params(struct dwc2_core_params *params, int value)
-{
-       int *p = (int *)params;
-       size_t size = sizeof(*params) / sizeof(*p);
-       int i;
-
-       for (i = 0; i < size; i++)
-               p[i] = value;
-}
-EXPORT_SYMBOL_GPL(dwc2_set_all_params);
-
-/*
- * Initializes the HCD. This function allocates memory for and initializes the
- * static parts of the usb_hcd and dwc2_hsotg structures. It also registers the
- * USB bus with the core and calls the hc_driver->start() function. It returns
- * a negative error on failure.
- */
-int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
-                 const struct dwc2_core_params *params)
-{
-       struct usb_hcd *hcd;
-       struct dwc2_host_chan *channel;
-       u32 hcfg;
-       int i, num_channels;
-       int retval;
-
-       dev_dbg(hsotg->dev, "DWC OTG HCD INIT\n");
-
-       /* Detect config values from hardware */
-       retval = dwc2_get_hwparams(hsotg);
-
-       if (retval)
-               return retval;
-
-       retval = -ENOMEM;
-
-       hcfg = readl(hsotg->regs + HCFG);
-       dev_dbg(hsotg->dev, "hcfg=%08x\n", hcfg);
-
-#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
-       hsotg->frame_num_array = kzalloc(sizeof(*hsotg->frame_num_array) *
-                                        FRAME_NUM_ARRAY_SIZE, GFP_KERNEL);
-       if (!hsotg->frame_num_array)
-               goto error1;
-       hsotg->last_frame_num_array = kzalloc(
-                       sizeof(*hsotg->last_frame_num_array) *
-                       FRAME_NUM_ARRAY_SIZE, GFP_KERNEL);
-       if (!hsotg->last_frame_num_array)
-               goto error1;
-       hsotg->last_frame_num = HFNUM_MAX_FRNUM;
-#endif
-
-       hsotg->core_params = kzalloc(sizeof(*hsotg->core_params), GFP_KERNEL);
-       if (!hsotg->core_params)
-               goto error1;
-
-       dwc2_set_all_params(hsotg->core_params, -1);
-
-       /* Validate parameter values */
-       dwc2_set_parameters(hsotg, params);
-
-       /* Check if the bus driver or platform code has setup a dma_mask */
-       if (hsotg->core_params->dma_enable > 0 &&
-           hsotg->dev->dma_mask == NULL) {
-               dev_warn(hsotg->dev,
-                        "dma_mask not set, disabling DMA\n");
-               hsotg->core_params->dma_enable = 0;
-               hsotg->core_params->dma_desc_enable = 0;
-       }
-
-       /* Set device flags indicating whether the HCD supports DMA */
-       if (hsotg->core_params->dma_enable > 0) {
-               if (dma_set_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0)
-                       dev_warn(hsotg->dev, "can't set DMA mask\n");
-               if (dma_set_coherent_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0)
-                       dev_warn(hsotg->dev, "can't set coherent DMA mask\n");
-       }
-
-       hcd = usb_create_hcd(&dwc2_hc_driver, hsotg->dev, dev_name(hsotg->dev));
-       if (!hcd)
-               goto error1;
-
-       if (hsotg->core_params->dma_enable <= 0)
-               hcd->self.uses_dma = 0;
-
-       hcd->has_tt = 1;
-
-       spin_lock_init(&hsotg->lock);
-       ((struct wrapper_priv_data *) &hcd->hcd_priv)->hsotg = hsotg;
-       hsotg->priv = hcd;
-
-       /*
-        * Disable the global interrupt until all the interrupt handlers are
-        * installed
-        */
-       dwc2_disable_global_interrupts(hsotg);
-
-       /* Initialize the DWC_otg core, and select the Phy type */
-       retval = dwc2_core_init(hsotg, true, irq);
-       if (retval)
-               goto error2;
-
-       /* Create new workqueue and init work */
-       retval = -ENOMEM;
-       hsotg->wq_otg = create_singlethread_workqueue("dwc2");
-       if (!hsotg->wq_otg) {
-               dev_err(hsotg->dev, "Failed to create workqueue\n");
-               goto error2;
-       }
-       INIT_WORK(&hsotg->wf_otg, dwc2_conn_id_status_change);
-
-       setup_timer(&hsotg->wkp_timer, dwc2_wakeup_detected,
-                   (unsigned long)hsotg);
-
-       /* Initialize the non-periodic schedule */
-       INIT_LIST_HEAD(&hsotg->non_periodic_sched_inactive);
-       INIT_LIST_HEAD(&hsotg->non_periodic_sched_active);
-
-       /* Initialize the periodic schedule */
-       INIT_LIST_HEAD(&hsotg->periodic_sched_inactive);
-       INIT_LIST_HEAD(&hsotg->periodic_sched_ready);
-       INIT_LIST_HEAD(&hsotg->periodic_sched_assigned);
-       INIT_LIST_HEAD(&hsotg->periodic_sched_queued);
-
-       /*
-        * Create a host channel descriptor for each host channel implemented
-        * in the controller. Initialize the channel descriptor array.
-        */
-       INIT_LIST_HEAD(&hsotg->free_hc_list);
-       num_channels = hsotg->core_params->host_channels;
-       memset(&hsotg->hc_ptr_array[0], 0, sizeof(hsotg->hc_ptr_array));
-
-       for (i = 0; i < num_channels; i++) {
-               channel = kzalloc(sizeof(*channel), GFP_KERNEL);
-               if (channel == NULL)
-                       goto error3;
-               channel->hc_num = i;
-               hsotg->hc_ptr_array[i] = channel;
-       }
-
-       if (hsotg->core_params->uframe_sched > 0)
-               dwc2_hcd_init_usecs(hsotg);
-
-       /* Initialize hsotg start work */
-       INIT_DELAYED_WORK(&hsotg->start_work, dwc2_hcd_start_func);
-
-       /* Initialize port reset work */
-       INIT_DELAYED_WORK(&hsotg->reset_work, dwc2_hcd_reset_func);
-
-       /*
-        * Allocate space for storing data on status transactions. Normally no
-        * data is sent, but this space acts as a bit bucket. This must be
-        * done after usb_add_hcd since that function allocates the DMA buffer
-        * pool.
-        */
-       if (hsotg->core_params->dma_enable > 0)
-               hsotg->status_buf = dma_alloc_coherent(hsotg->dev,
-                                       DWC2_HCD_STATUS_BUF_SIZE,
-                                       &hsotg->status_buf_dma, GFP_KERNEL);
-       else
-               hsotg->status_buf = kzalloc(DWC2_HCD_STATUS_BUF_SIZE,
-                                         GFP_KERNEL);
-
-       if (!hsotg->status_buf)
-               goto error3;
-
-       hsotg->otg_port = 1;
-       hsotg->frame_list = NULL;
-       hsotg->frame_list_dma = 0;
-       hsotg->periodic_qh_count = 0;
-
-       /* Initiate lx_state to L3 disconnected state */
-       hsotg->lx_state = DWC2_L3;
-
-       hcd->self.otg_port = hsotg->otg_port;
-
-       /* Don't support SG list at this point */
-       hcd->self.sg_tablesize = 0;
-
-       /*
-        * Finish generic HCD initialization and start the HCD. This function
-        * allocates the DMA buffer pool, registers the USB bus, requests the
-        * IRQ line, and calls hcd_start method.
-        */
-       retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
-       if (retval < 0)
-               goto error3;
-
-       dwc2_hcd_dump_state(hsotg);
-
-       dwc2_enable_global_interrupts(hsotg);
-
-       return 0;
-
-error3:
-       dwc2_hcd_release(hsotg);
-error2:
-       usb_put_hcd(hcd);
-error1:
-       kfree(hsotg->core_params);
-
-#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
-       kfree(hsotg->last_frame_num_array);
-       kfree(hsotg->frame_num_array);
-#endif
-
-       dev_err(hsotg->dev, "%s() FAILED, returning %d\n", __func__, retval);
-       return retval;
-}
-EXPORT_SYMBOL_GPL(dwc2_hcd_init);
-
-/*
- * Removes the HCD.
- * Frees memory and resources associated with the HCD and deregisters the bus.
- */
-void dwc2_hcd_remove(struct dwc2_hsotg *hsotg)
-{
-       struct usb_hcd *hcd;
-
-       dev_dbg(hsotg->dev, "DWC OTG HCD REMOVE\n");
-
-       hcd = dwc2_hsotg_to_hcd(hsotg);
-       dev_dbg(hsotg->dev, "hsotg->hcd = %p\n", hcd);
-
-       if (!hcd) {
-               dev_dbg(hsotg->dev, "%s: dwc2_hsotg_to_hcd(hsotg) NULL!\n",
-                       __func__);
-               return;
-       }
-
-       usb_remove_hcd(hcd);
-       hsotg->priv = NULL;
-       dwc2_hcd_release(hsotg);
-       usb_put_hcd(hcd);
-
-#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
-       kfree(hsotg->last_frame_num_array);
-       kfree(hsotg->frame_num_array);
-#endif
-}
-EXPORT_SYMBOL_GPL(dwc2_hcd_remove);
diff --git a/drivers/staging/dwc2/hcd.h b/drivers/staging/dwc2/hcd.h
deleted file mode 100644 (file)
index fdc6d48..0000000
+++ /dev/null
@@ -1,769 +0,0 @@
-/*
- * hcd.h - DesignWare HS OTG Controller host-mode declarations
- *
- * Copyright (C) 2004-2013 Synopsys, Inc.
- *
- * 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") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * 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 __DWC2_HCD_H__
-#define __DWC2_HCD_H__
-
-/*
- * This file contains the structures, constants, and interfaces for the
- * Host Contoller Driver (HCD)
- *
- * The Host Controller Driver (HCD) is responsible for translating requests
- * from the USB Driver into the appropriate actions on the DWC_otg controller.
- * It isolates the USBD from the specifics of the controller by providing an
- * API to the USBD.
- */
-
-struct dwc2_qh;
-
-/**
- * struct dwc2_host_chan - Software host channel descriptor
- *
- * @hc_num:             Host channel number, used for register address lookup
- * @dev_addr:           Address of the device
- * @ep_num:             Endpoint of the device
- * @ep_is_in:           Endpoint direction
- * @speed:              Device speed. One of the following values:
- *                       - USB_SPEED_LOW
- *                       - USB_SPEED_FULL
- *                       - USB_SPEED_HIGH
- * @ep_type:            Endpoint type. One of the following values:
- *                       - USB_ENDPOINT_XFER_CONTROL: 0
- *                       - USB_ENDPOINT_XFER_ISOC:    1
- *                       - USB_ENDPOINT_XFER_BULK:    2
- *                       - USB_ENDPOINT_XFER_INTR:    3
- * @max_packet:         Max packet size in bytes
- * @data_pid_start:     PID for initial transaction.
- *                       0: DATA0
- *                       1: DATA2
- *                       2: DATA1
- *                       3: MDATA (non-Control EP),
- *                          SETUP (Control EP)
- * @multi_count:        Number of additional periodic transactions per
- *                      (micro)frame
- * @xfer_buf:           Pointer to current transfer buffer position
- * @xfer_dma:           DMA address of xfer_buf
- * @align_buf:          In Buffer DMA mode this will be used if xfer_buf is not
- *                      DWORD aligned
- * @xfer_len:           Total number of bytes to transfer
- * @xfer_count:         Number of bytes transferred so far
- * @start_pkt_count:    Packet count at start of transfer
- * @xfer_started:       True if the transfer has been started
- * @ping:               True if a PING request should be issued on this channel
- * @error_state:        True if the error count for this transaction is non-zero
- * @halt_on_queue:      True if this channel should be halted the next time a
- *                      request is queued for the channel. This is necessary in
- *                      slave mode if no request queue space is available when
- *                      an attempt is made to halt the channel.
- * @halt_pending:       True if the host channel has been halted, but the core
- *                      is not finished flushing queued requests
- * @do_split:           Enable split for the channel
- * @complete_split:     Enable complete split
- * @hub_addr:           Address of high speed hub for the split
- * @hub_port:           Port of the low/full speed device for the split
- * @xact_pos:           Split transaction position. One of the following values:
- *                       - DWC2_HCSPLT_XACTPOS_MID
- *                       - DWC2_HCSPLT_XACTPOS_BEGIN
- *                       - DWC2_HCSPLT_XACTPOS_END
- *                       - DWC2_HCSPLT_XACTPOS_ALL
- * @requests:           Number of requests issued for this channel since it was
- *                      assigned to the current transfer (not counting PINGs)
- * @schinfo:            Scheduling micro-frame bitmap
- * @ntd:                Number of transfer descriptors for the transfer
- * @halt_status:        Reason for halting the host channel
- * @hcint               Contents of the HCINT register when the interrupt came
- * @qh:                 QH for the transfer being processed by this channel
- * @hc_list_entry:      For linking to list of host channels
- * @desc_list_addr:     Current QH's descriptor list DMA address
- *
- * This structure represents the state of a single host channel when acting in
- * host mode. It contains the data items needed to transfer packets to an
- * endpoint via a host channel.
- */
-struct dwc2_host_chan {
-       u8 hc_num;
-
-       unsigned dev_addr:7;
-       unsigned ep_num:4;
-       unsigned ep_is_in:1;
-       unsigned speed:4;
-       unsigned ep_type:2;
-       unsigned max_packet:11;
-       unsigned data_pid_start:2;
-#define DWC2_HC_PID_DATA0      TSIZ_SC_MC_PID_DATA0
-#define DWC2_HC_PID_DATA2      TSIZ_SC_MC_PID_DATA2
-#define DWC2_HC_PID_DATA1      TSIZ_SC_MC_PID_DATA1
-#define DWC2_HC_PID_MDATA      TSIZ_SC_MC_PID_MDATA
-#define DWC2_HC_PID_SETUP      TSIZ_SC_MC_PID_SETUP
-
-       unsigned multi_count:2;
-
-       u8 *xfer_buf;
-       dma_addr_t xfer_dma;
-       dma_addr_t align_buf;
-       u32 xfer_len;
-       u32 xfer_count;
-       u16 start_pkt_count;
-       u8 xfer_started;
-       u8 do_ping;
-       u8 error_state;
-       u8 halt_on_queue;
-       u8 halt_pending;
-       u8 do_split;
-       u8 complete_split;
-       u8 hub_addr;
-       u8 hub_port;
-       u8 xact_pos;
-#define DWC2_HCSPLT_XACTPOS_MID        HCSPLT_XACTPOS_MID
-#define DWC2_HCSPLT_XACTPOS_END        HCSPLT_XACTPOS_END
-#define DWC2_HCSPLT_XACTPOS_BEGIN HCSPLT_XACTPOS_BEGIN
-#define DWC2_HCSPLT_XACTPOS_ALL        HCSPLT_XACTPOS_ALL
-
-       u8 requests;
-       u8 schinfo;
-       u16 ntd;
-       enum dwc2_halt_status halt_status;
-       u32 hcint;
-       struct dwc2_qh *qh;
-       struct list_head hc_list_entry;
-       dma_addr_t desc_list_addr;
-};
-
-struct dwc2_hcd_pipe_info {
-       u8 dev_addr;
-       u8 ep_num;
-       u8 pipe_type;
-       u8 pipe_dir;
-       u16 mps;
-};
-
-struct dwc2_hcd_iso_packet_desc {
-       u32 offset;
-       u32 length;
-       u32 actual_length;
-       u32 status;
-};
-
-struct dwc2_qtd;
-
-struct dwc2_hcd_urb {
-       void *priv;
-       struct dwc2_qtd *qtd;
-       void *buf;
-       dma_addr_t dma;
-       void *setup_packet;
-       dma_addr_t setup_dma;
-       u32 length;
-       u32 actual_length;
-       u32 status;
-       u32 error_count;
-       u32 packet_count;
-       u32 flags;
-       u16 interval;
-       struct dwc2_hcd_pipe_info pipe_info;
-       struct dwc2_hcd_iso_packet_desc iso_descs[0];
-};
-
-/* Phases for control transfers */
-enum dwc2_control_phase {
-       DWC2_CONTROL_SETUP,
-       DWC2_CONTROL_DATA,
-       DWC2_CONTROL_STATUS,
-};
-
-/* Transaction types */
-enum dwc2_transaction_type {
-       DWC2_TRANSACTION_NONE,
-       DWC2_TRANSACTION_PERIODIC,
-       DWC2_TRANSACTION_NON_PERIODIC,
-       DWC2_TRANSACTION_ALL,
-};
-
-/**
- * struct dwc2_qh - Software queue head structure
- *
- * @ep_type:            Endpoint type. One of the following values:
- *                       - USB_ENDPOINT_XFER_CONTROL
- *                       - USB_ENDPOINT_XFER_BULK
- *                       - USB_ENDPOINT_XFER_INT
- *                       - USB_ENDPOINT_XFER_ISOC
- * @ep_is_in:           Endpoint direction
- * @maxp:               Value from wMaxPacketSize field of Endpoint Descriptor
- * @dev_speed:          Device speed. One of the following values:
- *                       - USB_SPEED_LOW
- *                       - USB_SPEED_FULL
- *                       - USB_SPEED_HIGH
- * @data_toggle:        Determines the PID of the next data packet for
- *                      non-controltransfers. Ignored for control transfers.
- *                      One of the following values:
- *                       - DWC2_HC_PID_DATA0
- *                       - DWC2_HC_PID_DATA1
- * @ping_state:         Ping state
- * @do_split:           Full/low speed endpoint on high-speed hub requires split
- * @td_first:           Index of first activated isochronous transfer descriptor
- * @td_last:            Index of last activated isochronous transfer descriptor
- * @usecs:              Bandwidth in microseconds per (micro)frame
- * @interval:           Interval between transfers in (micro)frames
- * @sched_frame:        (Micro)frame to initialize a periodic transfer.
- *                      The transfer executes in the following (micro)frame.
- * @frame_usecs:        Internal variable used by the microframe scheduler
- * @start_split_frame:  (Micro)frame at which last start split was initialized
- * @ntd:                Actual number of transfer descriptors in a list
- * @dw_align_buf:       Used instead of original buffer if its physical address
- *                      is not dword-aligned
- * @dw_align_buf_dma:   DMA address for align_buf
- * @qtd_list:           List of QTDs for this QH
- * @channel:            Host channel currently processing transfers for this QH
- * @qh_list_entry:      Entry for QH in either the periodic or non-periodic
- *                      schedule
- * @desc_list:          List of transfer descriptors
- * @desc_list_dma:      Physical address of desc_list
- * @n_bytes:            Xfer Bytes array. Each element corresponds to a transfer
- *                      descriptor and indicates original XferSize value for the
- *                      descriptor
- * @tt_buffer_dirty     True if clear_tt_buffer_complete is pending
- *
- * A Queue Head (QH) holds the static characteristics of an endpoint and
- * maintains a list of transfers (QTDs) for that endpoint. A QH structure may
- * be entered in either the non-periodic or periodic schedule.
- */
-struct dwc2_qh {
-       u8 ep_type;
-       u8 ep_is_in;
-       u16 maxp;
-       u8 dev_speed;
-       u8 data_toggle;
-       u8 ping_state;
-       u8 do_split;
-       u8 td_first;
-       u8 td_last;
-       u16 usecs;
-       u16 interval;
-       u16 sched_frame;
-       u16 frame_usecs[8];
-       u16 start_split_frame;
-       u16 ntd;
-       u8 *dw_align_buf;
-       dma_addr_t dw_align_buf_dma;
-       struct list_head qtd_list;
-       struct dwc2_host_chan *channel;
-       struct list_head qh_list_entry;
-       struct dwc2_hcd_dma_desc *desc_list;
-       dma_addr_t desc_list_dma;
-       u32 *n_bytes;
-       unsigned tt_buffer_dirty:1;
-};
-
-/**
- * struct dwc2_qtd - Software queue transfer descriptor (QTD)
- *
- * @control_phase:      Current phase for control transfers (Setup, Data, or
- *                      Status)
- * @in_process:         Indicates if this QTD is currently processed by HW
- * @data_toggle:        Determines the PID of the next data packet for the
- *                      data phase of control transfers. Ignored for other
- *                      transfer types. One of the following values:
- *                       - DWC2_HC_PID_DATA0
- *                       - DWC2_HC_PID_DATA1
- * @complete_split:     Keeps track of the current split type for FS/LS
- *                      endpoints on a HS Hub
- * @isoc_split_pos:     Position of the ISOC split in full/low speed
- * @isoc_frame_index:   Index of the next frame descriptor for an isochronous
- *                      transfer. A frame descriptor describes the buffer
- *                      position and length of the data to be transferred in the
- *                      next scheduled (micro)frame of an isochronous transfer.
- *                      It also holds status for that transaction. The frame
- *                      index starts at 0.
- * @isoc_split_offset:  Position of the ISOC split in the buffer for the
- *                      current frame
- * @ssplit_out_xfer_count: How many bytes transferred during SSPLIT OUT
- * @error_count:        Holds the number of bus errors that have occurred for
- *                      a transaction within this transfer
- * @n_desc:             Number of DMA descriptors for this QTD
- * @isoc_frame_index_last: Last activated frame (packet) index, used in
- *                      descriptor DMA mode only
- * @urb:                URB for this transfer
- * @qh:                 Queue head for this QTD
- * @qtd_list_entry:     For linking to the QH's list of QTDs
- *
- * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control,
- * interrupt, or isochronous transfer. A single QTD is created for each URB
- * (of one of these types) submitted to the HCD. The transfer associated with
- * a QTD may require one or multiple transactions.
- *
- * A QTD is linked to a Queue Head, which is entered in either the
- * non-periodic or periodic schedule for execution. When a QTD is chosen for
- * execution, some or all of its transactions may be executed. After
- * execution, the state of the QTD is updated. The QTD may be retired if all
- * its transactions are complete or if an error occurred. Otherwise, it
- * remains in the schedule so more transactions can be executed later.
- */
-struct dwc2_qtd {
-       enum dwc2_control_phase control_phase;
-       u8 in_process;
-       u8 data_toggle;
-       u8 complete_split;
-       u8 isoc_split_pos;
-       u16 isoc_frame_index;
-       u16 isoc_split_offset;
-       u32 ssplit_out_xfer_count;
-       u8 error_count;
-       u8 n_desc;
-       u16 isoc_frame_index_last;
-       struct dwc2_hcd_urb *urb;
-       struct dwc2_qh *qh;
-       struct list_head qtd_list_entry;
-};
-
-#ifdef DEBUG
-struct hc_xfer_info {
-       struct dwc2_hsotg *hsotg;
-       struct dwc2_host_chan *chan;
-};
-#endif
-
-/* Gets the struct usb_hcd that contains a struct dwc2_hsotg */
-static inline struct usb_hcd *dwc2_hsotg_to_hcd(struct dwc2_hsotg *hsotg)
-{
-       return (struct usb_hcd *)hsotg->priv;
-}
-
-/*
- * Inline used to disable one channel interrupt. Channel interrupts are
- * disabled when the channel is halted or released by the interrupt handler.
- * There is no need to handle further interrupts of that type until the
- * channel is re-assigned. In fact, subsequent handling may cause crashes
- * because the channel structures are cleaned up when the channel is released.
- */
-static inline void disable_hc_int(struct dwc2_hsotg *hsotg, int chnum, u32 intr)
-{
-       u32 mask = readl(hsotg->regs + HCINTMSK(chnum));
-
-       mask &= ~intr;
-       writel(mask, hsotg->regs + HCINTMSK(chnum));
-}
-
-/*
- * Returns the mode of operation, host or device
- */
-static inline int dwc2_is_host_mode(struct dwc2_hsotg *hsotg)
-{
-       return (readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) != 0;
-}
-static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg)
-{
-       return (readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) == 0;
-}
-
-/*
- * Reads HPRT0 in preparation to modify. It keeps the WC bits 0 so that if they
- * are read as 1, they won't clear when written back.
- */
-static inline u32 dwc2_read_hprt0(struct dwc2_hsotg *hsotg)
-{
-       u32 hprt0 = readl(hsotg->regs + HPRT0);
-
-       hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG | HPRT0_OVRCURRCHG);
-       return hprt0;
-}
-
-static inline u8 dwc2_hcd_get_ep_num(struct dwc2_hcd_pipe_info *pipe)
-{
-       return pipe->ep_num;
-}
-
-static inline u8 dwc2_hcd_get_pipe_type(struct dwc2_hcd_pipe_info *pipe)
-{
-       return pipe->pipe_type;
-}
-
-static inline u16 dwc2_hcd_get_mps(struct dwc2_hcd_pipe_info *pipe)
-{
-       return pipe->mps;
-}
-
-static inline u8 dwc2_hcd_get_dev_addr(struct dwc2_hcd_pipe_info *pipe)
-{
-       return pipe->dev_addr;
-}
-
-static inline u8 dwc2_hcd_is_pipe_isoc(struct dwc2_hcd_pipe_info *pipe)
-{
-       return pipe->pipe_type == USB_ENDPOINT_XFER_ISOC;
-}
-
-static inline u8 dwc2_hcd_is_pipe_int(struct dwc2_hcd_pipe_info *pipe)
-{
-       return pipe->pipe_type == USB_ENDPOINT_XFER_INT;
-}
-
-static inline u8 dwc2_hcd_is_pipe_bulk(struct dwc2_hcd_pipe_info *pipe)
-{
-       return pipe->pipe_type == USB_ENDPOINT_XFER_BULK;
-}
-
-static inline u8 dwc2_hcd_is_pipe_control(struct dwc2_hcd_pipe_info *pipe)
-{
-       return pipe->pipe_type == USB_ENDPOINT_XFER_CONTROL;
-}
-
-static inline u8 dwc2_hcd_is_pipe_in(struct dwc2_hcd_pipe_info *pipe)
-{
-       return pipe->pipe_dir == USB_DIR_IN;
-}
-
-static inline u8 dwc2_hcd_is_pipe_out(struct dwc2_hcd_pipe_info *pipe)
-{
-       return !dwc2_hcd_is_pipe_in(pipe);
-}
-
-extern int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
-                        const struct dwc2_core_params *params);
-extern void dwc2_hcd_remove(struct dwc2_hsotg *hsotg);
-extern void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
-                               const struct dwc2_core_params *params);
-extern void dwc2_set_all_params(struct dwc2_core_params *params, int value);
-extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
-
-/* Transaction Execution Functions */
-extern enum dwc2_transaction_type dwc2_hcd_select_transactions(
-                                               struct dwc2_hsotg *hsotg);
-extern void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
-                                       enum dwc2_transaction_type tr_type);
-
-/* Schedule Queue Functions */
-/* Implemented in hcd_queue.c */
-extern void dwc2_hcd_init_usecs(struct dwc2_hsotg *hsotg);
-extern void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
-extern int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
-extern void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
-extern void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
-                                  int sched_csplit);
-
-extern void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb);
-extern int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
-                           struct dwc2_qh **qh, gfp_t mem_flags);
-
-/* Unlinks and frees a QTD */
-static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
-                                               struct dwc2_qtd *qtd,
-                                               struct dwc2_qh *qh)
-{
-       list_del(&qtd->qtd_list_entry);
-       kfree(qtd);
-}
-
-/* Descriptor DMA support functions */
-extern void dwc2_hcd_start_xfer_ddma(struct dwc2_hsotg *hsotg,
-                                    struct dwc2_qh *qh);
-extern void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg,
-                                       struct dwc2_host_chan *chan, int chnum,
-                                       enum dwc2_halt_status halt_status);
-
-extern int dwc2_hcd_qh_init_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
-                                gfp_t mem_flags);
-extern void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
-
-/* Check if QH is non-periodic */
-#define dwc2_qh_is_non_per(_qh_ptr_) \
-       ((_qh_ptr_)->ep_type == USB_ENDPOINT_XFER_BULK || \
-        (_qh_ptr_)->ep_type == USB_ENDPOINT_XFER_CONTROL)
-
-#ifdef CONFIG_USB_DWC2_DEBUG_PERIODIC
-static inline bool dbg_hc(struct dwc2_host_chan *hc) { return true; }
-static inline bool dbg_qh(struct dwc2_qh *qh) { return true; }
-static inline bool dbg_urb(struct urb *urb) { return true; }
-static inline bool dbg_perio(void) { return true; }
-#else /* !CONFIG_USB_DWC2_DEBUG_PERIODIC */
-static inline bool dbg_hc(struct dwc2_host_chan *hc)
-{
-       return hc->ep_type == USB_ENDPOINT_XFER_BULK ||
-              hc->ep_type == USB_ENDPOINT_XFER_CONTROL;
-}
-
-static inline bool dbg_qh(struct dwc2_qh *qh)
-{
-       return qh->ep_type == USB_ENDPOINT_XFER_BULK ||
-              qh->ep_type == USB_ENDPOINT_XFER_CONTROL;
-}
-
-static inline bool dbg_urb(struct urb *urb)
-{
-       return usb_pipetype(urb->pipe) == PIPE_BULK ||
-              usb_pipetype(urb->pipe) == PIPE_CONTROL;
-}
-
-static inline bool dbg_perio(void) { return false; }
-#endif
-
-/* High bandwidth multiplier as encoded in highspeed endpoint descriptors */
-#define dwc2_hb_mult(wmaxpacketsize) (1 + (((wmaxpacketsize) >> 11) & 0x03))
-
-/* Packet size for any kind of endpoint descriptor */
-#define dwc2_max_packet(wmaxpacketsize) ((wmaxpacketsize) & 0x07ff)
-
-/*
- * Returns true if frame1 is less than or equal to frame2. The comparison is
- * done modulo HFNUM_MAX_FRNUM. This accounts for the rollover of the
- * frame number when the max frame number is reached.
- */
-static inline int dwc2_frame_num_le(u16 frame1, u16 frame2)
-{
-       return ((frame2 - frame1) & HFNUM_MAX_FRNUM) <= (HFNUM_MAX_FRNUM >> 1);
-}
-
-/*
- * Returns true if frame1 is greater than frame2. The comparison is done
- * modulo HFNUM_MAX_FRNUM. This accounts for the rollover of the frame
- * number when the max frame number is reached.
- */
-static inline int dwc2_frame_num_gt(u16 frame1, u16 frame2)
-{
-       return (frame1 != frame2) &&
-              ((frame1 - frame2) & HFNUM_MAX_FRNUM) < (HFNUM_MAX_FRNUM >> 1);
-}
-
-/*
- * Increments frame by the amount specified by inc. The addition is done
- * modulo HFNUM_MAX_FRNUM. Returns the incremented value.
- */
-static inline u16 dwc2_frame_num_inc(u16 frame, u16 inc)
-{
-       return (frame + inc) & HFNUM_MAX_FRNUM;
-}
-
-static inline u16 dwc2_full_frame_num(u16 frame)
-{
-       return (frame & HFNUM_MAX_FRNUM) >> 3;
-}
-
-static inline u16 dwc2_micro_frame_num(u16 frame)
-{
-       return frame & 0x7;
-}
-
-/*
- * Returns the Core Interrupt Status register contents, ANDed with the Core
- * Interrupt Mask register contents
- */
-static inline u32 dwc2_read_core_intr(struct dwc2_hsotg *hsotg)
-{
-       return readl(hsotg->regs + GINTSTS) & readl(hsotg->regs + GINTMSK);
-}
-
-static inline u32 dwc2_hcd_urb_get_status(struct dwc2_hcd_urb *dwc2_urb)
-{
-       return dwc2_urb->status;
-}
-
-static inline u32 dwc2_hcd_urb_get_actual_length(
-               struct dwc2_hcd_urb *dwc2_urb)
-{
-       return dwc2_urb->actual_length;
-}
-
-static inline u32 dwc2_hcd_urb_get_error_count(struct dwc2_hcd_urb *dwc2_urb)
-{
-       return dwc2_urb->error_count;
-}
-
-static inline void dwc2_hcd_urb_set_iso_desc_params(
-               struct dwc2_hcd_urb *dwc2_urb, int desc_num, u32 offset,
-               u32 length)
-{
-       dwc2_urb->iso_descs[desc_num].offset = offset;
-       dwc2_urb->iso_descs[desc_num].length = length;
-}
-
-static inline u32 dwc2_hcd_urb_get_iso_desc_status(
-               struct dwc2_hcd_urb *dwc2_urb, int desc_num)
-{
-       return dwc2_urb->iso_descs[desc_num].status;
-}
-
-static inline u32 dwc2_hcd_urb_get_iso_desc_actual_length(
-               struct dwc2_hcd_urb *dwc2_urb, int desc_num)
-{
-       return dwc2_urb->iso_descs[desc_num].actual_length;
-}
-
-static inline int dwc2_hcd_is_bandwidth_allocated(struct dwc2_hsotg *hsotg,
-                                                 struct usb_host_endpoint *ep)
-{
-       struct dwc2_qh *qh = ep->hcpriv;
-
-       if (qh && !list_empty(&qh->qh_list_entry))
-               return 1;
-
-       return 0;
-}
-
-static inline u16 dwc2_hcd_get_ep_bandwidth(struct dwc2_hsotg *hsotg,
-                                           struct usb_host_endpoint *ep)
-{
-       struct dwc2_qh *qh = ep->hcpriv;
-
-       if (!qh) {
-               WARN_ON(1);
-               return 0;
-       }
-
-       return qh->usecs;
-}
-
-extern void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg,
-                                     struct dwc2_host_chan *chan, int chnum,
-                                     struct dwc2_qtd *qtd);
-
-/* HCD Core API */
-
-/**
- * dwc2_handle_hcd_intr() - Called on every hardware interrupt
- *
- * @hsotg: The DWC2 HCD
- *
- * Returns IRQ_HANDLED if interrupt is handled
- * Return IRQ_NONE if interrupt is not handled
- */
-extern irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg);
-
-/**
- * dwc2_hcd_stop() - Halts the DWC_otg host mode operation
- *
- * @hsotg: The DWC2 HCD
- */
-extern void dwc2_hcd_stop(struct dwc2_hsotg *hsotg);
-
-extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
-extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg);
-
-/**
- * dwc2_hcd_is_b_host() - Returns 1 if core currently is acting as B host,
- * and 0 otherwise
- *
- * @hsotg: The DWC2 HCD
- */
-extern int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg);
-
-/**
- * dwc2_hcd_get_frame_number() - Returns current frame number
- *
- * @hsotg: The DWC2 HCD
- */
-extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg);
-
-/**
- * dwc2_hcd_dump_state() - Dumps hsotg state
- *
- * @hsotg: The DWC2 HCD
- *
- * NOTE: This function will be removed once the peripheral controller code
- * is integrated and the driver is stable
- */
-extern void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg);
-
-/**
- * dwc2_hcd_dump_frrem() - Dumps the average frame remaining at SOF
- *
- * @hsotg: The DWC2 HCD
- *
- * This can be used to determine average interrupt latency. Frame remaining is
- * also shown for start transfer and two additional sample points.
- *
- * NOTE: This function will be removed once the peripheral controller code
- * is integrated and the driver is stable
- */
-extern void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg);
-
-/* URB interface */
-
-/* Transfer flags */
-#define URB_GIVEBACK_ASAP      0x1
-#define URB_SEND_ZERO_PACKET   0x2
-
-/* Host driver callbacks */
-
-extern void dwc2_host_start(struct dwc2_hsotg *hsotg);
-extern void dwc2_host_disconnect(struct dwc2_hsotg *hsotg);
-extern void dwc2_host_hub_info(struct dwc2_hsotg *hsotg, void *context,
-                              int *hub_addr, int *hub_port);
-extern int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context);
-extern void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
-                              int status);
-
-#ifdef DEBUG
-/*
- * Macro to sample the remaining PHY clocks left in the current frame. This
- * may be used during debugging to determine the average time it takes to
- * execute sections of code. There are two possible sample points, "a" and
- * "b", so the _letter_ argument must be one of these values.
- *
- * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For
- * example, "cat /sys/devices/lm0/hcd_frrem".
- */
-#define dwc2_sample_frrem(_hcd_, _qh_, _letter_)                       \
-do {                                                                   \
-       struct hfnum_data _hfnum_;                                      \
-       struct dwc2_qtd *_qtd_;                                         \
-                                                                       \
-       _qtd_ = list_entry((_qh_)->qtd_list.next, struct dwc2_qtd,      \
-                          qtd_list_entry);                             \
-       if (usb_pipeint(_qtd_->urb->pipe) &&                            \
-           (_qh_)->start_split_frame != 0 && !_qtd_->complete_split) { \
-               _hfnum_.d32 = readl((_hcd_)->regs + HFNUM);             \
-               switch (_hfnum_.b.frnum & 0x7) {                        \
-               case 7:                                                 \
-                       (_hcd_)->hfnum_7_samples_##_letter_++;          \
-                       (_hcd_)->hfnum_7_frrem_accum_##_letter_ +=      \
-                               _hfnum_.b.frrem;                        \
-                       break;                                          \
-               case 0:                                                 \
-                       (_hcd_)->hfnum_0_samples_##_letter_++;          \
-                       (_hcd_)->hfnum_0_frrem_accum_##_letter_ +=      \
-                               _hfnum_.b.frrem;                        \
-                       break;                                          \
-               default:                                                \
-                       (_hcd_)->hfnum_other_samples_##_letter_++;      \
-                       (_hcd_)->hfnum_other_frrem_accum_##_letter_ +=  \
-                               _hfnum_.b.frrem;                        \
-                       break;                                          \
-               }                                                       \
-       }                                                               \
-} while (0)
-#else
-#define dwc2_sample_frrem(_hcd_, _qh_, _letter_)       do {} while (0)
-#endif
-
-#endif /* __DWC2_HCD_H__ */
diff --git a/drivers/staging/dwc2/hcd_ddma.c b/drivers/staging/dwc2/hcd_ddma.c
deleted file mode 100644 (file)
index 3376177..0000000
+++ /dev/null
@@ -1,1212 +0,0 @@
-/*
- * hcd_ddma.c - DesignWare HS OTG Controller descriptor DMA routines
- *
- * Copyright (C) 2004-2013 Synopsys, Inc.
- *
- * 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") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * 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.
- */
-
-/*
- * This file contains the Descriptor DMA implementation for Host mode
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-
-#include <linux/usb/hcd.h>
-#include <linux/usb/ch11.h>
-
-#include "core.h"
-#include "hcd.h"
-
-static u16 dwc2_frame_list_idx(u16 frame)
-{
-       return frame & (FRLISTEN_64_SIZE - 1);
-}
-
-static u16 dwc2_desclist_idx_inc(u16 idx, u16 inc, u8 speed)
-{
-       return (idx + inc) &
-               ((speed == USB_SPEED_HIGH ? MAX_DMA_DESC_NUM_HS_ISOC :
-                 MAX_DMA_DESC_NUM_GENERIC) - 1);
-}
-
-static u16 dwc2_desclist_idx_dec(u16 idx, u16 inc, u8 speed)
-{
-       return (idx - inc) &
-               ((speed == USB_SPEED_HIGH ? MAX_DMA_DESC_NUM_HS_ISOC :
-                 MAX_DMA_DESC_NUM_GENERIC) - 1);
-}
-
-static u16 dwc2_max_desc_num(struct dwc2_qh *qh)
-{
-       return (qh->ep_type == USB_ENDPOINT_XFER_ISOC &&
-               qh->dev_speed == USB_SPEED_HIGH) ?
-               MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC;
-}
-
-static u16 dwc2_frame_incr_val(struct dwc2_qh *qh)
-{
-       return qh->dev_speed == USB_SPEED_HIGH ?
-              (qh->interval + 8 - 1) / 8 : qh->interval;
-}
-
-static int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
-                               gfp_t flags)
-{
-       qh->desc_list = dma_alloc_coherent(hsotg->dev,
-                               sizeof(struct dwc2_hcd_dma_desc) *
-                               dwc2_max_desc_num(qh), &qh->desc_list_dma,
-                               flags);
-
-       if (!qh->desc_list)
-               return -ENOMEM;
-
-       memset(qh->desc_list, 0,
-              sizeof(struct dwc2_hcd_dma_desc) * dwc2_max_desc_num(qh));
-
-       qh->n_bytes = kzalloc(sizeof(u32) * dwc2_max_desc_num(qh), flags);
-       if (!qh->n_bytes) {
-               dma_free_coherent(hsotg->dev, sizeof(struct dwc2_hcd_dma_desc)
-                                 * dwc2_max_desc_num(qh), qh->desc_list,
-                                 qh->desc_list_dma);
-               qh->desc_list = NULL;
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-static void dwc2_desc_list_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
-{
-       if (qh->desc_list) {
-               dma_free_coherent(hsotg->dev, sizeof(struct dwc2_hcd_dma_desc)
-                                 * dwc2_max_desc_num(qh), qh->desc_list,
-                                 qh->desc_list_dma);
-               qh->desc_list = NULL;
-       }
-
-       kfree(qh->n_bytes);
-       qh->n_bytes = NULL;
-}
-
-static int dwc2_frame_list_alloc(struct dwc2_hsotg *hsotg, gfp_t mem_flags)
-{
-       if (hsotg->frame_list)
-               return 0;
-
-       hsotg->frame_list = dma_alloc_coherent(hsotg->dev,
-                                              4 * FRLISTEN_64_SIZE,
-                                              &hsotg->frame_list_dma,
-                                              mem_flags);
-       if (!hsotg->frame_list)
-               return -ENOMEM;
-
-       memset(hsotg->frame_list, 0, 4 * FRLISTEN_64_SIZE);
-       return 0;
-}
-
-static void dwc2_frame_list_free(struct dwc2_hsotg *hsotg)
-{
-       u32 *frame_list;
-       dma_addr_t frame_list_dma;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hsotg->lock, flags);
-
-       if (!hsotg->frame_list) {
-               spin_unlock_irqrestore(&hsotg->lock, flags);
-               return;
-       }
-
-       frame_list = hsotg->frame_list;
-       frame_list_dma = hsotg->frame_list_dma;
-       hsotg->frame_list = NULL;
-
-       spin_unlock_irqrestore(&hsotg->lock, flags);
-
-       dma_free_coherent(hsotg->dev, 4 * FRLISTEN_64_SIZE, frame_list,
-                         frame_list_dma);
-}
-
-static void dwc2_per_sched_enable(struct dwc2_hsotg *hsotg, u32 fr_list_en)
-{
-       u32 hcfg;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hsotg->lock, flags);
-
-       hcfg = readl(hsotg->regs + HCFG);
-       if (hcfg & HCFG_PERSCHEDENA) {
-               /* already enabled */
-               spin_unlock_irqrestore(&hsotg->lock, flags);
-               return;
-       }
-
-       writel(hsotg->frame_list_dma, hsotg->regs + HFLBADDR);
-
-       hcfg &= ~HCFG_FRLISTEN_MASK;
-       hcfg |= fr_list_en | HCFG_PERSCHEDENA;
-       dev_vdbg(hsotg->dev, "Enabling Periodic schedule\n");
-       writel(hcfg, hsotg->regs + HCFG);
-
-       spin_unlock_irqrestore(&hsotg->lock, flags);
-}
-
-static void dwc2_per_sched_disable(struct dwc2_hsotg *hsotg)
-{
-       u32 hcfg;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hsotg->lock, flags);
-
-       hcfg = readl(hsotg->regs + HCFG);
-       if (!(hcfg & HCFG_PERSCHEDENA)) {
-               /* already disabled */
-               spin_unlock_irqrestore(&hsotg->lock, flags);
-               return;
-       }
-
-       hcfg &= ~HCFG_PERSCHEDENA;
-       dev_vdbg(hsotg->dev, "Disabling Periodic schedule\n");
-       writel(hcfg, hsotg->regs + HCFG);
-
-       spin_unlock_irqrestore(&hsotg->lock, flags);
-}
-
-/*
- * Activates/Deactivates FrameList entries for the channel based on endpoint
- * servicing period
- */
-static void dwc2_update_frame_list(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
-                                  int enable)
-{
-       struct dwc2_host_chan *chan;
-       u16 i, j, inc;
-
-       if (!hsotg) {
-               pr_err("hsotg = %p\n", hsotg);
-               return;
-       }
-
-       if (!qh->channel) {
-               dev_err(hsotg->dev, "qh->channel = %p\n", qh->channel);
-               return;
-       }
-
-       if (!hsotg->frame_list) {
-               dev_err(hsotg->dev, "hsotg->frame_list = %p\n",
-                       hsotg->frame_list);
-               return;
-       }
-
-       chan = qh->channel;
-       inc = dwc2_frame_incr_val(qh);
-       if (qh->ep_type == USB_ENDPOINT_XFER_ISOC)
-               i = dwc2_frame_list_idx(qh->sched_frame);
-       else
-               i = 0;
-
-       j = i;
-       do {
-               if (enable)
-                       hsotg->frame_list[j] |= 1 << chan->hc_num;
-               else
-                       hsotg->frame_list[j] &= ~(1 << chan->hc_num);
-               j = (j + inc) & (FRLISTEN_64_SIZE - 1);
-       } while (j != i);
-
-       if (!enable)
-               return;
-
-       chan->schinfo = 0;
-       if (chan->speed == USB_SPEED_HIGH && qh->interval) {
-               j = 1;
-               /* TODO - check this */
-               inc = (8 + qh->interval - 1) / qh->interval;
-               for (i = 0; i < inc; i++) {
-                       chan->schinfo |= j;
-                       j = j << qh->interval;
-               }
-       } else {
-               chan->schinfo = 0xff;
-       }
-}
-
-static void dwc2_release_channel_ddma(struct dwc2_hsotg *hsotg,
-                                     struct dwc2_qh *qh)
-{
-       struct dwc2_host_chan *chan = qh->channel;
-
-       if (dwc2_qh_is_non_per(qh)) {
-               if (hsotg->core_params->uframe_sched > 0)
-                       hsotg->available_host_channels++;
-               else
-                       hsotg->non_periodic_channels--;
-       } else {
-               dwc2_update_frame_list(hsotg, qh, 0);
-       }
-
-       /*
-        * The condition is added to prevent double cleanup try in case of
-        * device disconnect. See channel cleanup in dwc2_hcd_disconnect().
-        */
-       if (chan->qh) {
-               if (!list_empty(&chan->hc_list_entry))
-                       list_del(&chan->hc_list_entry);
-               dwc2_hc_cleanup(hsotg, chan);
-               list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list);
-               chan->qh = NULL;
-       }
-
-       qh->channel = NULL;
-       qh->ntd = 0;
-
-       if (qh->desc_list)
-               memset(qh->desc_list, 0, sizeof(struct dwc2_hcd_dma_desc) *
-                      dwc2_max_desc_num(qh));
-}
-
-/**
- * dwc2_hcd_qh_init_ddma() - Initializes a QH structure's Descriptor DMA
- * related members
- *
- * @hsotg: The HCD state structure for the DWC OTG controller
- * @qh:    The QH to init
- *
- * Return: 0 if successful, negative error code otherwise
- *
- * Allocates memory for the descriptor list. For the first periodic QH,
- * allocates memory for the FrameList and enables periodic scheduling.
- */
-int dwc2_hcd_qh_init_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
-                         gfp_t mem_flags)
-{
-       int retval;
-
-       if (qh->do_split) {
-               dev_err(hsotg->dev,
-                       "SPLIT Transfers are not supported in Descriptor DMA mode.\n");
-               retval = -EINVAL;
-               goto err0;
-       }
-
-       retval = dwc2_desc_list_alloc(hsotg, qh, mem_flags);
-       if (retval)
-               goto err0;
-
-       if (qh->ep_type == USB_ENDPOINT_XFER_ISOC ||
-           qh->ep_type == USB_ENDPOINT_XFER_INT) {
-               if (!hsotg->frame_list) {
-                       retval = dwc2_frame_list_alloc(hsotg, mem_flags);
-                       if (retval)
-                               goto err1;
-                       /* Enable periodic schedule on first periodic QH */
-                       dwc2_per_sched_enable(hsotg, HCFG_FRLISTEN_64);
-               }
-       }
-
-       qh->ntd = 0;
-       return 0;
-
-err1:
-       dwc2_desc_list_free(hsotg, qh);
-err0:
-       return retval;
-}
-
-/**
- * dwc2_hcd_qh_free_ddma() - Frees a QH structure's Descriptor DMA related
- * members
- *
- * @hsotg: The HCD state structure for the DWC OTG controller
- * @qh:    The QH to free
- *
- * Frees descriptor list memory associated with the QH. If QH is periodic and
- * the last, frees FrameList memory and disables periodic scheduling.
- */
-void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
-{
-       dwc2_desc_list_free(hsotg, qh);
-
-       /*
-        * Channel still assigned due to some reasons.
-        * Seen on Isoc URB dequeue. Channel halted but no subsequent
-        * ChHalted interrupt to release the channel. Afterwards
-        * when it comes here from endpoint disable routine
-        * channel remains assigned.
-        */
-       if (qh->channel)
-               dwc2_release_channel_ddma(hsotg, qh);
-
-       if ((qh->ep_type == USB_ENDPOINT_XFER_ISOC ||
-            qh->ep_type == USB_ENDPOINT_XFER_INT) &&
-           (hsotg->core_params->uframe_sched > 0 ||
-            !hsotg->periodic_channels) && hsotg->frame_list) {
-               dwc2_per_sched_disable(hsotg);
-               dwc2_frame_list_free(hsotg);
-       }
-}
-
-static u8 dwc2_frame_to_desc_idx(struct dwc2_qh *qh, u16 frame_idx)
-{
-       if (qh->dev_speed == USB_SPEED_HIGH)
-               /* Descriptor set (8 descriptors) index which is 8-aligned */
-               return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8;
-       else
-               return frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1);
-}
-
-/*
- * Determine starting frame for Isochronous transfer.
- * Few frames skipped to prevent race condition with HC.
- */
-static u16 dwc2_calc_starting_frame(struct dwc2_hsotg *hsotg,
-                                   struct dwc2_qh *qh, u16 *skip_frames)
-{
-       u16 frame;
-
-       hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
-
-       /* sched_frame is always frame number (not uFrame) both in FS and HS! */
-
-       /*
-        * skip_frames is used to limit activated descriptors number
-        * to avoid the situation when HC services the last activated
-        * descriptor firstly.
-        * Example for FS:
-        * Current frame is 1, scheduled frame is 3. Since HC always fetches
-        * the descriptor corresponding to curr_frame+1, the descriptor
-        * corresponding to frame 2 will be fetched. If the number of
-        * descriptors is max=64 (or greather) the list will be fully programmed
-        * with Active descriptors and it is possible case (rare) that the
-        * latest descriptor(considering rollback) corresponding to frame 2 will
-        * be serviced first. HS case is more probable because, in fact, up to
-        * 11 uframes (16 in the code) may be skipped.
-        */
-       if (qh->dev_speed == USB_SPEED_HIGH) {
-               /*
-                * Consider uframe counter also, to start xfer asap. If half of
-                * the frame elapsed skip 2 frames otherwise just 1 frame.
-                * Starting descriptor index must be 8-aligned, so if the
-                * current frame is near to complete the next one is skipped as
-                * well.
-                */
-               if (dwc2_micro_frame_num(hsotg->frame_number) >= 5) {
-                       *skip_frames = 2 * 8;
-                       frame = dwc2_frame_num_inc(hsotg->frame_number,
-                                                  *skip_frames);
-               } else {
-                       *skip_frames = 1 * 8;
-                       frame = dwc2_frame_num_inc(hsotg->frame_number,
-                                                  *skip_frames);
-               }
-
-               frame = dwc2_full_frame_num(frame);
-       } else {
-               /*
-                * Two frames are skipped for FS - the current and the next.
-                * But for descriptor programming, 1 frame (descriptor) is
-                * enough, see example above.
-                */
-               *skip_frames = 1;
-               frame = dwc2_frame_num_inc(hsotg->frame_number, 2);
-       }
-
-       return frame;
-}
-
-/*
- * Calculate initial descriptor index for isochronous transfer based on
- * scheduled frame
- */
-static u16 dwc2_recalc_initial_desc_idx(struct dwc2_hsotg *hsotg,
-                                       struct dwc2_qh *qh)
-{
-       u16 frame, fr_idx, fr_idx_tmp, skip_frames;
-
-       /*
-        * With current ISOC processing algorithm the channel is being released
-        * when no more QTDs in the list (qh->ntd == 0). Thus this function is
-        * called only when qh->ntd == 0 and qh->channel == 0.
-        *
-        * So qh->channel != NULL branch is not used and just not removed from
-        * the source file. It is required for another possible approach which
-        * is, do not disable and release the channel when ISOC session
-        * completed, just move QH to inactive schedule until new QTD arrives.
-        * On new QTD, the QH moved back to 'ready' schedule, starting frame and
-        * therefore starting desc_index are recalculated. In this case channel
-        * is released only on ep_disable.
-        */
-
-       /*
-        * Calculate starting descriptor index. For INTERRUPT endpoint it is
-        * always 0.
-        */
-       if (qh->channel) {
-               frame = dwc2_calc_starting_frame(hsotg, qh, &skip_frames);
-               /*
-                * Calculate initial descriptor index based on FrameList current
-                * bitmap and servicing period
-                */
-               fr_idx_tmp = dwc2_frame_list_idx(frame);
-               fr_idx = (FRLISTEN_64_SIZE +
-                         dwc2_frame_list_idx(qh->sched_frame) - fr_idx_tmp)
-                        % dwc2_frame_incr_val(qh);
-               fr_idx = (fr_idx + fr_idx_tmp) % FRLISTEN_64_SIZE;
-       } else {
-               qh->sched_frame = dwc2_calc_starting_frame(hsotg, qh,
-                                                          &skip_frames);
-               fr_idx = dwc2_frame_list_idx(qh->sched_frame);
-       }
-
-       qh->td_first = qh->td_last = dwc2_frame_to_desc_idx(qh, fr_idx);
-
-       return skip_frames;
-}
-
-#define ISOC_URB_GIVEBACK_ASAP
-
-#define MAX_ISOC_XFER_SIZE_FS  1023
-#define MAX_ISOC_XFER_SIZE_HS  3072
-#define DESCNUM_THRESHOLD      4
-
-static void dwc2_fill_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
-                                        struct dwc2_qtd *qtd,
-                                        struct dwc2_qh *qh, u32 max_xfer_size,
-                                        u16 idx)
-{
-       struct dwc2_hcd_dma_desc *dma_desc = &qh->desc_list[idx];
-       struct dwc2_hcd_iso_packet_desc *frame_desc;
-
-       memset(dma_desc, 0, sizeof(*dma_desc));
-       frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
-
-       if (frame_desc->length > max_xfer_size)
-               qh->n_bytes[idx] = max_xfer_size;
-       else
-               qh->n_bytes[idx] = frame_desc->length;
-
-       dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset);
-       dma_desc->status = qh->n_bytes[idx] << HOST_DMA_ISOC_NBYTES_SHIFT &
-                          HOST_DMA_ISOC_NBYTES_MASK;
-
-#ifdef ISOC_URB_GIVEBACK_ASAP
-       /* Set IOC for each descriptor corresponding to last frame of URB */
-       if (qtd->isoc_frame_index_last == qtd->urb->packet_count)
-               dma_desc->status |= HOST_DMA_IOC;
-#endif
-
-       qh->ntd++;
-       qtd->isoc_frame_index_last++;
-}
-
-static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg,
-                                   struct dwc2_qh *qh, u16 skip_frames)
-{
-       struct dwc2_qtd *qtd;
-       u32 max_xfer_size;
-       u16 idx, inc, n_desc, ntd_max = 0;
-
-       idx = qh->td_last;
-       inc = qh->interval;
-       n_desc = 0;
-
-       if (qh->interval) {
-               ntd_max = (dwc2_max_desc_num(qh) + qh->interval - 1) /
-                               qh->interval;
-               if (skip_frames && !qh->channel)
-                       ntd_max -= skip_frames / qh->interval;
-       }
-
-       max_xfer_size = qh->dev_speed == USB_SPEED_HIGH ?
-                       MAX_ISOC_XFER_SIZE_HS : MAX_ISOC_XFER_SIZE_FS;
-
-       list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) {
-               while (qh->ntd < ntd_max && qtd->isoc_frame_index_last <
-                                               qtd->urb->packet_count) {
-                       if (n_desc > 1)
-                               qh->desc_list[n_desc - 1].status |= HOST_DMA_A;
-                       dwc2_fill_host_isoc_dma_desc(hsotg, qtd, qh,
-                                                    max_xfer_size, idx);
-                       idx = dwc2_desclist_idx_inc(idx, inc, qh->dev_speed);
-                       n_desc++;
-               }
-               qtd->in_process = 1;
-       }
-
-       qh->td_last = idx;
-
-#ifdef ISOC_URB_GIVEBACK_ASAP
-       /* Set IOC for last descriptor if descriptor list is full */
-       if (qh->ntd == ntd_max) {
-               idx = dwc2_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
-               qh->desc_list[idx].status |= HOST_DMA_IOC;
-       }
-#else
-       /*
-        * Set IOC bit only for one descriptor. Always try to be ahead of HW
-        * processing, i.e. on IOC generation driver activates next descriptor
-        * but core continues to process descriptors following the one with IOC
-        * set.
-        */
-
-       if (n_desc > DESCNUM_THRESHOLD)
-               /*
-                * Move IOC "up". Required even if there is only one QTD
-                * in the list, because QTDs might continue to be queued,
-                * but during the activation it was only one queued.
-                * Actually more than one QTD might be in the list if this
-                * function called from XferCompletion - QTDs was queued during
-                * HW processing of the previous descriptor chunk.
-                */
-               idx = dwc2_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2),
-                                           qh->dev_speed);
-       else
-               /*
-                * Set the IOC for the latest descriptor if either number of
-                * descriptors is not greater than threshold or no more new
-                * descriptors activated
-                */
-               idx = dwc2_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
-
-       qh->desc_list[idx].status |= HOST_DMA_IOC;
-#endif
-
-       if (n_desc) {
-               qh->desc_list[n_desc - 1].status |= HOST_DMA_A;
-               if (n_desc > 1)
-                       qh->desc_list[0].status |= HOST_DMA_A;
-       }
-}
-
-static void dwc2_fill_host_dma_desc(struct dwc2_hsotg *hsotg,
-                                   struct dwc2_host_chan *chan,
-                                   struct dwc2_qtd *qtd, struct dwc2_qh *qh,
-                                   int n_desc)
-{
-       struct dwc2_hcd_dma_desc *dma_desc = &qh->desc_list[n_desc];
-       int len = chan->xfer_len;
-
-       if (len > MAX_DMA_DESC_SIZE - (chan->max_packet - 1))
-               len = MAX_DMA_DESC_SIZE - (chan->max_packet - 1);
-
-       if (chan->ep_is_in) {
-               int num_packets;
-
-               if (len > 0 && chan->max_packet)
-                       num_packets = (len + chan->max_packet - 1)
-                                       / chan->max_packet;
-               else
-                       /* Need 1 packet for transfer length of 0 */
-                       num_packets = 1;
-
-               /* Always program an integral # of packets for IN transfers */
-               len = num_packets * chan->max_packet;
-       }
-
-       dma_desc->status = len << HOST_DMA_NBYTES_SHIFT & HOST_DMA_NBYTES_MASK;
-       qh->n_bytes[n_desc] = len;
-
-       if (qh->ep_type == USB_ENDPOINT_XFER_CONTROL &&
-           qtd->control_phase == DWC2_CONTROL_SETUP)
-               dma_desc->status |= HOST_DMA_SUP;
-
-       dma_desc->buf = (u32)chan->xfer_dma;
-
-       /*
-        * Last (or only) descriptor of IN transfer with actual size less
-        * than MaxPacket
-        */
-       if (len > chan->xfer_len) {
-               chan->xfer_len = 0;
-       } else {
-               chan->xfer_dma += len;
-               chan->xfer_len -= len;
-       }
-}
-
-static void dwc2_init_non_isoc_dma_desc(struct dwc2_hsotg *hsotg,
-                                       struct dwc2_qh *qh)
-{
-       struct dwc2_qtd *qtd;
-       struct dwc2_host_chan *chan = qh->channel;
-       int n_desc = 0;
-
-       dev_vdbg(hsotg->dev, "%s(): qh=%p dma=%08lx len=%d\n", __func__, qh,
-                (unsigned long)chan->xfer_dma, chan->xfer_len);
-
-       /*
-        * Start with chan->xfer_dma initialized in assign_and_init_hc(), then
-        * if SG transfer consists of multiple URBs, this pointer is re-assigned
-        * to the buffer of the currently processed QTD. For non-SG request
-        * there is always one QTD active.
-        */
-
-       list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) {
-               dev_vdbg(hsotg->dev, "qtd=%p\n", qtd);
-
-               if (n_desc) {
-                       /* SG request - more than 1 QTD */
-                       chan->xfer_dma = qtd->urb->dma +
-                                       qtd->urb->actual_length;
-                       chan->xfer_len = qtd->urb->length -
-                                       qtd->urb->actual_length;
-                       dev_vdbg(hsotg->dev, "buf=%08lx len=%d\n",
-                                (unsigned long)chan->xfer_dma, chan->xfer_len);
-               }
-
-               qtd->n_desc = 0;
-               do {
-                       if (n_desc > 1) {
-                               qh->desc_list[n_desc - 1].status |= HOST_DMA_A;
-                               dev_vdbg(hsotg->dev,
-                                        "set A bit in desc %d (%p)\n",
-                                        n_desc - 1,
-                                        &qh->desc_list[n_desc - 1]);
-                       }
-                       dwc2_fill_host_dma_desc(hsotg, chan, qtd, qh, n_desc);
-                       dev_vdbg(hsotg->dev,
-                                "desc %d (%p) buf=%08x status=%08x\n",
-                                n_desc, &qh->desc_list[n_desc],
-                                qh->desc_list[n_desc].buf,
-                                qh->desc_list[n_desc].status);
-                       qtd->n_desc++;
-                       n_desc++;
-               } while (chan->xfer_len > 0 &&
-                        n_desc != MAX_DMA_DESC_NUM_GENERIC);
-
-               dev_vdbg(hsotg->dev, "n_desc=%d\n", n_desc);
-               qtd->in_process = 1;
-               if (qh->ep_type == USB_ENDPOINT_XFER_CONTROL)
-                       break;
-               if (n_desc == MAX_DMA_DESC_NUM_GENERIC)
-                       break;
-       }
-
-       if (n_desc) {
-               qh->desc_list[n_desc - 1].status |=
-                               HOST_DMA_IOC | HOST_DMA_EOL | HOST_DMA_A;
-               dev_vdbg(hsotg->dev, "set IOC/EOL/A bits in desc %d (%p)\n",
-                        n_desc - 1, &qh->desc_list[n_desc - 1]);
-               if (n_desc > 1) {
-                       qh->desc_list[0].status |= HOST_DMA_A;
-                       dev_vdbg(hsotg->dev, "set A bit in desc 0 (%p)\n",
-                                &qh->desc_list[0]);
-               }
-               chan->ntd = n_desc;
-       }
-}
-
-/**
- * dwc2_hcd_start_xfer_ddma() - Starts a transfer in Descriptor DMA mode
- *
- * @hsotg: The HCD state structure for the DWC OTG controller
- * @qh:    The QH to init
- *
- * Return: 0 if successful, negative error code otherwise
- *
- * For Control and Bulk endpoints, initializes descriptor list and starts the
- * transfer. For Interrupt and Isochronous endpoints, initializes descriptor
- * list then updates FrameList, marking appropriate entries as active.
- *
- * For Isochronous endpoints the starting descriptor index is calculated based
- * on the scheduled frame, but only on the first transfer descriptor within a
- * session. Then the transfer is started via enabling the channel.
- *
- * For Isochronous endpoints the channel is not halted on XferComplete
- * interrupt so remains assigned to the endpoint(QH) until session is done.
- */
-void dwc2_hcd_start_xfer_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
-{
-       /* Channel is already assigned */
-       struct dwc2_host_chan *chan = qh->channel;
-       u16 skip_frames = 0;
-
-       switch (chan->ep_type) {
-       case USB_ENDPOINT_XFER_CONTROL:
-       case USB_ENDPOINT_XFER_BULK:
-               dwc2_init_non_isoc_dma_desc(hsotg, qh);
-               dwc2_hc_start_transfer_ddma(hsotg, chan);
-               break;
-       case USB_ENDPOINT_XFER_INT:
-               dwc2_init_non_isoc_dma_desc(hsotg, qh);
-               dwc2_update_frame_list(hsotg, qh, 1);
-               dwc2_hc_start_transfer_ddma(hsotg, chan);
-               break;
-       case USB_ENDPOINT_XFER_ISOC:
-               if (!qh->ntd)
-                       skip_frames = dwc2_recalc_initial_desc_idx(hsotg, qh);
-               dwc2_init_isoc_dma_desc(hsotg, qh, skip_frames);
-
-               if (!chan->xfer_started) {
-                       dwc2_update_frame_list(hsotg, qh, 1);
-
-                       /*
-                        * Always set to max, instead of actual size. Otherwise
-                        * ntd will be changed with channel being enabled. Not
-                        * recommended.
-                        */
-                       chan->ntd = dwc2_max_desc_num(qh);
-
-                       /* Enable channel only once for ISOC */
-                       dwc2_hc_start_transfer_ddma(hsotg, chan);
-               }
-
-               break;
-       default:
-               break;
-       }
-}
-
-#define DWC2_CMPL_DONE         1
-#define DWC2_CMPL_STOP         2
-
-static int dwc2_cmpl_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
-                                       struct dwc2_host_chan *chan,
-                                       struct dwc2_qtd *qtd,
-                                       struct dwc2_qh *qh, u16 idx)
-{
-       struct dwc2_hcd_dma_desc *dma_desc = &qh->desc_list[idx];
-       struct dwc2_hcd_iso_packet_desc *frame_desc;
-       u16 remain = 0;
-       int rc = 0;
-
-       if (!qtd->urb)
-               return -EINVAL;
-
-       frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
-       dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset);
-       if (chan->ep_is_in)
-               remain = (dma_desc->status & HOST_DMA_ISOC_NBYTES_MASK) >>
-                        HOST_DMA_ISOC_NBYTES_SHIFT;
-
-       if ((dma_desc->status & HOST_DMA_STS_MASK) == HOST_DMA_STS_PKTERR) {
-               /*
-                * XactError, or unable to complete all the transactions
-                * in the scheduled micro-frame/frame, both indicated by
-                * HOST_DMA_STS_PKTERR
-                */
-               qtd->urb->error_count++;
-               frame_desc->actual_length = qh->n_bytes[idx] - remain;
-               frame_desc->status = -EPROTO;
-       } else {
-               /* Success */
-               frame_desc->actual_length = qh->n_bytes[idx] - remain;
-               frame_desc->status = 0;
-       }
-
-       if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
-               /*
-                * urb->status is not used for isoc transfers here. The
-                * individual frame_desc status are used instead.
-                */
-               dwc2_host_complete(hsotg, qtd, 0);
-               dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
-
-               /*
-                * This check is necessary because urb_dequeue can be called
-                * from urb complete callback (sound driver for example). All
-                * pending URBs are dequeued there, so no need for further
-                * processing.
-                */
-               if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE)
-                       return -1;
-               rc = DWC2_CMPL_DONE;
-       }
-
-       qh->ntd--;
-
-       /* Stop if IOC requested descriptor reached */
-       if (dma_desc->status & HOST_DMA_IOC)
-               rc = DWC2_CMPL_STOP;
-
-       return rc;
-}
-
-static void dwc2_complete_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
-                                        struct dwc2_host_chan *chan,
-                                        enum dwc2_halt_status halt_status)
-{
-       struct dwc2_hcd_iso_packet_desc *frame_desc;
-       struct dwc2_qtd *qtd, *qtd_tmp;
-       struct dwc2_qh *qh;
-       u16 idx;
-       int rc;
-
-       qh = chan->qh;
-       idx = qh->td_first;
-
-       if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) {
-               list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry)
-                       qtd->in_process = 0;
-               return;
-       }
-
-       if (halt_status == DWC2_HC_XFER_AHB_ERR ||
-           halt_status == DWC2_HC_XFER_BABBLE_ERR) {
-               /*
-                * Channel is halted in these error cases, considered as serious
-                * issues.
-                * Complete all URBs marking all frames as failed, irrespective
-                * whether some of the descriptors (frames) succeeded or not.
-                * Pass error code to completion routine as well, to update
-                * urb->status, some of class drivers might use it to stop
-                * queing transfer requests.
-                */
-               int err = halt_status == DWC2_HC_XFER_AHB_ERR ?
-                         -EIO : -EOVERFLOW;
-
-               list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
-                                        qtd_list_entry) {
-                       if (qtd->urb) {
-                               for (idx = 0; idx < qtd->urb->packet_count;
-                                    idx++) {
-                                       frame_desc = &qtd->urb->iso_descs[idx];
-                                       frame_desc->status = err;
-                               }
-
-                               dwc2_host_complete(hsotg, qtd, err);
-                       }
-
-                       dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
-               }
-
-               return;
-       }
-
-       list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
-               if (!qtd->in_process)
-                       break;
-               do {
-                       rc = dwc2_cmpl_host_isoc_dma_desc(hsotg, chan, qtd, qh,
-                                                         idx);
-                       if (rc < 0)
-                               return;
-                       idx = dwc2_desclist_idx_inc(idx, qh->interval,
-                                                   chan->speed);
-                       if (rc == DWC2_CMPL_STOP)
-                               goto stop_scan;
-                       if (rc == DWC2_CMPL_DONE)
-                               break;
-               } while (idx != qh->td_first);
-       }
-
-stop_scan:
-       qh->td_first = idx;
-}
-
-static int dwc2_update_non_isoc_urb_state_ddma(struct dwc2_hsotg *hsotg,
-                                       struct dwc2_host_chan *chan,
-                                       struct dwc2_qtd *qtd,
-                                       struct dwc2_hcd_dma_desc *dma_desc,
-                                       enum dwc2_halt_status halt_status,
-                                       u32 n_bytes, int *xfer_done)
-{
-       struct dwc2_hcd_urb *urb = qtd->urb;
-       u16 remain = 0;
-
-       if (chan->ep_is_in)
-               remain = (dma_desc->status & HOST_DMA_NBYTES_MASK) >>
-                        HOST_DMA_NBYTES_SHIFT;
-
-       dev_vdbg(hsotg->dev, "remain=%d dwc2_urb=%p\n", remain, urb);
-
-       if (halt_status == DWC2_HC_XFER_AHB_ERR) {
-               dev_err(hsotg->dev, "EIO\n");
-               urb->status = -EIO;
-               return 1;
-       }
-
-       if ((dma_desc->status & HOST_DMA_STS_MASK) == HOST_DMA_STS_PKTERR) {
-               switch (halt_status) {
-               case DWC2_HC_XFER_STALL:
-                       dev_vdbg(hsotg->dev, "Stall\n");
-                       urb->status = -EPIPE;
-                       break;
-               case DWC2_HC_XFER_BABBLE_ERR:
-                       dev_err(hsotg->dev, "Babble\n");
-                       urb->status = -EOVERFLOW;
-                       break;
-               case DWC2_HC_XFER_XACT_ERR:
-                       dev_err(hsotg->dev, "XactErr\n");
-                       urb->status = -EPROTO;
-                       break;
-               default:
-                       dev_err(hsotg->dev,
-                               "%s: Unhandled descriptor error status (%d)\n",
-                               __func__, halt_status);
-                       break;
-               }
-               return 1;
-       }
-
-       if (dma_desc->status & HOST_DMA_A) {
-               dev_vdbg(hsotg->dev,
-                        "Active descriptor encountered on channel %d\n",
-                        chan->hc_num);
-               return 0;
-       }
-
-       if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL) {
-               if (qtd->control_phase == DWC2_CONTROL_DATA) {
-                       urb->actual_length += n_bytes - remain;
-                       if (remain || urb->actual_length >= urb->length) {
-                               /*
-                                * For Control Data stage do not set urb->status
-                                * to 0, to prevent URB callback. Set it when
-                                * Status phase is done. See below.
-                                */
-                               *xfer_done = 1;
-                       }
-               } else if (qtd->control_phase == DWC2_CONTROL_STATUS) {
-                       urb->status = 0;
-                       *xfer_done = 1;
-               }
-               /* No handling for SETUP stage */
-       } else {
-               /* BULK and INTR */
-               urb->actual_length += n_bytes - remain;
-               dev_vdbg(hsotg->dev, "length=%d actual=%d\n", urb->length,
-                        urb->actual_length);
-               if (remain || urb->actual_length >= urb->length) {
-                       urb->status = 0;
-                       *xfer_done = 1;
-               }
-       }
-
-       return 0;
-}
-
-static int dwc2_process_non_isoc_desc(struct dwc2_hsotg *hsotg,
-                                     struct dwc2_host_chan *chan,
-                                     int chnum, struct dwc2_qtd *qtd,
-                                     int desc_num,
-                                     enum dwc2_halt_status halt_status,
-                                     int *xfer_done)
-{
-       struct dwc2_qh *qh = chan->qh;
-       struct dwc2_hcd_urb *urb = qtd->urb;
-       struct dwc2_hcd_dma_desc *dma_desc;
-       u32 n_bytes;
-       int failed;
-
-       dev_vdbg(hsotg->dev, "%s()\n", __func__);
-
-       if (!urb)
-               return -EINVAL;
-
-       dma_desc = &qh->desc_list[desc_num];
-       n_bytes = qh->n_bytes[desc_num];
-       dev_vdbg(hsotg->dev,
-                "qtd=%p dwc2_urb=%p desc_num=%d desc=%p n_bytes=%d\n",
-                qtd, urb, desc_num, dma_desc, n_bytes);
-       failed = dwc2_update_non_isoc_urb_state_ddma(hsotg, chan, qtd, dma_desc,
-                                                    halt_status, n_bytes,
-                                                    xfer_done);
-       if (failed || (*xfer_done && urb->status != -EINPROGRESS)) {
-               dwc2_host_complete(hsotg, qtd, urb->status);
-               dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
-               dev_vdbg(hsotg->dev, "failed=%1x xfer_done=%1x status=%08x\n",
-                        failed, *xfer_done, urb->status);
-               return failed;
-       }
-
-       if (qh->ep_type == USB_ENDPOINT_XFER_CONTROL) {
-               switch (qtd->control_phase) {
-               case DWC2_CONTROL_SETUP:
-                       if (urb->length > 0)
-                               qtd->control_phase = DWC2_CONTROL_DATA;
-                       else
-                               qtd->control_phase = DWC2_CONTROL_STATUS;
-                       dev_vdbg(hsotg->dev,
-                                "  Control setup transaction done\n");
-                       break;
-               case DWC2_CONTROL_DATA:
-                       if (*xfer_done) {
-                               qtd->control_phase = DWC2_CONTROL_STATUS;
-                               dev_vdbg(hsotg->dev,
-                                        "  Control data transfer done\n");
-                       } else if (desc_num + 1 == qtd->n_desc) {
-                               /*
-                                * Last descriptor for Control data stage which
-                                * is not completed yet
-                                */
-                               dwc2_hcd_save_data_toggle(hsotg, chan, chnum,
-                                                         qtd);
-                       }
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       return 0;
-}
-
-static void dwc2_complete_non_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
-                                            struct dwc2_host_chan *chan,
-                                            int chnum,
-                                            enum dwc2_halt_status halt_status)
-{
-       struct list_head *qtd_item, *qtd_tmp;
-       struct dwc2_qh *qh = chan->qh;
-       struct dwc2_qtd *qtd = NULL;
-       int xfer_done;
-       int desc_num = 0;
-
-       if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) {
-               list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry)
-                       qtd->in_process = 0;
-               return;
-       }
-
-       list_for_each_safe(qtd_item, qtd_tmp, &qh->qtd_list) {
-               int i;
-
-               qtd = list_entry(qtd_item, struct dwc2_qtd, qtd_list_entry);
-               xfer_done = 0;
-
-               for (i = 0; i < qtd->n_desc; i++) {
-                       if (dwc2_process_non_isoc_desc(hsotg, chan, chnum, qtd,
-                                                      desc_num, halt_status,
-                                                      &xfer_done)) {
-                               qtd = NULL;
-                               break;
-                       }
-                       desc_num++;
-               }
-       }
-
-       if (qh->ep_type != USB_ENDPOINT_XFER_CONTROL) {
-               /*
-                * Resetting the data toggle for bulk and interrupt endpoints
-                * in case of stall. See handle_hc_stall_intr().
-                */
-               if (halt_status == DWC2_HC_XFER_STALL)
-                       qh->data_toggle = DWC2_HC_PID_DATA0;
-               else if (qtd)
-                       dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
-       }
-
-       if (halt_status == DWC2_HC_XFER_COMPLETE) {
-               if (chan->hcint & HCINTMSK_NYET) {
-                       /*
-                        * Got a NYET on the last transaction of the transfer.
-                        * It means that the endpoint should be in the PING
-                        * state at the beginning of the next transfer.
-                        */
-                       qh->ping_state = 1;
-               }
-       }
-}
-
-/**
- * dwc2_hcd_complete_xfer_ddma() - Scans the descriptor list, updates URB's
- * status and calls completion routine for the URB if it's done. Called from
- * interrupt handlers.
- *
- * @hsotg:       The HCD state structure for the DWC OTG controller
- * @chan:        Host channel the transfer is completed on
- * @chnum:       Index of Host channel registers
- * @halt_status: Reason the channel is being halted or just XferComplete
- *               for isochronous transfers
- *
- * Releases the channel to be used by other transfers.
- * In case of Isochronous endpoint the channel is not halted until the end of
- * the session, i.e. QTD list is empty.
- * If periodic channel released the FrameList is updated accordingly.
- * Calls transaction selection routines to activate pending transfers.
- */
-void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg,
-                                struct dwc2_host_chan *chan, int chnum,
-                                enum dwc2_halt_status halt_status)
-{
-       struct dwc2_qh *qh = chan->qh;
-       int continue_isoc_xfer = 0;
-       enum dwc2_transaction_type tr_type;
-
-       if (chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
-               dwc2_complete_isoc_xfer_ddma(hsotg, chan, halt_status);
-
-               /* Release the channel if halted or session completed */
-               if (halt_status != DWC2_HC_XFER_COMPLETE ||
-                   list_empty(&qh->qtd_list)) {
-                       /* Halt the channel if session completed */
-                       if (halt_status == DWC2_HC_XFER_COMPLETE)
-                               dwc2_hc_halt(hsotg, chan, halt_status);
-                       dwc2_release_channel_ddma(hsotg, qh);
-                       dwc2_hcd_qh_unlink(hsotg, qh);
-               } else {
-                       /* Keep in assigned schedule to continue transfer */
-                       list_move(&qh->qh_list_entry,
-                                 &hsotg->periodic_sched_assigned);
-                       continue_isoc_xfer = 1;
-               }
-               /*
-                * Todo: Consider the case when period exceeds FrameList size.
-                * Frame Rollover interrupt should be used.
-                */
-       } else {
-               /*
-                * Scan descriptor list to complete the URB(s), then release
-                * the channel
-                */
-               dwc2_complete_non_isoc_xfer_ddma(hsotg, chan, chnum,
-                                                halt_status);
-               dwc2_release_channel_ddma(hsotg, qh);
-               dwc2_hcd_qh_unlink(hsotg, qh);
-
-               if (!list_empty(&qh->qtd_list)) {
-                       /*
-                        * Add back to inactive non-periodic schedule on normal
-                        * completion
-                        */
-                       dwc2_hcd_qh_add(hsotg, qh);
-               }
-       }
-
-       tr_type = dwc2_hcd_select_transactions(hsotg);
-       if (tr_type != DWC2_TRANSACTION_NONE || continue_isoc_xfer) {
-               if (continue_isoc_xfer) {
-                       if (tr_type == DWC2_TRANSACTION_NONE)
-                               tr_type = DWC2_TRANSACTION_PERIODIC;
-                       else if (tr_type == DWC2_TRANSACTION_NON_PERIODIC)
-                               tr_type = DWC2_TRANSACTION_ALL;
-               }
-               dwc2_hcd_queue_transactions(hsotg, tr_type);
-       }
-}
diff --git a/drivers/staging/dwc2/hcd_intr.c b/drivers/staging/dwc2/hcd_intr.c
deleted file mode 100644 (file)
index 012f17e..0000000
+++ /dev/null
@@ -1,2119 +0,0 @@
-/*
- * hcd_intr.c - DesignWare HS OTG Controller host-mode interrupt handling
- *
- * Copyright (C) 2004-2013 Synopsys, Inc.
- *
- * 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") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * 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.
- */
-
-/*
- * This file contains the interrupt handlers for Host mode
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-
-#include <linux/usb/hcd.h>
-#include <linux/usb/ch11.h>
-
-#include "core.h"
-#include "hcd.h"
-
-/* This function is for debug only */
-static void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg)
-{
-#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
-       u16 curr_frame_number = hsotg->frame_number;
-
-       if (hsotg->frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
-               if (((hsotg->last_frame_num + 1) & HFNUM_MAX_FRNUM) !=
-                   curr_frame_number) {
-                       hsotg->frame_num_array[hsotg->frame_num_idx] =
-                                       curr_frame_number;
-                       hsotg->last_frame_num_array[hsotg->frame_num_idx] =
-                                       hsotg->last_frame_num;
-                       hsotg->frame_num_idx++;
-               }
-       } else if (!hsotg->dumped_frame_num_array) {
-               int i;
-
-               dev_info(hsotg->dev, "Frame     Last Frame\n");
-               dev_info(hsotg->dev, "-----     ----------\n");
-               for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) {
-                       dev_info(hsotg->dev, "0x%04x    0x%04x\n",
-                                hsotg->frame_num_array[i],
-                                hsotg->last_frame_num_array[i]);
-               }
-               hsotg->dumped_frame_num_array = 1;
-       }
-       hsotg->last_frame_num = curr_frame_number;
-#endif
-}
-
-static void dwc2_hc_handle_tt_clear(struct dwc2_hsotg *hsotg,
-                                   struct dwc2_host_chan *chan,
-                                   struct dwc2_qtd *qtd)
-{
-       struct urb *usb_urb;
-
-       if (!chan->qh)
-               return;
-
-       if (chan->qh->dev_speed == USB_SPEED_HIGH)
-               return;
-
-       if (!qtd->urb)
-               return;
-
-       usb_urb = qtd->urb->priv;
-       if (!usb_urb || !usb_urb->dev || !usb_urb->dev->tt)
-               return;
-
-       if (qtd->urb->status != -EPIPE && qtd->urb->status != -EREMOTEIO) {
-               chan->qh->tt_buffer_dirty = 1;
-               if (usb_hub_clear_tt_buffer(usb_urb))
-                       /* Clear failed; let's hope things work anyway */
-                       chan->qh->tt_buffer_dirty = 0;
-       }
-}
-
-/*
- * Handles the start-of-frame interrupt in host mode. Non-periodic
- * transactions may be queued to the DWC_otg controller for the current
- * (micro)frame. Periodic transactions may be queued to the controller
- * for the next (micro)frame.
- */
-static void dwc2_sof_intr(struct dwc2_hsotg *hsotg)
-{
-       struct list_head *qh_entry;
-       struct dwc2_qh *qh;
-       enum dwc2_transaction_type tr_type;
-
-#ifdef DEBUG_SOF
-       dev_vdbg(hsotg->dev, "--Start of Frame Interrupt--\n");
-#endif
-
-       hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
-
-       dwc2_track_missed_sofs(hsotg);
-
-       /* Determine whether any periodic QHs should be executed */
-       qh_entry = hsotg->periodic_sched_inactive.next;
-       while (qh_entry != &hsotg->periodic_sched_inactive) {
-               qh = list_entry(qh_entry, struct dwc2_qh, qh_list_entry);
-               qh_entry = qh_entry->next;
-               if (dwc2_frame_num_le(qh->sched_frame, hsotg->frame_number))
-                       /*
-                        * Move QH to the ready list to be executed next
-                        * (micro)frame
-                        */
-                       list_move(&qh->qh_list_entry,
-                                 &hsotg->periodic_sched_ready);
-       }
-       tr_type = dwc2_hcd_select_transactions(hsotg);
-       if (tr_type != DWC2_TRANSACTION_NONE)
-               dwc2_hcd_queue_transactions(hsotg, tr_type);
-
-       /* Clear interrupt */
-       writel(GINTSTS_SOF, hsotg->regs + GINTSTS);
-}
-
-/*
- * Handles the Rx FIFO Level Interrupt, which indicates that there is
- * at least one packet in the Rx FIFO. The packets are moved from the FIFO to
- * memory if the DWC_otg controller is operating in Slave mode.
- */
-static void dwc2_rx_fifo_level_intr(struct dwc2_hsotg *hsotg)
-{
-       u32 grxsts, chnum, bcnt, dpid, pktsts;
-       struct dwc2_host_chan *chan;
-
-       if (dbg_perio())
-               dev_vdbg(hsotg->dev, "--RxFIFO Level Interrupt--\n");
-
-       grxsts = readl(hsotg->regs + GRXSTSP);
-       chnum = (grxsts & GRXSTS_HCHNUM_MASK) >> GRXSTS_HCHNUM_SHIFT;
-       chan = hsotg->hc_ptr_array[chnum];
-       if (!chan) {
-               dev_err(hsotg->dev, "Unable to get corresponding channel\n");
-               return;
-       }
-
-       bcnt = (grxsts & GRXSTS_BYTECNT_MASK) >> GRXSTS_BYTECNT_SHIFT;
-       dpid = (grxsts & GRXSTS_DPID_MASK) >> GRXSTS_DPID_SHIFT;
-       pktsts = (grxsts & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT;
-
-       /* Packet Status */
-       if (dbg_perio()) {
-               dev_vdbg(hsotg->dev, "    Ch num = %d\n", chnum);
-               dev_vdbg(hsotg->dev, "    Count = %d\n", bcnt);
-               dev_vdbg(hsotg->dev, "    DPID = %d, chan.dpid = %d\n", dpid,
-                        chan->data_pid_start);
-               dev_vdbg(hsotg->dev, "    PStatus = %d\n", pktsts);
-       }
-
-       switch (pktsts) {
-       case GRXSTS_PKTSTS_HCHIN:
-               /* Read the data into the host buffer */
-               if (bcnt > 0) {
-                       dwc2_read_packet(hsotg, chan->xfer_buf, bcnt);
-
-                       /* Update the HC fields for the next packet received */
-                       chan->xfer_count += bcnt;
-                       chan->xfer_buf += bcnt;
-               }
-               break;
-       case GRXSTS_PKTSTS_HCHIN_XFER_COMP:
-       case GRXSTS_PKTSTS_DATATOGGLEERR:
-       case GRXSTS_PKTSTS_HCHHALTED:
-               /* Handled in interrupt, just ignore data */
-               break;
-       default:
-               dev_err(hsotg->dev,
-                       "RxFIFO Level Interrupt: Unknown status %d\n", pktsts);
-               break;
-       }
-}
-
-/*
- * This interrupt occurs when the non-periodic Tx FIFO is half-empty. More
- * data packets may be written to the FIFO for OUT transfers. More requests
- * may be written to the non-periodic request queue for IN transfers. This
- * interrupt is enabled only in Slave mode.
- */
-static void dwc2_np_tx_fifo_empty_intr(struct dwc2_hsotg *hsotg)
-{
-       dev_vdbg(hsotg->dev, "--Non-Periodic TxFIFO Empty Interrupt--\n");
-       dwc2_hcd_queue_transactions(hsotg, DWC2_TRANSACTION_NON_PERIODIC);
-}
-
-/*
- * This interrupt occurs when the periodic Tx FIFO is half-empty. More data
- * packets may be written to the FIFO for OUT transfers. More requests may be
- * written to the periodic request queue for IN transfers. This interrupt is
- * enabled only in Slave mode.
- */
-static void dwc2_perio_tx_fifo_empty_intr(struct dwc2_hsotg *hsotg)
-{
-       if (dbg_perio())
-               dev_vdbg(hsotg->dev, "--Periodic TxFIFO Empty Interrupt--\n");
-       dwc2_hcd_queue_transactions(hsotg, DWC2_TRANSACTION_PERIODIC);
-}
-
-static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
-                             u32 *hprt0_modify)
-{
-       struct dwc2_core_params *params = hsotg->core_params;
-       int do_reset = 0;
-       u32 usbcfg;
-       u32 prtspd;
-       u32 hcfg;
-       u32 fslspclksel;
-       u32 hfir;
-
-       dev_vdbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
-
-       /* Every time when port enables calculate HFIR.FrInterval */
-       hfir = readl(hsotg->regs + HFIR);
-       hfir &= ~HFIR_FRINT_MASK;
-       hfir |= dwc2_calc_frame_interval(hsotg) << HFIR_FRINT_SHIFT &
-               HFIR_FRINT_MASK;
-       writel(hfir, hsotg->regs + HFIR);
-
-       /* Check if we need to adjust the PHY clock speed for low power */
-       if (!params->host_support_fs_ls_low_power) {
-               /* Port has been enabled, set the reset change flag */
-               hsotg->flags.b.port_reset_change = 1;
-               return;
-       }
-
-       usbcfg = readl(hsotg->regs + GUSBCFG);
-       prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
-
-       if (prtspd == HPRT0_SPD_LOW_SPEED || prtspd == HPRT0_SPD_FULL_SPEED) {
-               /* Low power */
-               if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL)) {
-                       /* Set PHY low power clock select for FS/LS devices */
-                       usbcfg |= GUSBCFG_PHY_LP_CLK_SEL;
-                       writel(usbcfg, hsotg->regs + GUSBCFG);
-                       do_reset = 1;
-               }
-
-               hcfg = readl(hsotg->regs + HCFG);
-               fslspclksel = (hcfg & HCFG_FSLSPCLKSEL_MASK) >>
-                             HCFG_FSLSPCLKSEL_SHIFT;
-
-               if (prtspd == HPRT0_SPD_LOW_SPEED &&
-                   params->host_ls_low_power_phy_clk ==
-                   DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ) {
-                       /* 6 MHZ */
-                       dev_vdbg(hsotg->dev,
-                                "FS_PHY programming HCFG to 6 MHz\n");
-                       if (fslspclksel != HCFG_FSLSPCLKSEL_6_MHZ) {
-                               fslspclksel = HCFG_FSLSPCLKSEL_6_MHZ;
-                               hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
-                               hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
-                               writel(hcfg, hsotg->regs + HCFG);
-                               do_reset = 1;
-                       }
-               } else {
-                       /* 48 MHZ */
-                       dev_vdbg(hsotg->dev,
-                                "FS_PHY programming HCFG to 48 MHz\n");
-                       if (fslspclksel != HCFG_FSLSPCLKSEL_48_MHZ) {
-                               fslspclksel = HCFG_FSLSPCLKSEL_48_MHZ;
-                               hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
-                               hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
-                               writel(hcfg, hsotg->regs + HCFG);
-                               do_reset = 1;
-                       }
-               }
-       } else {
-               /* Not low power */
-               if (usbcfg & GUSBCFG_PHY_LP_CLK_SEL) {
-                       usbcfg &= ~GUSBCFG_PHY_LP_CLK_SEL;
-                       writel(usbcfg, hsotg->regs + GUSBCFG);
-                       do_reset = 1;
-               }
-       }
-
-       if (do_reset) {
-               *hprt0_modify |= HPRT0_RST;
-               queue_delayed_work(hsotg->wq_otg, &hsotg->reset_work,
-                                  msecs_to_jiffies(60));
-       } else {
-               /* Port has been enabled, set the reset change flag */
-               hsotg->flags.b.port_reset_change = 1;
-       }
-}
-
-/*
- * There are multiple conditions that can cause a port interrupt. This function
- * determines which interrupt conditions have occurred and handles them
- * appropriately.
- */
-static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
-{
-       u32 hprt0;
-       u32 hprt0_modify;
-
-       dev_vdbg(hsotg->dev, "--Port Interrupt--\n");
-
-       hprt0 = readl(hsotg->regs + HPRT0);
-       hprt0_modify = hprt0;
-
-       /*
-        * Clear appropriate bits in HPRT0 to clear the interrupt bit in
-        * GINTSTS
-        */
-       hprt0_modify &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG |
-                         HPRT0_OVRCURRCHG);
-
-       /*
-        * Port Connect Detected
-        * Set flag and clear if detected
-        */
-       if (hprt0 & HPRT0_CONNDET) {
-               dev_vdbg(hsotg->dev,
-                        "--Port Interrupt HPRT0=0x%08x Port Connect Detected--\n",
-                        hprt0);
-               hsotg->flags.b.port_connect_status_change = 1;
-               hsotg->flags.b.port_connect_status = 1;
-               hprt0_modify |= HPRT0_CONNDET;
-
-               /*
-                * The Hub driver asserts a reset when it sees port connect
-                * status change flag
-                */
-       }
-
-       /*
-        * Port Enable Changed
-        * Clear if detected - Set internal flag if disabled
-        */
-       if (hprt0 & HPRT0_ENACHG) {
-               dev_vdbg(hsotg->dev,
-                        "  --Port Interrupt HPRT0=0x%08x Port Enable Changed (now %d)--\n",
-                        hprt0, !!(hprt0 & HPRT0_ENA));
-               hprt0_modify |= HPRT0_ENACHG;
-               if (hprt0 & HPRT0_ENA)
-                       dwc2_hprt0_enable(hsotg, hprt0, &hprt0_modify);
-               else
-                       hsotg->flags.b.port_enable_change = 1;
-       }
-
-       /* Overcurrent Change Interrupt */
-       if (hprt0 & HPRT0_OVRCURRCHG) {
-               dev_vdbg(hsotg->dev,
-                        "  --Port Interrupt HPRT0=0x%08x Port Overcurrent Changed--\n",
-                        hprt0);
-               hsotg->flags.b.port_over_current_change = 1;
-               hprt0_modify |= HPRT0_OVRCURRCHG;
-       }
-
-       /* Clear Port Interrupts */
-       writel(hprt0_modify, hsotg->regs + HPRT0);
-}
-
-/*
- * Gets the actual length of a transfer after the transfer halts. halt_status
- * holds the reason for the halt.
- *
- * For IN transfers where halt_status is DWC2_HC_XFER_COMPLETE, *short_read
- * is set to 1 upon return if less than the requested number of bytes were
- * transferred. short_read may also be NULL on entry, in which case it remains
- * unchanged.
- */
-static u32 dwc2_get_actual_xfer_length(struct dwc2_hsotg *hsotg,
-                                      struct dwc2_host_chan *chan, int chnum,
-                                      struct dwc2_qtd *qtd,
-                                      enum dwc2_halt_status halt_status,
-                                      int *short_read)
-{
-       u32 hctsiz, count, length;
-
-       hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
-
-       if (halt_status == DWC2_HC_XFER_COMPLETE) {
-               if (chan->ep_is_in) {
-                       count = (hctsiz & TSIZ_XFERSIZE_MASK) >>
-                               TSIZ_XFERSIZE_SHIFT;
-                       length = chan->xfer_len - count;
-                       if (short_read != NULL)
-                               *short_read = (count != 0);
-               } else if (chan->qh->do_split) {
-                       length = qtd->ssplit_out_xfer_count;
-               } else {
-                       length = chan->xfer_len;
-               }
-       } else {
-               /*
-                * Must use the hctsiz.pktcnt field to determine how much data
-                * has been transferred. This field reflects the number of
-                * packets that have been transferred via the USB. This is
-                * always an integral number of packets if the transfer was
-                * halted before its normal completion. (Can't use the
-                * hctsiz.xfersize field because that reflects the number of
-                * bytes transferred via the AHB, not the USB).
-                */
-               count = (hctsiz & TSIZ_PKTCNT_MASK) >> TSIZ_PKTCNT_SHIFT;
-               length = (chan->start_pkt_count - count) * chan->max_packet;
-       }
-
-       return length;
-}
-
-/**
- * dwc2_update_urb_state() - Updates the state of the URB after a Transfer
- * Complete interrupt on the host channel. Updates the actual_length field
- * of the URB based on the number of bytes transferred via the host channel.
- * Sets the URB status if the data transfer is finished.
- *
- * Return: 1 if the data transfer specified by the URB is completely finished,
- * 0 otherwise
- */
-static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
-                                struct dwc2_host_chan *chan, int chnum,
-                                struct dwc2_hcd_urb *urb,
-                                struct dwc2_qtd *qtd)
-{
-       u32 hctsiz;
-       int xfer_done = 0;
-       int short_read = 0;
-       int xfer_length = dwc2_get_actual_xfer_length(hsotg, chan, chnum, qtd,
-                                                     DWC2_HC_XFER_COMPLETE,
-                                                     &short_read);
-
-       if (urb->actual_length + xfer_length > urb->length) {
-               dev_warn(hsotg->dev, "%s(): trimming xfer length\n", __func__);
-               xfer_length = urb->length - urb->actual_length;
-       }
-
-       /* Non DWORD-aligned buffer case handling */
-       if (chan->align_buf && xfer_length && chan->ep_is_in) {
-               dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
-               dma_sync_single_for_cpu(hsotg->dev, urb->dma, urb->length,
-                                       DMA_FROM_DEVICE);
-               memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
-                      xfer_length);
-               dma_sync_single_for_device(hsotg->dev, urb->dma, urb->length,
-                                          DMA_FROM_DEVICE);
-       }
-
-       dev_vdbg(hsotg->dev, "urb->actual_length=%d xfer_length=%d\n",
-                urb->actual_length, xfer_length);
-       urb->actual_length += xfer_length;
-
-       if (xfer_length && chan->ep_type == USB_ENDPOINT_XFER_BULK &&
-           (urb->flags & URB_SEND_ZERO_PACKET) &&
-           urb->actual_length >= urb->length &&
-           !(urb->length % chan->max_packet)) {
-               xfer_done = 0;
-       } else if (short_read || urb->actual_length >= urb->length) {
-               xfer_done = 1;
-               urb->status = 0;
-       }
-
-       hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
-       dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
-                __func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
-       dev_vdbg(hsotg->dev, "  chan->xfer_len %d\n", chan->xfer_len);
-       dev_vdbg(hsotg->dev, "  hctsiz.xfersize %d\n",
-                (hctsiz & TSIZ_XFERSIZE_MASK) >> TSIZ_XFERSIZE_SHIFT);
-       dev_vdbg(hsotg->dev, "  urb->transfer_buffer_length %d\n", urb->length);
-       dev_vdbg(hsotg->dev, "  urb->actual_length %d\n", urb->actual_length);
-       dev_vdbg(hsotg->dev, "  short_read %d, xfer_done %d\n", short_read,
-                xfer_done);
-
-       return xfer_done;
-}
-
-/*
- * Save the starting data toggle for the next transfer. The data toggle is
- * saved in the QH for non-control transfers and it's saved in the QTD for
- * control transfers.
- */
-void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg,
-                              struct dwc2_host_chan *chan, int chnum,
-                              struct dwc2_qtd *qtd)
-{
-       u32 hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
-       u32 pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT;
-
-       if (chan->ep_type != USB_ENDPOINT_XFER_CONTROL) {
-               if (pid == TSIZ_SC_MC_PID_DATA0)
-                       chan->qh->data_toggle = DWC2_HC_PID_DATA0;
-               else
-                       chan->qh->data_toggle = DWC2_HC_PID_DATA1;
-       } else {
-               if (pid == TSIZ_SC_MC_PID_DATA0)
-                       qtd->data_toggle = DWC2_HC_PID_DATA0;
-               else
-                       qtd->data_toggle = DWC2_HC_PID_DATA1;
-       }
-}
-
-/**
- * dwc2_update_isoc_urb_state() - Updates the state of an Isochronous URB when
- * the transfer is stopped for any reason. The fields of the current entry in
- * the frame descriptor array are set based on the transfer state and the input
- * halt_status. Completes the Isochronous URB if all the URB frames have been
- * completed.
- *
- * Return: DWC2_HC_XFER_COMPLETE if there are more frames remaining to be
- * transferred in the URB. Otherwise return DWC2_HC_XFER_URB_COMPLETE.
- */
-static enum dwc2_halt_status dwc2_update_isoc_urb_state(
-               struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
-               int chnum, struct dwc2_qtd *qtd,
-               enum dwc2_halt_status halt_status)
-{
-       struct dwc2_hcd_iso_packet_desc *frame_desc;
-       struct dwc2_hcd_urb *urb = qtd->urb;
-
-       if (!urb)
-               return DWC2_HC_XFER_NO_HALT_STATUS;
-
-       frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
-
-       switch (halt_status) {
-       case DWC2_HC_XFER_COMPLETE:
-               frame_desc->status = 0;
-               frame_desc->actual_length = dwc2_get_actual_xfer_length(hsotg,
-                                       chan, chnum, qtd, halt_status, NULL);
-
-               /* Non DWORD-aligned buffer case handling */
-               if (chan->align_buf && frame_desc->actual_length &&
-                   chan->ep_is_in) {
-                       dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
-                                __func__);
-                       dma_sync_single_for_cpu(hsotg->dev, urb->dma,
-                                               urb->length, DMA_FROM_DEVICE);
-                       memcpy(urb->buf + frame_desc->offset +
-                              qtd->isoc_split_offset, chan->qh->dw_align_buf,
-                              frame_desc->actual_length);
-                       dma_sync_single_for_device(hsotg->dev, urb->dma,
-                                                  urb->length,
-                                                  DMA_FROM_DEVICE);
-               }
-               break;
-       case DWC2_HC_XFER_FRAME_OVERRUN:
-               urb->error_count++;
-               if (chan->ep_is_in)
-                       frame_desc->status = -ENOSR;
-               else
-                       frame_desc->status = -ECOMM;
-               frame_desc->actual_length = 0;
-               break;
-       case DWC2_HC_XFER_BABBLE_ERR:
-               urb->error_count++;
-               frame_desc->status = -EOVERFLOW;
-               /* Don't need to update actual_length in this case */
-               break;
-       case DWC2_HC_XFER_XACT_ERR:
-               urb->error_count++;
-               frame_desc->status = -EPROTO;
-               frame_desc->actual_length = dwc2_get_actual_xfer_length(hsotg,
-                                       chan, chnum, qtd, halt_status, NULL);
-
-               /* Non DWORD-aligned buffer case handling */
-               if (chan->align_buf && frame_desc->actual_length &&
-                   chan->ep_is_in) {
-                       dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
-                                __func__);
-                       dma_sync_single_for_cpu(hsotg->dev, urb->dma,
-                                               urb->length, DMA_FROM_DEVICE);
-                       memcpy(urb->buf + frame_desc->offset +
-                              qtd->isoc_split_offset, chan->qh->dw_align_buf,
-                              frame_desc->actual_length);
-                       dma_sync_single_for_device(hsotg->dev, urb->dma,
-                                                  urb->length,
-                                                  DMA_FROM_DEVICE);
-               }
-
-               /* Skip whole frame */
-               if (chan->qh->do_split &&
-                   chan->ep_type == USB_ENDPOINT_XFER_ISOC && chan->ep_is_in &&
-                   hsotg->core_params->dma_enable > 0) {
-                       qtd->complete_split = 0;
-                       qtd->isoc_split_offset = 0;
-               }
-
-               break;
-       default:
-               dev_err(hsotg->dev, "Unhandled halt_status (%d)\n",
-                       halt_status);
-               break;
-       }
-
-       if (++qtd->isoc_frame_index == urb->packet_count) {
-               /*
-                * urb->status is not used for isoc transfers. The individual
-                * frame_desc statuses are used instead.
-                */
-               dwc2_host_complete(hsotg, qtd, 0);
-               halt_status = DWC2_HC_XFER_URB_COMPLETE;
-       } else {
-               halt_status = DWC2_HC_XFER_COMPLETE;
-       }
-
-       return halt_status;
-}
-
-/*
- * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic
- * QHs, removes the QH from the active non-periodic schedule. If any QTDs are
- * still linked to the QH, the QH is added to the end of the inactive
- * non-periodic schedule. For periodic QHs, removes the QH from the periodic
- * schedule if no more QTDs are linked to the QH.
- */
-static void dwc2_deactivate_qh(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
-                              int free_qtd)
-{
-       int continue_split = 0;
-       struct dwc2_qtd *qtd;
-
-       if (dbg_qh(qh))
-               dev_vdbg(hsotg->dev, "  %s(%p,%p,%d)\n", __func__,
-                        hsotg, qh, free_qtd);
-
-       if (list_empty(&qh->qtd_list)) {
-               dev_dbg(hsotg->dev, "## QTD list empty ##\n");
-               goto no_qtd;
-       }
-
-       qtd = list_first_entry(&qh->qtd_list, struct dwc2_qtd, qtd_list_entry);
-
-       if (qtd->complete_split)
-               continue_split = 1;
-       else if (qtd->isoc_split_pos == DWC2_HCSPLT_XACTPOS_MID ||
-                qtd->isoc_split_pos == DWC2_HCSPLT_XACTPOS_END)
-               continue_split = 1;
-
-       if (free_qtd) {
-               dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
-               continue_split = 0;
-       }
-
-no_qtd:
-       if (qh->channel)
-               qh->channel->align_buf = 0;
-       qh->channel = NULL;
-       dwc2_hcd_qh_deactivate(hsotg, qh, continue_split);
-}
-
-/**
- * dwc2_release_channel() - Releases a host channel for use by other transfers
- *
- * @hsotg:       The HCD state structure
- * @chan:        The host channel to release
- * @qtd:         The QTD associated with the host channel. This QTD may be
- *               freed if the transfer is complete or an error has occurred.
- * @halt_status: Reason the channel is being released. This status
- *               determines the actions taken by this function.
- *
- * Also attempts to select and queue more transactions since at least one host
- * channel is available.
- */
-static void dwc2_release_channel(struct dwc2_hsotg *hsotg,
-                                struct dwc2_host_chan *chan,
-                                struct dwc2_qtd *qtd,
-                                enum dwc2_halt_status halt_status)
-{
-       enum dwc2_transaction_type tr_type;
-       u32 haintmsk;
-       int free_qtd = 0;
-
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "  %s: channel %d, halt_status %d\n",
-                        __func__, chan->hc_num, halt_status);
-
-       switch (halt_status) {
-       case DWC2_HC_XFER_URB_COMPLETE:
-               free_qtd = 1;
-               break;
-       case DWC2_HC_XFER_AHB_ERR:
-       case DWC2_HC_XFER_STALL:
-       case DWC2_HC_XFER_BABBLE_ERR:
-               free_qtd = 1;
-               break;
-       case DWC2_HC_XFER_XACT_ERR:
-               if (qtd && qtd->error_count >= 3) {
-                       dev_vdbg(hsotg->dev,
-                                "  Complete URB with transaction error\n");
-                       free_qtd = 1;
-                       dwc2_host_complete(hsotg, qtd, -EPROTO);
-               }
-               break;
-       case DWC2_HC_XFER_URB_DEQUEUE:
-               /*
-                * The QTD has already been removed and the QH has been
-                * deactivated. Don't want to do anything except release the
-                * host channel and try to queue more transfers.
-                */
-               goto cleanup;
-       case DWC2_HC_XFER_PERIODIC_INCOMPLETE:
-               dev_vdbg(hsotg->dev, "  Complete URB with I/O error\n");
-               free_qtd = 1;
-               dwc2_host_complete(hsotg, qtd, -EIO);
-               break;
-       case DWC2_HC_XFER_NO_HALT_STATUS:
-       default:
-               break;
-       }
-
-       dwc2_deactivate_qh(hsotg, chan->qh, free_qtd);
-
-cleanup:
-       /*
-        * Release the host channel for use by other transfers. The cleanup
-        * function clears the channel interrupt enables and conditions, so
-        * there's no need to clear the Channel Halted interrupt separately.
-        */
-       if (!list_empty(&chan->hc_list_entry))
-               list_del(&chan->hc_list_entry);
-       dwc2_hc_cleanup(hsotg, chan);
-       list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list);
-
-       if (hsotg->core_params->uframe_sched > 0) {
-               hsotg->available_host_channels++;
-       } else {
-               switch (chan->ep_type) {
-               case USB_ENDPOINT_XFER_CONTROL:
-               case USB_ENDPOINT_XFER_BULK:
-                       hsotg->non_periodic_channels--;
-                       break;
-               default:
-                       /*
-                        * Don't release reservations for periodic channels
-                        * here. That's done when a periodic transfer is
-                        * descheduled (i.e. when the QH is removed from the
-                        * periodic schedule).
-                        */
-                       break;
-               }
-       }
-
-       haintmsk = readl(hsotg->regs + HAINTMSK);
-       haintmsk &= ~(1 << chan->hc_num);
-       writel(haintmsk, hsotg->regs + HAINTMSK);
-
-       /* Try to queue more transfers now that there's a free channel */
-       tr_type = dwc2_hcd_select_transactions(hsotg);
-       if (tr_type != DWC2_TRANSACTION_NONE)
-               dwc2_hcd_queue_transactions(hsotg, tr_type);
-}
-
-/*
- * Halts a host channel. If the channel cannot be halted immediately because
- * the request queue is full, this function ensures that the FIFO empty
- * interrupt for the appropriate queue is enabled so that the halt request can
- * be queued when there is space in the request queue.
- *
- * This function may also be called in DMA mode. In that case, the channel is
- * simply released since the core always halts the channel automatically in
- * DMA mode.
- */
-static void dwc2_halt_channel(struct dwc2_hsotg *hsotg,
-                             struct dwc2_host_chan *chan, struct dwc2_qtd *qtd,
-                             enum dwc2_halt_status halt_status)
-{
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "%s()\n", __func__);
-
-       if (hsotg->core_params->dma_enable > 0) {
-               if (dbg_hc(chan))
-                       dev_vdbg(hsotg->dev, "DMA enabled\n");
-               dwc2_release_channel(hsotg, chan, qtd, halt_status);
-               return;
-       }
-
-       /* Slave mode processing */
-       dwc2_hc_halt(hsotg, chan, halt_status);
-
-       if (chan->halt_on_queue) {
-               u32 gintmsk;
-
-               dev_vdbg(hsotg->dev, "Halt on queue\n");
-               if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL ||
-                   chan->ep_type == USB_ENDPOINT_XFER_BULK) {
-                       dev_vdbg(hsotg->dev, "control/bulk\n");
-                       /*
-                        * Make sure the Non-periodic Tx FIFO empty interrupt
-                        * is enabled so that the non-periodic schedule will
-                        * be processed
-                        */
-                       gintmsk = readl(hsotg->regs + GINTMSK);
-                       gintmsk |= GINTSTS_NPTXFEMP;
-                       writel(gintmsk, hsotg->regs + GINTMSK);
-               } else {
-                       dev_vdbg(hsotg->dev, "isoc/intr\n");
-                       /*
-                        * Move the QH from the periodic queued schedule to
-                        * the periodic assigned schedule. This allows the
-                        * halt to be queued when the periodic schedule is
-                        * processed.
-                        */
-                       list_move(&chan->qh->qh_list_entry,
-                                 &hsotg->periodic_sched_assigned);
-
-                       /*
-                        * Make sure the Periodic Tx FIFO Empty interrupt is
-                        * enabled so that the periodic schedule will be
-                        * processed
-                        */
-                       gintmsk = readl(hsotg->regs + GINTMSK);
-                       gintmsk |= GINTSTS_PTXFEMP;
-                       writel(gintmsk, hsotg->regs + GINTMSK);
-               }
-       }
-}
-
-/*
- * Performs common cleanup for non-periodic transfers after a Transfer
- * Complete interrupt. This function should be called after any endpoint type
- * specific handling is finished to release the host channel.
- */
-static void dwc2_complete_non_periodic_xfer(struct dwc2_hsotg *hsotg,
-                                           struct dwc2_host_chan *chan,
-                                           int chnum, struct dwc2_qtd *qtd,
-                                           enum dwc2_halt_status halt_status)
-{
-       dev_vdbg(hsotg->dev, "%s()\n", __func__);
-
-       qtd->error_count = 0;
-
-       if (chan->hcint & HCINTMSK_NYET) {
-               /*
-                * Got a NYET on the last transaction of the transfer. This
-                * means that the endpoint should be in the PING state at the
-                * beginning of the next transfer.
-                */
-               dev_vdbg(hsotg->dev, "got NYET\n");
-               chan->qh->ping_state = 1;
-       }
-
-       /*
-        * Always halt and release the host channel to make it available for
-        * more transfers. There may still be more phases for a control
-        * transfer or more data packets for a bulk transfer at this point,
-        * but the host channel is still halted. A channel will be reassigned
-        * to the transfer when the non-periodic schedule is processed after
-        * the channel is released. This allows transactions to be queued
-        * properly via dwc2_hcd_queue_transactions, which also enables the
-        * Tx FIFO Empty interrupt if necessary.
-        */
-       if (chan->ep_is_in) {
-               /*
-                * IN transfers in Slave mode require an explicit disable to
-                * halt the channel. (In DMA mode, this call simply releases
-                * the channel.)
-                */
-               dwc2_halt_channel(hsotg, chan, qtd, halt_status);
-       } else {
-               /*
-                * The channel is automatically disabled by the core for OUT
-                * transfers in Slave mode
-                */
-               dwc2_release_channel(hsotg, chan, qtd, halt_status);
-       }
-}
-
-/*
- * Performs common cleanup for periodic transfers after a Transfer Complete
- * interrupt. This function should be called after any endpoint type specific
- * handling is finished to release the host channel.
- */
-static void dwc2_complete_periodic_xfer(struct dwc2_hsotg *hsotg,
-                                       struct dwc2_host_chan *chan, int chnum,
-                                       struct dwc2_qtd *qtd,
-                                       enum dwc2_halt_status halt_status)
-{
-       u32 hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
-
-       qtd->error_count = 0;
-
-       if (!chan->ep_is_in || (hctsiz & TSIZ_PKTCNT_MASK) == 0)
-               /* Core halts channel in these cases */
-               dwc2_release_channel(hsotg, chan, qtd, halt_status);
-       else
-               /* Flush any outstanding requests from the Tx queue */
-               dwc2_halt_channel(hsotg, chan, qtd, halt_status);
-}
-
-static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg,
-                                      struct dwc2_host_chan *chan, int chnum,
-                                      struct dwc2_qtd *qtd)
-{
-       struct dwc2_hcd_iso_packet_desc *frame_desc;
-       u32 len;
-
-       if (!qtd->urb)
-               return 0;
-
-       frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
-       len = dwc2_get_actual_xfer_length(hsotg, chan, chnum, qtd,
-                                         DWC2_HC_XFER_COMPLETE, NULL);
-       if (!len) {
-               qtd->complete_split = 0;
-               qtd->isoc_split_offset = 0;
-               return 0;
-       }
-
-       frame_desc->actual_length += len;
-
-       if (chan->align_buf) {
-               dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
-               dma_sync_single_for_cpu(hsotg->dev, qtd->urb->dma,
-                                       qtd->urb->length, DMA_FROM_DEVICE);
-               memcpy(qtd->urb->buf + frame_desc->offset +
-                      qtd->isoc_split_offset, chan->qh->dw_align_buf, len);
-               dma_sync_single_for_device(hsotg->dev, qtd->urb->dma,
-                                          qtd->urb->length, DMA_FROM_DEVICE);
-       }
-
-       qtd->isoc_split_offset += len;
-
-       if (frame_desc->actual_length >= frame_desc->length) {
-               frame_desc->status = 0;
-               qtd->isoc_frame_index++;
-               qtd->complete_split = 0;
-               qtd->isoc_split_offset = 0;
-       }
-
-       if (qtd->isoc_frame_index == qtd->urb->packet_count) {
-               dwc2_host_complete(hsotg, qtd, 0);
-               dwc2_release_channel(hsotg, chan, qtd,
-                                    DWC2_HC_XFER_URB_COMPLETE);
-       } else {
-               dwc2_release_channel(hsotg, chan, qtd,
-                                    DWC2_HC_XFER_NO_HALT_STATUS);
-       }
-
-       return 1;       /* Indicates that channel released */
-}
-
-/*
- * Handles a host channel Transfer Complete interrupt. This handler may be
- * called in either DMA mode or Slave mode.
- */
-static void dwc2_hc_xfercomp_intr(struct dwc2_hsotg *hsotg,
-                                 struct dwc2_host_chan *chan, int chnum,
-                                 struct dwc2_qtd *qtd)
-{
-       struct dwc2_hcd_urb *urb = qtd->urb;
-       int pipe_type = dwc2_hcd_get_pipe_type(&urb->pipe_info);
-       enum dwc2_halt_status halt_status = DWC2_HC_XFER_COMPLETE;
-       int urb_xfer_done;
-
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev,
-                        "--Host Channel %d Interrupt: Transfer Complete--\n",
-                        chnum);
-
-       if (hsotg->core_params->dma_desc_enable > 0) {
-               dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, halt_status);
-               if (pipe_type == USB_ENDPOINT_XFER_ISOC)
-                       /* Do not disable the interrupt, just clear it */
-                       return;
-               goto handle_xfercomp_done;
-       }
-
-       /* Handle xfer complete on CSPLIT */
-       if (chan->qh->do_split) {
-               if (chan->ep_type == USB_ENDPOINT_XFER_ISOC && chan->ep_is_in &&
-                   hsotg->core_params->dma_enable > 0) {
-                       if (qtd->complete_split &&
-                           dwc2_xfercomp_isoc_split_in(hsotg, chan, chnum,
-                                                       qtd))
-                               goto handle_xfercomp_done;
-               } else {
-                       qtd->complete_split = 0;
-               }
-       }
-
-       if (!urb)
-               goto handle_xfercomp_done;
-
-       /* Update the QTD and URB states */
-       switch (pipe_type) {
-       case USB_ENDPOINT_XFER_CONTROL:
-               switch (qtd->control_phase) {
-               case DWC2_CONTROL_SETUP:
-                       if (urb->length > 0)
-                               qtd->control_phase = DWC2_CONTROL_DATA;
-                       else
-                               qtd->control_phase = DWC2_CONTROL_STATUS;
-                       dev_vdbg(hsotg->dev,
-                                "  Control setup transaction done\n");
-                       halt_status = DWC2_HC_XFER_COMPLETE;
-                       break;
-               case DWC2_CONTROL_DATA:
-                       urb_xfer_done = dwc2_update_urb_state(hsotg, chan,
-                                                             chnum, urb, qtd);
-                       if (urb_xfer_done) {
-                               qtd->control_phase = DWC2_CONTROL_STATUS;
-                               dev_vdbg(hsotg->dev,
-                                        "  Control data transfer done\n");
-                       } else {
-                               dwc2_hcd_save_data_toggle(hsotg, chan, chnum,
-                                                         qtd);
-                       }
-                       halt_status = DWC2_HC_XFER_COMPLETE;
-                       break;
-               case DWC2_CONTROL_STATUS:
-                       dev_vdbg(hsotg->dev, "  Control transfer complete\n");
-                       if (urb->status == -EINPROGRESS)
-                               urb->status = 0;
-                       dwc2_host_complete(hsotg, qtd, urb->status);
-                       halt_status = DWC2_HC_XFER_URB_COMPLETE;
-                       break;
-               }
-
-               dwc2_complete_non_periodic_xfer(hsotg, chan, chnum, qtd,
-                                               halt_status);
-               break;
-       case USB_ENDPOINT_XFER_BULK:
-               dev_vdbg(hsotg->dev, "  Bulk transfer complete\n");
-               urb_xfer_done = dwc2_update_urb_state(hsotg, chan, chnum, urb,
-                                                     qtd);
-               if (urb_xfer_done) {
-                       dwc2_host_complete(hsotg, qtd, urb->status);
-                       halt_status = DWC2_HC_XFER_URB_COMPLETE;
-               } else {
-                       halt_status = DWC2_HC_XFER_COMPLETE;
-               }
-
-               dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
-               dwc2_complete_non_periodic_xfer(hsotg, chan, chnum, qtd,
-                                               halt_status);
-               break;
-       case USB_ENDPOINT_XFER_INT:
-               dev_vdbg(hsotg->dev, "  Interrupt transfer complete\n");
-               urb_xfer_done = dwc2_update_urb_state(hsotg, chan, chnum, urb,
-                                                     qtd);
-
-               /*
-                * Interrupt URB is done on the first transfer complete
-                * interrupt
-                */
-               if (urb_xfer_done) {
-                       dwc2_host_complete(hsotg, qtd, urb->status);
-                       halt_status = DWC2_HC_XFER_URB_COMPLETE;
-               } else {
-                       halt_status = DWC2_HC_XFER_COMPLETE;
-               }
-
-               dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
-               dwc2_complete_periodic_xfer(hsotg, chan, chnum, qtd,
-                                           halt_status);
-               break;
-       case USB_ENDPOINT_XFER_ISOC:
-               if (dbg_perio())
-                       dev_vdbg(hsotg->dev, "  Isochronous transfer complete\n");
-               if (qtd->isoc_split_pos == DWC2_HCSPLT_XACTPOS_ALL)
-                       halt_status = dwc2_update_isoc_urb_state(hsotg, chan,
-                                       chnum, qtd, DWC2_HC_XFER_COMPLETE);
-               dwc2_complete_periodic_xfer(hsotg, chan, chnum, qtd,
-                                           halt_status);
-               break;
-       }
-
-handle_xfercomp_done:
-       disable_hc_int(hsotg, chnum, HCINTMSK_XFERCOMPL);
-}
-
-/*
- * Handles a host channel STALL interrupt. This handler may be called in
- * either DMA mode or Slave mode.
- */
-static void dwc2_hc_stall_intr(struct dwc2_hsotg *hsotg,
-                              struct dwc2_host_chan *chan, int chnum,
-                              struct dwc2_qtd *qtd)
-{
-       struct dwc2_hcd_urb *urb = qtd->urb;
-       int pipe_type = dwc2_hcd_get_pipe_type(&urb->pipe_info);
-
-       dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: STALL Received--\n",
-               chnum);
-
-       if (hsotg->core_params->dma_desc_enable > 0) {
-               dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
-                                           DWC2_HC_XFER_STALL);
-               goto handle_stall_done;
-       }
-
-       if (!urb)
-               goto handle_stall_halt;
-
-       if (pipe_type == USB_ENDPOINT_XFER_CONTROL)
-               dwc2_host_complete(hsotg, qtd, -EPIPE);
-
-       if (pipe_type == USB_ENDPOINT_XFER_BULK ||
-           pipe_type == USB_ENDPOINT_XFER_INT) {
-               dwc2_host_complete(hsotg, qtd, -EPIPE);
-               /*
-                * USB protocol requires resetting the data toggle for bulk
-                * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT)
-                * setup command is issued to the endpoint. Anticipate the
-                * CLEAR_FEATURE command since a STALL has occurred and reset
-                * the data toggle now.
-                */
-               chan->qh->data_toggle = 0;
-       }
-
-handle_stall_halt:
-       dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_STALL);
-
-handle_stall_done:
-       disable_hc_int(hsotg, chnum, HCINTMSK_STALL);
-}
-
-/*
- * Updates the state of the URB when a transfer has been stopped due to an
- * abnormal condition before the transfer completes. Modifies the
- * actual_length field of the URB to reflect the number of bytes that have
- * actually been transferred via the host channel.
- */
-static void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg,
-                                     struct dwc2_host_chan *chan, int chnum,
-                                     struct dwc2_hcd_urb *urb,
-                                     struct dwc2_qtd *qtd,
-                                     enum dwc2_halt_status halt_status)
-{
-       u32 xfer_length = dwc2_get_actual_xfer_length(hsotg, chan, chnum,
-                                                     qtd, halt_status, NULL);
-       u32 hctsiz;
-
-       if (urb->actual_length + xfer_length > urb->length) {
-               dev_warn(hsotg->dev, "%s(): trimming xfer length\n", __func__);
-               xfer_length = urb->length - urb->actual_length;
-       }
-
-       /* Non DWORD-aligned buffer case handling */
-       if (chan->align_buf && xfer_length && chan->ep_is_in) {
-               dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
-               dma_sync_single_for_cpu(hsotg->dev, urb->dma, urb->length,
-                                       DMA_FROM_DEVICE);
-               memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
-                      xfer_length);
-               dma_sync_single_for_device(hsotg->dev, urb->dma, urb->length,
-                                          DMA_FROM_DEVICE);
-       }
-
-       urb->actual_length += xfer_length;
-
-       hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
-       dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
-                __func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
-       dev_vdbg(hsotg->dev, "  chan->start_pkt_count %d\n",
-                chan->start_pkt_count);
-       dev_vdbg(hsotg->dev, "  hctsiz.pktcnt %d\n",
-                (hctsiz & TSIZ_PKTCNT_MASK) >> TSIZ_PKTCNT_SHIFT);
-       dev_vdbg(hsotg->dev, "  chan->max_packet %d\n", chan->max_packet);
-       dev_vdbg(hsotg->dev, "  bytes_transferred %d\n",
-                xfer_length);
-       dev_vdbg(hsotg->dev, "  urb->actual_length %d\n",
-                urb->actual_length);
-       dev_vdbg(hsotg->dev, "  urb->transfer_buffer_length %d\n",
-                urb->length);
-}
-
-/*
- * Handles a host channel NAK interrupt. This handler may be called in either
- * DMA mode or Slave mode.
- */
-static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg,
-                            struct dwc2_host_chan *chan, int chnum,
-                            struct dwc2_qtd *qtd)
-{
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: NAK Received--\n",
-                        chnum);
-
-       /*
-        * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
-        * interrupt. Re-start the SSPLIT transfer.
-        */
-       if (chan->do_split) {
-               if (chan->complete_split)
-                       qtd->error_count = 0;
-               qtd->complete_split = 0;
-               dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK);
-               goto handle_nak_done;
-       }
-
-       switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
-       case USB_ENDPOINT_XFER_CONTROL:
-       case USB_ENDPOINT_XFER_BULK:
-               if (hsotg->core_params->dma_enable > 0 && chan->ep_is_in) {
-                       /*
-                        * NAK interrupts are enabled on bulk/control IN
-                        * transfers in DMA mode for the sole purpose of
-                        * resetting the error count after a transaction error
-                        * occurs. The core will continue transferring data.
-                        */
-                       qtd->error_count = 0;
-                       break;
-               }
-
-               /*
-                * NAK interrupts normally occur during OUT transfers in DMA
-                * or Slave mode. For IN transfers, more requests will be
-                * queued as request queue space is available.
-                */
-               qtd->error_count = 0;
-
-               if (!chan->qh->ping_state) {
-                       dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb,
-                                                 qtd, DWC2_HC_XFER_NAK);
-                       dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
-
-                       if (chan->speed == USB_SPEED_HIGH)
-                               chan->qh->ping_state = 1;
-               }
-
-               /*
-                * Halt the channel so the transfer can be re-started from
-                * the appropriate point or the PING protocol will
-                * start/continue
-                */
-               dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK);
-               break;
-       case USB_ENDPOINT_XFER_INT:
-               qtd->error_count = 0;
-               dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK);
-               break;
-       case USB_ENDPOINT_XFER_ISOC:
-               /* Should never get called for isochronous transfers */
-               dev_err(hsotg->dev, "NACK interrupt for ISOC transfer\n");
-               break;
-       }
-
-handle_nak_done:
-       disable_hc_int(hsotg, chnum, HCINTMSK_NAK);
-}
-
-/*
- * Handles a host channel ACK interrupt. This interrupt is enabled when
- * performing the PING protocol in Slave mode, when errors occur during
- * either Slave mode or DMA mode, and during Start Split transactions.
- */
-static void dwc2_hc_ack_intr(struct dwc2_hsotg *hsotg,
-                            struct dwc2_host_chan *chan, int chnum,
-                            struct dwc2_qtd *qtd)
-{
-       struct dwc2_hcd_iso_packet_desc *frame_desc;
-
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: ACK Received--\n",
-                        chnum);
-
-       if (chan->do_split) {
-               /* Handle ACK on SSPLIT. ACK should not occur in CSPLIT. */
-               if (!chan->ep_is_in &&
-                   chan->data_pid_start != DWC2_HC_PID_SETUP)
-                       qtd->ssplit_out_xfer_count = chan->xfer_len;
-
-               if (chan->ep_type != USB_ENDPOINT_XFER_ISOC || chan->ep_is_in) {
-                       qtd->complete_split = 1;
-                       dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_ACK);
-               } else {
-                       /* ISOC OUT */
-                       switch (chan->xact_pos) {
-                       case DWC2_HCSPLT_XACTPOS_ALL:
-                               break;
-                       case DWC2_HCSPLT_XACTPOS_END:
-                               qtd->isoc_split_pos = DWC2_HCSPLT_XACTPOS_ALL;
-                               qtd->isoc_split_offset = 0;
-                               break;
-                       case DWC2_HCSPLT_XACTPOS_BEGIN:
-                       case DWC2_HCSPLT_XACTPOS_MID:
-                               /*
-                                * For BEGIN or MID, calculate the length for
-                                * the next microframe to determine the correct
-                                * SSPLIT token, either MID or END
-                                */
-                               frame_desc = &qtd->urb->iso_descs[
-                                               qtd->isoc_frame_index];
-                               qtd->isoc_split_offset += 188;
-
-                               if (frame_desc->length - qtd->isoc_split_offset
-                                                       <= 188)
-                                       qtd->isoc_split_pos =
-                                                       DWC2_HCSPLT_XACTPOS_END;
-                               else
-                                       qtd->isoc_split_pos =
-                                                       DWC2_HCSPLT_XACTPOS_MID;
-                               break;
-                       }
-               }
-       } else {
-               qtd->error_count = 0;
-
-               if (chan->qh->ping_state) {
-                       chan->qh->ping_state = 0;
-                       /*
-                        * Halt the channel so the transfer can be re-started
-                        * from the appropriate point. This only happens in
-                        * Slave mode. In DMA mode, the ping_state is cleared
-                        * when the transfer is started because the core
-                        * automatically executes the PING, then the transfer.
-                        */
-                       dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_ACK);
-               }
-       }
-
-       /*
-        * If the ACK occurred when _not_ in the PING state, let the channel
-        * continue transferring data after clearing the error count
-        */
-       disable_hc_int(hsotg, chnum, HCINTMSK_ACK);
-}
-
-/*
- * Handles a host channel NYET interrupt. This interrupt should only occur on
- * Bulk and Control OUT endpoints and for complete split transactions. If a
- * NYET occurs at the same time as a Transfer Complete interrupt, it is
- * handled in the xfercomp interrupt handler, not here. This handler may be
- * called in either DMA mode or Slave mode.
- */
-static void dwc2_hc_nyet_intr(struct dwc2_hsotg *hsotg,
-                             struct dwc2_host_chan *chan, int chnum,
-                             struct dwc2_qtd *qtd)
-{
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: NYET Received--\n",
-                        chnum);
-
-       /*
-        * NYET on CSPLIT
-        * re-do the CSPLIT immediately on non-periodic
-        */
-       if (chan->do_split && chan->complete_split) {
-               if (chan->ep_is_in && chan->ep_type == USB_ENDPOINT_XFER_ISOC &&
-                   hsotg->core_params->dma_enable > 0) {
-                       qtd->complete_split = 0;
-                       qtd->isoc_split_offset = 0;
-                       qtd->isoc_frame_index++;
-                       if (qtd->urb &&
-                           qtd->isoc_frame_index == qtd->urb->packet_count) {
-                               dwc2_host_complete(hsotg, qtd, 0);
-                               dwc2_release_channel(hsotg, chan, qtd,
-                                                    DWC2_HC_XFER_URB_COMPLETE);
-                       } else {
-                               dwc2_release_channel(hsotg, chan, qtd,
-                                               DWC2_HC_XFER_NO_HALT_STATUS);
-                       }
-                       goto handle_nyet_done;
-               }
-
-               if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
-                   chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
-                       int frnum = dwc2_hcd_get_frame_number(hsotg);
-
-                       if (dwc2_full_frame_num(frnum) !=
-                           dwc2_full_frame_num(chan->qh->sched_frame)) {
-                               /*
-                                * No longer in the same full speed frame.
-                                * Treat this as a transaction error.
-                                */
-#if 0
-                               /*
-                                * Todo: Fix system performance so this can
-                                * be treated as an error. Right now complete
-                                * splits cannot be scheduled precisely enough
-                                * due to other system activity, so this error
-                                * occurs regularly in Slave mode.
-                                */
-                               qtd->error_count++;
-#endif
-                               qtd->complete_split = 0;
-                               dwc2_halt_channel(hsotg, chan, qtd,
-                                                 DWC2_HC_XFER_XACT_ERR);
-                               /* Todo: add support for isoc release */
-                               goto handle_nyet_done;
-                       }
-               }
-
-               dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NYET);
-               goto handle_nyet_done;
-       }
-
-       chan->qh->ping_state = 1;
-       qtd->error_count = 0;
-
-       dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb, qtd,
-                                 DWC2_HC_XFER_NYET);
-       dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
-
-       /*
-        * Halt the channel and re-start the transfer so the PING protocol
-        * will start
-        */
-       dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NYET);
-
-handle_nyet_done:
-       disable_hc_int(hsotg, chnum, HCINTMSK_NYET);
-}
-
-/*
- * Handles a host channel babble interrupt. This handler may be called in
- * either DMA mode or Slave mode.
- */
-static void dwc2_hc_babble_intr(struct dwc2_hsotg *hsotg,
-                               struct dwc2_host_chan *chan, int chnum,
-                               struct dwc2_qtd *qtd)
-{
-       dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: Babble Error--\n",
-               chnum);
-
-       dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
-
-       if (hsotg->core_params->dma_desc_enable > 0) {
-               dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
-                                           DWC2_HC_XFER_BABBLE_ERR);
-               goto disable_int;
-       }
-
-       if (chan->ep_type != USB_ENDPOINT_XFER_ISOC) {
-               dwc2_host_complete(hsotg, qtd, -EOVERFLOW);
-               dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_BABBLE_ERR);
-       } else {
-               enum dwc2_halt_status halt_status;
-
-               halt_status = dwc2_update_isoc_urb_state(hsotg, chan, chnum,
-                                               qtd, DWC2_HC_XFER_BABBLE_ERR);
-               dwc2_halt_channel(hsotg, chan, qtd, halt_status);
-       }
-
-disable_int:
-       disable_hc_int(hsotg, chnum, HCINTMSK_BBLERR);
-}
-
-/*
- * Handles a host channel AHB error interrupt. This handler is only called in
- * DMA mode.
- */
-static void dwc2_hc_ahberr_intr(struct dwc2_hsotg *hsotg,
-                               struct dwc2_host_chan *chan, int chnum,
-                               struct dwc2_qtd *qtd)
-{
-       struct dwc2_hcd_urb *urb = qtd->urb;
-       char *pipetype, *speed;
-       u32 hcchar;
-       u32 hcsplt;
-       u32 hctsiz;
-       u32 hc_dma;
-
-       dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: AHB Error--\n",
-               chnum);
-
-       if (!urb)
-               goto handle_ahberr_halt;
-
-       dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
-
-       hcchar = readl(hsotg->regs + HCCHAR(chnum));
-       hcsplt = readl(hsotg->regs + HCSPLT(chnum));
-       hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
-       hc_dma = readl(hsotg->regs + HCDMA(chnum));
-
-       dev_err(hsotg->dev, "AHB ERROR, Channel %d\n", chnum);
-       dev_err(hsotg->dev, "  hcchar 0x%08x, hcsplt 0x%08x\n", hcchar, hcsplt);
-       dev_err(hsotg->dev, "  hctsiz 0x%08x, hc_dma 0x%08x\n", hctsiz, hc_dma);
-       dev_err(hsotg->dev, "  Device address: %d\n",
-               dwc2_hcd_get_dev_addr(&urb->pipe_info));
-       dev_err(hsotg->dev, "  Endpoint: %d, %s\n",
-               dwc2_hcd_get_ep_num(&urb->pipe_info),
-               dwc2_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
-
-       switch (dwc2_hcd_get_pipe_type(&urb->pipe_info)) {
-       case USB_ENDPOINT_XFER_CONTROL:
-               pipetype = "CONTROL";
-               break;
-       case USB_ENDPOINT_XFER_BULK:
-               pipetype = "BULK";
-               break;
-       case USB_ENDPOINT_XFER_INT:
-               pipetype = "INTERRUPT";
-               break;
-       case USB_ENDPOINT_XFER_ISOC:
-               pipetype = "ISOCHRONOUS";
-               break;
-       default:
-               pipetype = "UNKNOWN";
-               break;
-       }
-
-       dev_err(hsotg->dev, "  Endpoint type: %s\n", pipetype);
-
-       switch (chan->speed) {
-       case USB_SPEED_HIGH:
-               speed = "HIGH";
-               break;
-       case USB_SPEED_FULL:
-               speed = "FULL";
-               break;
-       case USB_SPEED_LOW:
-               speed = "LOW";
-               break;
-       default:
-               speed = "UNKNOWN";
-               break;
-       }
-
-       dev_err(hsotg->dev, "  Speed: %s\n", speed);
-
-       dev_err(hsotg->dev, "  Max packet size: %d\n",
-               dwc2_hcd_get_mps(&urb->pipe_info));
-       dev_err(hsotg->dev, "  Data buffer length: %d\n", urb->length);
-       dev_err(hsotg->dev, "  Transfer buffer: %p, Transfer DMA: %08lx\n",
-               urb->buf, (unsigned long)urb->dma);
-       dev_err(hsotg->dev, "  Setup buffer: %p, Setup DMA: %08lx\n",
-               urb->setup_packet, (unsigned long)urb->setup_dma);
-       dev_err(hsotg->dev, "  Interval: %d\n", urb->interval);
-
-       /* Core halts the channel for Descriptor DMA mode */
-       if (hsotg->core_params->dma_desc_enable > 0) {
-               dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
-                                           DWC2_HC_XFER_AHB_ERR);
-               goto handle_ahberr_done;
-       }
-
-       dwc2_host_complete(hsotg, qtd, -EIO);
-
-handle_ahberr_halt:
-       /*
-        * Force a channel halt. Don't call dwc2_halt_channel because that won't
-        * write to the HCCHARn register in DMA mode to force the halt.
-        */
-       dwc2_hc_halt(hsotg, chan, DWC2_HC_XFER_AHB_ERR);
-
-handle_ahberr_done:
-       disable_hc_int(hsotg, chnum, HCINTMSK_AHBERR);
-}
-
-/*
- * Handles a host channel transaction error interrupt. This handler may be
- * called in either DMA mode or Slave mode.
- */
-static void dwc2_hc_xacterr_intr(struct dwc2_hsotg *hsotg,
-                                struct dwc2_host_chan *chan, int chnum,
-                                struct dwc2_qtd *qtd)
-{
-       dev_dbg(hsotg->dev,
-               "--Host Channel %d Interrupt: Transaction Error--\n", chnum);
-
-       dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
-
-       if (hsotg->core_params->dma_desc_enable > 0) {
-               dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
-                                           DWC2_HC_XFER_XACT_ERR);
-               goto handle_xacterr_done;
-       }
-
-       switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
-       case USB_ENDPOINT_XFER_CONTROL:
-       case USB_ENDPOINT_XFER_BULK:
-               qtd->error_count++;
-               if (!chan->qh->ping_state) {
-
-                       dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb,
-                                                 qtd, DWC2_HC_XFER_XACT_ERR);
-                       dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
-                       if (!chan->ep_is_in && chan->speed == USB_SPEED_HIGH)
-                               chan->qh->ping_state = 1;
-               }
-
-               /*
-                * Halt the channel so the transfer can be re-started from
-                * the appropriate point or the PING protocol will start
-                */
-               dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_XACT_ERR);
-               break;
-       case USB_ENDPOINT_XFER_INT:
-               qtd->error_count++;
-               if (chan->do_split && chan->complete_split)
-                       qtd->complete_split = 0;
-               dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_XACT_ERR);
-               break;
-       case USB_ENDPOINT_XFER_ISOC:
-               {
-                       enum dwc2_halt_status halt_status;
-
-                       halt_status = dwc2_update_isoc_urb_state(hsotg, chan,
-                                       chnum, qtd, DWC2_HC_XFER_XACT_ERR);
-                       dwc2_halt_channel(hsotg, chan, qtd, halt_status);
-               }
-               break;
-       }
-
-handle_xacterr_done:
-       disable_hc_int(hsotg, chnum, HCINTMSK_XACTERR);
-}
-
-/*
- * Handles a host channel frame overrun interrupt. This handler may be called
- * in either DMA mode or Slave mode.
- */
-static void dwc2_hc_frmovrun_intr(struct dwc2_hsotg *hsotg,
-                                 struct dwc2_host_chan *chan, int chnum,
-                                 struct dwc2_qtd *qtd)
-{
-       enum dwc2_halt_status halt_status;
-
-       if (dbg_hc(chan))
-               dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: Frame Overrun--\n",
-                       chnum);
-
-       dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
-
-       switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
-       case USB_ENDPOINT_XFER_CONTROL:
-       case USB_ENDPOINT_XFER_BULK:
-               break;
-       case USB_ENDPOINT_XFER_INT:
-               dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_FRAME_OVERRUN);
-               break;
-       case USB_ENDPOINT_XFER_ISOC:
-               halt_status = dwc2_update_isoc_urb_state(hsotg, chan, chnum,
-                                       qtd, DWC2_HC_XFER_FRAME_OVERRUN);
-               dwc2_halt_channel(hsotg, chan, qtd, halt_status);
-               break;
-       }
-
-       disable_hc_int(hsotg, chnum, HCINTMSK_FRMOVRUN);
-}
-
-/*
- * Handles a host channel data toggle error interrupt. This handler may be
- * called in either DMA mode or Slave mode.
- */
-static void dwc2_hc_datatglerr_intr(struct dwc2_hsotg *hsotg,
-                                   struct dwc2_host_chan *chan, int chnum,
-                                   struct dwc2_qtd *qtd)
-{
-       dev_dbg(hsotg->dev,
-               "--Host Channel %d Interrupt: Data Toggle Error--\n", chnum);
-
-       if (chan->ep_is_in)
-               qtd->error_count = 0;
-       else
-               dev_err(hsotg->dev,
-                       "Data Toggle Error on OUT transfer, channel %d\n",
-                       chnum);
-
-       dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
-       disable_hc_int(hsotg, chnum, HCINTMSK_DATATGLERR);
-}
-
-/*
- * For debug only. It checks that a valid halt status is set and that
- * HCCHARn.chdis is clear. If there's a problem, corrective action is
- * taken and a warning is issued.
- *
- * Return: true if halt status is ok, false otherwise
- */
-static bool dwc2_halt_status_ok(struct dwc2_hsotg *hsotg,
-                               struct dwc2_host_chan *chan, int chnum,
-                               struct dwc2_qtd *qtd)
-{
-#ifdef DEBUG
-       u32 hcchar;
-       u32 hctsiz;
-       u32 hcintmsk;
-       u32 hcsplt;
-
-       if (chan->halt_status == DWC2_HC_XFER_NO_HALT_STATUS) {
-               /*
-                * This code is here only as a check. This condition should
-                * never happen. Ignore the halt if it does occur.
-                */
-               hcchar = readl(hsotg->regs + HCCHAR(chnum));
-               hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
-               hcintmsk = readl(hsotg->regs + HCINTMSK(chnum));
-               hcsplt = readl(hsotg->regs + HCSPLT(chnum));
-               dev_dbg(hsotg->dev,
-                       "%s: chan->halt_status DWC2_HC_XFER_NO_HALT_STATUS,\n",
-                        __func__);
-               dev_dbg(hsotg->dev,
-                       "channel %d, hcchar 0x%08x, hctsiz 0x%08x,\n",
-                       chnum, hcchar, hctsiz);
-               dev_dbg(hsotg->dev,
-                       "hcint 0x%08x, hcintmsk 0x%08x, hcsplt 0x%08x,\n",
-                       chan->hcint, hcintmsk, hcsplt);
-               if (qtd)
-                       dev_dbg(hsotg->dev, "qtd->complete_split %d\n",
-                               qtd->complete_split);
-               dev_warn(hsotg->dev,
-                        "%s: no halt status, channel %d, ignoring interrupt\n",
-                        __func__, chnum);
-               return false;
-       }
-
-       /*
-        * This code is here only as a check. hcchar.chdis should never be set
-        * when the halt interrupt occurs. Halt the channel again if it does
-        * occur.
-        */
-       hcchar = readl(hsotg->regs + HCCHAR(chnum));
-       if (hcchar & HCCHAR_CHDIS) {
-               dev_warn(hsotg->dev,
-                        "%s: hcchar.chdis set unexpectedly, hcchar 0x%08x, trying to halt again\n",
-                        __func__, hcchar);
-               chan->halt_pending = 0;
-               dwc2_halt_channel(hsotg, chan, qtd, chan->halt_status);
-               return false;
-       }
-#endif
-
-       return true;
-}
-
-/*
- * Handles a host Channel Halted interrupt in DMA mode. This handler
- * determines the reason the channel halted and proceeds accordingly.
- */
-static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg,
-                                   struct dwc2_host_chan *chan, int chnum,
-                                   struct dwc2_qtd *qtd)
-{
-       u32 hcintmsk;
-       int out_nak_enh = 0;
-
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev,
-                        "--Host Channel %d Interrupt: DMA Channel Halted--\n",
-                        chnum);
-
-       /*
-        * For core with OUT NAK enhancement, the flow for high-speed
-        * CONTROL/BULK OUT is handled a little differently
-        */
-       if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_71a) {
-               if (chan->speed == USB_SPEED_HIGH && !chan->ep_is_in &&
-                   (chan->ep_type == USB_ENDPOINT_XFER_CONTROL ||
-                    chan->ep_type == USB_ENDPOINT_XFER_BULK)) {
-                       out_nak_enh = 1;
-               }
-       }
-
-       if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE ||
-           (chan->halt_status == DWC2_HC_XFER_AHB_ERR &&
-            hsotg->core_params->dma_desc_enable <= 0)) {
-               if (hsotg->core_params->dma_desc_enable > 0)
-                       dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
-                                                   chan->halt_status);
-               else
-                       /*
-                        * Just release the channel. A dequeue can happen on a
-                        * transfer timeout. In the case of an AHB Error, the
-                        * channel was forced to halt because there's no way to
-                        * gracefully recover.
-                        */
-                       dwc2_release_channel(hsotg, chan, qtd,
-                                            chan->halt_status);
-               return;
-       }
-
-       hcintmsk = readl(hsotg->regs + HCINTMSK(chnum));
-
-       if (chan->hcint & HCINTMSK_XFERCOMPL) {
-               /*
-                * Todo: This is here because of a possible hardware bug. Spec
-                * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT
-                * interrupt w/ACK bit set should occur, but I only see the
-                * XFERCOMP bit, even with it masked out. This is a workaround
-                * for that behavior. Should fix this when hardware is fixed.
-                */
-               if (chan->ep_type == USB_ENDPOINT_XFER_ISOC && !chan->ep_is_in)
-                       dwc2_hc_ack_intr(hsotg, chan, chnum, qtd);
-               dwc2_hc_xfercomp_intr(hsotg, chan, chnum, qtd);
-       } else if (chan->hcint & HCINTMSK_STALL) {
-               dwc2_hc_stall_intr(hsotg, chan, chnum, qtd);
-       } else if ((chan->hcint & HCINTMSK_XACTERR) &&
-                  hsotg->core_params->dma_desc_enable <= 0) {
-               if (out_nak_enh) {
-                       if (chan->hcint &
-                           (HCINTMSK_NYET | HCINTMSK_NAK | HCINTMSK_ACK)) {
-                               dev_vdbg(hsotg->dev,
-                                        "XactErr with NYET/NAK/ACK\n");
-                               qtd->error_count = 0;
-                       } else {
-                               dev_vdbg(hsotg->dev,
-                                        "XactErr without NYET/NAK/ACK\n");
-                       }
-               }
-
-               /*
-                * Must handle xacterr before nak or ack. Could get a xacterr
-                * at the same time as either of these on a BULK/CONTROL OUT
-                * that started with a PING. The xacterr takes precedence.
-                */
-               dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd);
-       } else if ((chan->hcint & HCINTMSK_XCS_XACT) &&
-                  hsotg->core_params->dma_desc_enable > 0) {
-               dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd);
-       } else if ((chan->hcint & HCINTMSK_AHBERR) &&
-                  hsotg->core_params->dma_desc_enable > 0) {
-               dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd);
-       } else if (chan->hcint & HCINTMSK_BBLERR) {
-               dwc2_hc_babble_intr(hsotg, chan, chnum, qtd);
-       } else if (chan->hcint & HCINTMSK_FRMOVRUN) {
-               dwc2_hc_frmovrun_intr(hsotg, chan, chnum, qtd);
-       } else if (!out_nak_enh) {
-               if (chan->hcint & HCINTMSK_NYET) {
-                       /*
-                        * Must handle nyet before nak or ack. Could get a nyet
-                        * at the same time as either of those on a BULK/CONTROL
-                        * OUT that started with a PING. The nyet takes
-                        * precedence.
-                        */
-                       dwc2_hc_nyet_intr(hsotg, chan, chnum, qtd);
-               } else if ((chan->hcint & HCINTMSK_NAK) &&
-                          !(hcintmsk & HCINTMSK_NAK)) {
-                       /*
-                        * If nak is not masked, it's because a non-split IN
-                        * transfer is in an error state. In that case, the nak
-                        * is handled by the nak interrupt handler, not here.
-                        * Handle nak here for BULK/CONTROL OUT transfers, which
-                        * halt on a NAK to allow rewinding the buffer pointer.
-                        */
-                       dwc2_hc_nak_intr(hsotg, chan, chnum, qtd);
-               } else if ((chan->hcint & HCINTMSK_ACK) &&
-                          !(hcintmsk & HCINTMSK_ACK)) {
-                       /*
-                        * If ack is not masked, it's because a non-split IN
-                        * transfer is in an error state. In that case, the ack
-                        * is handled by the ack interrupt handler, not here.
-                        * Handle ack here for split transfers. Start splits
-                        * halt on ACK.
-                        */
-                       dwc2_hc_ack_intr(hsotg, chan, chnum, qtd);
-               } else {
-                       if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
-                           chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
-                               /*
-                                * A periodic transfer halted with no other
-                                * channel interrupts set. Assume it was halted
-                                * by the core because it could not be completed
-                                * in its scheduled (micro)frame.
-                                */
-                               dev_dbg(hsotg->dev,
-                                       "%s: Halt channel %d (assume incomplete periodic transfer)\n",
-                                       __func__, chnum);
-                               dwc2_halt_channel(hsotg, chan, qtd,
-                                       DWC2_HC_XFER_PERIODIC_INCOMPLETE);
-                       } else {
-                               dev_err(hsotg->dev,
-                                       "%s: Channel %d - ChHltd set, but reason is unknown\n",
-                                       __func__, chnum);
-                               dev_err(hsotg->dev,
-                                       "hcint 0x%08x, intsts 0x%08x\n",
-                                       chan->hcint,
-                                       readl(hsotg->regs + GINTSTS));
-                       }
-               }
-       } else {
-               dev_info(hsotg->dev,
-                        "NYET/NAK/ACK/other in non-error case, 0x%08x\n",
-                        chan->hcint);
-       }
-}
-
-/*
- * Handles a host channel Channel Halted interrupt
- *
- * In slave mode, this handler is called only when the driver specifically
- * requests a halt. This occurs during handling other host channel interrupts
- * (e.g. nak, xacterr, stall, nyet, etc.).
- *
- * In DMA mode, this is the interrupt that occurs when the core has finished
- * processing a transfer on a channel. Other host channel interrupts (except
- * ahberr) are disabled in DMA mode.
- */
-static void dwc2_hc_chhltd_intr(struct dwc2_hsotg *hsotg,
-                               struct dwc2_host_chan *chan, int chnum,
-                               struct dwc2_qtd *qtd)
-{
-       if (dbg_hc(chan))
-               dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: Channel Halted--\n",
-                        chnum);
-
-       if (hsotg->core_params->dma_enable > 0) {
-               dwc2_hc_chhltd_intr_dma(hsotg, chan, chnum, qtd);
-       } else {
-               if (!dwc2_halt_status_ok(hsotg, chan, chnum, qtd))
-                       return;
-               dwc2_release_channel(hsotg, chan, qtd, chan->halt_status);
-       }
-}
-
-/* Handles interrupt for a specific Host Channel */
-static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
-{
-       struct dwc2_qtd *qtd;
-       struct dwc2_host_chan *chan;
-       u32 hcint, hcintmsk;
-
-       chan = hsotg->hc_ptr_array[chnum];
-
-       hcint = readl(hsotg->regs + HCINT(chnum));
-       hcintmsk = readl(hsotg->regs + HCINTMSK(chnum));
-       if (!chan) {
-               dev_err(hsotg->dev, "## hc_ptr_array for channel is NULL ##\n");
-               writel(hcint, hsotg->regs + HCINT(chnum));
-               return;
-       }
-
-       if (dbg_hc(chan)) {
-               dev_vdbg(hsotg->dev, "--Host Channel Interrupt--, Channel %d\n",
-                        chnum);
-               dev_vdbg(hsotg->dev,
-                        "  hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
-                        hcint, hcintmsk, hcint & hcintmsk);
-       }
-
-       writel(hcint, hsotg->regs + HCINT(chnum));
-       chan->hcint = hcint;
-       hcint &= hcintmsk;
-
-       /*
-        * If the channel was halted due to a dequeue, the qtd list might
-        * be empty or at least the first entry will not be the active qtd.
-        * In this case, take a shortcut and just release the channel.
-        */
-       if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) {
-               /*
-                * If the channel was halted, this should be the only
-                * interrupt unmasked
-                */
-               WARN_ON(hcint != HCINTMSK_CHHLTD);
-               if (hsotg->core_params->dma_desc_enable > 0)
-                       dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
-                                                   chan->halt_status);
-               else
-                       dwc2_release_channel(hsotg, chan, NULL,
-                                            chan->halt_status);
-               return;
-       }
-
-       if (list_empty(&chan->qh->qtd_list)) {
-               /*
-                * TODO: Will this ever happen with the
-                * DWC2_HC_XFER_URB_DEQUEUE handling above?
-                */
-               dev_dbg(hsotg->dev, "## no QTD queued for channel %d ##\n",
-                       chnum);
-               dev_dbg(hsotg->dev,
-                       "  hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
-                       chan->hcint, hcintmsk, hcint);
-               chan->halt_status = DWC2_HC_XFER_NO_HALT_STATUS;
-               disable_hc_int(hsotg, chnum, HCINTMSK_CHHLTD);
-               chan->hcint = 0;
-               return;
-       }
-
-       qtd = list_first_entry(&chan->qh->qtd_list, struct dwc2_qtd,
-                              qtd_list_entry);
-
-       if (hsotg->core_params->dma_enable <= 0) {
-               if ((hcint & HCINTMSK_CHHLTD) && hcint != HCINTMSK_CHHLTD)
-                       hcint &= ~HCINTMSK_CHHLTD;
-       }
-
-       if (hcint & HCINTMSK_XFERCOMPL) {
-               dwc2_hc_xfercomp_intr(hsotg, chan, chnum, qtd);
-               /*
-                * If NYET occurred at same time as Xfer Complete, the NYET is
-                * handled by the Xfer Complete interrupt handler. Don't want
-                * to call the NYET interrupt handler in this case.
-                */
-               hcint &= ~HCINTMSK_NYET;
-       }
-       if (hcint & HCINTMSK_CHHLTD)
-               dwc2_hc_chhltd_intr(hsotg, chan, chnum, qtd);
-       if (hcint & HCINTMSK_AHBERR)
-               dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd);
-       if (hcint & HCINTMSK_STALL)
-               dwc2_hc_stall_intr(hsotg, chan, chnum, qtd);
-       if (hcint & HCINTMSK_NAK)
-               dwc2_hc_nak_intr(hsotg, chan, chnum, qtd);
-       if (hcint & HCINTMSK_ACK)
-               dwc2_hc_ack_intr(hsotg, chan, chnum, qtd);
-       if (hcint & HCINTMSK_NYET)
-               dwc2_hc_nyet_intr(hsotg, chan, chnum, qtd);
-       if (hcint & HCINTMSK_XACTERR)
-               dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd);
-       if (hcint & HCINTMSK_BBLERR)
-               dwc2_hc_babble_intr(hsotg, chan, chnum, qtd);
-       if (hcint & HCINTMSK_FRMOVRUN)
-               dwc2_hc_frmovrun_intr(hsotg, chan, chnum, qtd);
-       if (hcint & HCINTMSK_DATATGLERR)
-               dwc2_hc_datatglerr_intr(hsotg, chan, chnum, qtd);
-
-       chan->hcint = 0;
-}
-
-/*
- * This interrupt indicates that one or more host channels has a pending
- * interrupt. There are multiple conditions that can cause each host channel
- * interrupt. This function determines which conditions have occurred for each
- * host channel interrupt and handles them appropriately.
- */
-static void dwc2_hc_intr(struct dwc2_hsotg *hsotg)
-{
-       u32 haint;
-       int i;
-
-       haint = readl(hsotg->regs + HAINT);
-       if (dbg_perio()) {
-               dev_vdbg(hsotg->dev, "%s()\n", __func__);
-
-               dev_vdbg(hsotg->dev, "HAINT=%08x\n", haint);
-       }
-
-       for (i = 0; i < hsotg->core_params->host_channels; i++) {
-               if (haint & (1 << i))
-                       dwc2_hc_n_intr(hsotg, i);
-       }
-}
-
-/* This function handles interrupts for the HCD */
-irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg)
-{
-       u32 gintsts, dbg_gintsts;
-       irqreturn_t retval = IRQ_NONE;
-
-       if (!dwc2_is_controller_alive(hsotg)) {
-               dev_warn(hsotg->dev, "Controller is dead\n");
-               return retval;
-       }
-
-       spin_lock(&hsotg->lock);
-
-       /* Check if HOST Mode */
-       if (dwc2_is_host_mode(hsotg)) {
-               gintsts = dwc2_read_core_intr(hsotg);
-               if (!gintsts) {
-                       spin_unlock(&hsotg->lock);
-                       return retval;
-               }
-
-               retval = IRQ_HANDLED;
-
-               dbg_gintsts = gintsts;
-#ifndef DEBUG_SOF
-               dbg_gintsts &= ~GINTSTS_SOF;
-#endif
-               if (!dbg_perio())
-                       dbg_gintsts &= ~(GINTSTS_HCHINT | GINTSTS_RXFLVL |
-                                        GINTSTS_PTXFEMP);
-
-               /* Only print if there are any non-suppressed interrupts left */
-               if (dbg_gintsts)
-                       dev_vdbg(hsotg->dev,
-                                "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x\n",
-                                gintsts);
-
-               if (gintsts & GINTSTS_SOF)
-                       dwc2_sof_intr(hsotg);
-               if (gintsts & GINTSTS_RXFLVL)
-                       dwc2_rx_fifo_level_intr(hsotg);
-               if (gintsts & GINTSTS_NPTXFEMP)
-                       dwc2_np_tx_fifo_empty_intr(hsotg);
-               if (gintsts & GINTSTS_PRTINT)
-                       dwc2_port_intr(hsotg);
-               if (gintsts & GINTSTS_HCHINT)
-                       dwc2_hc_intr(hsotg);
-               if (gintsts & GINTSTS_PTXFEMP)
-                       dwc2_perio_tx_fifo_empty_intr(hsotg);
-
-               if (dbg_gintsts) {
-                       dev_vdbg(hsotg->dev,
-                                "DWC OTG HCD Finished Servicing Interrupts\n");
-                       dev_vdbg(hsotg->dev,
-                                "DWC OTG HCD gintsts=0x%08x gintmsk=0x%08x\n",
-                                readl(hsotg->regs + GINTSTS),
-                                readl(hsotg->regs + GINTMSK));
-               }
-       }
-
-       spin_unlock(&hsotg->lock);
-
-       return retval;
-}
diff --git a/drivers/staging/dwc2/hcd_queue.c b/drivers/staging/dwc2/hcd_queue.c
deleted file mode 100644 (file)
index 9540f7e..0000000
+++ /dev/null
@@ -1,835 +0,0 @@
-/*
- * hcd_queue.c - DesignWare HS OTG Controller host queuing routines
- *
- * Copyright (C) 2004-2013 Synopsys, Inc.
- *
- * 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") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * 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.
- */
-
-/*
- * This file contains the functions to manage Queue Heads and Queue
- * Transfer Descriptors for Host mode
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-
-#include <linux/usb/hcd.h>
-#include <linux/usb/ch11.h>
-
-#include "core.h"
-#include "hcd.h"
-
-/**
- * dwc2_qh_init() - Initializes a QH structure
- *
- * @hsotg: The HCD state structure for the DWC OTG controller
- * @qh:    The QH to init
- * @urb:   Holds the information about the device/endpoint needed to initialize
- *         the QH
- */
-#define SCHEDULE_SLOP 10
-static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
-                        struct dwc2_hcd_urb *urb)
-{
-       int dev_speed, hub_addr, hub_port;
-       char *speed, *type;
-
-       dev_vdbg(hsotg->dev, "%s()\n", __func__);
-
-       /* Initialize QH */
-       qh->ep_type = dwc2_hcd_get_pipe_type(&urb->pipe_info);
-       qh->ep_is_in = dwc2_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
-
-       qh->data_toggle = DWC2_HC_PID_DATA0;
-       qh->maxp = dwc2_hcd_get_mps(&urb->pipe_info);
-       INIT_LIST_HEAD(&qh->qtd_list);
-       INIT_LIST_HEAD(&qh->qh_list_entry);
-
-       /* FS/LS Endpoint on HS Hub, NOT virtual root hub */
-       dev_speed = dwc2_host_get_speed(hsotg, urb->priv);
-
-       dwc2_host_hub_info(hsotg, urb->priv, &hub_addr, &hub_port);
-
-       if ((dev_speed == USB_SPEED_LOW || dev_speed == USB_SPEED_FULL) &&
-           hub_addr != 0 && hub_addr != 1) {
-               dev_vdbg(hsotg->dev,
-                        "QH init: EP %d: TT found at hub addr %d, for port %d\n",
-                        dwc2_hcd_get_ep_num(&urb->pipe_info), hub_addr,
-                        hub_port);
-               qh->do_split = 1;
-       }
-
-       if (qh->ep_type == USB_ENDPOINT_XFER_INT ||
-           qh->ep_type == USB_ENDPOINT_XFER_ISOC) {
-               /* Compute scheduling parameters once and save them */
-               u32 hprt, prtspd;
-
-               /* Todo: Account for split transfers in the bus time */
-               int bytecount =
-                       dwc2_hb_mult(qh->maxp) * dwc2_max_packet(qh->maxp);
-
-               qh->usecs = NS_TO_US(usb_calc_bus_time(qh->do_split ?
-                               USB_SPEED_HIGH : dev_speed, qh->ep_is_in,
-                               qh->ep_type == USB_ENDPOINT_XFER_ISOC,
-                               bytecount));
-               /* Start in a slightly future (micro)frame */
-               qh->sched_frame = dwc2_frame_num_inc(hsotg->frame_number,
-                                                    SCHEDULE_SLOP);
-               qh->interval = urb->interval;
-#if 0
-               /* Increase interrupt polling rate for debugging */
-               if (qh->ep_type == USB_ENDPOINT_XFER_INT)
-                       qh->interval = 8;
-#endif
-               hprt = readl(hsotg->regs + HPRT0);
-               prtspd = (hprt & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
-               if (prtspd == HPRT0_SPD_HIGH_SPEED &&
-                   (dev_speed == USB_SPEED_LOW ||
-                    dev_speed == USB_SPEED_FULL)) {
-                       qh->interval *= 8;
-                       qh->sched_frame |= 0x7;
-                       qh->start_split_frame = qh->sched_frame;
-               }
-               dev_dbg(hsotg->dev, "interval=%d\n", qh->interval);
-       }
-
-       dev_vdbg(hsotg->dev, "DWC OTG HCD QH Initialized\n");
-       dev_vdbg(hsotg->dev, "DWC OTG HCD QH - qh = %p\n", qh);
-       dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Device Address = %d\n",
-                dwc2_hcd_get_dev_addr(&urb->pipe_info));
-       dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Endpoint %d, %s\n",
-                dwc2_hcd_get_ep_num(&urb->pipe_info),
-                dwc2_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
-
-       qh->dev_speed = dev_speed;
-
-       switch (dev_speed) {
-       case USB_SPEED_LOW:
-               speed = "low";
-               break;
-       case USB_SPEED_FULL:
-               speed = "full";
-               break;
-       case USB_SPEED_HIGH:
-               speed = "high";
-               break;
-       default:
-               speed = "?";
-               break;
-       }
-       dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Speed = %s\n", speed);
-
-       switch (qh->ep_type) {
-       case USB_ENDPOINT_XFER_ISOC:
-               type = "isochronous";
-               break;
-       case USB_ENDPOINT_XFER_INT:
-               type = "interrupt";
-               break;
-       case USB_ENDPOINT_XFER_CONTROL:
-               type = "control";
-               break;
-       case USB_ENDPOINT_XFER_BULK:
-               type = "bulk";
-               break;
-       default:
-               type = "?";
-               break;
-       }
-
-       dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Type = %s\n", type);
-
-       if (qh->ep_type == USB_ENDPOINT_XFER_INT) {
-               dev_vdbg(hsotg->dev, "DWC OTG HCD QH - usecs = %d\n",
-                        qh->usecs);
-               dev_vdbg(hsotg->dev, "DWC OTG HCD QH - interval = %d\n",
-                        qh->interval);
-       }
-}
-
-/**
- * dwc2_hcd_qh_create() - Allocates and initializes a QH
- *
- * @hsotg:        The HCD state structure for the DWC OTG controller
- * @urb:          Holds the information about the device/endpoint needed
- *                to initialize the QH
- * @atomic_alloc: Flag to do atomic allocation if needed
- *
- * Return: Pointer to the newly allocated QH, or NULL on error
- */
-static struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
-                                         struct dwc2_hcd_urb *urb,
-                                         gfp_t mem_flags)
-{
-       struct dwc2_qh *qh;
-
-       if (!urb->priv)
-               return NULL;
-
-       /* Allocate memory */
-       qh = kzalloc(sizeof(*qh), mem_flags);
-       if (!qh)
-               return NULL;
-
-       dwc2_qh_init(hsotg, qh, urb);
-
-       if (hsotg->core_params->dma_desc_enable > 0 &&
-           dwc2_hcd_qh_init_ddma(hsotg, qh, mem_flags) < 0) {
-               dwc2_hcd_qh_free(hsotg, qh);
-               return NULL;
-       }
-
-       return qh;
-}
-
-/**
- * dwc2_hcd_qh_free() - Frees the QH
- *
- * @hsotg: HCD instance
- * @qh:    The QH to free
- *
- * QH should already be removed from the list. QTD list should already be empty
- * if called from URB Dequeue.
- *
- * Must NOT be called with interrupt disabled or spinlock held
- */
-void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
-{
-       u32 buf_size;
-
-       if (hsotg->core_params->dma_desc_enable > 0) {
-               dwc2_hcd_qh_free_ddma(hsotg, qh);
-       } else if (qh->dw_align_buf) {
-               if (qh->ep_type == USB_ENDPOINT_XFER_ISOC)
-                       buf_size = 4096;
-               else
-                       buf_size = hsotg->core_params->max_transfer_size;
-               dma_free_coherent(hsotg->dev, buf_size, qh->dw_align_buf,
-                                 qh->dw_align_buf_dma);
-       }
-
-       kfree(qh);
-}
-
-/**
- * dwc2_periodic_channel_available() - Checks that a channel is available for a
- * periodic transfer
- *
- * @hsotg: The HCD state structure for the DWC OTG controller
- *
- * Return: 0 if successful, negative error code otherwise
- */
-static int dwc2_periodic_channel_available(struct dwc2_hsotg *hsotg)
-{
-       /*
-        * Currently assuming that there is a dedicated host channel for
-        * each periodic transaction plus at least one host channel for
-        * non-periodic transactions
-        */
-       int status;
-       int num_channels;
-
-       num_channels = hsotg->core_params->host_channels;
-       if (hsotg->periodic_channels + hsotg->non_periodic_channels <
-                                                               num_channels
-           && hsotg->periodic_channels < num_channels - 1) {
-               status = 0;
-       } else {
-               dev_dbg(hsotg->dev,
-                       "%s: Total channels: %d, Periodic: %d, "
-                       "Non-periodic: %d\n", __func__, num_channels,
-                       hsotg->periodic_channels, hsotg->non_periodic_channels);
-               status = -ENOSPC;
-       }
-
-       return status;
-}
-
-/**
- * dwc2_check_periodic_bandwidth() - Checks that there is sufficient bandwidth
- * for the specified QH in the periodic schedule
- *
- * @hsotg: The HCD state structure for the DWC OTG controller
- * @qh:    QH containing periodic bandwidth required
- *
- * Return: 0 if successful, negative error code otherwise
- *
- * For simplicity, this calculation assumes that all the transfers in the
- * periodic schedule may occur in the same (micro)frame
- */
-static int dwc2_check_periodic_bandwidth(struct dwc2_hsotg *hsotg,
-                                        struct dwc2_qh *qh)
-{
-       int status;
-       s16 max_claimed_usecs;
-
-       status = 0;
-
-       if (qh->dev_speed == USB_SPEED_HIGH || qh->do_split) {
-               /*
-                * High speed mode
-                * Max periodic usecs is 80% x 125 usec = 100 usec
-                */
-               max_claimed_usecs = 100 - qh->usecs;
-       } else {
-               /*
-                * Full speed mode
-                * Max periodic usecs is 90% x 1000 usec = 900 usec
-                */
-               max_claimed_usecs = 900 - qh->usecs;
-       }
-
-       if (hsotg->periodic_usecs > max_claimed_usecs) {
-               dev_err(hsotg->dev,
-                       "%s: already claimed usecs %d, required usecs %d\n",
-                       __func__, hsotg->periodic_usecs, qh->usecs);
-               status = -ENOSPC;
-       }
-
-       return status;
-}
-
-/**
- * Microframe scheduler
- * track the total use in hsotg->frame_usecs
- * keep each qh use in qh->frame_usecs
- * when surrendering the qh then donate the time back
- */
-static const unsigned short max_uframe_usecs[] = {
-       100, 100, 100, 100, 100, 100, 30, 0
-};
-
-void dwc2_hcd_init_usecs(struct dwc2_hsotg *hsotg)
-{
-       int i;
-
-       for (i = 0; i < 8; i++)
-               hsotg->frame_usecs[i] = max_uframe_usecs[i];
-}
-
-static int dwc2_find_single_uframe(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
-{
-       unsigned short utime = qh->usecs;
-       int i;
-
-       for (i = 0; i < 8; i++) {
-               /* At the start hsotg->frame_usecs[i] = max_uframe_usecs[i] */
-               if (utime <= hsotg->frame_usecs[i]) {
-                       hsotg->frame_usecs[i] -= utime;
-                       qh->frame_usecs[i] += utime;
-                       return i;
-               }
-       }
-       return -ENOSPC;
-}
-
-/*
- * use this for FS apps that can span multiple uframes
- */
-static int dwc2_find_multi_uframe(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
-{
-       unsigned short utime = qh->usecs;
-       unsigned short xtime;
-       int t_left;
-       int i;
-       int j;
-       int k;
-
-       for (i = 0; i < 8; i++) {
-               if (hsotg->frame_usecs[i] <= 0)
-                       continue;
-
-               /*
-                * we need n consecutive slots so use j as a start slot
-                * j plus j+1 must be enough time (for now)
-                */
-               xtime = hsotg->frame_usecs[i];
-               for (j = i + 1; j < 8; j++) {
-                       /*
-                        * if we add this frame remaining time to xtime we may
-                        * be OK, if not we need to test j for a complete frame
-                        */
-                       if (xtime + hsotg->frame_usecs[j] < utime) {
-                               if (hsotg->frame_usecs[j] <
-                                                       max_uframe_usecs[j])
-                                       continue;
-                       }
-                       if (xtime >= utime) {
-                               t_left = utime;
-                               for (k = i; k < 8; k++) {
-                                       t_left -= hsotg->frame_usecs[k];
-                                       if (t_left <= 0) {
-                                               qh->frame_usecs[k] +=
-                                                       hsotg->frame_usecs[k]
-                                                               + t_left;
-                                               hsotg->frame_usecs[k] = -t_left;
-                                               return i;
-                                       } else {
-                                               qh->frame_usecs[k] +=
-                                                       hsotg->frame_usecs[k];
-                                               hsotg->frame_usecs[k] = 0;
-                                       }
-                               }
-                       }
-                       /* add the frame time to x time */
-                       xtime += hsotg->frame_usecs[j];
-                       /* we must have a fully available next frame or break */
-                       if (xtime < utime &&
-                          hsotg->frame_usecs[j] == max_uframe_usecs[j])
-                               continue;
-               }
-       }
-       return -ENOSPC;
-}
-
-static int dwc2_find_uframe(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
-{
-       int ret;
-
-       if (qh->dev_speed == USB_SPEED_HIGH) {
-               /* if this is a hs transaction we need a full frame */
-               ret = dwc2_find_single_uframe(hsotg, qh);
-       } else {
-               /*
-                * if this is a fs transaction we may need a sequence
-                * of frames
-                */
-               ret = dwc2_find_multi_uframe(hsotg, qh);
-       }
-       return ret;
-}
-
-/**
- * dwc2_check_max_xfer_size() - Checks that the max transfer size allowed in a
- * host channel is large enough to handle the maximum data transfer in a single
- * (micro)frame for a periodic transfer
- *
- * @hsotg: The HCD state structure for the DWC OTG controller
- * @qh:    QH for a periodic endpoint
- *
- * Return: 0 if successful, negative error code otherwise
- */
-static int dwc2_check_max_xfer_size(struct dwc2_hsotg *hsotg,
-                                   struct dwc2_qh *qh)
-{
-       u32 max_xfer_size;
-       u32 max_channel_xfer_size;
-       int status = 0;
-
-       max_xfer_size = dwc2_max_packet(qh->maxp) * dwc2_hb_mult(qh->maxp);
-       max_channel_xfer_size = hsotg->core_params->max_transfer_size;
-
-       if (max_xfer_size > max_channel_xfer_size) {
-               dev_err(hsotg->dev,
-                       "%s: Periodic xfer length %d > max xfer length for channel %d\n",
-                       __func__, max_xfer_size, max_channel_xfer_size);
-               status = -ENOSPC;
-       }
-
-       return status;
-}
-
-/**
- * dwc2_schedule_periodic() - Schedules an interrupt or isochronous transfer in
- * the periodic schedule
- *
- * @hsotg: The HCD state structure for the DWC OTG controller
- * @qh:    QH for the periodic transfer. The QH should already contain the
- *         scheduling information.
- *
- * Return: 0 if successful, negative error code otherwise
- */
-static int dwc2_schedule_periodic(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
-{
-       int status;
-
-       if (hsotg->core_params->uframe_sched > 0) {
-               int frame = -1;
-
-               status = dwc2_find_uframe(hsotg, qh);
-               if (status == 0)
-                       frame = 7;
-               else if (status > 0)
-                       frame = status - 1;
-
-               /* Set the new frame up */
-               if (frame >= 0) {
-                       qh->sched_frame &= ~0x7;
-                       qh->sched_frame |= (frame & 7);
-               }
-
-               if (status > 0)
-                       status = 0;
-       } else {
-               status = dwc2_periodic_channel_available(hsotg);
-               if (status) {
-                       dev_info(hsotg->dev,
-                                "%s: No host channel available for periodic transfer\n",
-                                __func__);
-                       return status;
-               }
-
-               status = dwc2_check_periodic_bandwidth(hsotg, qh);
-       }
-
-       if (status) {
-               dev_dbg(hsotg->dev,
-                       "%s: Insufficient periodic bandwidth for periodic transfer\n",
-                       __func__);
-               return status;
-       }
-
-       status = dwc2_check_max_xfer_size(hsotg, qh);
-       if (status) {
-               dev_dbg(hsotg->dev,
-                       "%s: Channel max transfer size too small for periodic transfer\n",
-                       __func__);
-               return status;
-       }
-
-       if (hsotg->core_params->dma_desc_enable > 0)
-               /* Don't rely on SOF and start in ready schedule */
-               list_add_tail(&qh->qh_list_entry, &hsotg->periodic_sched_ready);
-       else
-               /* Always start in inactive schedule */
-               list_add_tail(&qh->qh_list_entry,
-                             &hsotg->periodic_sched_inactive);
-
-       if (hsotg->core_params->uframe_sched <= 0)
-               /* Reserve periodic channel */
-               hsotg->periodic_channels++;
-
-       /* Update claimed usecs per (micro)frame */
-       hsotg->periodic_usecs += qh->usecs;
-
-       return status;
-}
-
-/**
- * dwc2_deschedule_periodic() - Removes an interrupt or isochronous transfer
- * from the periodic schedule
- *
- * @hsotg: The HCD state structure for the DWC OTG controller
- * @qh:           QH for the periodic transfer
- */
-static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg,
-                                    struct dwc2_qh *qh)
-{
-       int i;
-
-       list_del_init(&qh->qh_list_entry);
-
-       /* Update claimed usecs per (micro)frame */
-       hsotg->periodic_usecs -= qh->usecs;
-
-       if (hsotg->core_params->uframe_sched > 0) {
-               for (i = 0; i < 8; i++) {
-                       hsotg->frame_usecs[i] += qh->frame_usecs[i];
-                       qh->frame_usecs[i] = 0;
-               }
-       } else {
-               /* Release periodic channel reservation */
-               hsotg->periodic_channels--;
-       }
-}
-
-/**
- * dwc2_hcd_qh_add() - Adds a QH to either the non periodic or periodic
- * schedule if it is not already in the schedule. If the QH is already in
- * the schedule, no action is taken.
- *
- * @hsotg: The HCD state structure for the DWC OTG controller
- * @qh:    The QH to add
- *
- * Return: 0 if successful, negative error code otherwise
- */
-int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
-{
-       int status;
-       u32 intr_mask;
-
-       if (dbg_qh(qh))
-               dev_vdbg(hsotg->dev, "%s()\n", __func__);
-
-       if (!list_empty(&qh->qh_list_entry))
-               /* QH already in a schedule */
-               return 0;
-
-       /* Add the new QH to the appropriate schedule */
-       if (dwc2_qh_is_non_per(qh)) {
-               /* Always start in inactive schedule */
-               list_add_tail(&qh->qh_list_entry,
-                             &hsotg->non_periodic_sched_inactive);
-               return 0;
-       }
-
-       status = dwc2_schedule_periodic(hsotg, qh);
-       if (status)
-               return status;
-       if (!hsotg->periodic_qh_count) {
-               intr_mask = readl(hsotg->regs + GINTMSK);
-               intr_mask |= GINTSTS_SOF;
-               writel(intr_mask, hsotg->regs + GINTMSK);
-       }
-       hsotg->periodic_qh_count++;
-
-       return 0;
-}
-
-/**
- * dwc2_hcd_qh_unlink() - Removes a QH from either the non-periodic or periodic
- * schedule. Memory is not freed.
- *
- * @hsotg: The HCD state structure
- * @qh:    QH to remove from schedule
- */
-void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
-{
-       u32 intr_mask;
-
-       dev_vdbg(hsotg->dev, "%s()\n", __func__);
-
-       if (list_empty(&qh->qh_list_entry))
-               /* QH is not in a schedule */
-               return;
-
-       if (dwc2_qh_is_non_per(qh)) {
-               if (hsotg->non_periodic_qh_ptr == &qh->qh_list_entry)
-                       hsotg->non_periodic_qh_ptr =
-                                       hsotg->non_periodic_qh_ptr->next;
-               list_del_init(&qh->qh_list_entry);
-               return;
-       }
-
-       dwc2_deschedule_periodic(hsotg, qh);
-       hsotg->periodic_qh_count--;
-       if (!hsotg->periodic_qh_count) {
-               intr_mask = readl(hsotg->regs + GINTMSK);
-               intr_mask &= ~GINTSTS_SOF;
-               writel(intr_mask, hsotg->regs + GINTMSK);
-       }
-}
-
-/*
- * Schedule the next continuing periodic split transfer
- */
-static void dwc2_sched_periodic_split(struct dwc2_hsotg *hsotg,
-                                     struct dwc2_qh *qh, u16 frame_number,
-                                     int sched_next_periodic_split)
-{
-       u16 incr;
-
-       if (sched_next_periodic_split) {
-               qh->sched_frame = frame_number;
-               incr = dwc2_frame_num_inc(qh->start_split_frame, 1);
-               if (dwc2_frame_num_le(frame_number, incr)) {
-                       /*
-                        * Allow one frame to elapse after start split
-                        * microframe before scheduling complete split, but
-                        * DON'T if we are doing the next start split in the
-                        * same frame for an ISOC out
-                        */
-                       if (qh->ep_type != USB_ENDPOINT_XFER_ISOC ||
-                           qh->ep_is_in != 0) {
-                               qh->sched_frame =
-                                       dwc2_frame_num_inc(qh->sched_frame, 1);
-                       }
-               }
-       } else {
-               qh->sched_frame = dwc2_frame_num_inc(qh->start_split_frame,
-                                                    qh->interval);
-               if (dwc2_frame_num_le(qh->sched_frame, frame_number))
-                       qh->sched_frame = frame_number;
-               qh->sched_frame |= 0x7;
-               qh->start_split_frame = qh->sched_frame;
-       }
-}
-
-/*
- * Deactivates a QH. For non-periodic QHs, removes the QH from the active
- * non-periodic schedule. The QH is added to the inactive non-periodic
- * schedule if any QTDs are still attached to the QH.
- *
- * For periodic QHs, the QH is removed from the periodic queued schedule. If
- * there are any QTDs still attached to the QH, the QH is added to either the
- * periodic inactive schedule or the periodic ready schedule and its next
- * scheduled frame is calculated. The QH is placed in the ready schedule if
- * the scheduled frame has been reached already. Otherwise it's placed in the
- * inactive schedule. If there are no QTDs attached to the QH, the QH is
- * completely removed from the periodic schedule.
- */
-void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
-                           int sched_next_periodic_split)
-{
-       u16 frame_number;
-
-       if (dbg_qh(qh))
-               dev_vdbg(hsotg->dev, "%s()\n", __func__);
-
-       if (dwc2_qh_is_non_per(qh)) {
-               dwc2_hcd_qh_unlink(hsotg, qh);
-               if (!list_empty(&qh->qtd_list))
-                       /* Add back to inactive non-periodic schedule */
-                       dwc2_hcd_qh_add(hsotg, qh);
-               return;
-       }
-
-       frame_number = dwc2_hcd_get_frame_number(hsotg);
-
-       if (qh->do_split) {
-               dwc2_sched_periodic_split(hsotg, qh, frame_number,
-                                         sched_next_periodic_split);
-       } else {
-               qh->sched_frame = dwc2_frame_num_inc(qh->sched_frame,
-                                                    qh->interval);
-               if (dwc2_frame_num_le(qh->sched_frame, frame_number))
-                       qh->sched_frame = frame_number;
-       }
-
-       if (list_empty(&qh->qtd_list)) {
-               dwc2_hcd_qh_unlink(hsotg, qh);
-               return;
-       }
-       /*
-        * Remove from periodic_sched_queued and move to
-        * appropriate queue
-        */
-       if ((hsotg->core_params->uframe_sched > 0 &&
-            dwc2_frame_num_le(qh->sched_frame, frame_number)) ||
-           (hsotg->core_params->uframe_sched <= 0 &&
-            qh->sched_frame == frame_number))
-               list_move(&qh->qh_list_entry, &hsotg->periodic_sched_ready);
-       else
-               list_move(&qh->qh_list_entry, &hsotg->periodic_sched_inactive);
-}
-
-/**
- * dwc2_hcd_qtd_init() - Initializes a QTD structure
- *
- * @qtd: The QTD to initialize
- * @urb: The associated URB
- */
-void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb)
-{
-       qtd->urb = urb;
-       if (dwc2_hcd_get_pipe_type(&urb->pipe_info) ==
-                       USB_ENDPOINT_XFER_CONTROL) {
-               /*
-                * The only time the QTD data toggle is used is on the data
-                * phase of control transfers. This phase always starts with
-                * DATA1.
-                */
-               qtd->data_toggle = DWC2_HC_PID_DATA1;
-               qtd->control_phase = DWC2_CONTROL_SETUP;
-       }
-
-       /* Start split */
-       qtd->complete_split = 0;
-       qtd->isoc_split_pos = DWC2_HCSPLT_XACTPOS_ALL;
-       qtd->isoc_split_offset = 0;
-       qtd->in_process = 0;
-
-       /* Store the qtd ptr in the urb to reference the QTD */
-       urb->qtd = qtd;
-}
-
-/**
- * dwc2_hcd_qtd_add() - Adds a QTD to the QTD-list of a QH
- *
- * @hsotg:        The DWC HCD structure
- * @qtd:          The QTD to add
- * @qh:           Out parameter to return queue head
- * @atomic_alloc: Flag to do atomic alloc if needed
- *
- * Return: 0 if successful, negative error code otherwise
- *
- * Finds the correct QH to place the QTD into. If it does not find a QH, it
- * will create a new QH. If the QH to which the QTD is added is not currently
- * scheduled, it is placed into the proper schedule based on its EP type.
- */
-int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
-                    struct dwc2_qh **qh, gfp_t mem_flags)
-{
-       struct dwc2_hcd_urb *urb = qtd->urb;
-       unsigned long flags;
-       int allocated = 0;
-       int retval;
-
-       /*
-        * Get the QH which holds the QTD-list to insert to. Create QH if it
-        * doesn't exist.
-        */
-       if (*qh == NULL) {
-               *qh = dwc2_hcd_qh_create(hsotg, urb, mem_flags);
-               if (*qh == NULL)
-                       return -ENOMEM;
-               allocated = 1;
-       }
-
-       spin_lock_irqsave(&hsotg->lock, flags);
-
-       retval = dwc2_hcd_qh_add(hsotg, *qh);
-       if (retval)
-               goto fail;
-
-       qtd->qh = *qh;
-       list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list);
-       spin_unlock_irqrestore(&hsotg->lock, flags);
-
-       return 0;
-
-fail:
-       if (allocated) {
-               struct dwc2_qtd *qtd2, *qtd2_tmp;
-               struct dwc2_qh *qh_tmp = *qh;
-
-               *qh = NULL;
-               dwc2_hcd_qh_unlink(hsotg, qh_tmp);
-
-               /* Free each QTD in the QH's QTD list */
-               list_for_each_entry_safe(qtd2, qtd2_tmp, &qh_tmp->qtd_list,
-                                        qtd_list_entry)
-                       dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh_tmp);
-
-               spin_unlock_irqrestore(&hsotg->lock, flags);
-               dwc2_hcd_qh_free(hsotg, qh_tmp);
-       } else {
-               spin_unlock_irqrestore(&hsotg->lock, flags);
-       }
-
-       return retval;
-}
diff --git a/drivers/staging/dwc2/hw.h b/drivers/staging/dwc2/hw.h
deleted file mode 100644 (file)
index 9c92a3c..0000000
+++ /dev/null
@@ -1,809 +0,0 @@
-/*
- * hw.h - DesignWare HS OTG Controller hardware definitions
- *
- * Copyright 2004-2013 Synopsys, Inc.
- *
- * 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") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * 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 __DWC2_HW_H__
-#define __DWC2_HW_H__
-
-#define HSOTG_REG(x)   (x)
-
-#define GOTGCTL                                HSOTG_REG(0x000)
-#define GOTGCTL_CHIRPEN                        (1 << 27)
-#define GOTGCTL_MULT_VALID_BC_MASK     (0x1f << 22)
-#define GOTGCTL_MULT_VALID_BC_SHIFT    22
-#define GOTGCTL_OTGVER                 (1 << 20)
-#define GOTGCTL_BSESVLD                        (1 << 19)
-#define GOTGCTL_ASESVLD                        (1 << 18)
-#define GOTGCTL_DBNC_SHORT             (1 << 17)
-#define GOTGCTL_CONID_B                        (1 << 16)
-#define GOTGCTL_DEVHNPEN               (1 << 11)
-#define GOTGCTL_HSTSETHNPEN            (1 << 10)
-#define GOTGCTL_HNPREQ                 (1 << 9)
-#define GOTGCTL_HSTNEGSCS              (1 << 8)
-#define GOTGCTL_SESREQ                 (1 << 1)
-#define GOTGCTL_SESREQSCS              (1 << 0)
-
-#define GOTGINT                                HSOTG_REG(0x004)
-#define GOTGINT_DBNCE_DONE             (1 << 19)
-#define GOTGINT_A_DEV_TOUT_CHG         (1 << 18)
-#define GOTGINT_HST_NEG_DET            (1 << 17)
-#define GOTGINT_HST_NEG_SUC_STS_CHNG   (1 << 9)
-#define GOTGINT_SES_REQ_SUC_STS_CHNG   (1 << 8)
-#define GOTGINT_SES_END_DET            (1 << 2)
-
-#define GAHBCFG                                HSOTG_REG(0x008)
-#define GAHBCFG_AHB_SINGLE             (1 << 23)
-#define GAHBCFG_NOTI_ALL_DMA_WRIT      (1 << 22)
-#define GAHBCFG_REM_MEM_SUPP           (1 << 21)
-#define GAHBCFG_P_TXF_EMP_LVL          (1 << 8)
-#define GAHBCFG_NP_TXF_EMP_LVL         (1 << 7)
-#define GAHBCFG_DMA_EN                 (1 << 5)
-#define GAHBCFG_HBSTLEN_MASK           (0xf << 1)
-#define GAHBCFG_HBSTLEN_SHIFT          1
-#define GAHBCFG_HBSTLEN_SINGLE         0
-#define GAHBCFG_HBSTLEN_INCR           1
-#define GAHBCFG_HBSTLEN_INCR4          3
-#define GAHBCFG_HBSTLEN_INCR8          5
-#define GAHBCFG_HBSTLEN_INCR16         7
-#define GAHBCFG_GLBL_INTR_EN           (1 << 0)
-#define GAHBCFG_CTRL_MASK              (GAHBCFG_P_TXF_EMP_LVL | \
-                                        GAHBCFG_NP_TXF_EMP_LVL | \
-                                        GAHBCFG_DMA_EN | \
-                                        GAHBCFG_GLBL_INTR_EN)
-
-#define GUSBCFG                                HSOTG_REG(0x00C)
-#define GUSBCFG_FORCEDEVMODE           (1 << 30)
-#define GUSBCFG_FORCEHOSTMODE          (1 << 29)
-#define GUSBCFG_TXENDDELAY             (1 << 28)
-#define GUSBCFG_ICTRAFFICPULLREMOVE    (1 << 27)
-#define GUSBCFG_ICUSBCAP               (1 << 26)
-#define GUSBCFG_ULPI_INT_PROT_DIS      (1 << 25)
-#define GUSBCFG_INDICATORPASSTHROUGH   (1 << 24)
-#define GUSBCFG_INDICATORCOMPLEMENT    (1 << 23)
-#define GUSBCFG_TERMSELDLPULSE         (1 << 22)
-#define GUSBCFG_ULPI_INT_VBUS_IND      (1 << 21)
-#define GUSBCFG_ULPI_EXT_VBUS_DRV      (1 << 20)
-#define GUSBCFG_ULPI_CLK_SUSP_M                (1 << 19)
-#define GUSBCFG_ULPI_AUTO_RES          (1 << 18)
-#define GUSBCFG_ULPI_FS_LS             (1 << 17)
-#define GUSBCFG_OTG_UTMI_FS_SEL                (1 << 16)
-#define GUSBCFG_PHY_LP_CLK_SEL         (1 << 15)
-#define GUSBCFG_USBTRDTIM_MASK         (0xf << 10)
-#define GUSBCFG_USBTRDTIM_SHIFT                10
-#define GUSBCFG_HNPCAP                 (1 << 9)
-#define GUSBCFG_SRPCAP                 (1 << 8)
-#define GUSBCFG_DDRSEL                 (1 << 7)
-#define GUSBCFG_PHYSEL                 (1 << 6)
-#define GUSBCFG_FSINTF                 (1 << 5)
-#define GUSBCFG_ULPI_UTMI_SEL          (1 << 4)
-#define GUSBCFG_PHYIF16                        (1 << 3)
-#define GUSBCFG_TOUTCAL_MASK           (0x7 << 0)
-#define GUSBCFG_TOUTCAL_SHIFT          0
-#define GUSBCFG_TOUTCAL_LIMIT          0x7
-#define GUSBCFG_TOUTCAL(_x)            ((_x) << 0)
-
-#define GRSTCTL                                HSOTG_REG(0x010)
-#define GRSTCTL_AHBIDLE                        (1 << 31)
-#define GRSTCTL_DMAREQ                 (1 << 30)
-#define GRSTCTL_TXFNUM_MASK            (0x1f << 6)
-#define GRSTCTL_TXFNUM_SHIFT           6
-#define GRSTCTL_TXFNUM_LIMIT           0x1f
-#define GRSTCTL_TXFNUM(_x)             ((_x) << 6)
-#define GRSTCTL_TXFFLSH                        (1 << 5)
-#define GRSTCTL_RXFFLSH                        (1 << 4)
-#define GRSTCTL_IN_TKNQ_FLSH           (1 << 3)
-#define GRSTCTL_FRMCNTRRST             (1 << 2)
-#define GRSTCTL_HSFTRST                        (1 << 1)
-#define GRSTCTL_CSFTRST                        (1 << 0)
-
-#define GINTSTS                                HSOTG_REG(0x014)
-#define GINTMSK                                HSOTG_REG(0x018)
-#define GINTSTS_WKUPINT                        (1 << 31)
-#define GINTSTS_SESSREQINT             (1 << 30)
-#define GINTSTS_DISCONNINT             (1 << 29)
-#define GINTSTS_CONIDSTSCHNG           (1 << 28)
-#define GINTSTS_LPMTRANRCVD            (1 << 27)
-#define GINTSTS_PTXFEMP                        (1 << 26)
-#define GINTSTS_HCHINT                 (1 << 25)
-#define GINTSTS_PRTINT                 (1 << 24)
-#define GINTSTS_RESETDET               (1 << 23)
-#define GINTSTS_FET_SUSP               (1 << 22)
-#define GINTSTS_INCOMPL_IP             (1 << 21)
-#define GINTSTS_INCOMPL_SOIN           (1 << 20)
-#define GINTSTS_OEPINT                 (1 << 19)
-#define GINTSTS_IEPINT                 (1 << 18)
-#define GINTSTS_EPMIS                  (1 << 17)
-#define GINTSTS_RESTOREDONE            (1 << 16)
-#define GINTSTS_EOPF                   (1 << 15)
-#define GINTSTS_ISOUTDROP              (1 << 14)
-#define GINTSTS_ENUMDONE               (1 << 13)
-#define GINTSTS_USBRST                 (1 << 12)
-#define GINTSTS_USBSUSP                        (1 << 11)
-#define GINTSTS_ERLYSUSP               (1 << 10)
-#define GINTSTS_I2CINT                 (1 << 9)
-#define GINTSTS_ULPI_CK_INT            (1 << 8)
-#define GINTSTS_GOUTNAKEFF             (1 << 7)
-#define GINTSTS_GINNAKEFF              (1 << 6)
-#define GINTSTS_NPTXFEMP               (1 << 5)
-#define GINTSTS_RXFLVL                 (1 << 4)
-#define GINTSTS_SOF                    (1 << 3)
-#define GINTSTS_OTGINT                 (1 << 2)
-#define GINTSTS_MODEMIS                        (1 << 1)
-#define GINTSTS_CURMODE_HOST           (1 << 0)
-
-#define GRXSTSR                                HSOTG_REG(0x01C)
-#define GRXSTSP                                HSOTG_REG(0x020)
-#define GRXSTS_FN_MASK                 (0x7f << 25)
-#define GRXSTS_FN_SHIFT                        25
-#define GRXSTS_PKTSTS_MASK             (0xf << 17)
-#define GRXSTS_PKTSTS_SHIFT            17
-#define GRXSTS_PKTSTS_GLOBALOUTNAK     1
-#define GRXSTS_PKTSTS_OUTRX            2
-#define GRXSTS_PKTSTS_HCHIN            2
-#define GRXSTS_PKTSTS_OUTDONE          3
-#define GRXSTS_PKTSTS_HCHIN_XFER_COMP  3
-#define GRXSTS_PKTSTS_SETUPDONE                4
-#define GRXSTS_PKTSTS_DATATOGGLEERR    5
-#define GRXSTS_PKTSTS_SETUPRX          6
-#define GRXSTS_PKTSTS_HCHHALTED                7
-#define GRXSTS_HCHNUM_MASK             (0xf << 0)
-#define GRXSTS_HCHNUM_SHIFT            0
-#define GRXSTS_DPID_MASK               (0x3 << 15)
-#define GRXSTS_DPID_SHIFT              15
-#define GRXSTS_BYTECNT_MASK            (0x7ff << 4)
-#define GRXSTS_BYTECNT_SHIFT           4
-#define GRXSTS_EPNUM_MASK              (0xf << 0)
-#define GRXSTS_EPNUM_SHIFT             0
-
-#define GRXFSIZ                                HSOTG_REG(0x024)
-#define GRXFSIZ_DEPTH_MASK             (0xffff << 0)
-#define GRXFSIZ_DEPTH_SHIFT            0
-
-#define GNPTXFSIZ                      HSOTG_REG(0x028)
-/* Use FIFOSIZE_* constants to access this register */
-
-#define GNPTXSTS                       HSOTG_REG(0x02C)
-#define GNPTXSTS_NP_TXQ_TOP_MASK               (0x7f << 24)
-#define GNPTXSTS_NP_TXQ_TOP_SHIFT              24
-#define GNPTXSTS_NP_TXQ_SPC_AVAIL_MASK         (0xff << 16)
-#define GNPTXSTS_NP_TXQ_SPC_AVAIL_SHIFT                16
-#define GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(_v)      (((_v) >> 16) & 0xff)
-#define GNPTXSTS_NP_TXF_SPC_AVAIL_MASK         (0xffff << 0)
-#define GNPTXSTS_NP_TXF_SPC_AVAIL_SHIFT                0
-#define GNPTXSTS_NP_TXF_SPC_AVAIL_GET(_v)      (((_v) >> 0) & 0xffff)
-
-#define GI2CCTL                                HSOTG_REG(0x0030)
-#define GI2CCTL_BSYDNE                 (1 << 31)
-#define GI2CCTL_RW                     (1 << 30)
-#define GI2CCTL_I2CDATSE0              (1 << 28)
-#define GI2CCTL_I2CDEVADDR_MASK                (0x3 << 26)
-#define GI2CCTL_I2CDEVADDR_SHIFT       26
-#define GI2CCTL_I2CSUSPCTL             (1 << 25)
-#define GI2CCTL_ACK                    (1 << 24)
-#define GI2CCTL_I2CEN                  (1 << 23)
-#define GI2CCTL_ADDR_MASK              (0x7f << 16)
-#define GI2CCTL_ADDR_SHIFT             16
-#define GI2CCTL_REGADDR_MASK           (0xff << 8)
-#define GI2CCTL_REGADDR_SHIFT          8
-#define GI2CCTL_RWDATA_MASK            (0xff << 0)
-#define GI2CCTL_RWDATA_SHIFT           0
-
-#define GPVNDCTL                       HSOTG_REG(0x0034)
-#define GGPIO                          HSOTG_REG(0x0038)
-#define GUID                           HSOTG_REG(0x003c)
-#define GSNPSID                                HSOTG_REG(0x0040)
-#define GHWCFG1                                HSOTG_REG(0x0044)
-
-#define GHWCFG2                                HSOTG_REG(0x0048)
-#define GHWCFG2_OTG_ENABLE_IC_USB              (1 << 31)
-#define GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK         (0x1f << 26)
-#define GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT                26
-#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK     (0x3 << 24)
-#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT    24
-#define GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK       (0x3 << 22)
-#define GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT      22
-#define GHWCFG2_MULTI_PROC_INT                 (1 << 20)
-#define GHWCFG2_DYNAMIC_FIFO                   (1 << 19)
-#define GHWCFG2_PERIO_EP_SUPPORTED             (1 << 18)
-#define GHWCFG2_NUM_HOST_CHAN_MASK             (0xf << 14)
-#define GHWCFG2_NUM_HOST_CHAN_SHIFT            14
-#define GHWCFG2_NUM_DEV_EP_MASK                        (0xf << 10)
-#define GHWCFG2_NUM_DEV_EP_SHIFT               10
-#define GHWCFG2_FS_PHY_TYPE_MASK               (0x3 << 8)
-#define GHWCFG2_FS_PHY_TYPE_SHIFT              8
-#define GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED      0
-#define GHWCFG2_FS_PHY_TYPE_DEDICATED          1
-#define GHWCFG2_FS_PHY_TYPE_SHARED_UTMI                2
-#define GHWCFG2_FS_PHY_TYPE_SHARED_ULPI                3
-#define GHWCFG2_HS_PHY_TYPE_MASK               (0x3 << 6)
-#define GHWCFG2_HS_PHY_TYPE_SHIFT              6
-#define GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED      0
-#define GHWCFG2_HS_PHY_TYPE_UTMI               1
-#define GHWCFG2_HS_PHY_TYPE_ULPI               2
-#define GHWCFG2_HS_PHY_TYPE_UTMI_ULPI          3
-#define GHWCFG2_POINT2POINT                    (1 << 5)
-#define GHWCFG2_ARCHITECTURE_MASK              (0x3 << 3)
-#define GHWCFG2_ARCHITECTURE_SHIFT             3
-#define GHWCFG2_SLAVE_ONLY_ARCH                        0
-#define GHWCFG2_EXT_DMA_ARCH                   1
-#define GHWCFG2_INT_DMA_ARCH                   2
-#define GHWCFG2_OP_MODE_MASK                   (0x7 << 0)
-#define GHWCFG2_OP_MODE_SHIFT                  0
-#define GHWCFG2_OP_MODE_HNP_SRP_CAPABLE                0
-#define GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE       1
-#define GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE     2
-#define GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE     3
-#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE  4
-#define GHWCFG2_OP_MODE_SRP_CAPABLE_HOST       5
-#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST    6
-#define GHWCFG2_OP_MODE_UNDEFINED              7
-
-#define GHWCFG3                                HSOTG_REG(0x004c)
-#define GHWCFG3_DFIFO_DEPTH_MASK               (0xffff << 16)
-#define GHWCFG3_DFIFO_DEPTH_SHIFT              16
-#define GHWCFG3_OTG_LPM_EN                     (1 << 15)
-#define GHWCFG3_BC_SUPPORT                     (1 << 14)
-#define GHWCFG3_OTG_ENABLE_HSIC                        (1 << 13)
-#define GHWCFG3_ADP_SUPP                       (1 << 12)
-#define GHWCFG3_SYNCH_RESET_TYPE               (1 << 11)
-#define GHWCFG3_OPTIONAL_FEATURES              (1 << 10)
-#define GHWCFG3_VENDOR_CTRL_IF                 (1 << 9)
-#define GHWCFG3_I2C                            (1 << 8)
-#define GHWCFG3_OTG_FUNC                       (1 << 7)
-#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK    (0x7 << 4)
-#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT   4
-#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK      (0xf << 0)
-#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT     0
-
-#define GHWCFG4                                HSOTG_REG(0x0050)
-#define GHWCFG4_DESC_DMA_DYN                   (1 << 31)
-#define GHWCFG4_DESC_DMA                       (1 << 30)
-#define GHWCFG4_NUM_IN_EPS_MASK                        (0xf << 26)
-#define GHWCFG4_NUM_IN_EPS_SHIFT               26
-#define GHWCFG4_DED_FIFO_EN                    (1 << 25)
-#define GHWCFG4_SESSION_END_FILT_EN            (1 << 24)
-#define GHWCFG4_B_VALID_FILT_EN                        (1 << 23)
-#define GHWCFG4_A_VALID_FILT_EN                        (1 << 22)
-#define GHWCFG4_VBUS_VALID_FILT_EN             (1 << 21)
-#define GHWCFG4_IDDIG_FILT_EN                  (1 << 20)
-#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_MASK      (0xf << 16)
-#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT     16
-#define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK       (0x3 << 14)
-#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT      14
-#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8          0
-#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16         1
-#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16    2
-#define GHWCFG4_XHIBER                         (1 << 7)
-#define GHWCFG4_HIBER                          (1 << 6)
-#define GHWCFG4_MIN_AHB_FREQ                   (1 << 5)
-#define GHWCFG4_POWER_OPTIMIZ                  (1 << 4)
-#define GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK       (0xf << 0)
-#define GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT      0
-
-#define GLPMCFG                                HSOTG_REG(0x0054)
-#define GLPMCFG_INV_SEL_HSIC           (1 << 31)
-#define GLPMCFG_HSIC_CONNECT           (1 << 30)
-#define GLPMCFG_RETRY_COUNT_STS_MASK   (0x7 << 25)
-#define GLPMCFG_RETRY_COUNT_STS_SHIFT  25
-#define GLPMCFG_SEND_LPM               (1 << 24)
-#define GLPMCFG_RETRY_COUNT_MASK       (0x7 << 21)
-#define GLPMCFG_RETRY_COUNT_SHIFT      21
-#define GLPMCFG_LPM_CHAN_INDEX_MASK    (0xf << 17)
-#define GLPMCFG_LPM_CHAN_INDEX_SHIFT   17
-#define GLPMCFG_SLEEP_STATE_RESUMEOK   (1 << 16)
-#define GLPMCFG_PRT_SLEEP_STS          (1 << 15)
-#define GLPMCFG_LPM_RESP_MASK          (0x3 << 13)
-#define GLPMCFG_LPM_RESP_SHIFT         13
-#define GLPMCFG_HIRD_THRES_MASK                (0x1f << 8)
-#define GLPMCFG_HIRD_THRES_SHIFT       8
-#define GLPMCFG_HIRD_THRES_EN                  (0x10 << 8)
-#define GLPMCFG_EN_UTMI_SLEEP          (1 << 7)
-#define GLPMCFG_REM_WKUP_EN            (1 << 6)
-#define GLPMCFG_HIRD_MASK              (0xf << 2)
-#define GLPMCFG_HIRD_SHIFT             2
-#define GLPMCFG_APPL_RESP              (1 << 1)
-#define GLPMCFG_LPM_CAP_EN             (1 << 0)
-
-#define GPWRDN                         HSOTG_REG(0x0058)
-#define GPWRDN_MULT_VAL_ID_BC_MASK     (0x1f << 24)
-#define GPWRDN_MULT_VAL_ID_BC_SHIFT    24
-#define GPWRDN_ADP_INT                 (1 << 23)
-#define GPWRDN_BSESSVLD                        (1 << 22)
-#define GPWRDN_IDSTS                   (1 << 21)
-#define GPWRDN_LINESTATE_MASK          (0x3 << 19)
-#define GPWRDN_LINESTATE_SHIFT         19
-#define GPWRDN_STS_CHGINT_MSK          (1 << 18)
-#define GPWRDN_STS_CHGINT              (1 << 17)
-#define GPWRDN_SRP_DET_MSK             (1 << 16)
-#define GPWRDN_SRP_DET                 (1 << 15)
-#define GPWRDN_CONNECT_DET_MSK         (1 << 14)
-#define GPWRDN_CONNECT_DET             (1 << 13)
-#define GPWRDN_DISCONN_DET_MSK         (1 << 12)
-#define GPWRDN_DISCONN_DET             (1 << 11)
-#define GPWRDN_RST_DET_MSK             (1 << 10)
-#define GPWRDN_RST_DET                 (1 << 9)
-#define GPWRDN_LNSTSCHG_MSK            (1 << 8)
-#define GPWRDN_LNSTSCHG                        (1 << 7)
-#define GPWRDN_DIS_VBUS                        (1 << 6)
-#define GPWRDN_PWRDNSWTCH              (1 << 5)
-#define GPWRDN_PWRDNRSTN               (1 << 4)
-#define GPWRDN_PWRDNCLMP               (1 << 3)
-#define GPWRDN_RESTORE                 (1 << 2)
-#define GPWRDN_PMUACTV                 (1 << 1)
-#define GPWRDN_PMUINTSEL               (1 << 0)
-
-#define GDFIFOCFG                      HSOTG_REG(0x005c)
-#define GDFIFOCFG_EPINFOBASE_MASK      (0xffff << 16)
-#define GDFIFOCFG_EPINFOBASE_SHIFT     16
-#define GDFIFOCFG_GDFIFOCFG_MASK       (0xffff << 0)
-#define GDFIFOCFG_GDFIFOCFG_SHIFT      0
-
-#define ADPCTL                         HSOTG_REG(0x0060)
-#define ADPCTL_AR_MASK                 (0x3 << 27)
-#define ADPCTL_AR_SHIFT                        27
-#define ADPCTL_ADP_TMOUT_INT_MSK       (1 << 26)
-#define ADPCTL_ADP_SNS_INT_MSK         (1 << 25)
-#define ADPCTL_ADP_PRB_INT_MSK         (1 << 24)
-#define ADPCTL_ADP_TMOUT_INT           (1 << 23)
-#define ADPCTL_ADP_SNS_INT             (1 << 22)
-#define ADPCTL_ADP_PRB_INT             (1 << 21)
-#define ADPCTL_ADPENA                  (1 << 20)
-#define ADPCTL_ADPRES                  (1 << 19)
-#define ADPCTL_ENASNS                  (1 << 18)
-#define ADPCTL_ENAPRB                  (1 << 17)
-#define ADPCTL_RTIM_MASK               (0x7ff << 6)
-#define ADPCTL_RTIM_SHIFT              6
-#define ADPCTL_PRB_PER_MASK            (0x3 << 4)
-#define ADPCTL_PRB_PER_SHIFT           4
-#define ADPCTL_PRB_DELTA_MASK          (0x3 << 2)
-#define ADPCTL_PRB_DELTA_SHIFT         2
-#define ADPCTL_PRB_DSCHRG_MASK         (0x3 << 0)
-#define ADPCTL_PRB_DSCHRG_SHIFT                0
-
-#define HPTXFSIZ                       HSOTG_REG(0x100)
-/* Use FIFOSIZE_* constants to access this register */
-
-#define DPTXFSIZN(_a)                  HSOTG_REG(0x104 + (((_a) - 1) * 4))
-/* Use FIFOSIZE_* constants to access this register */
-
-/* These apply to the GNPTXFSIZ, HPTXFSIZ and DPTXFSIZN registers */
-#define FIFOSIZE_DEPTH_MASK            (0xffff << 16)
-#define FIFOSIZE_DEPTH_SHIFT           16
-#define FIFOSIZE_STARTADDR_MASK                (0xffff << 0)
-#define FIFOSIZE_STARTADDR_SHIFT       0
-
-/* Device mode registers */
-
-#define DCFG                           HSOTG_REG(0x800)
-#define DCFG_EPMISCNT_MASK             (0x1f << 18)
-#define DCFG_EPMISCNT_SHIFT            18
-#define DCFG_EPMISCNT_LIMIT            0x1f
-#define DCFG_EPMISCNT(_x)              ((_x) << 18)
-#define DCFG_PERFRINT_MASK             (0x3 << 11)
-#define DCFG_PERFRINT_SHIFT            11
-#define DCFG_PERFRINT_LIMIT            0x3
-#define DCFG_PERFRINT(_x)              ((_x) << 11)
-#define DCFG_DEVADDR_MASK              (0x7f << 4)
-#define DCFG_DEVADDR_SHIFT             4
-#define DCFG_DEVADDR_LIMIT             0x7f
-#define DCFG_DEVADDR(_x)               ((_x) << 4)
-#define DCFG_NZ_STS_OUT_HSHK           (1 << 2)
-#define DCFG_DEVSPD_MASK               (0x3 << 0)
-#define DCFG_DEVSPD_SHIFT              0
-#define DCFG_DEVSPD_HS                 0
-#define DCFG_DEVSPD_FS                 1
-#define DCFG_DEVSPD_LS                 2
-#define DCFG_DEVSPD_FS48               3
-
-#define DCTL                           HSOTG_REG(0x804)
-#define DCTL_PWRONPRGDONE              (1 << 11)
-#define DCTL_CGOUTNAK                  (1 << 10)
-#define DCTL_SGOUTNAK                  (1 << 9)
-#define DCTL_CGNPINNAK                 (1 << 8)
-#define DCTL_SGNPINNAK                 (1 << 7)
-#define DCTL_TSTCTL_MASK               (0x7 << 4)
-#define DCTL_TSTCTL_SHIFT              4
-#define DCTL_GOUTNAKSTS                        (1 << 3)
-#define DCTL_GNPINNAKSTS               (1 << 2)
-#define DCTL_SFTDISCON                 (1 << 1)
-#define DCTL_RMTWKUPSIG                        (1 << 0)
-
-#define DSTS                           HSOTG_REG(0x808)
-#define DSTS_SOFFN_MASK                        (0x3fff << 8)
-#define DSTS_SOFFN_SHIFT               8
-#define DSTS_SOFFN_LIMIT               0x3fff
-#define DSTS_SOFFN(_x)                 ((_x) << 8)
-#define DSTS_ERRATICERR                        (1 << 3)
-#define DSTS_ENUMSPD_MASK              (0x3 << 1)
-#define DSTS_ENUMSPD_SHIFT             1
-#define DSTS_ENUMSPD_HS                        0
-#define DSTS_ENUMSPD_FS                        1
-#define DSTS_ENUMSPD_LS                        2
-#define DSTS_ENUMSPD_FS48              3
-#define DSTS_SUSPSTS                   (1 << 0)
-
-#define DIEPMSK                                HSOTG_REG(0x810)
-#define DIEPMSK_TXFIFOEMPTY            (1 << 7)
-#define DIEPMSK_INEPNAKEFFMSK          (1 << 6)
-#define DIEPMSK_INTKNEPMISMSK          (1 << 5)
-#define DIEPMSK_INTKNTXFEMPMSK         (1 << 4)
-#define DIEPMSK_TIMEOUTMSK             (1 << 3)
-#define DIEPMSK_AHBERRMSK              (1 << 2)
-#define DIEPMSK_EPDISBLDMSK            (1 << 1)
-#define DIEPMSK_XFERCOMPLMSK           (1 << 0)
-
-#define DOEPMSK                                HSOTG_REG(0x814)
-#define DOEPMSK_BACK2BACKSETUP         (1 << 6)
-#define DOEPMSK_OUTTKNEPDISMSK         (1 << 4)
-#define DOEPMSK_SETUPMSK               (1 << 3)
-#define DOEPMSK_AHBERRMSK              (1 << 2)
-#define DOEPMSK_EPDISBLDMSK            (1 << 1)
-#define DOEPMSK_XFERCOMPLMSK           (1 << 0)
-
-#define DAINT                          HSOTG_REG(0x818)
-#define DAINTMSK                       HSOTG_REG(0x81C)
-#define DAINT_OUTEP_SHIFT              16
-#define DAINT_OUTEP(_x)                        (1 << ((_x) + 16))
-#define DAINT_INEP(_x)                 (1 << (_x))
-
-#define DTKNQR1                                HSOTG_REG(0x820)
-#define DTKNQR2                                HSOTG_REG(0x824)
-#define DTKNQR3                                HSOTG_REG(0x830)
-#define DTKNQR4                                HSOTG_REG(0x834)
-
-#define DVBUSDIS                       HSOTG_REG(0x828)
-#define DVBUSPULSE                     HSOTG_REG(0x82C)
-
-#define DIEPCTL0                       HSOTG_REG(0x900)
-#define DIEPCTL(_a)                    HSOTG_REG(0x900 + ((_a) * 0x20))
-
-#define DOEPCTL0                       HSOTG_REG(0xB00)
-#define DOEPCTL(_a)                    HSOTG_REG(0xB00 + ((_a) * 0x20))
-
-/* EP0 specialness:
- * bits[29..28] - reserved (no SetD0PID, SetD1PID)
- * bits[25..22] - should always be zero, this isn't a periodic endpoint
- * bits[10..0]  - MPS setting different for EP0
- */
-#define D0EPCTL_MPS_MASK               (0x3 << 0)
-#define D0EPCTL_MPS_SHIFT              0
-#define D0EPCTL_MPS_64                 0
-#define D0EPCTL_MPS_32                 1
-#define D0EPCTL_MPS_16                 2
-#define D0EPCTL_MPS_8                  3
-
-#define DXEPCTL_EPENA                  (1 << 31)
-#define DXEPCTL_EPDIS                  (1 << 30)
-#define DXEPCTL_SETD1PID               (1 << 29)
-#define DXEPCTL_SETODDFR               (1 << 29)
-#define DXEPCTL_SETD0PID               (1 << 28)
-#define DXEPCTL_SETEVENFR              (1 << 28)
-#define DXEPCTL_SNAK                   (1 << 27)
-#define DXEPCTL_CNAK                   (1 << 26)
-#define DXEPCTL_TXFNUM_MASK            (0xf << 22)
-#define DXEPCTL_TXFNUM_SHIFT           22
-#define DXEPCTL_TXFNUM_LIMIT           0xf
-#define DXEPCTL_TXFNUM(_x)             ((_x) << 22)
-#define DXEPCTL_STALL                  (1 << 21)
-#define DXEPCTL_SNP                    (1 << 20)
-#define DXEPCTL_EPTYPE_MASK            (0x3 << 18)
-#define DXEPCTL_EPTYPE_SHIFT           18
-#define DXEPCTL_EPTYPE_CONTROL         0
-#define DXEPCTL_EPTYPE_ISO             1
-#define DXEPCTL_EPTYPE_BULK            2
-#define DXEPCTL_EPTYPE_INTTERUPT       3
-#define DXEPCTL_NAKSTS                 (1 << 17)
-#define DXEPCTL_DPID                   (1 << 16)
-#define DXEPCTL_EOFRNUM                        (1 << 16)
-#define DXEPCTL_USBACTEP               (1 << 15)
-#define DXEPCTL_NEXTEP_MASK            (0xf << 11)
-#define DXEPCTL_NEXTEP_SHIFT           11
-#define DXEPCTL_NEXTEP_LIMIT           0xf
-#define DXEPCTL_NEXTEP(_x)             ((_x) << 11)
-#define DXEPCTL_MPS_MASK               (0x7ff << 0)
-#define DXEPCTL_MPS_SHIFT              0
-#define DXEPCTL_MPS_LIMIT              0x7ff
-#define DXEPCTL_MPS(_x)                        ((_x) << 0)
-
-#define DIEPINT(_a)                    HSOTG_REG(0x908 + ((_a) * 0x20))
-#define DOEPINT(_a)                    HSOTG_REG(0xB08 + ((_a) * 0x20))
-#define DXEPINT_INEPNAKEFF             (1 << 6)
-#define DXEPINT_BACK2BACKSETUP         (1 << 6)
-#define DXEPINT_INTKNEPMIS             (1 << 5)
-#define DXEPINT_INTKNTXFEMP            (1 << 4)
-#define DXEPINT_OUTTKNEPDIS            (1 << 4)
-#define DXEPINT_TIMEOUT                        (1 << 3)
-#define DXEPINT_SETUP                  (1 << 3)
-#define DXEPINT_AHBERR                 (1 << 2)
-#define DXEPINT_EPDISBLD               (1 << 1)
-#define DXEPINT_XFERCOMPL              (1 << 0)
-
-#define DIEPTSIZ0                      HSOTG_REG(0x910)
-#define DIEPTSIZ0_PKTCNT_MASK          (0x3 << 19)
-#define DIEPTSIZ0_PKTCNT_SHIFT         19
-#define DIEPTSIZ0_PKTCNT_LIMIT         0x3
-#define DIEPTSIZ0_PKTCNT(_x)           ((_x) << 19)
-#define DIEPTSIZ0_XFERSIZE_MASK                (0x7f << 0)
-#define DIEPTSIZ0_XFERSIZE_SHIFT       0
-#define DIEPTSIZ0_XFERSIZE_LIMIT       0x7f
-#define DIEPTSIZ0_XFERSIZE(_x)         ((_x) << 0)
-
-#define DOEPTSIZ0                      HSOTG_REG(0xB10)
-#define DOEPTSIZ0_SUPCNT_MASK          (0x3 << 29)
-#define DOEPTSIZ0_SUPCNT_SHIFT         29
-#define DOEPTSIZ0_SUPCNT_LIMIT         0x3
-#define DOEPTSIZ0_SUPCNT(_x)           ((_x) << 29)
-#define DOEPTSIZ0_PKTCNT               (1 << 19)
-#define DOEPTSIZ0_XFERSIZE_MASK                (0x7f << 0)
-#define DOEPTSIZ0_XFERSIZE_SHIFT       0
-
-#define DIEPTSIZ(_a)                   HSOTG_REG(0x910 + ((_a) * 0x20))
-#define DOEPTSIZ(_a)                   HSOTG_REG(0xB10 + ((_a) * 0x20))
-#define DXEPTSIZ_MC_MASK               (0x3 << 29)
-#define DXEPTSIZ_MC_SHIFT              29
-#define DXEPTSIZ_MC_LIMIT              0x3
-#define DXEPTSIZ_MC(_x)                        ((_x) << 29)
-#define DXEPTSIZ_PKTCNT_MASK           (0x3ff << 19)
-#define DXEPTSIZ_PKTCNT_SHIFT          19
-#define DXEPTSIZ_PKTCNT_LIMIT          0x3ff
-#define DXEPTSIZ_PKTCNT_GET(_v)                (((_v) >> 19) & 0x3ff)
-#define DXEPTSIZ_PKTCNT(_x)            ((_x) << 19)
-#define DXEPTSIZ_XFERSIZE_MASK         (0x7ffff << 0)
-#define DXEPTSIZ_XFERSIZE_SHIFT                0
-#define DXEPTSIZ_XFERSIZE_LIMIT                0x7ffff
-#define DXEPTSIZ_XFERSIZE_GET(_v)      (((_v) >> 0) & 0x7ffff)
-#define DXEPTSIZ_XFERSIZE(_x)          ((_x) << 0)
-
-#define DIEPDMA(_a)                    HSOTG_REG(0x914 + ((_a) * 0x20))
-#define DOEPDMA(_a)                    HSOTG_REG(0xB14 + ((_a) * 0x20))
-
-#define DTXFSTS(_a)                    HSOTG_REG(0x918 + ((_a) * 0x20))
-
-#define PCGCTL                         HSOTG_REG(0x0e00)
-#define PCGCTL_IF_DEV_MODE             (1 << 31)
-#define PCGCTL_P2HD_PRT_SPD_MASK       (0x3 << 29)
-#define PCGCTL_P2HD_PRT_SPD_SHIFT      29
-#define PCGCTL_P2HD_DEV_ENUM_SPD_MASK  (0x3 << 27)
-#define PCGCTL_P2HD_DEV_ENUM_SPD_SHIFT 27
-#define PCGCTL_MAC_DEV_ADDR_MASK       (0x7f << 20)
-#define PCGCTL_MAC_DEV_ADDR_SHIFT      20
-#define PCGCTL_MAX_TERMSEL             (1 << 19)
-#define PCGCTL_MAX_XCVRSELECT_MASK     (0x3 << 17)
-#define PCGCTL_MAX_XCVRSELECT_SHIFT    17
-#define PCGCTL_PORT_POWER              (1 << 16)
-#define PCGCTL_PRT_CLK_SEL_MASK                (0x3 << 14)
-#define PCGCTL_PRT_CLK_SEL_SHIFT       14
-#define PCGCTL_ESS_REG_RESTORED                (1 << 13)
-#define PCGCTL_EXTND_HIBER_SWITCH      (1 << 12)
-#define PCGCTL_EXTND_HIBER_PWRCLMP     (1 << 11)
-#define PCGCTL_ENBL_EXTND_HIBER                (1 << 10)
-#define PCGCTL_RESTOREMODE             (1 << 9)
-#define PCGCTL_RESETAFTSUSP            (1 << 8)
-#define PCGCTL_DEEP_SLEEP              (1 << 7)
-#define PCGCTL_PHY_IN_SLEEP            (1 << 6)
-#define PCGCTL_ENBL_SLEEP_GATING       (1 << 5)
-#define PCGCTL_RSTPDWNMODULE           (1 << 3)
-#define PCGCTL_PWRCLMP                 (1 << 2)
-#define PCGCTL_GATEHCLK                        (1 << 1)
-#define PCGCTL_STOPPCLK                        (1 << 0)
-
-#define EPFIFO(_a)                     HSOTG_REG(0x1000 + ((_a) * 0x1000))
-
-/* Host Mode Registers */
-
-#define HCFG                           HSOTG_REG(0x0400)
-#define HCFG_MODECHTIMEN               (1 << 31)
-#define HCFG_PERSCHEDENA               (1 << 26)
-#define HCFG_FRLISTEN_MASK             (0x3 << 24)
-#define HCFG_FRLISTEN_SHIFT            24
-#define HCFG_FRLISTEN_8                                (0 << 24)
-#define FRLISTEN_8_SIZE                                8
-#define HCFG_FRLISTEN_16                       (1 << 24)
-#define FRLISTEN_16_SIZE                       16
-#define HCFG_FRLISTEN_32                       (2 << 24)
-#define FRLISTEN_32_SIZE                       32
-#define HCFG_FRLISTEN_64                       (3 << 24)
-#define FRLISTEN_64_SIZE                       64
-#define HCFG_DESCDMA                   (1 << 23)
-#define HCFG_RESVALID_MASK             (0xff << 8)
-#define HCFG_RESVALID_SHIFT            8
-#define HCFG_ENA32KHZ                  (1 << 7)
-#define HCFG_FSLSSUPP                  (1 << 2)
-#define HCFG_FSLSPCLKSEL_MASK          (0x3 << 0)
-#define HCFG_FSLSPCLKSEL_SHIFT         0
-#define HCFG_FSLSPCLKSEL_30_60_MHZ     0
-#define HCFG_FSLSPCLKSEL_48_MHZ                1
-#define HCFG_FSLSPCLKSEL_6_MHZ         2
-
-#define HFIR                           HSOTG_REG(0x0404)
-#define HFIR_FRINT_MASK                        (0xffff << 0)
-#define HFIR_FRINT_SHIFT               0
-#define HFIR_RLDCTRL                   (1 << 16)
-
-#define HFNUM                          HSOTG_REG(0x0408)
-#define HFNUM_FRREM_MASK               (0xffff << 16)
-#define HFNUM_FRREM_SHIFT              16
-#define HFNUM_FRNUM_MASK               (0xffff << 0)
-#define HFNUM_FRNUM_SHIFT              0
-#define HFNUM_MAX_FRNUM                        0x3fff
-
-#define HPTXSTS                                HSOTG_REG(0x0410)
-#define TXSTS_QTOP_ODD                 (1 << 31)
-#define TXSTS_QTOP_CHNEP_MASK          (0xf << 27)
-#define TXSTS_QTOP_CHNEP_SHIFT         27
-#define TXSTS_QTOP_TOKEN_MASK          (0x3 << 25)
-#define TXSTS_QTOP_TOKEN_SHIFT         25
-#define TXSTS_QTOP_TERMINATE           (1 << 24)
-#define TXSTS_QSPCAVAIL_MASK           (0xff << 16)
-#define TXSTS_QSPCAVAIL_SHIFT          16
-#define TXSTS_FSPCAVAIL_MASK           (0xffff << 0)
-#define TXSTS_FSPCAVAIL_SHIFT          0
-
-#define HAINT                          HSOTG_REG(0x0414)
-#define HAINTMSK                       HSOTG_REG(0x0418)
-#define HFLBADDR                       HSOTG_REG(0x041c)
-
-#define HPRT0                          HSOTG_REG(0x0440)
-#define HPRT0_SPD_MASK                 (0x3 << 17)
-#define HPRT0_SPD_SHIFT                        17
-#define HPRT0_SPD_HIGH_SPEED           0
-#define HPRT0_SPD_FULL_SPEED           1
-#define HPRT0_SPD_LOW_SPEED            2
-#define HPRT0_TSTCTL_MASK              (0xf << 13)
-#define HPRT0_TSTCTL_SHIFT             13
-#define HPRT0_PWR                      (1 << 12)
-#define HPRT0_LNSTS_MASK               (0x3 << 10)
-#define HPRT0_LNSTS_SHIFT              10
-#define HPRT0_RST                      (1 << 8)
-#define HPRT0_SUSP                     (1 << 7)
-#define HPRT0_RES                      (1 << 6)
-#define HPRT0_OVRCURRCHG               (1 << 5)
-#define HPRT0_OVRCURRACT               (1 << 4)
-#define HPRT0_ENACHG                   (1 << 3)
-#define HPRT0_ENA                      (1 << 2)
-#define HPRT0_CONNDET                  (1 << 1)
-#define HPRT0_CONNSTS                  (1 << 0)
-
-#define HCCHAR(_ch)                    HSOTG_REG(0x0500 + 0x20 * (_ch))
-#define HCCHAR_CHENA                   (1 << 31)
-#define HCCHAR_CHDIS                   (1 << 30)
-#define HCCHAR_ODDFRM                  (1 << 29)
-#define HCCHAR_DEVADDR_MASK            (0x7f << 22)
-#define HCCHAR_DEVADDR_SHIFT           22
-#define HCCHAR_MULTICNT_MASK           (0x3 << 20)
-#define HCCHAR_MULTICNT_SHIFT          20
-#define HCCHAR_EPTYPE_MASK             (0x3 << 18)
-#define HCCHAR_EPTYPE_SHIFT            18
-#define HCCHAR_LSPDDEV                 (1 << 17)
-#define HCCHAR_EPDIR                   (1 << 15)
-#define HCCHAR_EPNUM_MASK              (0xf << 11)
-#define HCCHAR_EPNUM_SHIFT             11
-#define HCCHAR_MPS_MASK                        (0x7ff << 0)
-#define HCCHAR_MPS_SHIFT               0
-
-#define HCSPLT(_ch)                    HSOTG_REG(0x0504 + 0x20 * (_ch))
-#define HCSPLT_SPLTENA                 (1 << 31)
-#define HCSPLT_COMPSPLT                        (1 << 16)
-#define HCSPLT_XACTPOS_MASK            (0x3 << 14)
-#define HCSPLT_XACTPOS_SHIFT           14
-#define HCSPLT_XACTPOS_MID             0
-#define HCSPLT_XACTPOS_END             1
-#define HCSPLT_XACTPOS_BEGIN           2
-#define HCSPLT_XACTPOS_ALL             3
-#define HCSPLT_HUBADDR_MASK            (0x7f << 7)
-#define HCSPLT_HUBADDR_SHIFT           7
-#define HCSPLT_PRTADDR_MASK            (0x7f << 0)
-#define HCSPLT_PRTADDR_SHIFT           0
-
-#define HCINT(_ch)                     HSOTG_REG(0x0508 + 0x20 * (_ch))
-#define HCINTMSK(_ch)                  HSOTG_REG(0x050c + 0x20 * (_ch))
-#define HCINTMSK_RESERVED14_31         (0x3ffff << 14)
-#define HCINTMSK_FRM_LIST_ROLL         (1 << 13)
-#define HCINTMSK_XCS_XACT              (1 << 12)
-#define HCINTMSK_BNA                   (1 << 11)
-#define HCINTMSK_DATATGLERR            (1 << 10)
-#define HCINTMSK_FRMOVRUN              (1 << 9)
-#define HCINTMSK_BBLERR                        (1 << 8)
-#define HCINTMSK_XACTERR               (1 << 7)
-#define HCINTMSK_NYET                  (1 << 6)
-#define HCINTMSK_ACK                   (1 << 5)
-#define HCINTMSK_NAK                   (1 << 4)
-#define HCINTMSK_STALL                 (1 << 3)
-#define HCINTMSK_AHBERR                        (1 << 2)
-#define HCINTMSK_CHHLTD                        (1 << 1)
-#define HCINTMSK_XFERCOMPL             (1 << 0)
-
-#define HCTSIZ(_ch)                    HSOTG_REG(0x0510 + 0x20 * (_ch))
-#define TSIZ_DOPNG                     (1 << 31)
-#define TSIZ_SC_MC_PID_MASK            (0x3 << 29)
-#define TSIZ_SC_MC_PID_SHIFT           29
-#define TSIZ_SC_MC_PID_DATA0           0
-#define TSIZ_SC_MC_PID_DATA2           1
-#define TSIZ_SC_MC_PID_DATA1           2
-#define TSIZ_SC_MC_PID_MDATA           3
-#define TSIZ_SC_MC_PID_SETUP           3
-#define TSIZ_PKTCNT_MASK               (0x3ff << 19)
-#define TSIZ_PKTCNT_SHIFT              19
-#define TSIZ_NTD_MASK                  (0xff << 8)
-#define TSIZ_NTD_SHIFT                 8
-#define TSIZ_SCHINFO_MASK              (0xff << 0)
-#define TSIZ_SCHINFO_SHIFT             0
-#define TSIZ_XFERSIZE_MASK             (0x7ffff << 0)
-#define TSIZ_XFERSIZE_SHIFT            0
-
-#define HCDMA(_ch)                     HSOTG_REG(0x0514 + 0x20 * (_ch))
-#define HCDMA_DMA_ADDR_MASK            (0x1fffff << 11)
-#define HCDMA_DMA_ADDR_SHIFT           11
-#define HCDMA_CTD_MASK                 (0xff << 3)
-#define HCDMA_CTD_SHIFT                        3
-
-#define HCDMAB(_ch)                    HSOTG_REG(0x051c + 0x20 * (_ch))
-
-#define HCFIFO(_ch)                    HSOTG_REG(0x1000 + 0x1000 * (_ch))
-
-/**
- * struct dwc2_hcd_dma_desc - Host-mode DMA descriptor structure
- *
- * @status: DMA descriptor status quadlet
- * @buf:    DMA descriptor data buffer pointer
- *
- * DMA Descriptor structure contains two quadlets:
- * Status quadlet and Data buffer pointer.
- */
-struct dwc2_hcd_dma_desc {
-       u32 status;
-       u32 buf;
-};
-
-#define HOST_DMA_A                     (1 << 31)
-#define HOST_DMA_STS_MASK              (0x3 << 28)
-#define HOST_DMA_STS_SHIFT             28
-#define HOST_DMA_STS_PKTERR            (1 << 28)
-#define HOST_DMA_EOL                   (1 << 26)
-#define HOST_DMA_IOC                   (1 << 25)
-#define HOST_DMA_SUP                   (1 << 24)
-#define HOST_DMA_ALT_QTD               (1 << 23)
-#define HOST_DMA_QTD_OFFSET_MASK       (0x3f << 17)
-#define HOST_DMA_QTD_OFFSET_SHIFT      17
-#define HOST_DMA_ISOC_NBYTES_MASK      (0xfff << 0)
-#define HOST_DMA_ISOC_NBYTES_SHIFT     0
-#define HOST_DMA_NBYTES_MASK           (0x1ffff << 0)
-#define HOST_DMA_NBYTES_SHIFT          0
-
-#define MAX_DMA_DESC_SIZE              131071
-#define MAX_DMA_DESC_NUM_GENERIC       64
-#define MAX_DMA_DESC_NUM_HS_ISOC       256
-
-#endif /* __DWC2_HW_H__ */
diff --git a/drivers/staging/dwc2/pci.c b/drivers/staging/dwc2/pci.c
deleted file mode 100644 (file)
index c291fca..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * pci.c - DesignWare HS OTG Controller PCI driver
- *
- * Copyright (C) 2004-2013 Synopsys, Inc.
- *
- * 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") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * 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.
- */
-
-/*
- * Provides the initialization and cleanup entry points for the DWC_otg PCI
- * driver
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/usb.h>
-
-#include <linux/usb/hcd.h>
-#include <linux/usb/ch11.h>
-
-#include "core.h"
-#include "hcd.h"
-
-#define PCI_VENDOR_ID_SYNOPSYS         0x16c3
-#define PCI_PRODUCT_ID_HAPS_HSOTG      0xabc0
-
-static const char dwc2_driver_name[] = "dwc2";
-
-static const struct dwc2_core_params dwc2_module_params = {
-       .otg_cap                        = -1,
-       .otg_ver                        = -1,
-       .dma_enable                     = -1,
-       .dma_desc_enable                = 0,
-       .speed                          = -1,
-       .enable_dynamic_fifo            = -1,
-       .en_multiple_tx_fifo            = -1,
-       .host_rx_fifo_size              = 1024,
-       .host_nperio_tx_fifo_size       = 256,
-       .host_perio_tx_fifo_size        = 1024,
-       .max_transfer_size              = 65535,
-       .max_packet_count               = 511,
-       .host_channels                  = -1,
-       .phy_type                       = -1,
-       .phy_utmi_width                 = -1,
-       .phy_ulpi_ddr                   = -1,
-       .phy_ulpi_ext_vbus              = -1,
-       .i2c_enable                     = -1,
-       .ulpi_fs_ls                     = -1,
-       .host_support_fs_ls_low_power   = -1,
-       .host_ls_low_power_phy_clk      = -1,
-       .ts_dline                       = -1,
-       .reload_ctl                     = -1,
-       .ahbcfg                         = -1,
-       .uframe_sched                   = -1,
-};
-
-/**
- * dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the
- * DWC_otg driver
- *
- * @dev: Bus device
- *
- * This routine is called, for example, when the rmmod command is executed. The
- * device may or may not be electrically present. If it is present, the driver
- * stops device processing. Any resources used on behalf of this device are
- * freed.
- */
-static void dwc2_driver_remove(struct pci_dev *dev)
-{
-       struct dwc2_hsotg *hsotg = pci_get_drvdata(dev);
-
-       dwc2_hcd_remove(hsotg);
-       pci_disable_device(dev);
-}
-
-/**
- * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg
- * driver
- *
- * @dev: Bus device
- *
- * This routine creates the driver components required to control the device
- * (core, HCD, and PCD) and initializes the device. The driver components are
- * stored in a dwc2_hsotg structure. A reference to the dwc2_hsotg is saved
- * in the device private data. This allows the driver to access the dwc2_hsotg
- * structure on subsequent calls to driver methods for this device.
- */
-static int dwc2_driver_probe(struct pci_dev *dev,
-                            const struct pci_device_id *id)
-{
-       struct dwc2_hsotg *hsotg;
-       int retval;
-
-       hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL);
-       if (!hsotg)
-               return -ENOMEM;
-
-       hsotg->dev = &dev->dev;
-       hsotg->regs = devm_ioremap_resource(&dev->dev, &dev->resource[0]);
-       if (IS_ERR(hsotg->regs))
-               return PTR_ERR(hsotg->regs);
-
-       dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
-               (unsigned long)pci_resource_start(dev, 0), hsotg->regs);
-
-       if (pci_enable_device(dev) < 0)
-               return -ENODEV;
-
-       pci_set_master(dev);
-
-       retval = dwc2_hcd_init(hsotg, dev->irq, &dwc2_module_params);
-       if (retval) {
-               pci_disable_device(dev);
-               return retval;
-       }
-
-       pci_set_drvdata(dev, hsotg);
-
-       return retval;
-}
-
-static const struct pci_device_id dwc2_pci_ids[] = {
-       {
-               PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, PCI_PRODUCT_ID_HAPS_HSOTG),
-       },
-       {
-               PCI_DEVICE(PCI_VENDOR_ID_STMICRO,
-                          PCI_DEVICE_ID_STMICRO_USB_OTG),
-       },
-       { /* end: all zeroes */ }
-};
-MODULE_DEVICE_TABLE(pci, dwc2_pci_ids);
-
-static struct pci_driver dwc2_pci_driver = {
-       .name = dwc2_driver_name,
-       .id_table = dwc2_pci_ids,
-       .probe = dwc2_driver_probe,
-       .remove = dwc2_driver_remove,
-};
-
-module_pci_driver(dwc2_pci_driver);
-
-MODULE_DESCRIPTION("DESIGNWARE HS OTG PCI Bus Glue");
-MODULE_AUTHOR("Synopsys, Inc.");
-MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/staging/dwc2/platform.c b/drivers/staging/dwc2/platform.c
deleted file mode 100644 (file)
index d01d0d3..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * platform.c - DesignWare HS OTG Controller platform driver
- *
- * Copyright (C) Matthijs Kooijman <matthijs@stdin.nl>
- *
- * 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") as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any
- * later version.
- *
- * 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/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-
-#include "core.h"
-#include "hcd.h"
-
-static const char dwc2_driver_name[] = "dwc2";
-
-static const struct dwc2_core_params params_bcm2835 = {
-       .otg_cap                        = 0,    /* HNP/SRP capable */
-       .otg_ver                        = 0,    /* 1.3 */
-       .dma_enable                     = 1,
-       .dma_desc_enable                = 0,
-       .speed                          = 0,    /* High Speed */
-       .enable_dynamic_fifo            = 1,
-       .en_multiple_tx_fifo            = 1,
-       .host_rx_fifo_size              = 774,  /* 774 DWORDs */
-       .host_nperio_tx_fifo_size       = 256,  /* 256 DWORDs */
-       .host_perio_tx_fifo_size        = 512,  /* 512 DWORDs */
-       .max_transfer_size              = 65535,
-       .max_packet_count               = 511,
-       .host_channels                  = 8,
-       .phy_type                       = 1,    /* UTMI */
-       .phy_utmi_width                 = 8,    /* 8 bits */
-       .phy_ulpi_ddr                   = 0,    /* Single */
-       .phy_ulpi_ext_vbus              = 0,
-       .i2c_enable                     = 0,
-       .ulpi_fs_ls                     = 0,
-       .host_support_fs_ls_low_power   = 0,
-       .host_ls_low_power_phy_clk      = 0,    /* 48 MHz */
-       .ts_dline                       = 0,
-       .reload_ctl                     = 0,
-       .ahbcfg                         = 0x10,
-       .uframe_sched                   = 0,
-};
-
-/**
- * dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the
- * DWC_otg driver
- *
- * @dev: Platform device
- *
- * This routine is called, for example, when the rmmod command is executed. The
- * device may or may not be electrically present. If it is present, the driver
- * stops device processing. Any resources used on behalf of this device are
- * freed.
- */
-static int dwc2_driver_remove(struct platform_device *dev)
-{
-       struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
-
-       dwc2_hcd_remove(hsotg);
-
-       return 0;
-}
-
-static const struct of_device_id dwc2_of_match_table[] = {
-       { .compatible = "brcm,bcm2835-usb", .data = &params_bcm2835 },
-       { .compatible = "snps,dwc2", .data = NULL },
-       {},
-};
-MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
-
-/**
- * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg
- * driver
- *
- * @dev: Platform device
- *
- * This routine creates the driver components required to control the device
- * (core, HCD, and PCD) and initializes the device. The driver components are
- * stored in a dwc2_hsotg structure. A reference to the dwc2_hsotg is saved
- * in the device private data. This allows the driver to access the dwc2_hsotg
- * structure on subsequent calls to driver methods for this device.
- */
-static int dwc2_driver_probe(struct platform_device *dev)
-{
-       const struct of_device_id *match;
-       const struct dwc2_core_params *params;
-       struct dwc2_core_params defparams;
-       struct dwc2_hsotg *hsotg;
-       struct resource *res;
-       int retval;
-       int irq;
-
-       match = of_match_device(dwc2_of_match_table, &dev->dev);
-       if (match && match->data) {
-               params = match->data;
-       } else {
-               /* Default all params to autodetect */
-               dwc2_set_all_params(&defparams, -1);
-               params = &defparams;
-       }
-
-       hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL);
-       if (!hsotg)
-               return -ENOMEM;
-
-       hsotg->dev = &dev->dev;
-
-       /*
-        * Use reasonable defaults so platforms don't have to provide these.
-        */
-       if (!dev->dev.dma_mask)
-               dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
-       retval = dma_set_coherent_mask(&dev->dev, DMA_BIT_MASK(32));
-       if (retval)
-               return retval;
-
-       irq = platform_get_irq(dev, 0);
-       if (irq < 0) {
-               dev_err(&dev->dev, "missing IRQ resource\n");
-               return irq;
-       }
-
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       hsotg->regs = devm_ioremap_resource(&dev->dev, res);
-       if (IS_ERR(hsotg->regs))
-               return PTR_ERR(hsotg->regs);
-
-       dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
-               (unsigned long)res->start, hsotg->regs);
-
-       retval = dwc2_hcd_init(hsotg, irq, params);
-       if (retval)
-               return retval;
-
-       platform_set_drvdata(dev, hsotg);
-
-       return retval;
-}
-
-static struct platform_driver dwc2_platform_driver = {
-       .driver = {
-               .name = dwc2_driver_name,
-               .of_match_table = dwc2_of_match_table,
-       },
-       .probe = dwc2_driver_probe,
-       .remove = dwc2_driver_remove,
-};
-
-module_platform_driver(dwc2_platform_driver);
-
-MODULE_DESCRIPTION("DESIGNWARE HS OTG Platform Glue");
-MODULE_AUTHOR("Matthijs Kooijman <matthijs@stdin.nl>");
-MODULE_LICENSE("Dual BSD/GPL");
index 2642b8a11e05f25c760ef84343d3dd7c17bb0390..7eb909aa8bc0f403518305dc5ba43702788952b4 100644 (file)
@@ -108,6 +108,8 @@ endif
 
 source "drivers/usb/dwc3/Kconfig"
 
+source "drivers/usb/dwc2/Kconfig"
+
 source "drivers/usb/chipidea/Kconfig"
 
 comment "USB port drivers"
index 70d7c5b92c3ced66e0e3a48804bf883011326f74..1ae2bf39d84bcdff88d69bf7383d2361a761bfbd 100644 (file)
@@ -7,6 +7,7 @@
 obj-$(CONFIG_USB)              += core/
 
 obj-$(CONFIG_USB_DWC3)         += dwc3/
+obj-$(CONFIG_USB_DWC2)         += dwc2/
 
 obj-$(CONFIG_USB_MON)          += mon/
 
diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig
new file mode 100644 (file)
index 0000000..be947d6
--- /dev/null
@@ -0,0 +1,53 @@
+config USB_DWC2
+       tristate "DesignWare USB2 DRD Core Support"
+       depends on USB
+       help
+         Say Y or M here if your system has a Dual Role HighSpeed
+         USB controller based on the DesignWare HSOTG IP Core.
+
+         If you choose to build this driver as dynamically linked
+         modules, the core module will be called dwc2.ko, the
+         PCI bus interface module (if you have a PCI bus system)
+         will be called dwc2_pci.ko and the platform interface module
+         (for controllers directly connected to the CPU) will be called
+         dwc2_platform.ko.
+
+         NOTE: This driver at present only implements the Host mode
+         of the controller. The existing s3c-hsotg driver supports
+         Peripheral mode, but only for the Samsung S3C platforms.
+         There are plans to merge the s3c-hsotg driver with this
+         driver in the near future to create a dual-role driver.
+
+if USB_DWC2
+
+config USB_DWC2_DEBUG
+       bool "Enable Debugging Messages"
+       help
+         Say Y here to enable debugging messages in the DWC2 Driver.
+
+config USB_DWC2_VERBOSE
+       bool "Enable Verbose Debugging Messages"
+       depends on USB_DWC2_DEBUG
+       help
+         Say Y here to enable verbose debugging messages in the DWC2 Driver.
+         WARNING: Enabling this will quickly fill your message log.
+         If in doubt, say N.
+
+config USB_DWC2_TRACK_MISSED_SOFS
+       bool "Enable Missed SOF Tracking"
+       help
+         Say Y here to enable logging of missed SOF events to the dmesg log.
+         WARNING: This feature is still experimental.
+         If in doubt, say N.
+
+config USB_DWC2_DEBUG_PERIODIC
+       bool "Enable Debugging Messages For Periodic Transfers"
+       depends on USB_DWC2_DEBUG || USB_DWC2_VERBOSE
+       default y
+       help
+         Say N here to disable (verbose) debugging messages to be
+         logged for periodic transfers. This allows better debugging of
+         non-periodic transfers, but of course the debug logs will be
+         incomplete. Note that this also disables some debug messages
+         for which the transfer type cannot be deduced.
+endif
diff --git a/drivers/usb/dwc2/Makefile b/drivers/usb/dwc2/Makefile
new file mode 100644 (file)
index 0000000..11529d3
--- /dev/null
@@ -0,0 +1,25 @@
+ccflags-$(CONFIG_USB_DWC2_DEBUG)       += -DDEBUG
+ccflags-$(CONFIG_USB_DWC2_VERBOSE)     += -DVERBOSE_DEBUG
+
+obj-$(CONFIG_USB_DWC2)                 += dwc2.o
+
+dwc2-y                                 += core.o core_intr.o
+
+# NOTE: This driver at present only implements the Host mode
+# of the controller. The existing s3c-hsotg driver supports
+# Peripheral mode, but only for the Samsung S3C platforms.
+# There are plans to merge the s3c-hsotg driver with this
+# driver in the near future to create a dual-role driver. Once
+# that is done, Host mode will become an optional feature that
+# is selected with a config option.
+
+dwc2-y                                 += hcd.o hcd_intr.o
+dwc2-y                                 += hcd_queue.o hcd_ddma.o
+
+ifneq ($(CONFIG_PCI),)
+       obj-$(CONFIG_USB_DWC2)          += dwc2_pci.o
+endif
+obj-$(CONFIG_USB_DWC2)                 += dwc2_platform.o
+
+dwc2_pci-y                             += pci.o
+dwc2_platform-y                                += platform.o
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
new file mode 100644 (file)
index 0000000..8565d87
--- /dev/null
@@ -0,0 +1,2777 @@
+/*
+ * core.c - DesignWare HS OTG Controller common routines
+ *
+ * Copyright (C) 2004-2013 Synopsys, Inc.
+ *
+ * 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") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * 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.
+ */
+
+/*
+ * The Core code provides basic services for accessing and managing the
+ * DWC_otg hardware. These services are used by both the Host Controller
+ * Driver and the Peripheral Controller Driver.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <linux/usb/hcd.h>
+#include <linux/usb/ch11.h>
+
+#include "core.h"
+#include "hcd.h"
+
+/**
+ * dwc2_enable_common_interrupts() - Initializes the commmon interrupts,
+ * used in both device and host modes
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ */
+static void dwc2_enable_common_interrupts(struct dwc2_hsotg *hsotg)
+{
+       u32 intmsk;
+
+       /* Clear any pending OTG Interrupts */
+       writel(0xffffffff, hsotg->regs + GOTGINT);
+
+       /* Clear any pending interrupts */
+       writel(0xffffffff, hsotg->regs + GINTSTS);
+
+       /* Enable the interrupts in the GINTMSK */
+       intmsk = GINTSTS_MODEMIS | GINTSTS_OTGINT;
+
+       if (hsotg->core_params->dma_enable <= 0)
+               intmsk |= GINTSTS_RXFLVL;
+
+       intmsk |= GINTSTS_CONIDSTSCHNG | GINTSTS_WKUPINT | GINTSTS_USBSUSP |
+                 GINTSTS_SESSREQINT;
+
+       writel(intmsk, hsotg->regs + GINTMSK);
+}
+
+/*
+ * Initializes the FSLSPClkSel field of the HCFG register depending on the
+ * PHY type
+ */
+static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)
+{
+       u32 hcfg, val;
+
+       if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
+            hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
+            hsotg->core_params->ulpi_fs_ls > 0) ||
+           hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) {
+               /* Full speed PHY */
+               val = HCFG_FSLSPCLKSEL_48_MHZ;
+       } else {
+               /* High speed PHY running at full speed or high speed */
+               val = HCFG_FSLSPCLKSEL_30_60_MHZ;
+       }
+
+       dev_dbg(hsotg->dev, "Initializing HCFG.FSLSPClkSel to %08x\n", val);
+       hcfg = readl(hsotg->regs + HCFG);
+       hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
+       hcfg |= val << HCFG_FSLSPCLKSEL_SHIFT;
+       writel(hcfg, hsotg->regs + HCFG);
+}
+
+/*
+ * Do core a soft reset of the core.  Be careful with this because it
+ * resets all the internal state machines of the core.
+ */
+static int dwc2_core_reset(struct dwc2_hsotg *hsotg)
+{
+       u32 greset;
+       int count = 0;
+
+       dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+       /* Wait for AHB master IDLE state */
+       do {
+               usleep_range(20000, 40000);
+               greset = readl(hsotg->regs + GRSTCTL);
+               if (++count > 50) {
+                       dev_warn(hsotg->dev,
+                                "%s() HANG! AHB Idle GRSTCTL=%0x\n",
+                                __func__, greset);
+                       return -EBUSY;
+               }
+       } while (!(greset & GRSTCTL_AHBIDLE));
+
+       /* Core Soft Reset */
+       count = 0;
+       greset |= GRSTCTL_CSFTRST;
+       writel(greset, hsotg->regs + GRSTCTL);
+       do {
+               usleep_range(20000, 40000);
+               greset = readl(hsotg->regs + GRSTCTL);
+               if (++count > 50) {
+                       dev_warn(hsotg->dev,
+                                "%s() HANG! Soft Reset GRSTCTL=%0x\n",
+                                __func__, greset);
+                       return -EBUSY;
+               }
+       } while (greset & GRSTCTL_CSFTRST);
+
+       /*
+        * NOTE: This long sleep is _very_ important, otherwise the core will
+        * not stay in host mode after a connector ID change!
+        */
+       usleep_range(150000, 200000);
+
+       return 0;
+}
+
+static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
+{
+       u32 usbcfg, i2cctl;
+       int retval = 0;
+
+       /*
+        * core_init() is now called on every switch so only call the
+        * following for the first time through
+        */
+       if (select_phy) {
+               dev_dbg(hsotg->dev, "FS PHY selected\n");
+               usbcfg = readl(hsotg->regs + GUSBCFG);
+               usbcfg |= GUSBCFG_PHYSEL;
+               writel(usbcfg, hsotg->regs + GUSBCFG);
+
+               /* Reset after a PHY select */
+               retval = dwc2_core_reset(hsotg);
+               if (retval) {
+                       dev_err(hsotg->dev, "%s() Reset failed, aborting",
+                                       __func__);
+                       return retval;
+               }
+       }
+
+       /*
+        * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also
+        * do this on HNP Dev/Host mode switches (done in dev_init and
+        * host_init).
+        */
+       if (dwc2_is_host_mode(hsotg))
+               dwc2_init_fs_ls_pclk_sel(hsotg);
+
+       if (hsotg->core_params->i2c_enable > 0) {
+               dev_dbg(hsotg->dev, "FS PHY enabling I2C\n");
+
+               /* Program GUSBCFG.OtgUtmiFsSel to I2C */
+               usbcfg = readl(hsotg->regs + GUSBCFG);
+               usbcfg |= GUSBCFG_OTG_UTMI_FS_SEL;
+               writel(usbcfg, hsotg->regs + GUSBCFG);
+
+               /* Program GI2CCTL.I2CEn */
+               i2cctl = readl(hsotg->regs + GI2CCTL);
+               i2cctl &= ~GI2CCTL_I2CDEVADDR_MASK;
+               i2cctl |= 1 << GI2CCTL_I2CDEVADDR_SHIFT;
+               i2cctl &= ~GI2CCTL_I2CEN;
+               writel(i2cctl, hsotg->regs + GI2CCTL);
+               i2cctl |= GI2CCTL_I2CEN;
+               writel(i2cctl, hsotg->regs + GI2CCTL);
+       }
+
+       return retval;
+}
+
+static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
+{
+       u32 usbcfg;
+       int retval = 0;
+
+       if (!select_phy)
+               return -ENODEV;
+
+       usbcfg = readl(hsotg->regs + GUSBCFG);
+
+       /*
+        * HS PHY parameters. These parameters are preserved during soft reset
+        * so only program the first time. Do a soft reset immediately after
+        * setting phyif.
+        */
+       switch (hsotg->core_params->phy_type) {
+       case DWC2_PHY_TYPE_PARAM_ULPI:
+               /* ULPI interface */
+               dev_dbg(hsotg->dev, "HS ULPI PHY selected\n");
+               usbcfg |= GUSBCFG_ULPI_UTMI_SEL;
+               usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL);
+               if (hsotg->core_params->phy_ulpi_ddr > 0)
+                       usbcfg |= GUSBCFG_DDRSEL;
+               break;
+       case DWC2_PHY_TYPE_PARAM_UTMI:
+               /* UTMI+ interface */
+               dev_dbg(hsotg->dev, "HS UTMI+ PHY selected\n");
+               usbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16);
+               if (hsotg->core_params->phy_utmi_width == 16)
+                       usbcfg |= GUSBCFG_PHYIF16;
+               break;
+       default:
+               dev_err(hsotg->dev, "FS PHY selected at HS!\n");
+               break;
+       }
+
+       writel(usbcfg, hsotg->regs + GUSBCFG);
+
+       /* Reset after setting the PHY parameters */
+       retval = dwc2_core_reset(hsotg);
+       if (retval) {
+               dev_err(hsotg->dev, "%s() Reset failed, aborting",
+                               __func__);
+               return retval;
+       }
+
+       return retval;
+}
+
+static int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
+{
+       u32 usbcfg;
+       int retval = 0;
+
+       if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL &&
+           hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) {
+               /* If FS mode with FS PHY */
+               retval = dwc2_fs_phy_init(hsotg, select_phy);
+               if (retval)
+                       return retval;
+       } else {
+               /* High speed PHY */
+               retval = dwc2_hs_phy_init(hsotg, select_phy);
+               if (retval)
+                       return retval;
+       }
+
+       if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
+           hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
+           hsotg->core_params->ulpi_fs_ls > 0) {
+               dev_dbg(hsotg->dev, "Setting ULPI FSLS\n");
+               usbcfg = readl(hsotg->regs + GUSBCFG);
+               usbcfg |= GUSBCFG_ULPI_FS_LS;
+               usbcfg |= GUSBCFG_ULPI_CLK_SUSP_M;
+               writel(usbcfg, hsotg->regs + GUSBCFG);
+       } else {
+               usbcfg = readl(hsotg->regs + GUSBCFG);
+               usbcfg &= ~GUSBCFG_ULPI_FS_LS;
+               usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M;
+               writel(usbcfg, hsotg->regs + GUSBCFG);
+       }
+
+       return retval;
+}
+
+static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg)
+{
+       u32 ahbcfg = readl(hsotg->regs + GAHBCFG);
+
+       switch (hsotg->hw_params.arch) {
+       case GHWCFG2_EXT_DMA_ARCH:
+               dev_err(hsotg->dev, "External DMA Mode not supported\n");
+               return -EINVAL;
+
+       case GHWCFG2_INT_DMA_ARCH:
+               dev_dbg(hsotg->dev, "Internal DMA Mode\n");
+               if (hsotg->core_params->ahbcfg != -1) {
+                       ahbcfg &= GAHBCFG_CTRL_MASK;
+                       ahbcfg |= hsotg->core_params->ahbcfg &
+                                 ~GAHBCFG_CTRL_MASK;
+               }
+               break;
+
+       case GHWCFG2_SLAVE_ONLY_ARCH:
+       default:
+               dev_dbg(hsotg->dev, "Slave Only Mode\n");
+               break;
+       }
+
+       dev_dbg(hsotg->dev, "dma_enable:%d dma_desc_enable:%d\n",
+               hsotg->core_params->dma_enable,
+               hsotg->core_params->dma_desc_enable);
+
+       if (hsotg->core_params->dma_enable > 0) {
+               if (hsotg->core_params->dma_desc_enable > 0)
+                       dev_dbg(hsotg->dev, "Using Descriptor DMA mode\n");
+               else
+                       dev_dbg(hsotg->dev, "Using Buffer DMA mode\n");
+       } else {
+               dev_dbg(hsotg->dev, "Using Slave mode\n");
+               hsotg->core_params->dma_desc_enable = 0;
+       }
+
+       if (hsotg->core_params->dma_enable > 0)
+               ahbcfg |= GAHBCFG_DMA_EN;
+
+       writel(ahbcfg, hsotg->regs + GAHBCFG);
+
+       return 0;
+}
+
+static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)
+{
+       u32 usbcfg;
+
+       usbcfg = readl(hsotg->regs + GUSBCFG);
+       usbcfg &= ~(GUSBCFG_HNPCAP | GUSBCFG_SRPCAP);
+
+       switch (hsotg->hw_params.op_mode) {
+       case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
+               if (hsotg->core_params->otg_cap ==
+                               DWC2_CAP_PARAM_HNP_SRP_CAPABLE)
+                       usbcfg |= GUSBCFG_HNPCAP;
+               if (hsotg->core_params->otg_cap !=
+                               DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE)
+                       usbcfg |= GUSBCFG_SRPCAP;
+               break;
+
+       case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
+       case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
+       case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
+               if (hsotg->core_params->otg_cap !=
+                               DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE)
+                       usbcfg |= GUSBCFG_SRPCAP;
+               break;
+
+       case GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE:
+       case GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE:
+       case GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST:
+       default:
+               break;
+       }
+
+       writel(usbcfg, hsotg->regs + GUSBCFG);
+}
+
+/**
+ * dwc2_core_init() - Initializes the DWC_otg controller registers and
+ * prepares the core for device mode or host mode operation
+ *
+ * @hsotg:      Programming view of the DWC_otg controller
+ * @select_phy: If true then also set the Phy type
+ * @irq:        If >= 0, the irq to register
+ */
+int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)
+{
+       u32 usbcfg, otgctl;
+       int retval;
+
+       dev_dbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
+
+       usbcfg = readl(hsotg->regs + GUSBCFG);
+
+       /* Set ULPI External VBUS bit if needed */
+       usbcfg &= ~GUSBCFG_ULPI_EXT_VBUS_DRV;
+       if (hsotg->core_params->phy_ulpi_ext_vbus ==
+                               DWC2_PHY_ULPI_EXTERNAL_VBUS)
+               usbcfg |= GUSBCFG_ULPI_EXT_VBUS_DRV;
+
+       /* Set external TS Dline pulsing bit if needed */
+       usbcfg &= ~GUSBCFG_TERMSELDLPULSE;
+       if (hsotg->core_params->ts_dline > 0)
+               usbcfg |= GUSBCFG_TERMSELDLPULSE;
+
+       writel(usbcfg, hsotg->regs + GUSBCFG);
+
+       /* Reset the Controller */
+       retval = dwc2_core_reset(hsotg);
+       if (retval) {
+               dev_err(hsotg->dev, "%s(): Reset failed, aborting\n",
+                               __func__);
+               return retval;
+       }
+
+       /*
+        * This needs to happen in FS mode before any other programming occurs
+        */
+       retval = dwc2_phy_init(hsotg, select_phy);
+       if (retval)
+               return retval;
+
+       /* Program the GAHBCFG Register */
+       retval = dwc2_gahbcfg_init(hsotg);
+       if (retval)
+               return retval;
+
+       /* Program the GUSBCFG register */
+       dwc2_gusbcfg_init(hsotg);
+
+       /* Program the GOTGCTL register */
+       otgctl = readl(hsotg->regs + GOTGCTL);
+       otgctl &= ~GOTGCTL_OTGVER;
+       if (hsotg->core_params->otg_ver > 0)
+               otgctl |= GOTGCTL_OTGVER;
+       writel(otgctl, hsotg->regs + GOTGCTL);
+       dev_dbg(hsotg->dev, "OTG VER PARAM: %d\n", hsotg->core_params->otg_ver);
+
+       /* Clear the SRP success bit for FS-I2c */
+       hsotg->srp_success = 0;
+
+       if (irq >= 0) {
+               dev_dbg(hsotg->dev, "registering common handler for irq%d\n",
+                       irq);
+               retval = devm_request_irq(hsotg->dev, irq,
+                                         dwc2_handle_common_intr, IRQF_SHARED,
+                                         dev_name(hsotg->dev), hsotg);
+               if (retval)
+                       return retval;
+       }
+
+       /* Enable common interrupts */
+       dwc2_enable_common_interrupts(hsotg);
+
+       /*
+        * Do device or host intialization based on mode during PCD and
+        * HCD initialization
+        */
+       if (dwc2_is_host_mode(hsotg)) {
+               dev_dbg(hsotg->dev, "Host Mode\n");
+               hsotg->op_state = OTG_STATE_A_HOST;
+       } else {
+               dev_dbg(hsotg->dev, "Device Mode\n");
+               hsotg->op_state = OTG_STATE_B_PERIPHERAL;
+       }
+
+       return 0;
+}
+
+/**
+ * dwc2_enable_host_interrupts() - Enables the Host mode interrupts
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ */
+void dwc2_enable_host_interrupts(struct dwc2_hsotg *hsotg)
+{
+       u32 intmsk;
+
+       dev_dbg(hsotg->dev, "%s()\n", __func__);
+
+       /* Disable all interrupts */
+       writel(0, hsotg->regs + GINTMSK);
+       writel(0, hsotg->regs + HAINTMSK);
+
+       /* Enable the common interrupts */
+       dwc2_enable_common_interrupts(hsotg);
+
+       /* Enable host mode interrupts without disturbing common interrupts */
+       intmsk = readl(hsotg->regs + GINTMSK);
+       intmsk |= GINTSTS_DISCONNINT | GINTSTS_PRTINT | GINTSTS_HCHINT;
+       writel(intmsk, hsotg->regs + GINTMSK);
+}
+
+/**
+ * dwc2_disable_host_interrupts() - Disables the Host Mode interrupts
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ */
+void dwc2_disable_host_interrupts(struct dwc2_hsotg *hsotg)
+{
+       u32 intmsk = readl(hsotg->regs + GINTMSK);
+
+       /* Disable host mode interrupts without disturbing common interrupts */
+       intmsk &= ~(GINTSTS_SOF | GINTSTS_PRTINT | GINTSTS_HCHINT |
+                   GINTSTS_PTXFEMP | GINTSTS_NPTXFEMP);
+       writel(intmsk, hsotg->regs + GINTMSK);
+}
+
+static void dwc2_config_fifos(struct dwc2_hsotg *hsotg)
+{
+       struct dwc2_core_params *params = hsotg->core_params;
+       u32 nptxfsiz, hptxfsiz, dfifocfg, grxfsiz;
+
+       if (!params->enable_dynamic_fifo)
+               return;
+
+       /* Rx FIFO */
+       grxfsiz = readl(hsotg->regs + GRXFSIZ);
+       dev_dbg(hsotg->dev, "initial grxfsiz=%08x\n", grxfsiz);
+       grxfsiz &= ~GRXFSIZ_DEPTH_MASK;
+       grxfsiz |= params->host_rx_fifo_size <<
+                  GRXFSIZ_DEPTH_SHIFT & GRXFSIZ_DEPTH_MASK;
+       writel(grxfsiz, hsotg->regs + GRXFSIZ);
+       dev_dbg(hsotg->dev, "new grxfsiz=%08x\n", readl(hsotg->regs + GRXFSIZ));
+
+       /* Non-periodic Tx FIFO */
+       dev_dbg(hsotg->dev, "initial gnptxfsiz=%08x\n",
+               readl(hsotg->regs + GNPTXFSIZ));
+       nptxfsiz = params->host_nperio_tx_fifo_size <<
+                  FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
+       nptxfsiz |= params->host_rx_fifo_size <<
+                   FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
+       writel(nptxfsiz, hsotg->regs + GNPTXFSIZ);
+       dev_dbg(hsotg->dev, "new gnptxfsiz=%08x\n",
+               readl(hsotg->regs + GNPTXFSIZ));
+
+       /* Periodic Tx FIFO */
+       dev_dbg(hsotg->dev, "initial hptxfsiz=%08x\n",
+               readl(hsotg->regs + HPTXFSIZ));
+       hptxfsiz = params->host_perio_tx_fifo_size <<
+                  FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
+       hptxfsiz |= (params->host_rx_fifo_size +
+                    params->host_nperio_tx_fifo_size) <<
+                   FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
+       writel(hptxfsiz, hsotg->regs + HPTXFSIZ);
+       dev_dbg(hsotg->dev, "new hptxfsiz=%08x\n",
+               readl(hsotg->regs + HPTXFSIZ));
+
+       if (hsotg->core_params->en_multiple_tx_fifo > 0 &&
+           hsotg->hw_params.snpsid <= DWC2_CORE_REV_2_94a) {
+               /*
+                * Global DFIFOCFG calculation for Host mode -
+                * include RxFIFO, NPTXFIFO and HPTXFIFO
+                */
+               dfifocfg = readl(hsotg->regs + GDFIFOCFG);
+               dfifocfg &= ~GDFIFOCFG_EPINFOBASE_MASK;
+               dfifocfg |= (params->host_rx_fifo_size +
+                            params->host_nperio_tx_fifo_size +
+                            params->host_perio_tx_fifo_size) <<
+                           GDFIFOCFG_EPINFOBASE_SHIFT &
+                           GDFIFOCFG_EPINFOBASE_MASK;
+               writel(dfifocfg, hsotg->regs + GDFIFOCFG);
+       }
+}
+
+/**
+ * dwc2_core_host_init() - Initializes the DWC_otg controller registers for
+ * Host mode
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ * This function flushes the Tx and Rx FIFOs and flushes any entries in the
+ * request queues. Host channels are reset to ensure that they are ready for
+ * performing transfers.
+ */
+void dwc2_core_host_init(struct dwc2_hsotg *hsotg)
+{
+       u32 hcfg, hfir, otgctl;
+
+       dev_dbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
+
+       /* Restart the Phy Clock */
+       writel(0, hsotg->regs + PCGCTL);
+
+       /* Initialize Host Configuration Register */
+       dwc2_init_fs_ls_pclk_sel(hsotg);
+       if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL) {
+               hcfg = readl(hsotg->regs + HCFG);
+               hcfg |= HCFG_FSLSSUPP;
+               writel(hcfg, hsotg->regs + HCFG);
+       }
+
+       /*
+        * This bit allows dynamic reloading of the HFIR register during
+        * runtime. This bit needs to be programmed during initial configuration
+        * and its value must not be changed during runtime.
+        */
+       if (hsotg->core_params->reload_ctl > 0) {
+               hfir = readl(hsotg->regs + HFIR);
+               hfir |= HFIR_RLDCTRL;
+               writel(hfir, hsotg->regs + HFIR);
+       }
+
+       if (hsotg->core_params->dma_desc_enable > 0) {
+               u32 op_mode = hsotg->hw_params.op_mode;
+               if (hsotg->hw_params.snpsid < DWC2_CORE_REV_2_90a ||
+                   !hsotg->hw_params.dma_desc_enable ||
+                   op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE ||
+                   op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE ||
+                   op_mode == GHWCFG2_OP_MODE_UNDEFINED) {
+                       dev_err(hsotg->dev,
+                               "Hardware does not support descriptor DMA mode -\n");
+                       dev_err(hsotg->dev,
+                               "falling back to buffer DMA mode.\n");
+                       hsotg->core_params->dma_desc_enable = 0;
+               } else {
+                       hcfg = readl(hsotg->regs + HCFG);
+                       hcfg |= HCFG_DESCDMA;
+                       writel(hcfg, hsotg->regs + HCFG);
+               }
+       }
+
+       /* Configure data FIFO sizes */
+       dwc2_config_fifos(hsotg);
+
+       /* TODO - check this */
+       /* Clear Host Set HNP Enable in the OTG Control Register */
+       otgctl = readl(hsotg->regs + GOTGCTL);
+       otgctl &= ~GOTGCTL_HSTSETHNPEN;
+       writel(otgctl, hsotg->regs + GOTGCTL);
+
+       /* Make sure the FIFOs are flushed */
+       dwc2_flush_tx_fifo(hsotg, 0x10 /* all TX FIFOs */);
+       dwc2_flush_rx_fifo(hsotg);
+
+       /* Clear Host Set HNP Enable in the OTG Control Register */
+       otgctl = readl(hsotg->regs + GOTGCTL);
+       otgctl &= ~GOTGCTL_HSTSETHNPEN;
+       writel(otgctl, hsotg->regs + GOTGCTL);
+
+       if (hsotg->core_params->dma_desc_enable <= 0) {
+               int num_channels, i;
+               u32 hcchar;
+
+               /* Flush out any leftover queued requests */
+               num_channels = hsotg->core_params->host_channels;
+               for (i = 0; i < num_channels; i++) {
+                       hcchar = readl(hsotg->regs + HCCHAR(i));
+                       hcchar &= ~HCCHAR_CHENA;
+                       hcchar |= HCCHAR_CHDIS;
+                       hcchar &= ~HCCHAR_EPDIR;
+                       writel(hcchar, hsotg->regs + HCCHAR(i));
+               }
+
+               /* Halt all channels to put them into a known state */
+               for (i = 0; i < num_channels; i++) {
+                       int count = 0;
+
+                       hcchar = readl(hsotg->regs + HCCHAR(i));
+                       hcchar |= HCCHAR_CHENA | HCCHAR_CHDIS;
+                       hcchar &= ~HCCHAR_EPDIR;
+                       writel(hcchar, hsotg->regs + HCCHAR(i));
+                       dev_dbg(hsotg->dev, "%s: Halt channel %d\n",
+                               __func__, i);
+                       do {
+                               hcchar = readl(hsotg->regs + HCCHAR(i));
+                               if (++count > 1000) {
+                                       dev_err(hsotg->dev,
+                                               "Unable to clear enable on channel %d\n",
+                                               i);
+                                       break;
+                               }
+                               udelay(1);
+                       } while (hcchar & HCCHAR_CHENA);
+               }
+       }
+
+       /* Turn on the vbus power */
+       dev_dbg(hsotg->dev, "Init: Port Power? op_state=%d\n", hsotg->op_state);
+       if (hsotg->op_state == OTG_STATE_A_HOST) {
+               u32 hprt0 = dwc2_read_hprt0(hsotg);
+
+               dev_dbg(hsotg->dev, "Init: Power Port (%d)\n",
+                       !!(hprt0 & HPRT0_PWR));
+               if (!(hprt0 & HPRT0_PWR)) {
+                       hprt0 |= HPRT0_PWR;
+                       writel(hprt0, hsotg->regs + HPRT0);
+               }
+       }
+
+       dwc2_enable_host_interrupts(hsotg);
+}
+
+static void dwc2_hc_enable_slave_ints(struct dwc2_hsotg *hsotg,
+                                     struct dwc2_host_chan *chan)
+{
+       u32 hcintmsk = HCINTMSK_CHHLTD;
+
+       switch (chan->ep_type) {
+       case USB_ENDPOINT_XFER_CONTROL:
+       case USB_ENDPOINT_XFER_BULK:
+               dev_vdbg(hsotg->dev, "control/bulk\n");
+               hcintmsk |= HCINTMSK_XFERCOMPL;
+               hcintmsk |= HCINTMSK_STALL;
+               hcintmsk |= HCINTMSK_XACTERR;
+               hcintmsk |= HCINTMSK_DATATGLERR;
+               if (chan->ep_is_in) {
+                       hcintmsk |= HCINTMSK_BBLERR;
+               } else {
+                       hcintmsk |= HCINTMSK_NAK;
+                       hcintmsk |= HCINTMSK_NYET;
+                       if (chan->do_ping)
+                               hcintmsk |= HCINTMSK_ACK;
+               }
+
+               if (chan->do_split) {
+                       hcintmsk |= HCINTMSK_NAK;
+                       if (chan->complete_split)
+                               hcintmsk |= HCINTMSK_NYET;
+                       else
+                               hcintmsk |= HCINTMSK_ACK;
+               }
+
+               if (chan->error_state)
+                       hcintmsk |= HCINTMSK_ACK;
+               break;
+
+       case USB_ENDPOINT_XFER_INT:
+               if (dbg_perio())
+                       dev_vdbg(hsotg->dev, "intr\n");
+               hcintmsk |= HCINTMSK_XFERCOMPL;
+               hcintmsk |= HCINTMSK_NAK;
+               hcintmsk |= HCINTMSK_STALL;
+               hcintmsk |= HCINTMSK_XACTERR;
+               hcintmsk |= HCINTMSK_DATATGLERR;
+               hcintmsk |= HCINTMSK_FRMOVRUN;
+
+               if (chan->ep_is_in)
+                       hcintmsk |= HCINTMSK_BBLERR;
+               if (chan->error_state)
+                       hcintmsk |= HCINTMSK_ACK;
+               if (chan->do_split) {
+                       if (chan->complete_split)
+                               hcintmsk |= HCINTMSK_NYET;
+                       else
+                               hcintmsk |= HCINTMSK_ACK;
+               }
+               break;
+
+       case USB_ENDPOINT_XFER_ISOC:
+               if (dbg_perio())
+                       dev_vdbg(hsotg->dev, "isoc\n");
+               hcintmsk |= HCINTMSK_XFERCOMPL;
+               hcintmsk |= HCINTMSK_FRMOVRUN;
+               hcintmsk |= HCINTMSK_ACK;
+
+               if (chan->ep_is_in) {
+                       hcintmsk |= HCINTMSK_XACTERR;
+                       hcintmsk |= HCINTMSK_BBLERR;
+               }
+               break;
+       default:
+               dev_err(hsotg->dev, "## Unknown EP type ##\n");
+               break;
+       }
+
+       writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num));
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "set HCINTMSK to %08x\n", hcintmsk);
+}
+
+static void dwc2_hc_enable_dma_ints(struct dwc2_hsotg *hsotg,
+                                   struct dwc2_host_chan *chan)
+{
+       u32 hcintmsk = HCINTMSK_CHHLTD;
+
+       /*
+        * For Descriptor DMA mode core halts the channel on AHB error.
+        * Interrupt is not required.
+        */
+       if (hsotg->core_params->dma_desc_enable <= 0) {
+               if (dbg_hc(chan))
+                       dev_vdbg(hsotg->dev, "desc DMA disabled\n");
+               hcintmsk |= HCINTMSK_AHBERR;
+       } else {
+               if (dbg_hc(chan))
+                       dev_vdbg(hsotg->dev, "desc DMA enabled\n");
+               if (chan->ep_type == USB_ENDPOINT_XFER_ISOC)
+                       hcintmsk |= HCINTMSK_XFERCOMPL;
+       }
+
+       if (chan->error_state && !chan->do_split &&
+           chan->ep_type != USB_ENDPOINT_XFER_ISOC) {
+               if (dbg_hc(chan))
+                       dev_vdbg(hsotg->dev, "setting ACK\n");
+               hcintmsk |= HCINTMSK_ACK;
+               if (chan->ep_is_in) {
+                       hcintmsk |= HCINTMSK_DATATGLERR;
+                       if (chan->ep_type != USB_ENDPOINT_XFER_INT)
+                               hcintmsk |= HCINTMSK_NAK;
+               }
+       }
+
+       writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num));
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "set HCINTMSK to %08x\n", hcintmsk);
+}
+
+static void dwc2_hc_enable_ints(struct dwc2_hsotg *hsotg,
+                               struct dwc2_host_chan *chan)
+{
+       u32 intmsk;
+
+       if (hsotg->core_params->dma_enable > 0) {
+               if (dbg_hc(chan))
+                       dev_vdbg(hsotg->dev, "DMA enabled\n");
+               dwc2_hc_enable_dma_ints(hsotg, chan);
+       } else {
+               if (dbg_hc(chan))
+                       dev_vdbg(hsotg->dev, "DMA disabled\n");
+               dwc2_hc_enable_slave_ints(hsotg, chan);
+       }
+
+       /* Enable the top level host channel interrupt */
+       intmsk = readl(hsotg->regs + HAINTMSK);
+       intmsk |= 1 << chan->hc_num;
+       writel(intmsk, hsotg->regs + HAINTMSK);
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "set HAINTMSK to %08x\n", intmsk);
+
+       /* Make sure host channel interrupts are enabled */
+       intmsk = readl(hsotg->regs + GINTMSK);
+       intmsk |= GINTSTS_HCHINT;
+       writel(intmsk, hsotg->regs + GINTMSK);
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "set GINTMSK to %08x\n", intmsk);
+}
+
+/**
+ * dwc2_hc_init() - Prepares a host channel for transferring packets to/from
+ * a specific endpoint
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan:  Information needed to initialize the host channel
+ *
+ * The HCCHARn register is set up with the characteristics specified in chan.
+ * Host channel interrupts that may need to be serviced while this transfer is
+ * in progress are enabled.
+ */
+void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
+{
+       u8 hc_num = chan->hc_num;
+       u32 hcintmsk;
+       u32 hcchar;
+       u32 hcsplt = 0;
+
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+       /* Clear old interrupt conditions for this host channel */
+       hcintmsk = 0xffffffff;
+       hcintmsk &= ~HCINTMSK_RESERVED14_31;
+       writel(hcintmsk, hsotg->regs + HCINT(hc_num));
+
+       /* Enable channel interrupts required for this transfer */
+       dwc2_hc_enable_ints(hsotg, chan);
+
+       /*
+        * Program the HCCHARn register with the endpoint characteristics for
+        * the current transfer
+        */
+       hcchar = chan->dev_addr << HCCHAR_DEVADDR_SHIFT & HCCHAR_DEVADDR_MASK;
+       hcchar |= chan->ep_num << HCCHAR_EPNUM_SHIFT & HCCHAR_EPNUM_MASK;
+       if (chan->ep_is_in)
+               hcchar |= HCCHAR_EPDIR;
+       if (chan->speed == USB_SPEED_LOW)
+               hcchar |= HCCHAR_LSPDDEV;
+       hcchar |= chan->ep_type << HCCHAR_EPTYPE_SHIFT & HCCHAR_EPTYPE_MASK;
+       hcchar |= chan->max_packet << HCCHAR_MPS_SHIFT & HCCHAR_MPS_MASK;
+       writel(hcchar, hsotg->regs + HCCHAR(hc_num));
+       if (dbg_hc(chan)) {
+               dev_vdbg(hsotg->dev, "set HCCHAR(%d) to %08x\n",
+                        hc_num, hcchar);
+
+               dev_vdbg(hsotg->dev, "%s: Channel %d\n",
+                        __func__, hc_num);
+               dev_vdbg(hsotg->dev, "   Dev Addr: %d\n",
+                        chan->dev_addr);
+               dev_vdbg(hsotg->dev, "   Ep Num: %d\n",
+                        chan->ep_num);
+               dev_vdbg(hsotg->dev, "   Is In: %d\n",
+                        chan->ep_is_in);
+               dev_vdbg(hsotg->dev, "   Is Low Speed: %d\n",
+                        chan->speed == USB_SPEED_LOW);
+               dev_vdbg(hsotg->dev, "   Ep Type: %d\n",
+                        chan->ep_type);
+               dev_vdbg(hsotg->dev, "   Max Pkt: %d\n",
+                        chan->max_packet);
+       }
+
+       /* Program the HCSPLT register for SPLITs */
+       if (chan->do_split) {
+               if (dbg_hc(chan))
+                       dev_vdbg(hsotg->dev,
+                                "Programming HC %d with split --> %s\n",
+                                hc_num,
+                                chan->complete_split ? "CSPLIT" : "SSPLIT");
+               if (chan->complete_split)
+                       hcsplt |= HCSPLT_COMPSPLT;
+               hcsplt |= chan->xact_pos << HCSPLT_XACTPOS_SHIFT &
+                         HCSPLT_XACTPOS_MASK;
+               hcsplt |= chan->hub_addr << HCSPLT_HUBADDR_SHIFT &
+                         HCSPLT_HUBADDR_MASK;
+               hcsplt |= chan->hub_port << HCSPLT_PRTADDR_SHIFT &
+                         HCSPLT_PRTADDR_MASK;
+               if (dbg_hc(chan)) {
+                       dev_vdbg(hsotg->dev, "    comp split %d\n",
+                                chan->complete_split);
+                       dev_vdbg(hsotg->dev, "    xact pos %d\n",
+                                chan->xact_pos);
+                       dev_vdbg(hsotg->dev, "    hub addr %d\n",
+                                chan->hub_addr);
+                       dev_vdbg(hsotg->dev, "    hub port %d\n",
+                                chan->hub_port);
+                       dev_vdbg(hsotg->dev, "    is_in %d\n",
+                                chan->ep_is_in);
+                       dev_vdbg(hsotg->dev, "    Max Pkt %d\n",
+                                chan->max_packet);
+                       dev_vdbg(hsotg->dev, "    xferlen %d\n",
+                                chan->xfer_len);
+               }
+       }
+
+       writel(hcsplt, hsotg->regs + HCSPLT(hc_num));
+}
+
+/**
+ * dwc2_hc_halt() - Attempts to halt a host channel
+ *
+ * @hsotg:       Controller register interface
+ * @chan:        Host channel to halt
+ * @halt_status: Reason for halting the channel
+ *
+ * This function should only be called in Slave mode or to abort a transfer in
+ * either Slave mode or DMA mode. Under normal circumstances in DMA mode, the
+ * controller halts the channel when the transfer is complete or a condition
+ * occurs that requires application intervention.
+ *
+ * In slave mode, checks for a free request queue entry, then sets the Channel
+ * Enable and Channel Disable bits of the Host Channel Characteristics
+ * register of the specified channel to intiate the halt. If there is no free
+ * request queue entry, sets only the Channel Disable bit of the HCCHARn
+ * register to flush requests for this channel. In the latter case, sets a
+ * flag to indicate that the host channel needs to be halted when a request
+ * queue slot is open.
+ *
+ * In DMA mode, always sets the Channel Enable and Channel Disable bits of the
+ * HCCHARn register. The controller ensures there is space in the request
+ * queue before submitting the halt request.
+ *
+ * Some time may elapse before the core flushes any posted requests for this
+ * host channel and halts. The Channel Halted interrupt handler completes the
+ * deactivation of the host channel.
+ */
+void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
+                 enum dwc2_halt_status halt_status)
+{
+       u32 nptxsts, hptxsts, hcchar;
+
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "%s()\n", __func__);
+       if (halt_status == DWC2_HC_XFER_NO_HALT_STATUS)
+               dev_err(hsotg->dev, "!!! halt_status = %d !!!\n", halt_status);
+
+       if (halt_status == DWC2_HC_XFER_URB_DEQUEUE ||
+           halt_status == DWC2_HC_XFER_AHB_ERR) {
+               /*
+                * Disable all channel interrupts except Ch Halted. The QTD
+                * and QH state associated with this transfer has been cleared
+                * (in the case of URB_DEQUEUE), so the channel needs to be
+                * shut down carefully to prevent crashes.
+                */
+               u32 hcintmsk = HCINTMSK_CHHLTD;
+
+               dev_vdbg(hsotg->dev, "dequeue/error\n");
+               writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num));
+
+               /*
+                * Make sure no other interrupts besides halt are currently
+                * pending. Handling another interrupt could cause a crash due
+                * to the QTD and QH state.
+                */
+               writel(~hcintmsk, hsotg->regs + HCINT(chan->hc_num));
+
+               /*
+                * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
+                * even if the channel was already halted for some other
+                * reason
+                */
+               chan->halt_status = halt_status;
+
+               hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
+               if (!(hcchar & HCCHAR_CHENA)) {
+                       /*
+                        * The channel is either already halted or it hasn't
+                        * started yet. In DMA mode, the transfer may halt if
+                        * it finishes normally or a condition occurs that
+                        * requires driver intervention. Don't want to halt
+                        * the channel again. In either Slave or DMA mode,
+                        * it's possible that the transfer has been assigned
+                        * to a channel, but not started yet when an URB is
+                        * dequeued. Don't want to halt a channel that hasn't
+                        * started yet.
+                        */
+                       return;
+               }
+       }
+       if (chan->halt_pending) {
+               /*
+                * A halt has already been issued for this channel. This might
+                * happen when a transfer is aborted by a higher level in
+                * the stack.
+                */
+               dev_vdbg(hsotg->dev,
+                        "*** %s: Channel %d, chan->halt_pending already set ***\n",
+                        __func__, chan->hc_num);
+               return;
+       }
+
+       hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
+
+       /* No need to set the bit in DDMA for disabling the channel */
+       /* TODO check it everywhere channel is disabled */
+       if (hsotg->core_params->dma_desc_enable <= 0) {
+               if (dbg_hc(chan))
+                       dev_vdbg(hsotg->dev, "desc DMA disabled\n");
+               hcchar |= HCCHAR_CHENA;
+       } else {
+               if (dbg_hc(chan))
+                       dev_dbg(hsotg->dev, "desc DMA enabled\n");
+       }
+       hcchar |= HCCHAR_CHDIS;
+
+       if (hsotg->core_params->dma_enable <= 0) {
+               if (dbg_hc(chan))
+                       dev_vdbg(hsotg->dev, "DMA not enabled\n");
+               hcchar |= HCCHAR_CHENA;
+
+               /* Check for space in the request queue to issue the halt */
+               if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL ||
+                   chan->ep_type == USB_ENDPOINT_XFER_BULK) {
+                       dev_vdbg(hsotg->dev, "control/bulk\n");
+                       nptxsts = readl(hsotg->regs + GNPTXSTS);
+                       if ((nptxsts & TXSTS_QSPCAVAIL_MASK) == 0) {
+                               dev_vdbg(hsotg->dev, "Disabling channel\n");
+                               hcchar &= ~HCCHAR_CHENA;
+                       }
+               } else {
+                       if (dbg_perio())
+                               dev_vdbg(hsotg->dev, "isoc/intr\n");
+                       hptxsts = readl(hsotg->regs + HPTXSTS);
+                       if ((hptxsts & TXSTS_QSPCAVAIL_MASK) == 0 ||
+                           hsotg->queuing_high_bandwidth) {
+                               if (dbg_perio())
+                                       dev_vdbg(hsotg->dev, "Disabling channel\n");
+                               hcchar &= ~HCCHAR_CHENA;
+                       }
+               }
+       } else {
+               if (dbg_hc(chan))
+                       dev_vdbg(hsotg->dev, "DMA enabled\n");
+       }
+
+       writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+       chan->halt_status = halt_status;
+
+       if (hcchar & HCCHAR_CHENA) {
+               if (dbg_hc(chan))
+                       dev_vdbg(hsotg->dev, "Channel enabled\n");
+               chan->halt_pending = 1;
+               chan->halt_on_queue = 0;
+       } else {
+               if (dbg_hc(chan))
+                       dev_vdbg(hsotg->dev, "Channel disabled\n");
+               chan->halt_on_queue = 1;
+       }
+
+       if (dbg_hc(chan)) {
+               dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
+                        chan->hc_num);
+               dev_vdbg(hsotg->dev, "   hcchar: 0x%08x\n",
+                        hcchar);
+               dev_vdbg(hsotg->dev, "   halt_pending: %d\n",
+                        chan->halt_pending);
+               dev_vdbg(hsotg->dev, "   halt_on_queue: %d\n",
+                        chan->halt_on_queue);
+               dev_vdbg(hsotg->dev, "   halt_status: %d\n",
+                        chan->halt_status);
+       }
+}
+
+/**
+ * dwc2_hc_cleanup() - Clears the transfer state for a host channel
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan:  Identifies the host channel to clean up
+ *
+ * This function is normally called after a transfer is done and the host
+ * channel is being released
+ */
+void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
+{
+       u32 hcintmsk;
+
+       chan->xfer_started = 0;
+
+       /*
+        * Clear channel interrupt enables and any unhandled channel interrupt
+        * conditions
+        */
+       writel(0, hsotg->regs + HCINTMSK(chan->hc_num));
+       hcintmsk = 0xffffffff;
+       hcintmsk &= ~HCINTMSK_RESERVED14_31;
+       writel(hcintmsk, hsotg->regs + HCINT(chan->hc_num));
+}
+
+/**
+ * dwc2_hc_set_even_odd_frame() - Sets the channel property that indicates in
+ * which frame a periodic transfer should occur
+ *
+ * @hsotg:  Programming view of DWC_otg controller
+ * @chan:   Identifies the host channel to set up and its properties
+ * @hcchar: Current value of the HCCHAR register for the specified host channel
+ *
+ * This function has no effect on non-periodic transfers
+ */
+static void dwc2_hc_set_even_odd_frame(struct dwc2_hsotg *hsotg,
+                                      struct dwc2_host_chan *chan, u32 *hcchar)
+{
+       if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+           chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
+               /* 1 if _next_ frame is odd, 0 if it's even */
+               if (!(dwc2_hcd_get_frame_number(hsotg) & 0x1))
+                       *hcchar |= HCCHAR_ODDFRM;
+       }
+}
+
+static void dwc2_set_pid_isoc(struct dwc2_host_chan *chan)
+{
+       /* Set up the initial PID for the transfer */
+       if (chan->speed == USB_SPEED_HIGH) {
+               if (chan->ep_is_in) {
+                       if (chan->multi_count == 1)
+                               chan->data_pid_start = DWC2_HC_PID_DATA0;
+                       else if (chan->multi_count == 2)
+                               chan->data_pid_start = DWC2_HC_PID_DATA1;
+                       else
+                               chan->data_pid_start = DWC2_HC_PID_DATA2;
+               } else {
+                       if (chan->multi_count == 1)
+                               chan->data_pid_start = DWC2_HC_PID_DATA0;
+                       else
+                               chan->data_pid_start = DWC2_HC_PID_MDATA;
+               }
+       } else {
+               chan->data_pid_start = DWC2_HC_PID_DATA0;
+       }
+}
+
+/**
+ * dwc2_hc_write_packet() - Writes a packet into the Tx FIFO associated with
+ * the Host Channel
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan:  Information needed to initialize the host channel
+ *
+ * This function should only be called in Slave mode. For a channel associated
+ * with a non-periodic EP, the non-periodic Tx FIFO is written. For a channel
+ * associated with a periodic EP, the periodic Tx FIFO is written.
+ *
+ * Upon return the xfer_buf and xfer_count fields in chan are incremented by
+ * the number of bytes written to the Tx FIFO.
+ */
+static void dwc2_hc_write_packet(struct dwc2_hsotg *hsotg,
+                                struct dwc2_host_chan *chan)
+{
+       u32 i;
+       u32 remaining_count;
+       u32 byte_count;
+       u32 dword_count;
+       u32 __iomem *data_fifo;
+       u32 *data_buf = (u32 *)chan->xfer_buf;
+
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+       data_fifo = (u32 __iomem *)(hsotg->regs + HCFIFO(chan->hc_num));
+
+       remaining_count = chan->xfer_len - chan->xfer_count;
+       if (remaining_count > chan->max_packet)
+               byte_count = chan->max_packet;
+       else
+               byte_count = remaining_count;
+
+       dword_count = (byte_count + 3) / 4;
+
+       if (((unsigned long)data_buf & 0x3) == 0) {
+               /* xfer_buf is DWORD aligned */
+               for (i = 0; i < dword_count; i++, data_buf++)
+                       writel(*data_buf, data_fifo);
+       } else {
+               /* xfer_buf is not DWORD aligned */
+               for (i = 0; i < dword_count; i++, data_buf++) {
+                       u32 data = data_buf[0] | data_buf[1] << 8 |
+                                  data_buf[2] << 16 | data_buf[3] << 24;
+                       writel(data, data_fifo);
+               }
+       }
+
+       chan->xfer_count += byte_count;
+       chan->xfer_buf += byte_count;
+}
+
+/**
+ * dwc2_hc_start_transfer() - Does the setup for a data transfer for a host
+ * channel and starts the transfer
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan:  Information needed to initialize the host channel. The xfer_len value
+ *         may be reduced to accommodate the max widths of the XferSize and
+ *         PktCnt fields in the HCTSIZn register. The multi_count value may be
+ *         changed to reflect the final xfer_len value.
+ *
+ * This function may be called in either Slave mode or DMA mode. In Slave mode,
+ * the caller must ensure that there is sufficient space in the request queue
+ * and Tx Data FIFO.
+ *
+ * For an OUT transfer in Slave mode, it loads a data packet into the
+ * appropriate FIFO. If necessary, additional data packets are loaded in the
+ * Host ISR.
+ *
+ * For an IN transfer in Slave mode, a data packet is requested. The data
+ * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
+ * additional data packets are requested in the Host ISR.
+ *
+ * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
+ * register along with a packet count of 1 and the channel is enabled. This
+ * causes a single PING transaction to occur. Other fields in HCTSIZ are
+ * simply set to 0 since no data transfer occurs in this case.
+ *
+ * For a PING transfer in DMA mode, the HCTSIZ register is initialized with
+ * all the information required to perform the subsequent data transfer. In
+ * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
+ * controller performs the entire PING protocol, then starts the data
+ * transfer.
+ */
+void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
+                           struct dwc2_host_chan *chan)
+{
+       u32 max_hc_xfer_size = hsotg->core_params->max_transfer_size;
+       u16 max_hc_pkt_count = hsotg->core_params->max_packet_count;
+       u32 hcchar;
+       u32 hctsiz = 0;
+       u16 num_packets;
+
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+       if (chan->do_ping) {
+               if (hsotg->core_params->dma_enable <= 0) {
+                       if (dbg_hc(chan))
+                               dev_vdbg(hsotg->dev, "ping, no DMA\n");
+                       dwc2_hc_do_ping(hsotg, chan);
+                       chan->xfer_started = 1;
+                       return;
+               } else {
+                       if (dbg_hc(chan))
+                               dev_vdbg(hsotg->dev, "ping, DMA\n");
+                       hctsiz |= TSIZ_DOPNG;
+               }
+       }
+
+       if (chan->do_split) {
+               if (dbg_hc(chan))
+                       dev_vdbg(hsotg->dev, "split\n");
+               num_packets = 1;
+
+               if (chan->complete_split && !chan->ep_is_in)
+                       /*
+                        * For CSPLIT OUT Transfer, set the size to 0 so the
+                        * core doesn't expect any data written to the FIFO
+                        */
+                       chan->xfer_len = 0;
+               else if (chan->ep_is_in || chan->xfer_len > chan->max_packet)
+                       chan->xfer_len = chan->max_packet;
+               else if (!chan->ep_is_in && chan->xfer_len > 188)
+                       chan->xfer_len = 188;
+
+               hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT &
+                         TSIZ_XFERSIZE_MASK;
+       } else {
+               if (dbg_hc(chan))
+                       dev_vdbg(hsotg->dev, "no split\n");
+               /*
+                * Ensure that the transfer length and packet count will fit
+                * in the widths allocated for them in the HCTSIZn register
+                */
+               if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+                   chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
+                       /*
+                        * Make sure the transfer size is no larger than one
+                        * (micro)frame's worth of data. (A check was done
+                        * when the periodic transfer was accepted to ensure
+                        * that a (micro)frame's worth of data can be
+                        * programmed into a channel.)
+                        */
+                       u32 max_periodic_len =
+                               chan->multi_count * chan->max_packet;
+
+                       if (chan->xfer_len > max_periodic_len)
+                               chan->xfer_len = max_periodic_len;
+               } else if (chan->xfer_len > max_hc_xfer_size) {
+                       /*
+                        * Make sure that xfer_len is a multiple of max packet
+                        * size
+                        */
+                       chan->xfer_len =
+                               max_hc_xfer_size - chan->max_packet + 1;
+               }
+
+               if (chan->xfer_len > 0) {
+                       num_packets = (chan->xfer_len + chan->max_packet - 1) /
+                                       chan->max_packet;
+                       if (num_packets > max_hc_pkt_count) {
+                               num_packets = max_hc_pkt_count;
+                               chan->xfer_len = num_packets * chan->max_packet;
+                       }
+               } else {
+                       /* Need 1 packet for transfer length of 0 */
+                       num_packets = 1;
+               }
+
+               if (chan->ep_is_in)
+                       /*
+                        * Always program an integral # of max packets for IN
+                        * transfers
+                        */
+                       chan->xfer_len = num_packets * chan->max_packet;
+
+               if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+                   chan->ep_type == USB_ENDPOINT_XFER_ISOC)
+                       /*
+                        * Make sure that the multi_count field matches the
+                        * actual transfer length
+                        */
+                       chan->multi_count = num_packets;
+
+               if (chan->ep_type == USB_ENDPOINT_XFER_ISOC)
+                       dwc2_set_pid_isoc(chan);
+
+               hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT &
+                         TSIZ_XFERSIZE_MASK;
+       }
+
+       chan->start_pkt_count = num_packets;
+       hctsiz |= num_packets << TSIZ_PKTCNT_SHIFT & TSIZ_PKTCNT_MASK;
+       hctsiz |= chan->data_pid_start << TSIZ_SC_MC_PID_SHIFT &
+                 TSIZ_SC_MC_PID_MASK;
+       writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
+       if (dbg_hc(chan)) {
+               dev_vdbg(hsotg->dev, "Wrote %08x to HCTSIZ(%d)\n",
+                        hctsiz, chan->hc_num);
+
+               dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
+                        chan->hc_num);
+               dev_vdbg(hsotg->dev, "   Xfer Size: %d\n",
+                        (hctsiz & TSIZ_XFERSIZE_MASK) >>
+                        TSIZ_XFERSIZE_SHIFT);
+               dev_vdbg(hsotg->dev, "   Num Pkts: %d\n",
+                        (hctsiz & TSIZ_PKTCNT_MASK) >>
+                        TSIZ_PKTCNT_SHIFT);
+               dev_vdbg(hsotg->dev, "   Start PID: %d\n",
+                        (hctsiz & TSIZ_SC_MC_PID_MASK) >>
+                        TSIZ_SC_MC_PID_SHIFT);
+       }
+
+       if (hsotg->core_params->dma_enable > 0) {
+               dma_addr_t dma_addr;
+
+               if (chan->align_buf) {
+                       if (dbg_hc(chan))
+                               dev_vdbg(hsotg->dev, "align_buf\n");
+                       dma_addr = chan->align_buf;
+               } else {
+                       dma_addr = chan->xfer_dma;
+               }
+               writel((u32)dma_addr, hsotg->regs + HCDMA(chan->hc_num));
+               if (dbg_hc(chan))
+                       dev_vdbg(hsotg->dev, "Wrote %08lx to HCDMA(%d)\n",
+                                (unsigned long)dma_addr, chan->hc_num);
+       }
+
+       /* Start the split */
+       if (chan->do_split) {
+               u32 hcsplt = readl(hsotg->regs + HCSPLT(chan->hc_num));
+
+               hcsplt |= HCSPLT_SPLTENA;
+               writel(hcsplt, hsotg->regs + HCSPLT(chan->hc_num));
+       }
+
+       hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
+       hcchar &= ~HCCHAR_MULTICNT_MASK;
+       hcchar |= chan->multi_count << HCCHAR_MULTICNT_SHIFT &
+                 HCCHAR_MULTICNT_MASK;
+       dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar);
+
+       if (hcchar & HCCHAR_CHDIS)
+               dev_warn(hsotg->dev,
+                        "%s: chdis set, channel %d, hcchar 0x%08x\n",
+                        __func__, chan->hc_num, hcchar);
+
+       /* Set host channel enable after all other setup is complete */
+       hcchar |= HCCHAR_CHENA;
+       hcchar &= ~HCCHAR_CHDIS;
+
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "   Multi Cnt: %d\n",
+                        (hcchar & HCCHAR_MULTICNT_MASK) >>
+                        HCCHAR_MULTICNT_SHIFT);
+
+       writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "Wrote %08x to HCCHAR(%d)\n", hcchar,
+                        chan->hc_num);
+
+       chan->xfer_started = 1;
+       chan->requests++;
+
+       if (hsotg->core_params->dma_enable <= 0 &&
+           !chan->ep_is_in && chan->xfer_len > 0)
+               /* Load OUT packet into the appropriate Tx FIFO */
+               dwc2_hc_write_packet(hsotg, chan);
+}
+
+/**
+ * dwc2_hc_start_transfer_ddma() - Does the setup for a data transfer for a
+ * host channel and starts the transfer in Descriptor DMA mode
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan:  Information needed to initialize the host channel
+ *
+ * Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set.
+ * Sets PID and NTD values. For periodic transfers initializes SCHED_INFO field
+ * with micro-frame bitmap.
+ *
+ * Initializes HCDMA register with descriptor list address and CTD value then
+ * starts the transfer via enabling the channel.
+ */
+void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
+                                struct dwc2_host_chan *chan)
+{
+       u32 hcchar;
+       u32 hc_dma;
+       u32 hctsiz = 0;
+
+       if (chan->do_ping)
+               hctsiz |= TSIZ_DOPNG;
+
+       if (chan->ep_type == USB_ENDPOINT_XFER_ISOC)
+               dwc2_set_pid_isoc(chan);
+
+       /* Packet Count and Xfer Size are not used in Descriptor DMA mode */
+       hctsiz |= chan->data_pid_start << TSIZ_SC_MC_PID_SHIFT &
+                 TSIZ_SC_MC_PID_MASK;
+
+       /* 0 - 1 descriptor, 1 - 2 descriptors, etc */
+       hctsiz |= (chan->ntd - 1) << TSIZ_NTD_SHIFT & TSIZ_NTD_MASK;
+
+       /* Non-zero only for high-speed interrupt endpoints */
+       hctsiz |= chan->schinfo << TSIZ_SCHINFO_SHIFT & TSIZ_SCHINFO_MASK;
+
+       if (dbg_hc(chan)) {
+               dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
+                        chan->hc_num);
+               dev_vdbg(hsotg->dev, "   Start PID: %d\n",
+                        chan->data_pid_start);
+               dev_vdbg(hsotg->dev, "   NTD: %d\n", chan->ntd - 1);
+       }
+
+       writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
+
+       hc_dma = (u32)chan->desc_list_addr & HCDMA_DMA_ADDR_MASK;
+
+       /* Always start from first descriptor */
+       hc_dma &= ~HCDMA_CTD_MASK;
+       writel(hc_dma, hsotg->regs + HCDMA(chan->hc_num));
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "Wrote %08x to HCDMA(%d)\n",
+                        hc_dma, chan->hc_num);
+
+       hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
+       hcchar &= ~HCCHAR_MULTICNT_MASK;
+       hcchar |= chan->multi_count << HCCHAR_MULTICNT_SHIFT &
+                 HCCHAR_MULTICNT_MASK;
+
+       if (hcchar & HCCHAR_CHDIS)
+               dev_warn(hsotg->dev,
+                        "%s: chdis set, channel %d, hcchar 0x%08x\n",
+                        __func__, chan->hc_num, hcchar);
+
+       /* Set host channel enable after all other setup is complete */
+       hcchar |= HCCHAR_CHENA;
+       hcchar &= ~HCCHAR_CHDIS;
+
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "   Multi Cnt: %d\n",
+                        (hcchar & HCCHAR_MULTICNT_MASK) >>
+                        HCCHAR_MULTICNT_SHIFT);
+
+       writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "Wrote %08x to HCCHAR(%d)\n", hcchar,
+                        chan->hc_num);
+
+       chan->xfer_started = 1;
+       chan->requests++;
+}
+
+/**
+ * dwc2_hc_continue_transfer() - Continues a data transfer that was started by
+ * a previous call to dwc2_hc_start_transfer()
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan:  Information needed to initialize the host channel
+ *
+ * The caller must ensure there is sufficient space in the request queue and Tx
+ * Data FIFO. This function should only be called in Slave mode. In DMA mode,
+ * the controller acts autonomously to complete transfers programmed to a host
+ * channel.
+ *
+ * For an OUT transfer, a new data packet is loaded into the appropriate FIFO
+ * if there is any data remaining to be queued. For an IN transfer, another
+ * data packet is always requested. For the SETUP phase of a control transfer,
+ * this function does nothing.
+ *
+ * Return: 1 if a new request is queued, 0 if no more requests are required
+ * for this transfer
+ */
+int dwc2_hc_continue_transfer(struct dwc2_hsotg *hsotg,
+                             struct dwc2_host_chan *chan)
+{
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
+                        chan->hc_num);
+
+       if (chan->do_split)
+               /* SPLITs always queue just once per channel */
+               return 0;
+
+       if (chan->data_pid_start == DWC2_HC_PID_SETUP)
+               /* SETUPs are queued only once since they can't be NAK'd */
+               return 0;
+
+       if (chan->ep_is_in) {
+               /*
+                * Always queue another request for other IN transfers. If
+                * back-to-back INs are issued and NAKs are received for both,
+                * the driver may still be processing the first NAK when the
+                * second NAK is received. When the interrupt handler clears
+                * the NAK interrupt for the first NAK, the second NAK will
+                * not be seen. So we can't depend on the NAK interrupt
+                * handler to requeue a NAK'd request. Instead, IN requests
+                * are issued each time this function is called. When the
+                * transfer completes, the extra requests for the channel will
+                * be flushed.
+                */
+               u32 hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
+
+               dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar);
+               hcchar |= HCCHAR_CHENA;
+               hcchar &= ~HCCHAR_CHDIS;
+               if (dbg_hc(chan))
+                       dev_vdbg(hsotg->dev, "   IN xfer: hcchar = 0x%08x\n",
+                                hcchar);
+               writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+               chan->requests++;
+               return 1;
+       }
+
+       /* OUT transfers */
+
+       if (chan->xfer_count < chan->xfer_len) {
+               if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+                   chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
+                       u32 hcchar = readl(hsotg->regs +
+                                          HCCHAR(chan->hc_num));
+
+                       dwc2_hc_set_even_odd_frame(hsotg, chan,
+                                                  &hcchar);
+               }
+
+               /* Load OUT packet into the appropriate Tx FIFO */
+               dwc2_hc_write_packet(hsotg, chan);
+               chan->requests++;
+               return 1;
+       }
+
+       return 0;
+}
+
+/**
+ * dwc2_hc_do_ping() - Starts a PING transfer
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan:  Information needed to initialize the host channel
+ *
+ * This function should only be called in Slave mode. The Do Ping bit is set in
+ * the HCTSIZ register, then the channel is enabled.
+ */
+void dwc2_hc_do_ping(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
+{
+       u32 hcchar;
+       u32 hctsiz;
+
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
+                        chan->hc_num);
+
+
+       hctsiz = TSIZ_DOPNG;
+       hctsiz |= 1 << TSIZ_PKTCNT_SHIFT;
+       writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
+
+       hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
+       hcchar |= HCCHAR_CHENA;
+       hcchar &= ~HCCHAR_CHDIS;
+       writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+}
+
+/**
+ * dwc2_calc_frame_interval() - Calculates the correct frame Interval value for
+ * the HFIR register according to PHY type and speed
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ * NOTE: The caller can modify the value of the HFIR register only after the
+ * Port Enable bit of the Host Port Control and Status register (HPRT.EnaPort)
+ * has been set
+ */
+u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg)
+{
+       u32 usbcfg;
+       u32 hprt0;
+       int clock = 60; /* default value */
+
+       usbcfg = readl(hsotg->regs + GUSBCFG);
+       hprt0 = readl(hsotg->regs + HPRT0);
+
+       if (!(usbcfg & GUSBCFG_PHYSEL) && (usbcfg & GUSBCFG_ULPI_UTMI_SEL) &&
+           !(usbcfg & GUSBCFG_PHYIF16))
+               clock = 60;
+       if ((usbcfg & GUSBCFG_PHYSEL) && hsotg->hw_params.fs_phy_type ==
+           GHWCFG2_FS_PHY_TYPE_SHARED_ULPI)
+               clock = 48;
+       if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
+           !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && (usbcfg & GUSBCFG_PHYIF16))
+               clock = 30;
+       if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
+           !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && !(usbcfg & GUSBCFG_PHYIF16))
+               clock = 60;
+       if ((usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
+           !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && (usbcfg & GUSBCFG_PHYIF16))
+               clock = 48;
+       if ((usbcfg & GUSBCFG_PHYSEL) && !(usbcfg & GUSBCFG_PHYIF16) &&
+           hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_SHARED_UTMI)
+               clock = 48;
+       if ((usbcfg & GUSBCFG_PHYSEL) &&
+           hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED)
+               clock = 48;
+
+       if ((hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT == HPRT0_SPD_HIGH_SPEED)
+               /* High speed case */
+               return 125 * clock;
+       else
+               /* FS/LS case */
+               return 1000 * clock;
+}
+
+/**
+ * dwc2_read_packet() - Reads a packet from the Rx FIFO into the destination
+ * buffer
+ *
+ * @core_if: Programming view of DWC_otg controller
+ * @dest:    Destination buffer for the packet
+ * @bytes:   Number of bytes to copy to the destination
+ */
+void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes)
+{
+       u32 __iomem *fifo = hsotg->regs + HCFIFO(0);
+       u32 *data_buf = (u32 *)dest;
+       int word_count = (bytes + 3) / 4;
+       int i;
+
+       /*
+        * Todo: Account for the case where dest is not dword aligned. This
+        * requires reading data from the FIFO into a u32 temp buffer, then
+        * moving it into the data buffer.
+        */
+
+       dev_vdbg(hsotg->dev, "%s(%p,%p,%d)\n", __func__, hsotg, dest, bytes);
+
+       for (i = 0; i < word_count; i++, data_buf++)
+               *data_buf = readl(fifo);
+}
+
+/**
+ * dwc2_dump_host_registers() - Prints the host registers
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ * NOTE: This function will be removed once the peripheral controller code
+ * is integrated and the driver is stable
+ */
+void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg)
+{
+#ifdef DEBUG
+       u32 __iomem *addr;
+       int i;
+
+       dev_dbg(hsotg->dev, "Host Global Registers\n");
+       addr = hsotg->regs + HCFG;
+       dev_dbg(hsotg->dev, "HCFG        @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + HFIR;
+       dev_dbg(hsotg->dev, "HFIR        @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + HFNUM;
+       dev_dbg(hsotg->dev, "HFNUM       @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + HPTXSTS;
+       dev_dbg(hsotg->dev, "HPTXSTS     @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + HAINT;
+       dev_dbg(hsotg->dev, "HAINT       @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + HAINTMSK;
+       dev_dbg(hsotg->dev, "HAINTMSK    @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       if (hsotg->core_params->dma_desc_enable > 0) {
+               addr = hsotg->regs + HFLBADDR;
+               dev_dbg(hsotg->dev, "HFLBADDR @0x%08lX : 0x%08X\n",
+                       (unsigned long)addr, readl(addr));
+       }
+
+       addr = hsotg->regs + HPRT0;
+       dev_dbg(hsotg->dev, "HPRT0       @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+
+       for (i = 0; i < hsotg->core_params->host_channels; i++) {
+               dev_dbg(hsotg->dev, "Host Channel %d Specific Registers\n", i);
+               addr = hsotg->regs + HCCHAR(i);
+               dev_dbg(hsotg->dev, "HCCHAR      @0x%08lX : 0x%08X\n",
+                       (unsigned long)addr, readl(addr));
+               addr = hsotg->regs + HCSPLT(i);
+               dev_dbg(hsotg->dev, "HCSPLT      @0x%08lX : 0x%08X\n",
+                       (unsigned long)addr, readl(addr));
+               addr = hsotg->regs + HCINT(i);
+               dev_dbg(hsotg->dev, "HCINT       @0x%08lX : 0x%08X\n",
+                       (unsigned long)addr, readl(addr));
+               addr = hsotg->regs + HCINTMSK(i);
+               dev_dbg(hsotg->dev, "HCINTMSK    @0x%08lX : 0x%08X\n",
+                       (unsigned long)addr, readl(addr));
+               addr = hsotg->regs + HCTSIZ(i);
+               dev_dbg(hsotg->dev, "HCTSIZ      @0x%08lX : 0x%08X\n",
+                       (unsigned long)addr, readl(addr));
+               addr = hsotg->regs + HCDMA(i);
+               dev_dbg(hsotg->dev, "HCDMA       @0x%08lX : 0x%08X\n",
+                       (unsigned long)addr, readl(addr));
+               if (hsotg->core_params->dma_desc_enable > 0) {
+                       addr = hsotg->regs + HCDMAB(i);
+                       dev_dbg(hsotg->dev, "HCDMAB      @0x%08lX : 0x%08X\n",
+                               (unsigned long)addr, readl(addr));
+               }
+       }
+#endif
+}
+
+/**
+ * dwc2_dump_global_registers() - Prints the core global registers
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ * NOTE: This function will be removed once the peripheral controller code
+ * is integrated and the driver is stable
+ */
+void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg)
+{
+#ifdef DEBUG
+       u32 __iomem *addr;
+
+       dev_dbg(hsotg->dev, "Core Global Registers\n");
+       addr = hsotg->regs + GOTGCTL;
+       dev_dbg(hsotg->dev, "GOTGCTL     @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GOTGINT;
+       dev_dbg(hsotg->dev, "GOTGINT     @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GAHBCFG;
+       dev_dbg(hsotg->dev, "GAHBCFG     @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GUSBCFG;
+       dev_dbg(hsotg->dev, "GUSBCFG     @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GRSTCTL;
+       dev_dbg(hsotg->dev, "GRSTCTL     @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GINTSTS;
+       dev_dbg(hsotg->dev, "GINTSTS     @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GINTMSK;
+       dev_dbg(hsotg->dev, "GINTMSK     @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GRXSTSR;
+       dev_dbg(hsotg->dev, "GRXSTSR     @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GRXFSIZ;
+       dev_dbg(hsotg->dev, "GRXFSIZ     @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GNPTXFSIZ;
+       dev_dbg(hsotg->dev, "GNPTXFSIZ   @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GNPTXSTS;
+       dev_dbg(hsotg->dev, "GNPTXSTS    @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GI2CCTL;
+       dev_dbg(hsotg->dev, "GI2CCTL     @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GPVNDCTL;
+       dev_dbg(hsotg->dev, "GPVNDCTL    @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GGPIO;
+       dev_dbg(hsotg->dev, "GGPIO       @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GUID;
+       dev_dbg(hsotg->dev, "GUID        @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GSNPSID;
+       dev_dbg(hsotg->dev, "GSNPSID     @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GHWCFG1;
+       dev_dbg(hsotg->dev, "GHWCFG1     @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GHWCFG2;
+       dev_dbg(hsotg->dev, "GHWCFG2     @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GHWCFG3;
+       dev_dbg(hsotg->dev, "GHWCFG3     @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GHWCFG4;
+       dev_dbg(hsotg->dev, "GHWCFG4     @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GLPMCFG;
+       dev_dbg(hsotg->dev, "GLPMCFG     @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GPWRDN;
+       dev_dbg(hsotg->dev, "GPWRDN      @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + GDFIFOCFG;
+       dev_dbg(hsotg->dev, "GDFIFOCFG   @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+       addr = hsotg->regs + HPTXFSIZ;
+       dev_dbg(hsotg->dev, "HPTXFSIZ    @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+
+       addr = hsotg->regs + PCGCTL;
+       dev_dbg(hsotg->dev, "PCGCTL      @0x%08lX : 0x%08X\n",
+               (unsigned long)addr, readl(addr));
+#endif
+}
+
+/**
+ * dwc2_flush_tx_fifo() - Flushes a Tx FIFO
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @num:   Tx FIFO to flush
+ */
+void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num)
+{
+       u32 greset;
+       int count = 0;
+
+       dev_vdbg(hsotg->dev, "Flush Tx FIFO %d\n", num);
+
+       greset = GRSTCTL_TXFFLSH;
+       greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK;
+       writel(greset, hsotg->regs + GRSTCTL);
+
+       do {
+               greset = readl(hsotg->regs + GRSTCTL);
+               if (++count > 10000) {
+                       dev_warn(hsotg->dev,
+                                "%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
+                                __func__, greset,
+                                readl(hsotg->regs + GNPTXSTS));
+                       break;
+               }
+               udelay(1);
+       } while (greset & GRSTCTL_TXFFLSH);
+
+       /* Wait for at least 3 PHY Clocks */
+       udelay(1);
+}
+
+/**
+ * dwc2_flush_rx_fifo() - Flushes the Rx FIFO
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ */
+void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg)
+{
+       u32 greset;
+       int count = 0;
+
+       dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+       greset = GRSTCTL_RXFFLSH;
+       writel(greset, hsotg->regs + GRSTCTL);
+
+       do {
+               greset = readl(hsotg->regs + GRSTCTL);
+               if (++count > 10000) {
+                       dev_warn(hsotg->dev, "%s() HANG! GRSTCTL=%0x\n",
+                                __func__, greset);
+                       break;
+               }
+               udelay(1);
+       } while (greset & GRSTCTL_RXFFLSH);
+
+       /* Wait for at least 3 PHY Clocks */
+       udelay(1);
+}
+
+#define DWC2_OUT_OF_BOUNDS(a, b, c)    ((a) < (b) || (a) > (c))
+
+/* Parameter access functions */
+void dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg, int val)
+{
+       int valid = 1;
+
+       switch (val) {
+       case DWC2_CAP_PARAM_HNP_SRP_CAPABLE:
+               if (hsotg->hw_params.op_mode != GHWCFG2_OP_MODE_HNP_SRP_CAPABLE)
+                       valid = 0;
+               break;
+       case DWC2_CAP_PARAM_SRP_ONLY_CAPABLE:
+               switch (hsotg->hw_params.op_mode) {
+               case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
+               case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
+               case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
+               case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
+                       break;
+               default:
+                       valid = 0;
+                       break;
+               }
+               break;
+       case DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE:
+               /* always valid */
+               break;
+       default:
+               valid = 0;
+               break;
+       }
+
+       if (!valid) {
+               if (val >= 0)
+                       dev_err(hsotg->dev,
+                               "%d invalid for otg_cap parameter. Check HW configuration.\n",
+                               val);
+               switch (hsotg->hw_params.op_mode) {
+               case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
+                       val = DWC2_CAP_PARAM_HNP_SRP_CAPABLE;
+                       break;
+               case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
+               case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
+               case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
+                       val = DWC2_CAP_PARAM_SRP_ONLY_CAPABLE;
+                       break;
+               default:
+                       val = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
+                       break;
+               }
+               dev_dbg(hsotg->dev, "Setting otg_cap to %d\n", val);
+       }
+
+       hsotg->core_params->otg_cap = val;
+}
+
+void dwc2_set_param_dma_enable(struct dwc2_hsotg *hsotg, int val)
+{
+       int valid = 1;
+
+       if (val > 0 && hsotg->hw_params.arch == GHWCFG2_SLAVE_ONLY_ARCH)
+               valid = 0;
+       if (val < 0)
+               valid = 0;
+
+       if (!valid) {
+               if (val >= 0)
+                       dev_err(hsotg->dev,
+                               "%d invalid for dma_enable parameter. Check HW configuration.\n",
+                               val);
+               val = hsotg->hw_params.arch != GHWCFG2_SLAVE_ONLY_ARCH;
+               dev_dbg(hsotg->dev, "Setting dma_enable to %d\n", val);
+       }
+
+       hsotg->core_params->dma_enable = val;
+}
+
+void dwc2_set_param_dma_desc_enable(struct dwc2_hsotg *hsotg, int val)
+{
+       int valid = 1;
+
+       if (val > 0 && (hsotg->core_params->dma_enable <= 0 ||
+                       !hsotg->hw_params.dma_desc_enable))
+               valid = 0;
+       if (val < 0)
+               valid = 0;
+
+       if (!valid) {
+               if (val >= 0)
+                       dev_err(hsotg->dev,
+                               "%d invalid for dma_desc_enable parameter. Check HW configuration.\n",
+                               val);
+               val = (hsotg->core_params->dma_enable > 0 &&
+                       hsotg->hw_params.dma_desc_enable);
+               dev_dbg(hsotg->dev, "Setting dma_desc_enable to %d\n", val);
+       }
+
+       hsotg->core_params->dma_desc_enable = val;
+}
+
+void dwc2_set_param_host_support_fs_ls_low_power(struct dwc2_hsotg *hsotg,
+                                                int val)
+{
+       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
+               if (val >= 0) {
+                       dev_err(hsotg->dev,
+                               "Wrong value for host_support_fs_low_power\n");
+                       dev_err(hsotg->dev,
+                               "host_support_fs_low_power must be 0 or 1\n");
+               }
+               val = 0;
+               dev_dbg(hsotg->dev,
+                       "Setting host_support_fs_low_power to %d\n", val);
+       }
+
+       hsotg->core_params->host_support_fs_ls_low_power = val;
+}
+
+void dwc2_set_param_enable_dynamic_fifo(struct dwc2_hsotg *hsotg, int val)
+{
+       int valid = 1;
+
+       if (val > 0 && !hsotg->hw_params.enable_dynamic_fifo)
+               valid = 0;
+       if (val < 0)
+               valid = 0;
+
+       if (!valid) {
+               if (val >= 0)
+                       dev_err(hsotg->dev,
+                               "%d invalid for enable_dynamic_fifo parameter. Check HW configuration.\n",
+                               val);
+               val = hsotg->hw_params.enable_dynamic_fifo;
+               dev_dbg(hsotg->dev, "Setting enable_dynamic_fifo to %d\n", val);
+       }
+
+       hsotg->core_params->enable_dynamic_fifo = val;
+}
+
+void dwc2_set_param_host_rx_fifo_size(struct dwc2_hsotg *hsotg, int val)
+{
+       int valid = 1;
+
+       if (val < 16 || val > hsotg->hw_params.host_rx_fifo_size)
+               valid = 0;
+
+       if (!valid) {
+               if (val >= 0)
+                       dev_err(hsotg->dev,
+                               "%d invalid for host_rx_fifo_size. Check HW configuration.\n",
+                               val);
+               val = hsotg->hw_params.host_rx_fifo_size;
+               dev_dbg(hsotg->dev, "Setting host_rx_fifo_size to %d\n", val);
+       }
+
+       hsotg->core_params->host_rx_fifo_size = val;
+}
+
+void dwc2_set_param_host_nperio_tx_fifo_size(struct dwc2_hsotg *hsotg, int val)
+{
+       int valid = 1;
+
+       if (val < 16 || val > hsotg->hw_params.host_nperio_tx_fifo_size)
+               valid = 0;
+
+       if (!valid) {
+               if (val >= 0)
+                       dev_err(hsotg->dev,
+                               "%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n",
+                               val);
+               val = hsotg->hw_params.host_nperio_tx_fifo_size;
+               dev_dbg(hsotg->dev, "Setting host_nperio_tx_fifo_size to %d\n",
+                       val);
+       }
+
+       hsotg->core_params->host_nperio_tx_fifo_size = val;
+}
+
+void dwc2_set_param_host_perio_tx_fifo_size(struct dwc2_hsotg *hsotg, int val)
+{
+       int valid = 1;
+
+       if (val < 16 || val > hsotg->hw_params.host_perio_tx_fifo_size)
+               valid = 0;
+
+       if (!valid) {
+               if (val >= 0)
+                       dev_err(hsotg->dev,
+                               "%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n",
+                               val);
+               val = hsotg->hw_params.host_perio_tx_fifo_size;
+               dev_dbg(hsotg->dev, "Setting host_perio_tx_fifo_size to %d\n",
+                       val);
+       }
+
+       hsotg->core_params->host_perio_tx_fifo_size = val;
+}
+
+void dwc2_set_param_max_transfer_size(struct dwc2_hsotg *hsotg, int val)
+{
+       int valid = 1;
+
+       if (val < 2047 || val > hsotg->hw_params.max_transfer_size)
+               valid = 0;
+
+       if (!valid) {
+               if (val >= 0)
+                       dev_err(hsotg->dev,
+                               "%d invalid for max_transfer_size. Check HW configuration.\n",
+                               val);
+               val = hsotg->hw_params.max_transfer_size;
+               dev_dbg(hsotg->dev, "Setting max_transfer_size to %d\n", val);
+       }
+
+       hsotg->core_params->max_transfer_size = val;
+}
+
+void dwc2_set_param_max_packet_count(struct dwc2_hsotg *hsotg, int val)
+{
+       int valid = 1;
+
+       if (val < 15 || val > hsotg->hw_params.max_packet_count)
+               valid = 0;
+
+       if (!valid) {
+               if (val >= 0)
+                       dev_err(hsotg->dev,
+                               "%d invalid for max_packet_count. Check HW configuration.\n",
+                               val);
+               val = hsotg->hw_params.max_packet_count;
+               dev_dbg(hsotg->dev, "Setting max_packet_count to %d\n", val);
+       }
+
+       hsotg->core_params->max_packet_count = val;
+}
+
+void dwc2_set_param_host_channels(struct dwc2_hsotg *hsotg, int val)
+{
+       int valid = 1;
+
+       if (val < 1 || val > hsotg->hw_params.host_channels)
+               valid = 0;
+
+       if (!valid) {
+               if (val >= 0)
+                       dev_err(hsotg->dev,
+                               "%d invalid for host_channels. Check HW configuration.\n",
+                               val);
+               val = hsotg->hw_params.host_channels;
+               dev_dbg(hsotg->dev, "Setting host_channels to %d\n", val);
+       }
+
+       hsotg->core_params->host_channels = val;
+}
+
+void dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg, int val)
+{
+       int valid = 0;
+       u32 hs_phy_type, fs_phy_type;
+
+       if (DWC2_OUT_OF_BOUNDS(val, DWC2_PHY_TYPE_PARAM_FS,
+                              DWC2_PHY_TYPE_PARAM_ULPI)) {
+               if (val >= 0) {
+                       dev_err(hsotg->dev, "Wrong value for phy_type\n");
+                       dev_err(hsotg->dev, "phy_type must be 0, 1 or 2\n");
+               }
+
+               valid = 0;
+       }
+
+       hs_phy_type = hsotg->hw_params.hs_phy_type;
+       fs_phy_type = hsotg->hw_params.fs_phy_type;
+       if (val == DWC2_PHY_TYPE_PARAM_UTMI &&
+           (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI ||
+            hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI))
+               valid = 1;
+       else if (val == DWC2_PHY_TYPE_PARAM_ULPI &&
+                (hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI ||
+                 hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI))
+               valid = 1;
+       else if (val == DWC2_PHY_TYPE_PARAM_FS &&
+                fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED)
+               valid = 1;
+
+       if (!valid) {
+               if (val >= 0)
+                       dev_err(hsotg->dev,
+                               "%d invalid for phy_type. Check HW configuration.\n",
+                               val);
+               val = DWC2_PHY_TYPE_PARAM_FS;
+               if (hs_phy_type != GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED) {
+                       if (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI ||
+                           hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI)
+                               val = DWC2_PHY_TYPE_PARAM_UTMI;
+                       else
+                               val = DWC2_PHY_TYPE_PARAM_ULPI;
+               }
+               dev_dbg(hsotg->dev, "Setting phy_type to %d\n", val);
+       }
+
+       hsotg->core_params->phy_type = val;
+}
+
+static int dwc2_get_param_phy_type(struct dwc2_hsotg *hsotg)
+{
+       return hsotg->core_params->phy_type;
+}
+
+void dwc2_set_param_speed(struct dwc2_hsotg *hsotg, int val)
+{
+       int valid = 1;
+
+       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
+               if (val >= 0) {
+                       dev_err(hsotg->dev, "Wrong value for speed parameter\n");
+                       dev_err(hsotg->dev, "max_speed parameter must be 0 or 1\n");
+               }
+               valid = 0;
+       }
+
+       if (val == DWC2_SPEED_PARAM_HIGH &&
+           dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS)
+               valid = 0;
+
+       if (!valid) {
+               if (val >= 0)
+                       dev_err(hsotg->dev,
+                               "%d invalid for speed parameter. Check HW configuration.\n",
+                               val);
+               val = dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS ?
+                               DWC2_SPEED_PARAM_FULL : DWC2_SPEED_PARAM_HIGH;
+               dev_dbg(hsotg->dev, "Setting speed to %d\n", val);
+       }
+
+       hsotg->core_params->speed = val;
+}
+
+void dwc2_set_param_host_ls_low_power_phy_clk(struct dwc2_hsotg *hsotg, int val)
+{
+       int valid = 1;
+
+       if (DWC2_OUT_OF_BOUNDS(val, DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ,
+                              DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)) {
+               if (val >= 0) {
+                       dev_err(hsotg->dev,
+                               "Wrong value for host_ls_low_power_phy_clk parameter\n");
+                       dev_err(hsotg->dev,
+                               "host_ls_low_power_phy_clk must be 0 or 1\n");
+               }
+               valid = 0;
+       }
+
+       if (val == DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ &&
+           dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS)
+               valid = 0;
+
+       if (!valid) {
+               if (val >= 0)
+                       dev_err(hsotg->dev,
+                               "%d invalid for host_ls_low_power_phy_clk. Check HW configuration.\n",
+                               val);
+               val = dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS
+                       ? DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ
+                       : DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ;
+               dev_dbg(hsotg->dev, "Setting host_ls_low_power_phy_clk to %d\n",
+                       val);
+       }
+
+       hsotg->core_params->host_ls_low_power_phy_clk = val;
+}
+
+void dwc2_set_param_phy_ulpi_ddr(struct dwc2_hsotg *hsotg, int val)
+{
+       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
+               if (val >= 0) {
+                       dev_err(hsotg->dev, "Wrong value for phy_ulpi_ddr\n");
+                       dev_err(hsotg->dev, "phy_upli_ddr must be 0 or 1\n");
+               }
+               val = 0;
+               dev_dbg(hsotg->dev, "Setting phy_upli_ddr to %d\n", val);
+       }
+
+       hsotg->core_params->phy_ulpi_ddr = val;
+}
+
+void dwc2_set_param_phy_ulpi_ext_vbus(struct dwc2_hsotg *hsotg, int val)
+{
+       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
+               if (val >= 0) {
+                       dev_err(hsotg->dev,
+                               "Wrong value for phy_ulpi_ext_vbus\n");
+                       dev_err(hsotg->dev,
+                               "phy_ulpi_ext_vbus must be 0 or 1\n");
+               }
+               val = 0;
+               dev_dbg(hsotg->dev, "Setting phy_ulpi_ext_vbus to %d\n", val);
+       }
+
+       hsotg->core_params->phy_ulpi_ext_vbus = val;
+}
+
+void dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg, int val)
+{
+       int valid = 0;
+
+       switch (hsotg->hw_params.utmi_phy_data_width) {
+       case GHWCFG4_UTMI_PHY_DATA_WIDTH_8:
+               valid = (val == 8);
+               break;
+       case GHWCFG4_UTMI_PHY_DATA_WIDTH_16:
+               valid = (val == 16);
+               break;
+       case GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16:
+               valid = (val == 8 || val == 16);
+               break;
+       }
+
+       if (!valid) {
+               if (val >= 0) {
+                       dev_err(hsotg->dev,
+                               "%d invalid for phy_utmi_width. Check HW configuration.\n",
+                               val);
+               }
+               val = (hsotg->hw_params.utmi_phy_data_width ==
+                      GHWCFG4_UTMI_PHY_DATA_WIDTH_8) ? 8 : 16;
+               dev_dbg(hsotg->dev, "Setting phy_utmi_width to %d\n", val);
+       }
+
+       hsotg->core_params->phy_utmi_width = val;
+}
+
+void dwc2_set_param_ulpi_fs_ls(struct dwc2_hsotg *hsotg, int val)
+{
+       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
+               if (val >= 0) {
+                       dev_err(hsotg->dev, "Wrong value for ulpi_fs_ls\n");
+                       dev_err(hsotg->dev, "ulpi_fs_ls must be 0 or 1\n");
+               }
+               val = 0;
+               dev_dbg(hsotg->dev, "Setting ulpi_fs_ls to %d\n", val);
+       }
+
+       hsotg->core_params->ulpi_fs_ls = val;
+}
+
+void dwc2_set_param_ts_dline(struct dwc2_hsotg *hsotg, int val)
+{
+       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
+               if (val >= 0) {
+                       dev_err(hsotg->dev, "Wrong value for ts_dline\n");
+                       dev_err(hsotg->dev, "ts_dline must be 0 or 1\n");
+               }
+               val = 0;
+               dev_dbg(hsotg->dev, "Setting ts_dline to %d\n", val);
+       }
+
+       hsotg->core_params->ts_dline = val;
+}
+
+void dwc2_set_param_i2c_enable(struct dwc2_hsotg *hsotg, int val)
+{
+       int valid = 1;
+
+       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
+               if (val >= 0) {
+                       dev_err(hsotg->dev, "Wrong value for i2c_enable\n");
+                       dev_err(hsotg->dev, "i2c_enable must be 0 or 1\n");
+               }
+
+               valid = 0;
+       }
+
+       if (val == 1 && !(hsotg->hw_params.i2c_enable))
+               valid = 0;
+
+       if (!valid) {
+               if (val >= 0)
+                       dev_err(hsotg->dev,
+                               "%d invalid for i2c_enable. Check HW configuration.\n",
+                               val);
+               val = hsotg->hw_params.i2c_enable;
+               dev_dbg(hsotg->dev, "Setting i2c_enable to %d\n", val);
+       }
+
+       hsotg->core_params->i2c_enable = val;
+}
+
+void dwc2_set_param_en_multiple_tx_fifo(struct dwc2_hsotg *hsotg, int val)
+{
+       int valid = 1;
+
+       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
+               if (val >= 0) {
+                       dev_err(hsotg->dev,
+                               "Wrong value for en_multiple_tx_fifo,\n");
+                       dev_err(hsotg->dev,
+                               "en_multiple_tx_fifo must be 0 or 1\n");
+               }
+               valid = 0;
+       }
+
+       if (val == 1 && !hsotg->hw_params.en_multiple_tx_fifo)
+               valid = 0;
+
+       if (!valid) {
+               if (val >= 0)
+                       dev_err(hsotg->dev,
+                               "%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n",
+                               val);
+               val = hsotg->hw_params.en_multiple_tx_fifo;
+               dev_dbg(hsotg->dev, "Setting en_multiple_tx_fifo to %d\n", val);
+       }
+
+       hsotg->core_params->en_multiple_tx_fifo = val;
+}
+
+void dwc2_set_param_reload_ctl(struct dwc2_hsotg *hsotg, int val)
+{
+       int valid = 1;
+
+       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
+               if (val >= 0) {
+                       dev_err(hsotg->dev,
+                               "'%d' invalid for parameter reload_ctl\n", val);
+                       dev_err(hsotg->dev, "reload_ctl must be 0 or 1\n");
+               }
+               valid = 0;
+       }
+
+       if (val == 1 && hsotg->hw_params.snpsid < DWC2_CORE_REV_2_92a)
+               valid = 0;
+
+       if (!valid) {
+               if (val >= 0)
+                       dev_err(hsotg->dev,
+                               "%d invalid for parameter reload_ctl. Check HW configuration.\n",
+                               val);
+               val = hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_92a;
+               dev_dbg(hsotg->dev, "Setting reload_ctl to %d\n", val);
+       }
+
+       hsotg->core_params->reload_ctl = val;
+}
+
+void dwc2_set_param_ahbcfg(struct dwc2_hsotg *hsotg, int val)
+{
+       if (val != -1)
+               hsotg->core_params->ahbcfg = val;
+       else
+               hsotg->core_params->ahbcfg = GAHBCFG_HBSTLEN_INCR4 <<
+                                               GAHBCFG_HBSTLEN_SHIFT;
+}
+
+void dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val)
+{
+       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
+               if (val >= 0) {
+                       dev_err(hsotg->dev,
+                               "'%d' invalid for parameter otg_ver\n", val);
+                       dev_err(hsotg->dev,
+                               "otg_ver must be 0 (for OTG 1.3 support) or 1 (for OTG 2.0 support)\n");
+               }
+               val = 0;
+               dev_dbg(hsotg->dev, "Setting otg_ver to %d\n", val);
+       }
+
+       hsotg->core_params->otg_ver = val;
+}
+
+static void dwc2_set_param_uframe_sched(struct dwc2_hsotg *hsotg, int val)
+{
+       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
+               if (val >= 0) {
+                       dev_err(hsotg->dev,
+                               "'%d' invalid for parameter uframe_sched\n",
+                               val);
+                       dev_err(hsotg->dev, "uframe_sched must be 0 or 1\n");
+               }
+               val = 1;
+               dev_dbg(hsotg->dev, "Setting uframe_sched to %d\n", val);
+       }
+
+       hsotg->core_params->uframe_sched = val;
+}
+
+/*
+ * This function is called during module intialization to pass module parameters
+ * for the DWC_otg core.
+ */
+void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
+                        const struct dwc2_core_params *params)
+{
+       dev_dbg(hsotg->dev, "%s()\n", __func__);
+
+       dwc2_set_param_otg_cap(hsotg, params->otg_cap);
+       dwc2_set_param_dma_enable(hsotg, params->dma_enable);
+       dwc2_set_param_dma_desc_enable(hsotg, params->dma_desc_enable);
+       dwc2_set_param_host_support_fs_ls_low_power(hsotg,
+                       params->host_support_fs_ls_low_power);
+       dwc2_set_param_enable_dynamic_fifo(hsotg,
+                       params->enable_dynamic_fifo);
+       dwc2_set_param_host_rx_fifo_size(hsotg,
+                       params->host_rx_fifo_size);
+       dwc2_set_param_host_nperio_tx_fifo_size(hsotg,
+                       params->host_nperio_tx_fifo_size);
+       dwc2_set_param_host_perio_tx_fifo_size(hsotg,
+                       params->host_perio_tx_fifo_size);
+       dwc2_set_param_max_transfer_size(hsotg,
+                       params->max_transfer_size);
+       dwc2_set_param_max_packet_count(hsotg,
+                       params->max_packet_count);
+       dwc2_set_param_host_channels(hsotg, params->host_channels);
+       dwc2_set_param_phy_type(hsotg, params->phy_type);
+       dwc2_set_param_speed(hsotg, params->speed);
+       dwc2_set_param_host_ls_low_power_phy_clk(hsotg,
+                       params->host_ls_low_power_phy_clk);
+       dwc2_set_param_phy_ulpi_ddr(hsotg, params->phy_ulpi_ddr);
+       dwc2_set_param_phy_ulpi_ext_vbus(hsotg,
+                       params->phy_ulpi_ext_vbus);
+       dwc2_set_param_phy_utmi_width(hsotg, params->phy_utmi_width);
+       dwc2_set_param_ulpi_fs_ls(hsotg, params->ulpi_fs_ls);
+       dwc2_set_param_ts_dline(hsotg, params->ts_dline);
+       dwc2_set_param_i2c_enable(hsotg, params->i2c_enable);
+       dwc2_set_param_en_multiple_tx_fifo(hsotg,
+                       params->en_multiple_tx_fifo);
+       dwc2_set_param_reload_ctl(hsotg, params->reload_ctl);
+       dwc2_set_param_ahbcfg(hsotg, params->ahbcfg);
+       dwc2_set_param_otg_ver(hsotg, params->otg_ver);
+       dwc2_set_param_uframe_sched(hsotg, params->uframe_sched);
+}
+
+/**
+ * During device initialization, read various hardware configuration
+ * registers and interpret the contents.
+ */
+int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
+{
+       struct dwc2_hw_params *hw = &hsotg->hw_params;
+       unsigned width;
+       u32 hwcfg1, hwcfg2, hwcfg3, hwcfg4;
+       u32 hptxfsiz, grxfsiz, gnptxfsiz;
+       u32 gusbcfg;
+
+       /*
+        * Attempt to ensure this device is really a DWC_otg Controller.
+        * Read and verify the GSNPSID register contents. The value should be
+        * 0x45f42xxx or 0x45f43xxx, which corresponds to either "OT2" or "OT3",
+        * as in "OTG version 2.xx" or "OTG version 3.xx".
+        */
+       hw->snpsid = readl(hsotg->regs + GSNPSID);
+       if ((hw->snpsid & 0xfffff000) != 0x4f542000 &&
+           (hw->snpsid & 0xfffff000) != 0x4f543000) {
+               dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n",
+                       hw->snpsid);
+               return -ENODEV;
+       }
+
+       dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x (snpsid=%x)\n",
+               hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
+               hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
+
+       hwcfg1 = readl(hsotg->regs + GHWCFG1);
+       hwcfg2 = readl(hsotg->regs + GHWCFG2);
+       hwcfg3 = readl(hsotg->regs + GHWCFG3);
+       hwcfg4 = readl(hsotg->regs + GHWCFG4);
+       gnptxfsiz = readl(hsotg->regs + GNPTXFSIZ);
+       grxfsiz = readl(hsotg->regs + GRXFSIZ);
+
+       dev_dbg(hsotg->dev, "hwcfg1=%08x\n", hwcfg1);
+       dev_dbg(hsotg->dev, "hwcfg2=%08x\n", hwcfg2);
+       dev_dbg(hsotg->dev, "hwcfg3=%08x\n", hwcfg3);
+       dev_dbg(hsotg->dev, "hwcfg4=%08x\n", hwcfg4);
+       dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz);
+       dev_dbg(hsotg->dev, "grxfsiz=%08x\n", grxfsiz);
+
+       /* Force host mode to get HPTXFSIZ exact power on value */
+       gusbcfg = readl(hsotg->regs + GUSBCFG);
+       gusbcfg |= GUSBCFG_FORCEHOSTMODE;
+       writel(gusbcfg, hsotg->regs + GUSBCFG);
+       usleep_range(100000, 150000);
+
+       hptxfsiz = readl(hsotg->regs + HPTXFSIZ);
+       dev_dbg(hsotg->dev, "hptxfsiz=%08x\n", hptxfsiz);
+       gusbcfg = readl(hsotg->regs + GUSBCFG);
+       gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
+       writel(gusbcfg, hsotg->regs + GUSBCFG);
+       usleep_range(100000, 150000);
+
+       /* hwcfg2 */
+       hw->op_mode = (hwcfg2 & GHWCFG2_OP_MODE_MASK) >>
+                     GHWCFG2_OP_MODE_SHIFT;
+       hw->arch = (hwcfg2 & GHWCFG2_ARCHITECTURE_MASK) >>
+                  GHWCFG2_ARCHITECTURE_SHIFT;
+       hw->enable_dynamic_fifo = !!(hwcfg2 & GHWCFG2_DYNAMIC_FIFO);
+       hw->host_channels = 1 + ((hwcfg2 & GHWCFG2_NUM_HOST_CHAN_MASK) >>
+                               GHWCFG2_NUM_HOST_CHAN_SHIFT);
+       hw->hs_phy_type = (hwcfg2 & GHWCFG2_HS_PHY_TYPE_MASK) >>
+                         GHWCFG2_HS_PHY_TYPE_SHIFT;
+       hw->fs_phy_type = (hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK) >>
+                         GHWCFG2_FS_PHY_TYPE_SHIFT;
+       hw->num_dev_ep = (hwcfg2 & GHWCFG2_NUM_DEV_EP_MASK) >>
+                        GHWCFG2_NUM_DEV_EP_SHIFT;
+       hw->nperio_tx_q_depth =
+               (hwcfg2 & GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK) >>
+               GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT << 1;
+       hw->host_perio_tx_q_depth =
+               (hwcfg2 & GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK) >>
+               GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT << 1;
+       hw->dev_token_q_depth =
+               (hwcfg2 & GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK) >>
+               GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT;
+
+       /* hwcfg3 */
+       width = (hwcfg3 & GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK) >>
+               GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT;
+       hw->max_transfer_size = (1 << (width + 11)) - 1;
+       width = (hwcfg3 & GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK) >>
+               GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT;
+       hw->max_packet_count = (1 << (width + 4)) - 1;
+       hw->i2c_enable = !!(hwcfg3 & GHWCFG3_I2C);
+       hw->total_fifo_size = (hwcfg3 & GHWCFG3_DFIFO_DEPTH_MASK) >>
+                             GHWCFG3_DFIFO_DEPTH_SHIFT;
+
+       /* hwcfg4 */
+       hw->en_multiple_tx_fifo = !!(hwcfg4 & GHWCFG4_DED_FIFO_EN);
+       hw->num_dev_perio_in_ep = (hwcfg4 & GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK) >>
+                                 GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT;
+       hw->dma_desc_enable = !!(hwcfg4 & GHWCFG4_DESC_DMA);
+       hw->power_optimized = !!(hwcfg4 & GHWCFG4_POWER_OPTIMIZ);
+       hw->utmi_phy_data_width = (hwcfg4 & GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK) >>
+                                 GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT;
+
+       /* fifo sizes */
+       hw->host_rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >>
+                               GRXFSIZ_DEPTH_SHIFT;
+       hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >>
+                                      FIFOSIZE_DEPTH_SHIFT;
+       hw->host_perio_tx_fifo_size = (hptxfsiz & FIFOSIZE_DEPTH_MASK) >>
+                                     FIFOSIZE_DEPTH_SHIFT;
+
+       dev_dbg(hsotg->dev, "Detected values from hardware:\n");
+       dev_dbg(hsotg->dev, "  op_mode=%d\n",
+               hw->op_mode);
+       dev_dbg(hsotg->dev, "  arch=%d\n",
+               hw->arch);
+       dev_dbg(hsotg->dev, "  dma_desc_enable=%d\n",
+               hw->dma_desc_enable);
+       dev_dbg(hsotg->dev, "  power_optimized=%d\n",
+               hw->power_optimized);
+       dev_dbg(hsotg->dev, "  i2c_enable=%d\n",
+               hw->i2c_enable);
+       dev_dbg(hsotg->dev, "  hs_phy_type=%d\n",
+               hw->hs_phy_type);
+       dev_dbg(hsotg->dev, "  fs_phy_type=%d\n",
+               hw->fs_phy_type);
+       dev_dbg(hsotg->dev, "  utmi_phy_data_wdith=%d\n",
+               hw->utmi_phy_data_width);
+       dev_dbg(hsotg->dev, "  num_dev_ep=%d\n",
+               hw->num_dev_ep);
+       dev_dbg(hsotg->dev, "  num_dev_perio_in_ep=%d\n",
+               hw->num_dev_perio_in_ep);
+       dev_dbg(hsotg->dev, "  host_channels=%d\n",
+               hw->host_channels);
+       dev_dbg(hsotg->dev, "  max_transfer_size=%d\n",
+               hw->max_transfer_size);
+       dev_dbg(hsotg->dev, "  max_packet_count=%d\n",
+               hw->max_packet_count);
+       dev_dbg(hsotg->dev, "  nperio_tx_q_depth=0x%0x\n",
+               hw->nperio_tx_q_depth);
+       dev_dbg(hsotg->dev, "  host_perio_tx_q_depth=0x%0x\n",
+               hw->host_perio_tx_q_depth);
+       dev_dbg(hsotg->dev, "  dev_token_q_depth=0x%0x\n",
+               hw->dev_token_q_depth);
+       dev_dbg(hsotg->dev, "  enable_dynamic_fifo=%d\n",
+               hw->enable_dynamic_fifo);
+       dev_dbg(hsotg->dev, "  en_multiple_tx_fifo=%d\n",
+               hw->en_multiple_tx_fifo);
+       dev_dbg(hsotg->dev, "  total_fifo_size=%d\n",
+               hw->total_fifo_size);
+       dev_dbg(hsotg->dev, "  host_rx_fifo_size=%d\n",
+               hw->host_rx_fifo_size);
+       dev_dbg(hsotg->dev, "  host_nperio_tx_fifo_size=%d\n",
+               hw->host_nperio_tx_fifo_size);
+       dev_dbg(hsotg->dev, "  host_perio_tx_fifo_size=%d\n",
+               hw->host_perio_tx_fifo_size);
+       dev_dbg(hsotg->dev, "\n");
+
+       return 0;
+}
+
+u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg)
+{
+       return hsotg->core_params->otg_ver == 1 ? 0x0200 : 0x0103;
+}
+
+bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg)
+{
+       if (readl(hsotg->regs + GSNPSID) == 0xffffffff)
+               return false;
+       else
+               return true;
+}
+
+/**
+ * dwc2_enable_global_interrupts() - Enables the controller's Global
+ * Interrupt in the AHB Config register
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ */
+void dwc2_enable_global_interrupts(struct dwc2_hsotg *hsotg)
+{
+       u32 ahbcfg = readl(hsotg->regs + GAHBCFG);
+
+       ahbcfg |= GAHBCFG_GLBL_INTR_EN;
+       writel(ahbcfg, hsotg->regs + GAHBCFG);
+}
+
+/**
+ * dwc2_disable_global_interrupts() - Disables the controller's Global
+ * Interrupt in the AHB Config register
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ */
+void dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg)
+{
+       u32 ahbcfg = readl(hsotg->regs + GAHBCFG);
+
+       ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
+       writel(ahbcfg, hsotg->regs + GAHBCFG);
+}
+
+MODULE_DESCRIPTION("DESIGNWARE HS OTG Core");
+MODULE_AUTHOR("Synopsys, Inc.");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
new file mode 100644 (file)
index 0000000..648519c
--- /dev/null
@@ -0,0 +1,768 @@
+/*
+ * core.h - DesignWare HS OTG Controller common declarations
+ *
+ * Copyright (C) 2004-2013 Synopsys, Inc.
+ *
+ * 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") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * 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 __DWC2_CORE_H__
+#define __DWC2_CORE_H__
+
+#include <linux/usb/phy.h>
+#include "hw.h"
+
+#ifdef DWC2_LOG_WRITES
+static inline void do_write(u32 value, void *addr)
+{
+       writel(value, addr);
+       pr_info("INFO:: wrote %08x to %p\n", value, addr);
+}
+
+#undef writel
+#define writel(v, a)   do_write(v, a)
+#endif
+
+/* Maximum number of Endpoints/HostChannels */
+#define MAX_EPS_CHANNELS       16
+
+struct dwc2_hsotg;
+struct dwc2_host_chan;
+
+/* Device States */
+enum dwc2_lx_state {
+       DWC2_L0,        /* On state */
+       DWC2_L1,        /* LPM sleep state */
+       DWC2_L2,        /* USB suspend state */
+       DWC2_L3,        /* Off state */
+};
+
+/**
+ * struct dwc2_core_params - Parameters for configuring the core
+ *
+ * @otg_cap:            Specifies the OTG capabilities.
+ *                       0 - HNP and SRP capable
+ *                       1 - SRP Only capable
+ *                       2 - No HNP/SRP capable (always available)
+ *                      Defaults to best available option (0, 1, then 2)
+ * @otg_ver:            OTG version supported
+ *                       0 - 1.3 (default)
+ *                       1 - 2.0
+ * @dma_enable:         Specifies whether to use slave or DMA mode for accessing
+ *                      the data FIFOs. The driver will automatically detect the
+ *                      value for this parameter if none is specified.
+ *                       0 - Slave (always available)
+ *                       1 - DMA (default, if available)
+ * @dma_desc_enable:    When DMA mode is enabled, specifies whether to use
+ *                      address DMA mode or descriptor DMA mode for accessing
+ *                      the data FIFOs. The driver will automatically detect the
+ *                      value for this if none is specified.
+ *                       0 - Address DMA
+ *                       1 - Descriptor DMA (default, if available)
+ * @speed:              Specifies the maximum speed of operation in host and
+ *                      device mode. The actual speed depends on the speed of
+ *                      the attached device and the value of phy_type.
+ *                       0 - High Speed
+ *                           (default when phy_type is UTMI+ or ULPI)
+ *                       1 - Full Speed
+ *                           (default when phy_type is Full Speed)
+ * @enable_dynamic_fifo: 0 - Use coreConsultant-specified FIFO size parameters
+ *                       1 - Allow dynamic FIFO sizing (default, if available)
+ * @en_multiple_tx_fifo: Specifies whether dedicated per-endpoint transmit FIFOs
+ *                      are enabled
+ * @host_rx_fifo_size:  Number of 4-byte words in the Rx FIFO in host mode when
+ *                      dynamic FIFO sizing is enabled
+ *                       16 to 32768
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
+ * @host_nperio_tx_fifo_size: Number of 4-byte words in the non-periodic Tx FIFO
+ *                      in host mode when dynamic FIFO sizing is enabled
+ *                       16 to 32768
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
+ * @host_perio_tx_fifo_size: Number of 4-byte words in the periodic Tx FIFO in
+ *                      host mode when dynamic FIFO sizing is enabled
+ *                       16 to 32768
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
+ * @max_transfer_size:  The maximum transfer size supported, in bytes
+ *                       2047 to 65,535
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
+ * @max_packet_count:   The maximum number of packets in a transfer
+ *                       15 to 511
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
+ * @host_channels:      The number of host channel registers to use
+ *                       1 to 16
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
+ * @phy_type:           Specifies the type of PHY interface to use. By default,
+ *                      the driver will automatically detect the phy_type.
+ *                       0 - Full Speed Phy
+ *                       1 - UTMI+ Phy
+ *                       2 - ULPI Phy
+ *                      Defaults to best available option (2, 1, then 0)
+ * @phy_utmi_width:     Specifies the UTMI+ Data Width (in bits). This parameter
+ *                      is applicable for a phy_type of UTMI+ or ULPI. (For a
+ *                      ULPI phy_type, this parameter indicates the data width
+ *                      between the MAC and the ULPI Wrapper.) Also, this
+ *                      parameter is applicable only if the OTG_HSPHY_WIDTH cC
+ *                      parameter was set to "8 and 16 bits", meaning that the
+ *                      core has been configured to work at either data path
+ *                      width.
+ *                       8 or 16 (default 16 if available)
+ * @phy_ulpi_ddr:       Specifies whether the ULPI operates at double or single
+ *                      data rate. This parameter is only applicable if phy_type
+ *                      is ULPI.
+ *                       0 - single data rate ULPI interface with 8 bit wide
+ *                           data bus (default)
+ *                       1 - double data rate ULPI interface with 4 bit wide
+ *                           data bus
+ * @phy_ulpi_ext_vbus:  For a ULPI phy, specifies whether to use the internal or
+ *                      external supply to drive the VBus
+ *                       0 - Internal supply (default)
+ *                       1 - External supply
+ * @i2c_enable:         Specifies whether to use the I2Cinterface for a full
+ *                      speed PHY. This parameter is only applicable if phy_type
+ *                      is FS.
+ *                       0 - No (default)
+ *                       1 - Yes
+ * @ulpi_fs_ls:         Make ULPI phy operate in FS/LS mode only
+ *                       0 - No (default)
+ *                       1 - Yes
+ * @host_support_fs_ls_low_power: Specifies whether low power mode is supported
+ *                      when attached to a Full Speed or Low Speed device in
+ *                      host mode.
+ *                       0 - Don't support low power mode (default)
+ *                       1 - Support low power mode
+ * @host_ls_low_power_phy_clk: Specifies the PHY clock rate in low power mode
+ *                      when connected to a Low Speed device in host
+ *                      mode. This parameter is applicable only if
+ *                      host_support_fs_ls_low_power is enabled.
+ *                       0 - 48 MHz
+ *                           (default when phy_type is UTMI+ or ULPI)
+ *                       1 - 6 MHz
+ *                           (default when phy_type is Full Speed)
+ * @ts_dline:           Enable Term Select Dline pulsing
+ *                       0 - No (default)
+ *                       1 - Yes
+ * @reload_ctl:         Allow dynamic reloading of HFIR register during runtime
+ *                       0 - No (default for core < 2.92a)
+ *                       1 - Yes (default for core >= 2.92a)
+ * @ahbcfg:             This field allows the default value of the GAHBCFG
+ *                      register to be overridden
+ *                       -1         - GAHBCFG value will be set to 0x06
+ *                                    (INCR4, default)
+ *                       all others - GAHBCFG value will be overridden with
+ *                                    this value
+ *                      Not all bits can be controlled like this, the
+ *                      bits defined by GAHBCFG_CTRL_MASK are controlled
+ *                      by the driver and are ignored in this
+ *                      configuration value.
+ * @uframe_sched:       True to enable the microframe scheduler
+ *
+ * The following parameters may be specified when starting the module. These
+ * parameters define how the DWC_otg controller should be configured. A
+ * value of -1 (or any other out of range value) for any parameter means
+ * to read the value from hardware (if possible) or use the builtin
+ * default described above.
+ */
+struct dwc2_core_params {
+       /*
+        * Don't add any non-int members here, this will break
+        * dwc2_set_all_params!
+        */
+       int otg_cap;
+       int otg_ver;
+       int dma_enable;
+       int dma_desc_enable;
+       int speed;
+       int enable_dynamic_fifo;
+       int en_multiple_tx_fifo;
+       int host_rx_fifo_size;
+       int host_nperio_tx_fifo_size;
+       int host_perio_tx_fifo_size;
+       int max_transfer_size;
+       int max_packet_count;
+       int host_channels;
+       int phy_type;
+       int phy_utmi_width;
+       int phy_ulpi_ddr;
+       int phy_ulpi_ext_vbus;
+       int i2c_enable;
+       int ulpi_fs_ls;
+       int host_support_fs_ls_low_power;
+       int host_ls_low_power_phy_clk;
+       int ts_dline;
+       int reload_ctl;
+       int ahbcfg;
+       int uframe_sched;
+};
+
+/**
+ * struct dwc2_hw_params - Autodetected parameters.
+ *
+ * These parameters are the various parameters read from hardware
+ * registers during initialization. They typically contain the best
+ * supported or maximum value that can be configured in the
+ * corresponding dwc2_core_params value.
+ *
+ * The values that are not in dwc2_core_params are documented below.
+ *
+ * @op_mode             Mode of Operation
+ *                       0 - HNP- and SRP-Capable OTG (Host & Device)
+ *                       1 - SRP-Capable OTG (Host & Device)
+ *                       2 - Non-HNP and Non-SRP Capable OTG (Host & Device)
+ *                       3 - SRP-Capable Device
+ *                       4 - Non-OTG Device
+ *                       5 - SRP-Capable Host
+ *                       6 - Non-OTG Host
+ * @arch                Architecture
+ *                       0 - Slave only
+ *                       1 - External DMA
+ *                       2 - Internal DMA
+ * @power_optimized     Are power optimizations enabled?
+ * @num_dev_ep          Number of device endpoints available
+ * @num_dev_perio_in_ep Number of device periodic IN endpoints
+ *                      avaialable
+ * @dev_token_q_depth   Device Mode IN Token Sequence Learning Queue
+ *                      Depth
+ *                       0 to 30
+ * @host_perio_tx_q_depth
+ *                      Host Mode Periodic Request Queue Depth
+ *                       2, 4 or 8
+ * @nperio_tx_q_depth
+ *                      Non-Periodic Request Queue Depth
+ *                       2, 4 or 8
+ * @hs_phy_type         High-speed PHY interface type
+ *                       0 - High-speed interface not supported
+ *                       1 - UTMI+
+ *                       2 - ULPI
+ *                       3 - UTMI+ and ULPI
+ * @fs_phy_type         Full-speed PHY interface type
+ *                       0 - Full speed interface not supported
+ *                       1 - Dedicated full speed interface
+ *                       2 - FS pins shared with UTMI+ pins
+ *                       3 - FS pins shared with ULPI pins
+ * @total_fifo_size:    Total internal RAM for FIFOs (bytes)
+ * @utmi_phy_data_width UTMI+ PHY data width
+ *                       0 - 8 bits
+ *                       1 - 16 bits
+ *                       2 - 8 or 16 bits
+ * @snpsid:             Value from SNPSID register
+ */
+struct dwc2_hw_params {
+       unsigned op_mode:3;
+       unsigned arch:2;
+       unsigned dma_desc_enable:1;
+       unsigned enable_dynamic_fifo:1;
+       unsigned en_multiple_tx_fifo:1;
+       unsigned host_rx_fifo_size:16;
+       unsigned host_nperio_tx_fifo_size:16;
+       unsigned host_perio_tx_fifo_size:16;
+       unsigned nperio_tx_q_depth:3;
+       unsigned host_perio_tx_q_depth:3;
+       unsigned dev_token_q_depth:5;
+       unsigned max_transfer_size:26;
+       unsigned max_packet_count:11;
+       unsigned host_channels:5;
+       unsigned hs_phy_type:2;
+       unsigned fs_phy_type:2;
+       unsigned i2c_enable:1;
+       unsigned num_dev_ep:4;
+       unsigned num_dev_perio_in_ep:4;
+       unsigned total_fifo_size:16;
+       unsigned power_optimized:1;
+       unsigned utmi_phy_data_width:2;
+       u32 snpsid;
+};
+
+/**
+ * struct dwc2_hsotg - Holds the state of the driver, including the non-periodic
+ * and periodic schedules
+ *
+ * @dev:                The struct device pointer
+ * @regs:              Pointer to controller regs
+ * @core_params:        Parameters that define how the core should be configured
+ * @hw_params:          Parameters that were autodetected from the
+ *                      hardware registers
+ * @op_state:           The operational State, during transitions (a_host=>
+ *                      a_peripheral and b_device=>b_host) this may not match
+ *                      the core, but allows the software to determine
+ *                      transitions
+ * @queuing_high_bandwidth: True if multiple packets of a high-bandwidth
+ *                      transfer are in process of being queued
+ * @srp_success:        Stores status of SRP request in the case of a FS PHY
+ *                      with an I2C interface
+ * @wq_otg:             Workqueue object used for handling of some interrupts
+ * @wf_otg:             Work object for handling Connector ID Status Change
+ *                      interrupt
+ * @wkp_timer:          Timer object for handling Wakeup Detected interrupt
+ * @lx_state:           Lx state of connected device
+ * @flags:              Flags for handling root port state changes
+ * @non_periodic_sched_inactive: Inactive QHs in the non-periodic schedule.
+ *                      Transfers associated with these QHs are not currently
+ *                      assigned to a host channel.
+ * @non_periodic_sched_active: Active QHs in the non-periodic schedule.
+ *                      Transfers associated with these QHs are currently
+ *                      assigned to a host channel.
+ * @non_periodic_qh_ptr: Pointer to next QH to process in the active
+ *                      non-periodic schedule
+ * @periodic_sched_inactive: Inactive QHs in the periodic schedule. This is a
+ *                      list of QHs for periodic transfers that are _not_
+ *                      scheduled for the next frame. Each QH in the list has an
+ *                      interval counter that determines when it needs to be
+ *                      scheduled for execution. This scheduling mechanism
+ *                      allows only a simple calculation for periodic bandwidth
+ *                      used (i.e. must assume that all periodic transfers may
+ *                      need to execute in the same frame). However, it greatly
+ *                      simplifies scheduling and should be sufficient for the
+ *                      vast majority of OTG hosts, which need to connect to a
+ *                      small number of peripherals at one time. Items move from
+ *                      this list to periodic_sched_ready when the QH interval
+ *                      counter is 0 at SOF.
+ * @periodic_sched_ready:  List of periodic QHs that are ready for execution in
+ *                      the next frame, but have not yet been assigned to host
+ *                      channels. Items move from this list to
+ *                      periodic_sched_assigned as host channels become
+ *                      available during the current frame.
+ * @periodic_sched_assigned: List of periodic QHs to be executed in the next
+ *                      frame that are assigned to host channels. Items move
+ *                      from this list to periodic_sched_queued as the
+ *                      transactions for the QH are queued to the DWC_otg
+ *                      controller.
+ * @periodic_sched_queued: List of periodic QHs that have been queued for
+ *                      execution. Items move from this list to either
+ *                      periodic_sched_inactive or periodic_sched_ready when the
+ *                      channel associated with the transfer is released. If the
+ *                      interval for the QH is 1, the item moves to
+ *                      periodic_sched_ready because it must be rescheduled for
+ *                      the next frame. Otherwise, the item moves to
+ *                      periodic_sched_inactive.
+ * @periodic_usecs:     Total bandwidth claimed so far for periodic transfers.
+ *                      This value is in microseconds per (micro)frame. The
+ *                      assumption is that all periodic transfers may occur in
+ *                      the same (micro)frame.
+ * @frame_usecs:        Internal variable used by the microframe scheduler
+ * @frame_number:       Frame number read from the core at SOF. The value ranges
+ *                      from 0 to HFNUM_MAX_FRNUM.
+ * @periodic_qh_count:  Count of periodic QHs, if using several eps. Used for
+ *                      SOF enable/disable.
+ * @free_hc_list:       Free host channels in the controller. This is a list of
+ *                      struct dwc2_host_chan items.
+ * @periodic_channels:  Number of host channels assigned to periodic transfers.
+ *                      Currently assuming that there is a dedicated host
+ *                      channel for each periodic transaction and at least one
+ *                      host channel is available for non-periodic transactions.
+ * @non_periodic_channels: Number of host channels assigned to non-periodic
+ *                      transfers
+ * @available_host_channels Number of host channels available for the microframe
+ *                      scheduler to use
+ * @hc_ptr_array:       Array of pointers to the host channel descriptors.
+ *                      Allows accessing a host channel descriptor given the
+ *                      host channel number. This is useful in interrupt
+ *                      handlers.
+ * @status_buf:         Buffer used for data received during the status phase of
+ *                      a control transfer.
+ * @status_buf_dma:     DMA address for status_buf
+ * @start_work:         Delayed work for handling host A-cable connection
+ * @reset_work:         Delayed work for handling a port reset
+ * @lock:               Spinlock that protects all the driver data structures
+ * @priv:               Stores a pointer to the struct usb_hcd
+ * @otg_port:           OTG port number
+ * @frame_list:         Frame list
+ * @frame_list_dma:     Frame list DMA address
+ */
+struct dwc2_hsotg {
+       struct device *dev;
+       void __iomem *regs;
+       /** Params detected from hardware */
+       struct dwc2_hw_params hw_params;
+       /** Params to actually use */
+       struct dwc2_core_params *core_params;
+       enum usb_otg_state op_state;
+
+       unsigned int queuing_high_bandwidth:1;
+       unsigned int srp_success:1;
+
+       struct workqueue_struct *wq_otg;
+       struct work_struct wf_otg;
+       struct timer_list wkp_timer;
+       enum dwc2_lx_state lx_state;
+
+       union dwc2_hcd_internal_flags {
+               u32 d32;
+               struct {
+                       unsigned port_connect_status_change:1;
+                       unsigned port_connect_status:1;
+                       unsigned port_reset_change:1;
+                       unsigned port_enable_change:1;
+                       unsigned port_suspend_change:1;
+                       unsigned port_over_current_change:1;
+                       unsigned port_l1_change:1;
+                       unsigned reserved:26;
+               } b;
+       } flags;
+
+       struct list_head non_periodic_sched_inactive;
+       struct list_head non_periodic_sched_active;
+       struct list_head *non_periodic_qh_ptr;
+       struct list_head periodic_sched_inactive;
+       struct list_head periodic_sched_ready;
+       struct list_head periodic_sched_assigned;
+       struct list_head periodic_sched_queued;
+       u16 periodic_usecs;
+       u16 frame_usecs[8];
+       u16 frame_number;
+       u16 periodic_qh_count;
+
+#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
+#define FRAME_NUM_ARRAY_SIZE 1000
+       u16 last_frame_num;
+       u16 *frame_num_array;
+       u16 *last_frame_num_array;
+       int frame_num_idx;
+       int dumped_frame_num_array;
+#endif
+
+       struct list_head free_hc_list;
+       int periodic_channels;
+       int non_periodic_channels;
+       int available_host_channels;
+       struct dwc2_host_chan *hc_ptr_array[MAX_EPS_CHANNELS];
+       u8 *status_buf;
+       dma_addr_t status_buf_dma;
+#define DWC2_HCD_STATUS_BUF_SIZE 64
+
+       struct delayed_work start_work;
+       struct delayed_work reset_work;
+       spinlock_t lock;
+       void *priv;
+       u8 otg_port;
+       u32 *frame_list;
+       dma_addr_t frame_list_dma;
+
+       /* DWC OTG HW Release versions */
+#define DWC2_CORE_REV_2_71a    0x4f54271a
+#define DWC2_CORE_REV_2_90a    0x4f54290a
+#define DWC2_CORE_REV_2_92a    0x4f54292a
+#define DWC2_CORE_REV_2_94a    0x4f54294a
+#define DWC2_CORE_REV_3_00a    0x4f54300a
+
+#ifdef DEBUG
+       u32 frrem_samples;
+       u64 frrem_accum;
+
+       u32 hfnum_7_samples_a;
+       u64 hfnum_7_frrem_accum_a;
+       u32 hfnum_0_samples_a;
+       u64 hfnum_0_frrem_accum_a;
+       u32 hfnum_other_samples_a;
+       u64 hfnum_other_frrem_accum_a;
+
+       u32 hfnum_7_samples_b;
+       u64 hfnum_7_frrem_accum_b;
+       u32 hfnum_0_samples_b;
+       u64 hfnum_0_frrem_accum_b;
+       u32 hfnum_other_samples_b;
+       u64 hfnum_other_frrem_accum_b;
+#endif
+};
+
+/* Reasons for halting a host channel */
+enum dwc2_halt_status {
+       DWC2_HC_XFER_NO_HALT_STATUS,
+       DWC2_HC_XFER_COMPLETE,
+       DWC2_HC_XFER_URB_COMPLETE,
+       DWC2_HC_XFER_ACK,
+       DWC2_HC_XFER_NAK,
+       DWC2_HC_XFER_NYET,
+       DWC2_HC_XFER_STALL,
+       DWC2_HC_XFER_XACT_ERR,
+       DWC2_HC_XFER_FRAME_OVERRUN,
+       DWC2_HC_XFER_BABBLE_ERR,
+       DWC2_HC_XFER_DATA_TOGGLE_ERR,
+       DWC2_HC_XFER_AHB_ERR,
+       DWC2_HC_XFER_PERIODIC_INCOMPLETE,
+       DWC2_HC_XFER_URB_DEQUEUE,
+};
+
+/*
+ * The following functions support initialization of the core driver component
+ * and the DWC_otg controller
+ */
+extern void dwc2_core_host_init(struct dwc2_hsotg *hsotg);
+
+/*
+ * Host core Functions.
+ * The following functions support managing the DWC_otg controller in host
+ * mode.
+ */
+extern void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan);
+extern void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
+                        enum dwc2_halt_status halt_status);
+extern void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg,
+                           struct dwc2_host_chan *chan);
+extern void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
+                                  struct dwc2_host_chan *chan);
+extern void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
+                                       struct dwc2_host_chan *chan);
+extern int dwc2_hc_continue_transfer(struct dwc2_hsotg *hsotg,
+                                    struct dwc2_host_chan *chan);
+extern void dwc2_hc_do_ping(struct dwc2_hsotg *hsotg,
+                           struct dwc2_host_chan *chan);
+extern void dwc2_enable_host_interrupts(struct dwc2_hsotg *hsotg);
+extern void dwc2_disable_host_interrupts(struct dwc2_hsotg *hsotg);
+
+extern u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg);
+extern bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg);
+
+/*
+ * Common core Functions.
+ * The following functions support managing the DWC_otg controller in either
+ * device or host mode.
+ */
+extern void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes);
+extern void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num);
+extern void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg);
+
+extern int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq);
+extern void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd);
+extern void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd);
+
+/* This function should be called on every hardware interrupt. */
+extern irqreturn_t dwc2_handle_common_intr(int irq, void *dev);
+
+/* OTG Core Parameters */
+
+/*
+ * Specifies the OTG capabilities. The driver will automatically
+ * detect the value for this parameter if none is specified.
+ * 0 - HNP and SRP capable (default)
+ * 1 - SRP Only capable
+ * 2 - No HNP/SRP capable
+ */
+extern void dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg, int val);
+#define DWC2_CAP_PARAM_HNP_SRP_CAPABLE         0
+#define DWC2_CAP_PARAM_SRP_ONLY_CAPABLE                1
+#define DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE      2
+
+/*
+ * Specifies whether to use slave or DMA mode for accessing the data
+ * FIFOs. The driver will automatically detect the value for this
+ * parameter if none is specified.
+ * 0 - Slave
+ * 1 - DMA (default, if available)
+ */
+extern void dwc2_set_param_dma_enable(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * When DMA mode is enabled specifies whether to use
+ * address DMA or DMA Descritor mode for accessing the data
+ * FIFOs in device mode. The driver will automatically detect
+ * the value for this parameter if none is specified.
+ * 0 - address DMA
+ * 1 - DMA Descriptor(default, if available)
+ */
+extern void dwc2_set_param_dma_desc_enable(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * Specifies the maximum speed of operation in host and device mode.
+ * The actual speed depends on the speed of the attached device and
+ * the value of phy_type. The actual speed depends on the speed of the
+ * attached device.
+ * 0 - High Speed (default)
+ * 1 - Full Speed
+ */
+extern void dwc2_set_param_speed(struct dwc2_hsotg *hsotg, int val);
+#define DWC2_SPEED_PARAM_HIGH  0
+#define DWC2_SPEED_PARAM_FULL  1
+
+/*
+ * Specifies whether low power mode is supported when attached
+ * to a Full Speed or Low Speed device in host mode.
+ *
+ * 0 - Don't support low power mode (default)
+ * 1 - Support low power mode
+ */
+extern void dwc2_set_param_host_support_fs_ls_low_power(
+               struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * Specifies the PHY clock rate in low power mode when connected to a
+ * Low Speed device in host mode. This parameter is applicable only if
+ * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
+ * then defaults to 6 MHZ otherwise 48 MHZ.
+ *
+ * 0 - 48 MHz
+ * 1 - 6 MHz
+ */
+extern void dwc2_set_param_host_ls_low_power_phy_clk(struct dwc2_hsotg *hsotg,
+                                                    int val);
+#define DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ     0
+#define DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ      1
+
+/*
+ * 0 - Use cC FIFO size parameters
+ * 1 - Allow dynamic FIFO sizing (default)
+ */
+extern void dwc2_set_param_enable_dynamic_fifo(struct dwc2_hsotg *hsotg,
+                                              int val);
+
+/*
+ * Number of 4-byte words in the Rx FIFO in host mode when dynamic
+ * FIFO sizing is enabled.
+ * 16 to 32768 (default 1024)
+ */
+extern void dwc2_set_param_host_rx_fifo_size(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * Number of 4-byte words in the non-periodic Tx FIFO in host mode
+ * when Dynamic FIFO sizing is enabled in the core.
+ * 16 to 32768 (default 256)
+ */
+extern void dwc2_set_param_host_nperio_tx_fifo_size(struct dwc2_hsotg *hsotg,
+                                                   int val);
+
+/*
+ * Number of 4-byte words in the host periodic Tx FIFO when dynamic
+ * FIFO sizing is enabled.
+ * 16 to 32768 (default 256)
+ */
+extern void dwc2_set_param_host_perio_tx_fifo_size(struct dwc2_hsotg *hsotg,
+                                                  int val);
+
+/*
+ * The maximum transfer size supported in bytes.
+ * 2047 to 65,535  (default 65,535)
+ */
+extern void dwc2_set_param_max_transfer_size(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * The maximum number of packets in a transfer.
+ * 15 to 511  (default 511)
+ */
+extern void dwc2_set_param_max_packet_count(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * The number of host channel registers to use.
+ * 1 to 16 (default 11)
+ * Note: The FPGA configuration supports a maximum of 11 host channels.
+ */
+extern void dwc2_set_param_host_channels(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * Specifies the type of PHY interface to use. By default, the driver
+ * will automatically detect the phy_type.
+ *
+ * 0 - Full Speed PHY
+ * 1 - UTMI+ (default)
+ * 2 - ULPI
+ */
+extern void dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg, int val);
+#define DWC2_PHY_TYPE_PARAM_FS         0
+#define DWC2_PHY_TYPE_PARAM_UTMI       1
+#define DWC2_PHY_TYPE_PARAM_ULPI       2
+
+/*
+ * Specifies the UTMI+ Data Width. This parameter is
+ * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
+ * PHY_TYPE, this parameter indicates the data width between
+ * the MAC and the ULPI Wrapper.) Also, this parameter is
+ * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
+ * to "8 and 16 bits", meaning that the core has been
+ * configured to work at either data path width.
+ *
+ * 8 or 16 bits (default 16)
+ */
+extern void dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * Specifies whether the ULPI operates at double or single
+ * data rate. This parameter is only applicable if PHY_TYPE is
+ * ULPI.
+ *
+ * 0 - single data rate ULPI interface with 8 bit wide data
+ * bus (default)
+ * 1 - double data rate ULPI interface with 4 bit wide data
+ * bus
+ */
+extern void dwc2_set_param_phy_ulpi_ddr(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * Specifies whether to use the internal or external supply to
+ * drive the vbus with a ULPI phy.
+ */
+extern void dwc2_set_param_phy_ulpi_ext_vbus(struct dwc2_hsotg *hsotg, int val);
+#define DWC2_PHY_ULPI_INTERNAL_VBUS    0
+#define DWC2_PHY_ULPI_EXTERNAL_VBUS    1
+
+/*
+ * Specifies whether to use the I2Cinterface for full speed PHY. This
+ * parameter is only applicable if PHY_TYPE is FS.
+ * 0 - No (default)
+ * 1 - Yes
+ */
+extern void dwc2_set_param_i2c_enable(struct dwc2_hsotg *hsotg, int val);
+
+extern void dwc2_set_param_ulpi_fs_ls(struct dwc2_hsotg *hsotg, int val);
+
+extern void dwc2_set_param_ts_dline(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * Specifies whether dedicated transmit FIFOs are
+ * enabled for non periodic IN endpoints in device mode
+ * 0 - No
+ * 1 - Yes
+ */
+extern void dwc2_set_param_en_multiple_tx_fifo(struct dwc2_hsotg *hsotg,
+                                              int val);
+
+extern void dwc2_set_param_reload_ctl(struct dwc2_hsotg *hsotg, int val);
+
+extern void dwc2_set_param_ahbcfg(struct dwc2_hsotg *hsotg, int val);
+
+extern void dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * Dump core registers and SPRAM
+ */
+extern void dwc2_dump_dev_registers(struct dwc2_hsotg *hsotg);
+extern void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg);
+extern void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg);
+
+/*
+ * Return OTG version - either 1.3 or 2.0
+ */
+extern u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg);
+
+#endif /* __DWC2_CORE_H__ */
diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
new file mode 100644 (file)
index 0000000..8205799
--- /dev/null
@@ -0,0 +1,492 @@
+/*
+ * core_intr.c - DesignWare HS OTG Controller common interrupt handling
+ *
+ * Copyright (C) 2004-2013 Synopsys, Inc.
+ *
+ * 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") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * 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.
+ */
+
+/*
+ * This file contains the common interrupt handlers
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <linux/usb/hcd.h>
+#include <linux/usb/ch11.h>
+
+#include "core.h"
+#include "hcd.h"
+
+static const char *dwc2_op_state_str(struct dwc2_hsotg *hsotg)
+{
+       switch (hsotg->op_state) {
+       case OTG_STATE_A_HOST:
+               return "a_host";
+       case OTG_STATE_A_SUSPEND:
+               return "a_suspend";
+       case OTG_STATE_A_PERIPHERAL:
+               return "a_peripheral";
+       case OTG_STATE_B_PERIPHERAL:
+               return "b_peripheral";
+       case OTG_STATE_B_HOST:
+               return "b_host";
+       default:
+               return "unknown";
+       }
+}
+
+/**
+ * dwc2_handle_mode_mismatch_intr() - Logs a mode mismatch warning message
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ */
+static void dwc2_handle_mode_mismatch_intr(struct dwc2_hsotg *hsotg)
+{
+       dev_warn(hsotg->dev, "Mode Mismatch Interrupt: currently in %s mode\n",
+                dwc2_is_host_mode(hsotg) ? "Host" : "Device");
+
+       /* Clear interrupt */
+       writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS);
+}
+
+/**
+ * dwc2_handle_otg_intr() - Handles the OTG Interrupts. It reads the OTG
+ * Interrupt Register (GOTGINT) to determine what interrupt has occurred.
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ */
+static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
+{
+       u32 gotgint;
+       u32 gotgctl;
+       u32 gintmsk;
+
+       gotgint = readl(hsotg->regs + GOTGINT);
+       gotgctl = readl(hsotg->regs + GOTGCTL);
+       dev_dbg(hsotg->dev, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint,
+               dwc2_op_state_str(hsotg));
+
+       if (gotgint & GOTGINT_SES_END_DET) {
+               dev_dbg(hsotg->dev,
+                       " ++OTG Interrupt: Session End Detected++ (%s)\n",
+                       dwc2_op_state_str(hsotg));
+               gotgctl = readl(hsotg->regs + GOTGCTL);
+
+               if (hsotg->op_state == OTG_STATE_B_HOST) {
+                       hsotg->op_state = OTG_STATE_B_PERIPHERAL;
+               } else {
+                       /*
+                        * If not B_HOST and Device HNP still set, HNP did
+                        * not succeed!
+                        */
+                       if (gotgctl & GOTGCTL_DEVHNPEN) {
+                               dev_dbg(hsotg->dev, "Session End Detected\n");
+                               dev_err(hsotg->dev,
+                                       "Device Not Connected/Responding!\n");
+                       }
+
+                       /*
+                        * If Session End Detected the B-Cable has been
+                        * disconnected
+                        */
+                       /* Reset to a clean state */
+                       hsotg->lx_state = DWC2_L0;
+               }
+
+               gotgctl = readl(hsotg->regs + GOTGCTL);
+               gotgctl &= ~GOTGCTL_DEVHNPEN;
+               writel(gotgctl, hsotg->regs + GOTGCTL);
+       }
+
+       if (gotgint & GOTGINT_SES_REQ_SUC_STS_CHNG) {
+               dev_dbg(hsotg->dev,
+                       " ++OTG Interrupt: Session Request Success Status Change++\n");
+               gotgctl = readl(hsotg->regs + GOTGCTL);
+               if (gotgctl & GOTGCTL_SESREQSCS) {
+                       if (hsotg->core_params->phy_type ==
+                                       DWC2_PHY_TYPE_PARAM_FS
+                           && hsotg->core_params->i2c_enable > 0) {
+                               hsotg->srp_success = 1;
+                       } else {
+                               /* Clear Session Request */
+                               gotgctl = readl(hsotg->regs + GOTGCTL);
+                               gotgctl &= ~GOTGCTL_SESREQ;
+                               writel(gotgctl, hsotg->regs + GOTGCTL);
+                       }
+               }
+       }
+
+       if (gotgint & GOTGINT_HST_NEG_SUC_STS_CHNG) {
+               /*
+                * Print statements during the HNP interrupt handling
+                * can cause it to fail
+                */
+               gotgctl = readl(hsotg->regs + GOTGCTL);
+               /*
+                * WA for 3.00a- HW is not setting cur_mode, even sometimes
+                * this does not help
+                */
+               if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a)
+                       udelay(100);
+               if (gotgctl & GOTGCTL_HSTNEGSCS) {
+                       if (dwc2_is_host_mode(hsotg)) {
+                               hsotg->op_state = OTG_STATE_B_HOST;
+                               /*
+                                * Need to disable SOF interrupt immediately.
+                                * When switching from device to host, the PCD
+                                * interrupt handler won't handle the interrupt
+                                * if host mode is already set. The HCD
+                                * interrupt handler won't get called if the
+                                * HCD state is HALT. This means that the
+                                * interrupt does not get handled and Linux
+                                * complains loudly.
+                                */
+                               gintmsk = readl(hsotg->regs + GINTMSK);
+                               gintmsk &= ~GINTSTS_SOF;
+                               writel(gintmsk, hsotg->regs + GINTMSK);
+
+                               /*
+                                * Call callback function with spin lock
+                                * released
+                                */
+                               spin_unlock(&hsotg->lock);
+
+                               /* Initialize the Core for Host mode */
+                               dwc2_hcd_start(hsotg);
+                               spin_lock(&hsotg->lock);
+                               hsotg->op_state = OTG_STATE_B_HOST;
+                       }
+               } else {
+                       gotgctl = readl(hsotg->regs + GOTGCTL);
+                       gotgctl &= ~(GOTGCTL_HNPREQ | GOTGCTL_DEVHNPEN);
+                       writel(gotgctl, hsotg->regs + GOTGCTL);
+                       dev_dbg(hsotg->dev, "HNP Failed\n");
+                       dev_err(hsotg->dev,
+                               "Device Not Connected/Responding\n");
+               }
+       }
+
+       if (gotgint & GOTGINT_HST_NEG_DET) {
+               /*
+                * The disconnect interrupt is set at the same time as
+                * Host Negotiation Detected. During the mode switch all
+                * interrupts are cleared so the disconnect interrupt
+                * handler will not get executed.
+                */
+               dev_dbg(hsotg->dev,
+                       " ++OTG Interrupt: Host Negotiation Detected++ (%s)\n",
+                       (dwc2_is_host_mode(hsotg) ? "Host" : "Device"));
+               if (dwc2_is_device_mode(hsotg)) {
+                       dev_dbg(hsotg->dev, "a_suspend->a_peripheral (%d)\n",
+                               hsotg->op_state);
+                       spin_unlock(&hsotg->lock);
+                       dwc2_hcd_disconnect(hsotg);
+                       spin_lock(&hsotg->lock);
+                       hsotg->op_state = OTG_STATE_A_PERIPHERAL;
+               } else {
+                       /* Need to disable SOF interrupt immediately */
+                       gintmsk = readl(hsotg->regs + GINTMSK);
+                       gintmsk &= ~GINTSTS_SOF;
+                       writel(gintmsk, hsotg->regs + GINTMSK);
+                       spin_unlock(&hsotg->lock);
+                       dwc2_hcd_start(hsotg);
+                       spin_lock(&hsotg->lock);
+                       hsotg->op_state = OTG_STATE_A_HOST;
+               }
+       }
+
+       if (gotgint & GOTGINT_A_DEV_TOUT_CHG)
+               dev_dbg(hsotg->dev,
+                       " ++OTG Interrupt: A-Device Timeout Change++\n");
+       if (gotgint & GOTGINT_DBNCE_DONE)
+               dev_dbg(hsotg->dev, " ++OTG Interrupt: Debounce Done++\n");
+
+       /* Clear GOTGINT */
+       writel(gotgint, hsotg->regs + GOTGINT);
+}
+
+/**
+ * dwc2_handle_conn_id_status_change_intr() - Handles the Connector ID Status
+ * Change Interrupt
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ * Reads the OTG Interrupt Register (GOTCTL) to determine whether this is a
+ * Device to Host Mode transition or a Host to Device Mode transition. This only
+ * occurs when the cable is connected/removed from the PHY connector.
+ */
+static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
+{
+       u32 gintmsk = readl(hsotg->regs + GINTMSK);
+
+       /* Need to disable SOF interrupt immediately */
+       gintmsk &= ~GINTSTS_SOF;
+       writel(gintmsk, hsotg->regs + GINTMSK);
+
+       dev_dbg(hsotg->dev, " ++Connector ID Status Change Interrupt++  (%s)\n",
+               dwc2_is_host_mode(hsotg) ? "Host" : "Device");
+
+       /*
+        * Need to schedule a work, as there are possible DELAY function calls.
+        * Release lock before scheduling workq as it holds spinlock during
+        * scheduling.
+        */
+       spin_unlock(&hsotg->lock);
+       queue_work(hsotg->wq_otg, &hsotg->wf_otg);
+       spin_lock(&hsotg->lock);
+
+       /* Clear interrupt */
+       writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS);
+}
+
+/**
+ * dwc2_handle_session_req_intr() - This interrupt indicates that a device is
+ * initiating the Session Request Protocol to request the host to turn on bus
+ * power so a new session can begin
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ * This handler responds by turning on bus power. If the DWC_otg controller is
+ * in low power mode, this handler brings the controller out of low power mode
+ * before turning on bus power.
+ */
+static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
+{
+       dev_dbg(hsotg->dev, "++Session Request Interrupt++\n");
+
+       /* Clear interrupt */
+       writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
+}
+
+/*
+ * This interrupt indicates that the DWC_otg controller has detected a
+ * resume or remote wakeup sequence. If the DWC_otg controller is in
+ * low power mode, the handler must brings the controller out of low
+ * power mode. The controller automatically begins resume signaling.
+ * The handler schedules a time to stop resume signaling.
+ */
+static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
+{
+       dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
+       dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
+
+       if (dwc2_is_device_mode(hsotg)) {
+               dev_dbg(hsotg->dev, "DSTS=0x%0x\n", readl(hsotg->regs + DSTS));
+               if (hsotg->lx_state == DWC2_L2) {
+                       u32 dctl = readl(hsotg->regs + DCTL);
+
+                       /* Clear Remote Wakeup Signaling */
+                       dctl &= ~DCTL_RMTWKUPSIG;
+                       writel(dctl, hsotg->regs + DCTL);
+               }
+               /* Change to L0 state */
+               hsotg->lx_state = DWC2_L0;
+       } else {
+               if (hsotg->lx_state != DWC2_L1) {
+                       u32 pcgcctl = readl(hsotg->regs + PCGCTL);
+
+                       /* Restart the Phy Clock */
+                       pcgcctl &= ~PCGCTL_STOPPCLK;
+                       writel(pcgcctl, hsotg->regs + PCGCTL);
+                       mod_timer(&hsotg->wkp_timer,
+                                 jiffies + msecs_to_jiffies(71));
+               } else {
+                       /* Change to L0 state */
+                       hsotg->lx_state = DWC2_L0;
+               }
+       }
+
+       /* Clear interrupt */
+       writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
+}
+
+/*
+ * This interrupt indicates that a device has been disconnected from the
+ * root port
+ */
+static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
+{
+       dev_dbg(hsotg->dev, "++Disconnect Detected Interrupt++ (%s) %s\n",
+               dwc2_is_host_mode(hsotg) ? "Host" : "Device",
+               dwc2_op_state_str(hsotg));
+
+       /* Change to L3 (OFF) state */
+       hsotg->lx_state = DWC2_L3;
+
+       writel(GINTSTS_DISCONNINT, hsotg->regs + GINTSTS);
+}
+
+/*
+ * This interrupt indicates that SUSPEND state has been detected on the USB.
+ *
+ * For HNP the USB Suspend interrupt signals the change from "a_peripheral"
+ * to "a_host".
+ *
+ * When power management is enabled the core will be put in low power mode.
+ */
+static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
+{
+       u32 dsts;
+
+       dev_dbg(hsotg->dev, "USB SUSPEND\n");
+
+       if (dwc2_is_device_mode(hsotg)) {
+               /*
+                * Check the Device status register to determine if the Suspend
+                * state is active
+                */
+               dsts = readl(hsotg->regs + DSTS);
+               dev_dbg(hsotg->dev, "DSTS=0x%0x\n", dsts);
+               dev_dbg(hsotg->dev,
+                       "DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
+                       !!(dsts & DSTS_SUSPSTS),
+                       hsotg->hw_params.power_optimized);
+       } else {
+               if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
+                       dev_dbg(hsotg->dev, "a_peripheral->a_host\n");
+
+                       /* Clear the a_peripheral flag, back to a_host */
+                       spin_unlock(&hsotg->lock);
+                       dwc2_hcd_start(hsotg);
+                       spin_lock(&hsotg->lock);
+                       hsotg->op_state = OTG_STATE_A_HOST;
+               }
+       }
+
+       /* Change to L2 (suspend) state */
+       hsotg->lx_state = DWC2_L2;
+
+       /* Clear interrupt */
+       writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
+}
+
+#define GINTMSK_COMMON (GINTSTS_WKUPINT | GINTSTS_SESSREQINT |         \
+                        GINTSTS_CONIDSTSCHNG | GINTSTS_OTGINT |        \
+                        GINTSTS_MODEMIS | GINTSTS_DISCONNINT |         \
+                        GINTSTS_USBSUSP | GINTSTS_PRTINT)
+
+/*
+ * This function returns the Core Interrupt register
+ */
+static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg)
+{
+       u32 gintsts;
+       u32 gintmsk;
+       u32 gahbcfg;
+       u32 gintmsk_common = GINTMSK_COMMON;
+
+       gintsts = readl(hsotg->regs + GINTSTS);
+       gintmsk = readl(hsotg->regs + GINTMSK);
+       gahbcfg = readl(hsotg->regs + GAHBCFG);
+
+       /* If any common interrupts set */
+       if (gintsts & gintmsk_common)
+               dev_dbg(hsotg->dev, "gintsts=%08x  gintmsk=%08x\n",
+                       gintsts, gintmsk);
+
+       if (gahbcfg & GAHBCFG_GLBL_INTR_EN)
+               return gintsts & gintmsk & gintmsk_common;
+       else
+               return 0;
+}
+
+/*
+ * Common interrupt handler
+ *
+ * The common interrupts are those that occur in both Host and Device mode.
+ * This handler handles the following interrupts:
+ * - Mode Mismatch Interrupt
+ * - OTG Interrupt
+ * - Connector ID Status Change Interrupt
+ * - Disconnect Interrupt
+ * - Session Request Interrupt
+ * - Resume / Remote Wakeup Detected Interrupt
+ * - Suspend Interrupt
+ */
+irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
+{
+       struct dwc2_hsotg *hsotg = dev;
+       u32 gintsts;
+       irqreturn_t retval = IRQ_NONE;
+
+       if (!dwc2_is_controller_alive(hsotg)) {
+               dev_warn(hsotg->dev, "Controller is dead\n");
+               goto out;
+       }
+
+       spin_lock(&hsotg->lock);
+
+       gintsts = dwc2_read_common_intr(hsotg);
+       if (gintsts & ~GINTSTS_PRTINT)
+               retval = IRQ_HANDLED;
+
+       if (gintsts & GINTSTS_MODEMIS)
+               dwc2_handle_mode_mismatch_intr(hsotg);
+       if (gintsts & GINTSTS_OTGINT)
+               dwc2_handle_otg_intr(hsotg);
+       if (gintsts & GINTSTS_CONIDSTSCHNG)
+               dwc2_handle_conn_id_status_change_intr(hsotg);
+       if (gintsts & GINTSTS_DISCONNINT)
+               dwc2_handle_disconnect_intr(hsotg);
+       if (gintsts & GINTSTS_SESSREQINT)
+               dwc2_handle_session_req_intr(hsotg);
+       if (gintsts & GINTSTS_WKUPINT)
+               dwc2_handle_wakeup_detected_intr(hsotg);
+       if (gintsts & GINTSTS_USBSUSP)
+               dwc2_handle_usb_suspend_intr(hsotg);
+
+       if (gintsts & GINTSTS_PRTINT) {
+               /*
+                * The port interrupt occurs while in device mode with HPRT0
+                * Port Enable/Disable
+                */
+               if (dwc2_is_device_mode(hsotg)) {
+                       dev_dbg(hsotg->dev,
+                               " --Port interrupt received in Device mode--\n");
+                       gintsts = GINTSTS_PRTINT;
+                       writel(gintsts, hsotg->regs + GINTSTS);
+                       retval = 1;
+               }
+       }
+
+       spin_unlock(&hsotg->lock);
+out:
+       return retval;
+}
+EXPORT_SYMBOL_GPL(dwc2_handle_common_intr);
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
new file mode 100644 (file)
index 0000000..07dfe85
--- /dev/null
@@ -0,0 +1,2990 @@
+/*
+ * hcd.c - DesignWare HS OTG Controller host-mode routines
+ *
+ * Copyright (C) 2004-2013 Synopsys, Inc.
+ *
+ * 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") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * 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.
+ */
+
+/*
+ * This file contains the core HCD code, and implements the Linux hc_driver
+ * API
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <linux/usb/hcd.h>
+#include <linux/usb/ch11.h>
+
+#include "core.h"
+#include "hcd.h"
+
+/**
+ * dwc2_dump_channel_info() - Prints the state of a host channel
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan:  Pointer to the channel to dump
+ *
+ * Must be called with interrupt disabled and spinlock held
+ *
+ * NOTE: This function will be removed once the peripheral controller code
+ * is integrated and the driver is stable
+ */
+static void dwc2_dump_channel_info(struct dwc2_hsotg *hsotg,
+                                  struct dwc2_host_chan *chan)
+{
+#ifdef VERBOSE_DEBUG
+       int num_channels = hsotg->core_params->host_channels;
+       struct dwc2_qh *qh;
+       u32 hcchar;
+       u32 hcsplt;
+       u32 hctsiz;
+       u32 hc_dma;
+       int i;
+
+       if (chan == NULL)
+               return;
+
+       hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
+       hcsplt = readl(hsotg->regs + HCSPLT(chan->hc_num));
+       hctsiz = readl(hsotg->regs + HCTSIZ(chan->hc_num));
+       hc_dma = readl(hsotg->regs + HCDMA(chan->hc_num));
+
+       dev_dbg(hsotg->dev, "  Assigned to channel %p:\n", chan);
+       dev_dbg(hsotg->dev, "    hcchar 0x%08x, hcsplt 0x%08x\n",
+               hcchar, hcsplt);
+       dev_dbg(hsotg->dev, "    hctsiz 0x%08x, hc_dma 0x%08x\n",
+               hctsiz, hc_dma);
+       dev_dbg(hsotg->dev, "    dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
+               chan->dev_addr, chan->ep_num, chan->ep_is_in);
+       dev_dbg(hsotg->dev, "    ep_type: %d\n", chan->ep_type);
+       dev_dbg(hsotg->dev, "    max_packet: %d\n", chan->max_packet);
+       dev_dbg(hsotg->dev, "    data_pid_start: %d\n", chan->data_pid_start);
+       dev_dbg(hsotg->dev, "    xfer_started: %d\n", chan->xfer_started);
+       dev_dbg(hsotg->dev, "    halt_status: %d\n", chan->halt_status);
+       dev_dbg(hsotg->dev, "    xfer_buf: %p\n", chan->xfer_buf);
+       dev_dbg(hsotg->dev, "    xfer_dma: %08lx\n",
+               (unsigned long)chan->xfer_dma);
+       dev_dbg(hsotg->dev, "    xfer_len: %d\n", chan->xfer_len);
+       dev_dbg(hsotg->dev, "    qh: %p\n", chan->qh);
+       dev_dbg(hsotg->dev, "  NP inactive sched:\n");
+       list_for_each_entry(qh, &hsotg->non_periodic_sched_inactive,
+                           qh_list_entry)
+               dev_dbg(hsotg->dev, "    %p\n", qh);
+       dev_dbg(hsotg->dev, "  NP active sched:\n");
+       list_for_each_entry(qh, &hsotg->non_periodic_sched_active,
+                           qh_list_entry)
+               dev_dbg(hsotg->dev, "    %p\n", qh);
+       dev_dbg(hsotg->dev, "  Channels:\n");
+       for (i = 0; i < num_channels; i++) {
+               struct dwc2_host_chan *chan = hsotg->hc_ptr_array[i];
+
+               dev_dbg(hsotg->dev, "    %2d: %p\n", i, chan);
+       }
+#endif /* VERBOSE_DEBUG */
+}
+
+/*
+ * Processes all the URBs in a single list of QHs. Completes them with
+ * -ETIMEDOUT and frees the QTD.
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+static void dwc2_kill_urbs_in_qh_list(struct dwc2_hsotg *hsotg,
+                                     struct list_head *qh_list)
+{
+       struct dwc2_qh *qh, *qh_tmp;
+       struct dwc2_qtd *qtd, *qtd_tmp;
+
+       list_for_each_entry_safe(qh, qh_tmp, qh_list, qh_list_entry) {
+               list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
+                                        qtd_list_entry) {
+                       dwc2_host_complete(hsotg, qtd, -ETIMEDOUT);
+                       dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
+               }
+       }
+}
+
+static void dwc2_qh_list_free(struct dwc2_hsotg *hsotg,
+                             struct list_head *qh_list)
+{
+       struct dwc2_qtd *qtd, *qtd_tmp;
+       struct dwc2_qh *qh, *qh_tmp;
+       unsigned long flags;
+
+       if (!qh_list->next)
+               /* The list hasn't been initialized yet */
+               return;
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+
+       /* Ensure there are no QTDs or URBs left */
+       dwc2_kill_urbs_in_qh_list(hsotg, qh_list);
+
+       list_for_each_entry_safe(qh, qh_tmp, qh_list, qh_list_entry) {
+               dwc2_hcd_qh_unlink(hsotg, qh);
+
+               /* Free each QTD in the QH's QTD list */
+               list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
+                                        qtd_list_entry)
+                       dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
+
+               spin_unlock_irqrestore(&hsotg->lock, flags);
+               dwc2_hcd_qh_free(hsotg, qh);
+               spin_lock_irqsave(&hsotg->lock, flags);
+       }
+
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+}
+
+/*
+ * Responds with an error status of -ETIMEDOUT to all URBs in the non-periodic
+ * and periodic schedules. The QTD associated with each URB is removed from
+ * the schedule and freed. This function may be called when a disconnect is
+ * detected or when the HCD is being stopped.
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+static void dwc2_kill_all_urbs(struct dwc2_hsotg *hsotg)
+{
+       dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_inactive);
+       dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_active);
+       dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_inactive);
+       dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_ready);
+       dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_assigned);
+       dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_queued);
+}
+
+/**
+ * dwc2_hcd_start() - Starts the HCD when switching to Host mode
+ *
+ * @hsotg: Pointer to struct dwc2_hsotg
+ */
+void dwc2_hcd_start(struct dwc2_hsotg *hsotg)
+{
+       u32 hprt0;
+
+       if (hsotg->op_state == OTG_STATE_B_HOST) {
+               /*
+                * Reset the port. During a HNP mode switch the reset
+                * needs to occur within 1ms and have a duration of at
+                * least 50ms.
+                */
+               hprt0 = dwc2_read_hprt0(hsotg);
+               hprt0 |= HPRT0_RST;
+               writel(hprt0, hsotg->regs + HPRT0);
+       }
+
+       queue_delayed_work(hsotg->wq_otg, &hsotg->start_work,
+                          msecs_to_jiffies(50));
+}
+
+/* Must be called with interrupt disabled and spinlock held */
+static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg)
+{
+       int num_channels = hsotg->core_params->host_channels;
+       struct dwc2_host_chan *channel;
+       u32 hcchar;
+       int i;
+
+       if (hsotg->core_params->dma_enable <= 0) {
+               /* Flush out any channel requests in slave mode */
+               for (i = 0; i < num_channels; i++) {
+                       channel = hsotg->hc_ptr_array[i];
+                       if (!list_empty(&channel->hc_list_entry))
+                               continue;
+                       hcchar = readl(hsotg->regs + HCCHAR(i));
+                       if (hcchar & HCCHAR_CHENA) {
+                               hcchar &= ~(HCCHAR_CHENA | HCCHAR_EPDIR);
+                               hcchar |= HCCHAR_CHDIS;
+                               writel(hcchar, hsotg->regs + HCCHAR(i));
+                       }
+               }
+       }
+
+       for (i = 0; i < num_channels; i++) {
+               channel = hsotg->hc_ptr_array[i];
+               if (!list_empty(&channel->hc_list_entry))
+                       continue;
+               hcchar = readl(hsotg->regs + HCCHAR(i));
+               if (hcchar & HCCHAR_CHENA) {
+                       /* Halt the channel */
+                       hcchar |= HCCHAR_CHDIS;
+                       writel(hcchar, hsotg->regs + HCCHAR(i));
+               }
+
+               dwc2_hc_cleanup(hsotg, channel);
+               list_add_tail(&channel->hc_list_entry, &hsotg->free_hc_list);
+               /*
+                * Added for Descriptor DMA to prevent channel double cleanup in
+                * release_channel_ddma(), which is called from ep_disable when
+                * device disconnects
+                */
+               channel->qh = NULL;
+       }
+}
+
+/**
+ * dwc2_hcd_disconnect() - Handles disconnect of the HCD
+ *
+ * @hsotg: Pointer to struct dwc2_hsotg
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
+{
+       u32 intr;
+
+       /* Set status flags for the hub driver */
+       hsotg->flags.b.port_connect_status_change = 1;
+       hsotg->flags.b.port_connect_status = 0;
+
+       /*
+        * Shutdown any transfers in process by clearing the Tx FIFO Empty
+        * interrupt mask and status bits and disabling subsequent host
+        * channel interrupts.
+        */
+       intr = readl(hsotg->regs + GINTMSK);
+       intr &= ~(GINTSTS_NPTXFEMP | GINTSTS_PTXFEMP | GINTSTS_HCHINT);
+       writel(intr, hsotg->regs + GINTMSK);
+       intr = GINTSTS_NPTXFEMP | GINTSTS_PTXFEMP | GINTSTS_HCHINT;
+       writel(intr, hsotg->regs + GINTSTS);
+
+       /*
+        * Turn off the vbus power only if the core has transitioned to device
+        * mode. If still in host mode, need to keep power on to detect a
+        * reconnection.
+        */
+       if (dwc2_is_device_mode(hsotg)) {
+               if (hsotg->op_state != OTG_STATE_A_SUSPEND) {
+                       dev_dbg(hsotg->dev, "Disconnect: PortPower off\n");
+                       writel(0, hsotg->regs + HPRT0);
+               }
+
+               dwc2_disable_host_interrupts(hsotg);
+       }
+
+       /* Respond with an error status to all URBs in the schedule */
+       dwc2_kill_all_urbs(hsotg);
+
+       if (dwc2_is_host_mode(hsotg))
+               /* Clean up any host channels that were in use */
+               dwc2_hcd_cleanup_channels(hsotg);
+
+       dwc2_host_disconnect(hsotg);
+}
+
+/**
+ * dwc2_hcd_rem_wakeup() - Handles Remote Wakeup
+ *
+ * @hsotg: Pointer to struct dwc2_hsotg
+ */
+static void dwc2_hcd_rem_wakeup(struct dwc2_hsotg *hsotg)
+{
+       if (hsotg->lx_state == DWC2_L2)
+               hsotg->flags.b.port_suspend_change = 1;
+       else
+               hsotg->flags.b.port_l1_change = 1;
+}
+
+/**
+ * dwc2_hcd_stop() - Halts the DWC_otg host mode operations in a clean manner
+ *
+ * @hsotg: Pointer to struct dwc2_hsotg
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+void dwc2_hcd_stop(struct dwc2_hsotg *hsotg)
+{
+       dev_dbg(hsotg->dev, "DWC OTG HCD STOP\n");
+
+       /*
+        * The root hub should be disconnected before this function is called.
+        * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
+        * and the QH lists (via ..._hcd_endpoint_disable).
+        */
+
+       /* Turn off all host-specific interrupts */
+       dwc2_disable_host_interrupts(hsotg);
+
+       /* Turn off the vbus power */
+       dev_dbg(hsotg->dev, "PortPower off\n");
+       writel(0, hsotg->regs + HPRT0);
+}
+
+static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
+                               struct dwc2_hcd_urb *urb, void **ep_handle,
+                               gfp_t mem_flags)
+{
+       struct dwc2_qtd *qtd;
+       unsigned long flags;
+       u32 intr_mask;
+       int retval;
+       int dev_speed;
+
+       if (!hsotg->flags.b.port_connect_status) {
+               /* No longer connected */
+               dev_err(hsotg->dev, "Not connected\n");
+               return -ENODEV;
+       }
+
+       dev_speed = dwc2_host_get_speed(hsotg, urb->priv);
+
+       /* Some configurations cannot support LS traffic on a FS root port */
+       if ((dev_speed == USB_SPEED_LOW) &&
+           (hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED) &&
+           (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI)) {
+               u32 hprt0 = readl(hsotg->regs + HPRT0);
+               u32 prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
+
+               if (prtspd == HPRT0_SPD_FULL_SPEED)
+                       return -ENODEV;
+       }
+
+       qtd = kzalloc(sizeof(*qtd), mem_flags);
+       if (!qtd)
+               return -ENOMEM;
+
+       dwc2_hcd_qtd_init(qtd, urb);
+       retval = dwc2_hcd_qtd_add(hsotg, qtd, (struct dwc2_qh **)ep_handle,
+                                 mem_flags);
+       if (retval) {
+               dev_err(hsotg->dev,
+                       "DWC OTG HCD URB Enqueue failed adding QTD. Error status %d\n",
+                       retval);
+               kfree(qtd);
+               return retval;
+       }
+
+       intr_mask = readl(hsotg->regs + GINTMSK);
+       if (!(intr_mask & GINTSTS_SOF)) {
+               enum dwc2_transaction_type tr_type;
+
+               if (qtd->qh->ep_type == USB_ENDPOINT_XFER_BULK &&
+                   !(qtd->urb->flags & URB_GIVEBACK_ASAP))
+                       /*
+                        * Do not schedule SG transactions until qtd has
+                        * URB_GIVEBACK_ASAP set
+                        */
+                       return 0;
+
+               spin_lock_irqsave(&hsotg->lock, flags);
+               tr_type = dwc2_hcd_select_transactions(hsotg);
+               if (tr_type != DWC2_TRANSACTION_NONE)
+                       dwc2_hcd_queue_transactions(hsotg, tr_type);
+               spin_unlock_irqrestore(&hsotg->lock, flags);
+       }
+
+       return 0;
+}
+
+/* Must be called with interrupt disabled and spinlock held */
+static int dwc2_hcd_urb_dequeue(struct dwc2_hsotg *hsotg,
+                               struct dwc2_hcd_urb *urb)
+{
+       struct dwc2_qh *qh;
+       struct dwc2_qtd *urb_qtd;
+
+       urb_qtd = urb->qtd;
+       if (!urb_qtd) {
+               dev_dbg(hsotg->dev, "## Urb QTD is NULL ##\n");
+               return -EINVAL;
+       }
+
+       qh = urb_qtd->qh;
+       if (!qh) {
+               dev_dbg(hsotg->dev, "## Urb QTD QH is NULL ##\n");
+               return -EINVAL;
+       }
+
+       urb->priv = NULL;
+
+       if (urb_qtd->in_process && qh->channel) {
+               dwc2_dump_channel_info(hsotg, qh->channel);
+
+               /* The QTD is in process (it has been assigned to a channel) */
+               if (hsotg->flags.b.port_connect_status)
+                       /*
+                        * If still connected (i.e. in host mode), halt the
+                        * channel so it can be used for other transfers. If
+                        * no longer connected, the host registers can't be
+                        * written to halt the channel since the core is in
+                        * device mode.
+                        */
+                       dwc2_hc_halt(hsotg, qh->channel,
+                                    DWC2_HC_XFER_URB_DEQUEUE);
+       }
+
+       /*
+        * Free the QTD and clean up the associated QH. Leave the QH in the
+        * schedule if it has any remaining QTDs.
+        */
+       if (hsotg->core_params->dma_desc_enable <= 0) {
+               u8 in_process = urb_qtd->in_process;
+
+               dwc2_hcd_qtd_unlink_and_free(hsotg, urb_qtd, qh);
+               if (in_process) {
+                       dwc2_hcd_qh_deactivate(hsotg, qh, 0);
+                       qh->channel = NULL;
+               } else if (list_empty(&qh->qtd_list)) {
+                       dwc2_hcd_qh_unlink(hsotg, qh);
+               }
+       } else {
+               dwc2_hcd_qtd_unlink_and_free(hsotg, urb_qtd, qh);
+       }
+
+       return 0;
+}
+
+/* Must NOT be called with interrupt disabled or spinlock held */
+static int dwc2_hcd_endpoint_disable(struct dwc2_hsotg *hsotg,
+                                    struct usb_host_endpoint *ep, int retry)
+{
+       struct dwc2_qtd *qtd, *qtd_tmp;
+       struct dwc2_qh *qh;
+       unsigned long flags;
+       int rc;
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+
+       qh = ep->hcpriv;
+       if (!qh) {
+               rc = -EINVAL;
+               goto err;
+       }
+
+       while (!list_empty(&qh->qtd_list) && retry--) {
+               if (retry == 0) {
+                       dev_err(hsotg->dev,
+                               "## timeout in dwc2_hcd_endpoint_disable() ##\n");
+                       rc = -EBUSY;
+                       goto err;
+               }
+
+               spin_unlock_irqrestore(&hsotg->lock, flags);
+               usleep_range(20000, 40000);
+               spin_lock_irqsave(&hsotg->lock, flags);
+               qh = ep->hcpriv;
+               if (!qh) {
+                       rc = -EINVAL;
+                       goto err;
+               }
+       }
+
+       dwc2_hcd_qh_unlink(hsotg, qh);
+
+       /* Free each QTD in the QH's QTD list */
+       list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry)
+               dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
+
+       ep->hcpriv = NULL;
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+       dwc2_hcd_qh_free(hsotg, qh);
+
+       return 0;
+
+err:
+       ep->hcpriv = NULL;
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+
+       return rc;
+}
+
+/* Must be called with interrupt disabled and spinlock held */
+static int dwc2_hcd_endpoint_reset(struct dwc2_hsotg *hsotg,
+                                  struct usb_host_endpoint *ep)
+{
+       struct dwc2_qh *qh = ep->hcpriv;
+
+       if (!qh)
+               return -EINVAL;
+
+       qh->data_toggle = DWC2_HC_PID_DATA0;
+
+       return 0;
+}
+
+/*
+ * Initializes dynamic portions of the DWC_otg HCD state
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+static void dwc2_hcd_reinit(struct dwc2_hsotg *hsotg)
+{
+       struct dwc2_host_chan *chan, *chan_tmp;
+       int num_channels;
+       int i;
+
+       hsotg->flags.d32 = 0;
+       hsotg->non_periodic_qh_ptr = &hsotg->non_periodic_sched_active;
+
+       if (hsotg->core_params->uframe_sched > 0) {
+               hsotg->available_host_channels =
+                       hsotg->core_params->host_channels;
+       } else {
+               hsotg->non_periodic_channels = 0;
+               hsotg->periodic_channels = 0;
+       }
+
+       /*
+        * Put all channels in the free channel list and clean up channel
+        * states
+        */
+       list_for_each_entry_safe(chan, chan_tmp, &hsotg->free_hc_list,
+                                hc_list_entry)
+               list_del_init(&chan->hc_list_entry);
+
+       num_channels = hsotg->core_params->host_channels;
+       for (i = 0; i < num_channels; i++) {
+               chan = hsotg->hc_ptr_array[i];
+               list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list);
+               dwc2_hc_cleanup(hsotg, chan);
+       }
+
+       /* Initialize the DWC core for host mode operation */
+       dwc2_core_host_init(hsotg);
+}
+
+static void dwc2_hc_init_split(struct dwc2_hsotg *hsotg,
+                              struct dwc2_host_chan *chan,
+                              struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb)
+{
+       int hub_addr, hub_port;
+
+       chan->do_split = 1;
+       chan->xact_pos = qtd->isoc_split_pos;
+       chan->complete_split = qtd->complete_split;
+       dwc2_host_hub_info(hsotg, urb->priv, &hub_addr, &hub_port);
+       chan->hub_addr = (u8)hub_addr;
+       chan->hub_port = (u8)hub_port;
+}
+
+static void *dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg,
+                              struct dwc2_host_chan *chan,
+                              struct dwc2_qtd *qtd, void *bufptr)
+{
+       struct dwc2_hcd_urb *urb = qtd->urb;
+       struct dwc2_hcd_iso_packet_desc *frame_desc;
+
+       switch (dwc2_hcd_get_pipe_type(&urb->pipe_info)) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               chan->ep_type = USB_ENDPOINT_XFER_CONTROL;
+
+               switch (qtd->control_phase) {
+               case DWC2_CONTROL_SETUP:
+                       dev_vdbg(hsotg->dev, "  Control setup transaction\n");
+                       chan->do_ping = 0;
+                       chan->ep_is_in = 0;
+                       chan->data_pid_start = DWC2_HC_PID_SETUP;
+                       if (hsotg->core_params->dma_enable > 0)
+                               chan->xfer_dma = urb->setup_dma;
+                       else
+                               chan->xfer_buf = urb->setup_packet;
+                       chan->xfer_len = 8;
+                       bufptr = NULL;
+                       break;
+
+               case DWC2_CONTROL_DATA:
+                       dev_vdbg(hsotg->dev, "  Control data transaction\n");
+                       chan->data_pid_start = qtd->data_toggle;
+                       break;
+
+               case DWC2_CONTROL_STATUS:
+                       /*
+                        * Direction is opposite of data direction or IN if no
+                        * data
+                        */
+                       dev_vdbg(hsotg->dev, "  Control status transaction\n");
+                       if (urb->length == 0)
+                               chan->ep_is_in = 1;
+                       else
+                               chan->ep_is_in =
+                                       dwc2_hcd_is_pipe_out(&urb->pipe_info);
+                       if (chan->ep_is_in)
+                               chan->do_ping = 0;
+                       chan->data_pid_start = DWC2_HC_PID_DATA1;
+                       chan->xfer_len = 0;
+                       if (hsotg->core_params->dma_enable > 0)
+                               chan->xfer_dma = hsotg->status_buf_dma;
+                       else
+                               chan->xfer_buf = hsotg->status_buf;
+                       bufptr = NULL;
+                       break;
+               }
+               break;
+
+       case USB_ENDPOINT_XFER_BULK:
+               chan->ep_type = USB_ENDPOINT_XFER_BULK;
+               break;
+
+       case USB_ENDPOINT_XFER_INT:
+               chan->ep_type = USB_ENDPOINT_XFER_INT;
+               break;
+
+       case USB_ENDPOINT_XFER_ISOC:
+               chan->ep_type = USB_ENDPOINT_XFER_ISOC;
+               if (hsotg->core_params->dma_desc_enable > 0)
+                       break;
+
+               frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
+               frame_desc->status = 0;
+
+               if (hsotg->core_params->dma_enable > 0) {
+                       chan->xfer_dma = urb->dma;
+                       chan->xfer_dma += frame_desc->offset +
+                                       qtd->isoc_split_offset;
+               } else {
+                       chan->xfer_buf = urb->buf;
+                       chan->xfer_buf += frame_desc->offset +
+                                       qtd->isoc_split_offset;
+               }
+
+               chan->xfer_len = frame_desc->length - qtd->isoc_split_offset;
+
+               /* For non-dword aligned buffers */
+               if (hsotg->core_params->dma_enable > 0 &&
+                   (chan->xfer_dma & 0x3))
+                       bufptr = (u8 *)urb->buf + frame_desc->offset +
+                                       qtd->isoc_split_offset;
+               else
+                       bufptr = NULL;
+
+               if (chan->xact_pos == DWC2_HCSPLT_XACTPOS_ALL) {
+                       if (chan->xfer_len <= 188)
+                               chan->xact_pos = DWC2_HCSPLT_XACTPOS_ALL;
+                       else
+                               chan->xact_pos = DWC2_HCSPLT_XACTPOS_BEGIN;
+               }
+               break;
+       }
+
+       return bufptr;
+}
+
+static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+                                  struct dwc2_host_chan *chan, void *bufptr)
+{
+       u32 buf_size;
+
+       if (chan->ep_type != USB_ENDPOINT_XFER_ISOC)
+               buf_size = hsotg->core_params->max_transfer_size;
+       else
+               buf_size = 4096;
+
+       if (!qh->dw_align_buf) {
+               qh->dw_align_buf = dma_alloc_coherent(hsotg->dev, buf_size,
+                                                     &qh->dw_align_buf_dma,
+                                                     GFP_ATOMIC);
+               if (!qh->dw_align_buf)
+                       return -ENOMEM;
+       }
+
+       if (!chan->ep_is_in && chan->xfer_len) {
+               dma_sync_single_for_cpu(hsotg->dev, chan->xfer_dma, buf_size,
+                                       DMA_TO_DEVICE);
+               memcpy(qh->dw_align_buf, bufptr, chan->xfer_len);
+               dma_sync_single_for_device(hsotg->dev, chan->xfer_dma, buf_size,
+                                          DMA_TO_DEVICE);
+       }
+
+       chan->align_buf = qh->dw_align_buf_dma;
+       return 0;
+}
+
+/**
+ * dwc2_assign_and_init_hc() - Assigns transactions from a QTD to a free host
+ * channel and initializes the host channel to perform the transactions. The
+ * host channel is removed from the free list.
+ *
+ * @hsotg: The HCD state structure
+ * @qh:    Transactions from the first QTD for this QH are selected and assigned
+ *         to a free host channel
+ */
+static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+       struct dwc2_host_chan *chan;
+       struct dwc2_hcd_urb *urb;
+       struct dwc2_qtd *qtd;
+       void *bufptr = NULL;
+
+       if (dbg_qh(qh))
+               dev_vdbg(hsotg->dev, "%s(%p,%p)\n", __func__, hsotg, qh);
+
+       if (list_empty(&qh->qtd_list)) {
+               dev_dbg(hsotg->dev, "No QTDs in QH list\n");
+               return -ENOMEM;
+       }
+
+       if (list_empty(&hsotg->free_hc_list)) {
+               dev_dbg(hsotg->dev, "No free channel to assign\n");
+               return -ENOMEM;
+       }
+
+       chan = list_first_entry(&hsotg->free_hc_list, struct dwc2_host_chan,
+                               hc_list_entry);
+
+       /* Remove host channel from free list */
+       list_del_init(&chan->hc_list_entry);
+
+       qtd = list_first_entry(&qh->qtd_list, struct dwc2_qtd, qtd_list_entry);
+       urb = qtd->urb;
+       qh->channel = chan;
+       qtd->in_process = 1;
+
+       /*
+        * Use usb_pipedevice to determine device address. This address is
+        * 0 before the SET_ADDRESS command and the correct address afterward.
+        */
+       chan->dev_addr = dwc2_hcd_get_dev_addr(&urb->pipe_info);
+       chan->ep_num = dwc2_hcd_get_ep_num(&urb->pipe_info);
+       chan->speed = qh->dev_speed;
+       chan->max_packet = dwc2_max_packet(qh->maxp);
+
+       chan->xfer_started = 0;
+       chan->halt_status = DWC2_HC_XFER_NO_HALT_STATUS;
+       chan->error_state = (qtd->error_count > 0);
+       chan->halt_on_queue = 0;
+       chan->halt_pending = 0;
+       chan->requests = 0;
+
+       /*
+        * The following values may be modified in the transfer type section
+        * below. The xfer_len value may be reduced when the transfer is
+        * started to accommodate the max widths of the XferSize and PktCnt
+        * fields in the HCTSIZn register.
+        */
+
+       chan->ep_is_in = (dwc2_hcd_is_pipe_in(&urb->pipe_info) != 0);
+       if (chan->ep_is_in)
+               chan->do_ping = 0;
+       else
+               chan->do_ping = qh->ping_state;
+
+       chan->data_pid_start = qh->data_toggle;
+       chan->multi_count = 1;
+
+       if (urb->actual_length > urb->length &&
+               !dwc2_hcd_is_pipe_in(&urb->pipe_info))
+               urb->actual_length = urb->length;
+
+       if (hsotg->core_params->dma_enable > 0) {
+               chan->xfer_dma = urb->dma + urb->actual_length;
+
+               /* For non-dword aligned case */
+               if (hsotg->core_params->dma_desc_enable <= 0 &&
+                   (chan->xfer_dma & 0x3))
+                       bufptr = (u8 *)urb->buf + urb->actual_length;
+       } else {
+               chan->xfer_buf = (u8 *)urb->buf + urb->actual_length;
+       }
+
+       chan->xfer_len = urb->length - urb->actual_length;
+       chan->xfer_count = 0;
+
+       /* Set the split attributes if required */
+       if (qh->do_split)
+               dwc2_hc_init_split(hsotg, chan, qtd, urb);
+       else
+               chan->do_split = 0;
+
+       /* Set the transfer attributes */
+       bufptr = dwc2_hc_init_xfer(hsotg, chan, qtd, bufptr);
+
+       /* Non DWORD-aligned buffer case */
+       if (bufptr) {
+               dev_vdbg(hsotg->dev, "Non-aligned buffer\n");
+               if (dwc2_hc_setup_align_buf(hsotg, qh, chan, bufptr)) {
+                       dev_err(hsotg->dev,
+                               "%s: Failed to allocate memory to handle non-dword aligned buffer\n",
+                               __func__);
+                       /* Add channel back to free list */
+                       chan->align_buf = 0;
+                       chan->multi_count = 0;
+                       list_add_tail(&chan->hc_list_entry,
+                                     &hsotg->free_hc_list);
+                       qtd->in_process = 0;
+                       qh->channel = NULL;
+                       return -ENOMEM;
+               }
+       } else {
+               chan->align_buf = 0;
+       }
+
+       if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+           chan->ep_type == USB_ENDPOINT_XFER_ISOC)
+               /*
+                * This value may be modified when the transfer is started
+                * to reflect the actual transfer length
+                */
+               chan->multi_count = dwc2_hb_mult(qh->maxp);
+
+       if (hsotg->core_params->dma_desc_enable > 0)
+               chan->desc_list_addr = qh->desc_list_dma;
+
+       dwc2_hc_init(hsotg, chan);
+       chan->qh = qh;
+
+       return 0;
+}
+
+/**
+ * dwc2_hcd_select_transactions() - Selects transactions from the HCD transfer
+ * schedule and assigns them to available host channels. Called from the HCD
+ * interrupt handler functions.
+ *
+ * @hsotg: The HCD state structure
+ *
+ * Return: The types of new transactions that were assigned to host channels
+ */
+enum dwc2_transaction_type dwc2_hcd_select_transactions(
+               struct dwc2_hsotg *hsotg)
+{
+       enum dwc2_transaction_type ret_val = DWC2_TRANSACTION_NONE;
+       struct list_head *qh_ptr;
+       struct dwc2_qh *qh;
+       int num_channels;
+
+#ifdef DWC2_DEBUG_SOF
+       dev_vdbg(hsotg->dev, "  Select Transactions\n");
+#endif
+
+       /* Process entries in the periodic ready list */
+       qh_ptr = hsotg->periodic_sched_ready.next;
+       while (qh_ptr != &hsotg->periodic_sched_ready) {
+               if (list_empty(&hsotg->free_hc_list))
+                       break;
+               if (hsotg->core_params->uframe_sched > 0) {
+                       if (hsotg->available_host_channels <= 1)
+                               break;
+                       hsotg->available_host_channels--;
+               }
+               qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry);
+               if (dwc2_assign_and_init_hc(hsotg, qh))
+                       break;
+
+               /*
+                * Move the QH from the periodic ready schedule to the
+                * periodic assigned schedule
+                */
+               qh_ptr = qh_ptr->next;
+               list_move(&qh->qh_list_entry, &hsotg->periodic_sched_assigned);
+               ret_val = DWC2_TRANSACTION_PERIODIC;
+       }
+
+       /*
+        * Process entries in the inactive portion of the non-periodic
+        * schedule. Some free host channels may not be used if they are
+        * reserved for periodic transfers.
+        */
+       num_channels = hsotg->core_params->host_channels;
+       qh_ptr = hsotg->non_periodic_sched_inactive.next;
+       while (qh_ptr != &hsotg->non_periodic_sched_inactive) {
+               if (hsotg->core_params->uframe_sched <= 0 &&
+                   hsotg->non_periodic_channels >= num_channels -
+                                               hsotg->periodic_channels)
+                       break;
+               if (list_empty(&hsotg->free_hc_list))
+                       break;
+               qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry);
+               if (hsotg->core_params->uframe_sched > 0) {
+                       if (hsotg->available_host_channels < 1)
+                               break;
+                       hsotg->available_host_channels--;
+               }
+
+               if (dwc2_assign_and_init_hc(hsotg, qh))
+                       break;
+
+               /*
+                * Move the QH from the non-periodic inactive schedule to the
+                * non-periodic active schedule
+                */
+               qh_ptr = qh_ptr->next;
+               list_move(&qh->qh_list_entry,
+                         &hsotg->non_periodic_sched_active);
+
+               if (ret_val == DWC2_TRANSACTION_NONE)
+                       ret_val = DWC2_TRANSACTION_NON_PERIODIC;
+               else
+                       ret_val = DWC2_TRANSACTION_ALL;
+
+               if (hsotg->core_params->uframe_sched <= 0)
+                       hsotg->non_periodic_channels++;
+       }
+
+       return ret_val;
+}
+
+/**
+ * dwc2_queue_transaction() - Attempts to queue a single transaction request for
+ * a host channel associated with either a periodic or non-periodic transfer
+ *
+ * @hsotg: The HCD state structure
+ * @chan:  Host channel descriptor associated with either a periodic or
+ *         non-periodic transfer
+ * @fifo_dwords_avail: Number of DWORDs available in the periodic Tx FIFO
+ *                     for periodic transfers or the non-periodic Tx FIFO
+ *                     for non-periodic transfers
+ *
+ * Return: 1 if a request is queued and more requests may be needed to
+ * complete the transfer, 0 if no more requests are required for this
+ * transfer, -1 if there is insufficient space in the Tx FIFO
+ *
+ * This function assumes that there is space available in the appropriate
+ * request queue. For an OUT transfer or SETUP transaction in Slave mode,
+ * it checks whether space is available in the appropriate Tx FIFO.
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+static int dwc2_queue_transaction(struct dwc2_hsotg *hsotg,
+                                 struct dwc2_host_chan *chan,
+                                 u16 fifo_dwords_avail)
+{
+       int retval = 0;
+
+       if (hsotg->core_params->dma_enable > 0) {
+               if (hsotg->core_params->dma_desc_enable > 0) {
+                       if (!chan->xfer_started ||
+                           chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
+                               dwc2_hcd_start_xfer_ddma(hsotg, chan->qh);
+                               chan->qh->ping_state = 0;
+                       }
+               } else if (!chan->xfer_started) {
+                       dwc2_hc_start_transfer(hsotg, chan);
+                       chan->qh->ping_state = 0;
+               }
+       } else if (chan->halt_pending) {
+               /* Don't queue a request if the channel has been halted */
+       } else if (chan->halt_on_queue) {
+               dwc2_hc_halt(hsotg, chan, chan->halt_status);
+       } else if (chan->do_ping) {
+               if (!chan->xfer_started)
+                       dwc2_hc_start_transfer(hsotg, chan);
+       } else if (!chan->ep_is_in ||
+                  chan->data_pid_start == DWC2_HC_PID_SETUP) {
+               if ((fifo_dwords_avail * 4) >= chan->max_packet) {
+                       if (!chan->xfer_started) {
+                               dwc2_hc_start_transfer(hsotg, chan);
+                               retval = 1;
+                       } else {
+                               retval = dwc2_hc_continue_transfer(hsotg, chan);
+                       }
+               } else {
+                       retval = -1;
+               }
+       } else {
+               if (!chan->xfer_started) {
+                       dwc2_hc_start_transfer(hsotg, chan);
+                       retval = 1;
+               } else {
+                       retval = dwc2_hc_continue_transfer(hsotg, chan);
+               }
+       }
+
+       return retval;
+}
+
+/*
+ * Processes periodic channels for the next frame and queues transactions for
+ * these channels to the DWC_otg controller. After queueing transactions, the
+ * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions
+ * to queue as Periodic Tx FIFO or request queue space becomes available.
+ * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled.
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
+{
+       struct list_head *qh_ptr;
+       struct dwc2_qh *qh;
+       u32 tx_status;
+       u32 fspcavail;
+       u32 gintmsk;
+       int status;
+       int no_queue_space = 0;
+       int no_fifo_space = 0;
+       u32 qspcavail;
+
+       if (dbg_perio())
+               dev_vdbg(hsotg->dev, "Queue periodic transactions\n");
+
+       tx_status = readl(hsotg->regs + HPTXSTS);
+       qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
+                   TXSTS_QSPCAVAIL_SHIFT;
+       fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
+                   TXSTS_FSPCAVAIL_SHIFT;
+
+       if (dbg_perio()) {
+               dev_vdbg(hsotg->dev, "  P Tx Req Queue Space Avail (before queue): %d\n",
+                        qspcavail);
+               dev_vdbg(hsotg->dev, "  P Tx FIFO Space Avail (before queue): %d\n",
+                        fspcavail);
+       }
+
+       qh_ptr = hsotg->periodic_sched_assigned.next;
+       while (qh_ptr != &hsotg->periodic_sched_assigned) {
+               tx_status = readl(hsotg->regs + HPTXSTS);
+               qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
+                           TXSTS_QSPCAVAIL_SHIFT;
+               if (qspcavail == 0) {
+                       no_queue_space = 1;
+                       break;
+               }
+
+               qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry);
+               if (!qh->channel) {
+                       qh_ptr = qh_ptr->next;
+                       continue;
+               }
+
+               /* Make sure EP's TT buffer is clean before queueing qtds */
+               if (qh->tt_buffer_dirty) {
+                       qh_ptr = qh_ptr->next;
+                       continue;
+               }
+
+               /*
+                * Set a flag if we're queuing high-bandwidth in slave mode.
+                * The flag prevents any halts to get into the request queue in
+                * the middle of multiple high-bandwidth packets getting queued.
+                */
+               if (hsotg->core_params->dma_enable <= 0 &&
+                               qh->channel->multi_count > 1)
+                       hsotg->queuing_high_bandwidth = 1;
+
+               fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
+                           TXSTS_FSPCAVAIL_SHIFT;
+               status = dwc2_queue_transaction(hsotg, qh->channel, fspcavail);
+               if (status < 0) {
+                       no_fifo_space = 1;
+                       break;
+               }
+
+               /*
+                * In Slave mode, stay on the current transfer until there is
+                * nothing more to do or the high-bandwidth request count is
+                * reached. In DMA mode, only need to queue one request. The
+                * controller automatically handles multiple packets for
+                * high-bandwidth transfers.
+                */
+               if (hsotg->core_params->dma_enable > 0 || status == 0 ||
+                   qh->channel->requests == qh->channel->multi_count) {
+                       qh_ptr = qh_ptr->next;
+                       /*
+                        * Move the QH from the periodic assigned schedule to
+                        * the periodic queued schedule
+                        */
+                       list_move(&qh->qh_list_entry,
+                                 &hsotg->periodic_sched_queued);
+
+                       /* done queuing high bandwidth */
+                       hsotg->queuing_high_bandwidth = 0;
+               }
+       }
+
+       if (hsotg->core_params->dma_enable <= 0) {
+               tx_status = readl(hsotg->regs + HPTXSTS);
+               qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
+                           TXSTS_QSPCAVAIL_SHIFT;
+               fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
+                           TXSTS_FSPCAVAIL_SHIFT;
+               if (dbg_perio()) {
+                       dev_vdbg(hsotg->dev,
+                                "  P Tx Req Queue Space Avail (after queue): %d\n",
+                                qspcavail);
+                       dev_vdbg(hsotg->dev,
+                                "  P Tx FIFO Space Avail (after queue): %d\n",
+                                fspcavail);
+               }
+
+               if (!list_empty(&hsotg->periodic_sched_assigned) ||
+                   no_queue_space || no_fifo_space) {
+                       /*
+                        * May need to queue more transactions as the request
+                        * queue or Tx FIFO empties. Enable the periodic Tx
+                        * FIFO empty interrupt. (Always use the half-empty
+                        * level to ensure that new requests are loaded as
+                        * soon as possible.)
+                        */
+                       gintmsk = readl(hsotg->regs + GINTMSK);
+                       gintmsk |= GINTSTS_PTXFEMP;
+                       writel(gintmsk, hsotg->regs + GINTMSK);
+               } else {
+                       /*
+                        * Disable the Tx FIFO empty interrupt since there are
+                        * no more transactions that need to be queued right
+                        * now. This function is called from interrupt
+                        * handlers to queue more transactions as transfer
+                        * states change.
+                        */
+                       gintmsk = readl(hsotg->regs + GINTMSK);
+                       gintmsk &= ~GINTSTS_PTXFEMP;
+                       writel(gintmsk, hsotg->regs + GINTMSK);
+               }
+       }
+}
+
+/*
+ * Processes active non-periodic channels and queues transactions for these
+ * channels to the DWC_otg controller. After queueing transactions, the NP Tx
+ * FIFO Empty interrupt is enabled if there are more transactions to queue as
+ * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx
+ * FIFO Empty interrupt is disabled.
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+static void dwc2_process_non_periodic_channels(struct dwc2_hsotg *hsotg)
+{
+       struct list_head *orig_qh_ptr;
+       struct dwc2_qh *qh;
+       u32 tx_status;
+       u32 qspcavail;
+       u32 fspcavail;
+       u32 gintmsk;
+       int status;
+       int no_queue_space = 0;
+       int no_fifo_space = 0;
+       int more_to_do = 0;
+
+       dev_vdbg(hsotg->dev, "Queue non-periodic transactions\n");
+
+       tx_status = readl(hsotg->regs + GNPTXSTS);
+       qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
+                   TXSTS_QSPCAVAIL_SHIFT;
+       fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
+                   TXSTS_FSPCAVAIL_SHIFT;
+       dev_vdbg(hsotg->dev, "  NP Tx Req Queue Space Avail (before queue): %d\n",
+                qspcavail);
+       dev_vdbg(hsotg->dev, "  NP Tx FIFO Space Avail (before queue): %d\n",
+                fspcavail);
+
+       /*
+        * Keep track of the starting point. Skip over the start-of-list
+        * entry.
+        */
+       if (hsotg->non_periodic_qh_ptr == &hsotg->non_periodic_sched_active)
+               hsotg->non_periodic_qh_ptr = hsotg->non_periodic_qh_ptr->next;
+       orig_qh_ptr = hsotg->non_periodic_qh_ptr;
+
+       /*
+        * Process once through the active list or until no more space is
+        * available in the request queue or the Tx FIFO
+        */
+       do {
+               tx_status = readl(hsotg->regs + GNPTXSTS);
+               qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
+                           TXSTS_QSPCAVAIL_SHIFT;
+               if (hsotg->core_params->dma_enable <= 0 && qspcavail == 0) {
+                       no_queue_space = 1;
+                       break;
+               }
+
+               qh = list_entry(hsotg->non_periodic_qh_ptr, struct dwc2_qh,
+                               qh_list_entry);
+               if (!qh->channel)
+                       goto next;
+
+               /* Make sure EP's TT buffer is clean before queueing qtds */
+               if (qh->tt_buffer_dirty)
+                       goto next;
+
+               fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
+                           TXSTS_FSPCAVAIL_SHIFT;
+               status = dwc2_queue_transaction(hsotg, qh->channel, fspcavail);
+
+               if (status > 0) {
+                       more_to_do = 1;
+               } else if (status < 0) {
+                       no_fifo_space = 1;
+                       break;
+               }
+next:
+               /* Advance to next QH, skipping start-of-list entry */
+               hsotg->non_periodic_qh_ptr = hsotg->non_periodic_qh_ptr->next;
+               if (hsotg->non_periodic_qh_ptr ==
+                               &hsotg->non_periodic_sched_active)
+                       hsotg->non_periodic_qh_ptr =
+                                       hsotg->non_periodic_qh_ptr->next;
+       } while (hsotg->non_periodic_qh_ptr != orig_qh_ptr);
+
+       if (hsotg->core_params->dma_enable <= 0) {
+               tx_status = readl(hsotg->regs + GNPTXSTS);
+               qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
+                           TXSTS_QSPCAVAIL_SHIFT;
+               fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
+                           TXSTS_FSPCAVAIL_SHIFT;
+               dev_vdbg(hsotg->dev,
+                        "  NP Tx Req Queue Space Avail (after queue): %d\n",
+                        qspcavail);
+               dev_vdbg(hsotg->dev,
+                        "  NP Tx FIFO Space Avail (after queue): %d\n",
+                        fspcavail);
+
+               if (more_to_do || no_queue_space || no_fifo_space) {
+                       /*
+                        * May need to queue more transactions as the request
+                        * queue or Tx FIFO empties. Enable the non-periodic
+                        * Tx FIFO empty interrupt. (Always use the half-empty
+                        * level to ensure that new requests are loaded as
+                        * soon as possible.)
+                        */
+                       gintmsk = readl(hsotg->regs + GINTMSK);
+                       gintmsk |= GINTSTS_NPTXFEMP;
+                       writel(gintmsk, hsotg->regs + GINTMSK);
+               } else {
+                       /*
+                        * Disable the Tx FIFO empty interrupt since there are
+                        * no more transactions that need to be queued right
+                        * now. This function is called from interrupt
+                        * handlers to queue more transactions as transfer
+                        * states change.
+                        */
+                       gintmsk = readl(hsotg->regs + GINTMSK);
+                       gintmsk &= ~GINTSTS_NPTXFEMP;
+                       writel(gintmsk, hsotg->regs + GINTMSK);
+               }
+       }
+}
+
+/**
+ * dwc2_hcd_queue_transactions() - Processes the currently active host channels
+ * and queues transactions for these channels to the DWC_otg controller. Called
+ * from the HCD interrupt handler functions.
+ *
+ * @hsotg:   The HCD state structure
+ * @tr_type: The type(s) of transactions to queue (non-periodic, periodic,
+ *           or both)
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
+                                enum dwc2_transaction_type tr_type)
+{
+#ifdef DWC2_DEBUG_SOF
+       dev_vdbg(hsotg->dev, "Queue Transactions\n");
+#endif
+       /* Process host channels associated with periodic transfers */
+       if ((tr_type == DWC2_TRANSACTION_PERIODIC ||
+            tr_type == DWC2_TRANSACTION_ALL) &&
+           !list_empty(&hsotg->periodic_sched_assigned))
+               dwc2_process_periodic_channels(hsotg);
+
+       /* Process host channels associated with non-periodic transfers */
+       if (tr_type == DWC2_TRANSACTION_NON_PERIODIC ||
+           tr_type == DWC2_TRANSACTION_ALL) {
+               if (!list_empty(&hsotg->non_periodic_sched_active)) {
+                       dwc2_process_non_periodic_channels(hsotg);
+               } else {
+                       /*
+                        * Ensure NP Tx FIFO empty interrupt is disabled when
+                        * there are no non-periodic transfers to process
+                        */
+                       u32 gintmsk = readl(hsotg->regs + GINTMSK);
+
+                       gintmsk &= ~GINTSTS_NPTXFEMP;
+                       writel(gintmsk, hsotg->regs + GINTMSK);
+               }
+       }
+}
+
+static void dwc2_conn_id_status_change(struct work_struct *work)
+{
+       struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg,
+                                               wf_otg);
+       u32 count = 0;
+       u32 gotgctl;
+
+       dev_dbg(hsotg->dev, "%s()\n", __func__);
+
+       gotgctl = readl(hsotg->regs + GOTGCTL);
+       dev_dbg(hsotg->dev, "gotgctl=%0x\n", gotgctl);
+       dev_dbg(hsotg->dev, "gotgctl.b.conidsts=%d\n",
+               !!(gotgctl & GOTGCTL_CONID_B));
+
+       /* B-Device connector (Device Mode) */
+       if (gotgctl & GOTGCTL_CONID_B) {
+               /* Wait for switch to device mode */
+               dev_dbg(hsotg->dev, "connId B\n");
+               while (!dwc2_is_device_mode(hsotg)) {
+                       dev_info(hsotg->dev,
+                                "Waiting for Peripheral Mode, Mode=%s\n",
+                                dwc2_is_host_mode(hsotg) ? "Host" :
+                                "Peripheral");
+                       usleep_range(20000, 40000);
+                       if (++count > 250)
+                               break;
+               }
+               if (count > 250)
+                       dev_err(hsotg->dev,
+                               "Connection id status change timed out\n");
+               hsotg->op_state = OTG_STATE_B_PERIPHERAL;
+               dwc2_core_init(hsotg, false, -1);
+               dwc2_enable_global_interrupts(hsotg);
+       } else {
+               /* A-Device connector (Host Mode) */
+               dev_dbg(hsotg->dev, "connId A\n");
+               while (!dwc2_is_host_mode(hsotg)) {
+                       dev_info(hsotg->dev, "Waiting for Host Mode, Mode=%s\n",
+                                dwc2_is_host_mode(hsotg) ?
+                                "Host" : "Peripheral");
+                       usleep_range(20000, 40000);
+                       if (++count > 250)
+                               break;
+               }
+               if (count > 250)
+                       dev_err(hsotg->dev,
+                               "Connection id status change timed out\n");
+               hsotg->op_state = OTG_STATE_A_HOST;
+
+               /* Initialize the Core for Host mode */
+               dwc2_core_init(hsotg, false, -1);
+               dwc2_enable_global_interrupts(hsotg);
+               dwc2_hcd_start(hsotg);
+       }
+}
+
+static void dwc2_wakeup_detected(unsigned long data)
+{
+       struct dwc2_hsotg *hsotg = (struct dwc2_hsotg *)data;
+       u32 hprt0;
+
+       dev_dbg(hsotg->dev, "%s()\n", __func__);
+
+       /*
+        * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
+        * so that OPT tests pass with all PHYs.)
+        */
+       hprt0 = dwc2_read_hprt0(hsotg);
+       dev_dbg(hsotg->dev, "Resume: HPRT0=%0x\n", hprt0);
+       hprt0 &= ~HPRT0_RES;
+       writel(hprt0, hsotg->regs + HPRT0);
+       dev_dbg(hsotg->dev, "Clear Resume: HPRT0=%0x\n",
+               readl(hsotg->regs + HPRT0));
+
+       dwc2_hcd_rem_wakeup(hsotg);
+
+       /* Change to L0 state */
+       hsotg->lx_state = DWC2_L0;
+}
+
+static int dwc2_host_is_b_hnp_enabled(struct dwc2_hsotg *hsotg)
+{
+       struct usb_hcd *hcd = dwc2_hsotg_to_hcd(hsotg);
+
+       return hcd->self.b_hnp_enable;
+}
+
+/* Must NOT be called with interrupt disabled or spinlock held */
+static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
+{
+       unsigned long flags;
+       u32 hprt0;
+       u32 pcgctl;
+       u32 gotgctl;
+
+       dev_dbg(hsotg->dev, "%s()\n", __func__);
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+
+       if (windex == hsotg->otg_port && dwc2_host_is_b_hnp_enabled(hsotg)) {
+               gotgctl = readl(hsotg->regs + GOTGCTL);
+               gotgctl |= GOTGCTL_HSTSETHNPEN;
+               writel(gotgctl, hsotg->regs + GOTGCTL);
+               hsotg->op_state = OTG_STATE_A_SUSPEND;
+       }
+
+       hprt0 = dwc2_read_hprt0(hsotg);
+       hprt0 |= HPRT0_SUSP;
+       writel(hprt0, hsotg->regs + HPRT0);
+
+       /* Update lx_state */
+       hsotg->lx_state = DWC2_L2;
+
+       /* Suspend the Phy Clock */
+       pcgctl = readl(hsotg->regs + PCGCTL);
+       pcgctl |= PCGCTL_STOPPCLK;
+       writel(pcgctl, hsotg->regs + PCGCTL);
+       udelay(10);
+
+       /* For HNP the bus must be suspended for at least 200ms */
+       if (dwc2_host_is_b_hnp_enabled(hsotg)) {
+               pcgctl = readl(hsotg->regs + PCGCTL);
+               pcgctl &= ~PCGCTL_STOPPCLK;
+               writel(pcgctl, hsotg->regs + PCGCTL);
+
+               spin_unlock_irqrestore(&hsotg->lock, flags);
+
+               usleep_range(200000, 250000);
+       } else {
+               spin_unlock_irqrestore(&hsotg->lock, flags);
+       }
+}
+
+/* Handles hub class-specific requests */
+static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
+                               u16 wvalue, u16 windex, char *buf, u16 wlength)
+{
+       struct usb_hub_descriptor *hub_desc;
+       int retval = 0;
+       u32 hprt0;
+       u32 port_status;
+       u32 speed;
+       u32 pcgctl;
+
+       switch (typereq) {
+       case ClearHubFeature:
+               dev_dbg(hsotg->dev, "ClearHubFeature %1xh\n", wvalue);
+
+               switch (wvalue) {
+               case C_HUB_LOCAL_POWER:
+               case C_HUB_OVER_CURRENT:
+                       /* Nothing required here */
+                       break;
+
+               default:
+                       retval = -EINVAL;
+                       dev_err(hsotg->dev,
+                               "ClearHubFeature request %1xh unknown\n",
+                               wvalue);
+               }
+               break;
+
+       case ClearPortFeature:
+               if (wvalue != USB_PORT_FEAT_L1)
+                       if (!windex || windex > 1)
+                               goto error;
+               switch (wvalue) {
+               case USB_PORT_FEAT_ENABLE:
+                       dev_dbg(hsotg->dev,
+                               "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
+                       hprt0 = dwc2_read_hprt0(hsotg);
+                       hprt0 |= HPRT0_ENA;
+                       writel(hprt0, hsotg->regs + HPRT0);
+                       break;
+
+               case USB_PORT_FEAT_SUSPEND:
+                       dev_dbg(hsotg->dev,
+                               "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
+                       writel(0, hsotg->regs + PCGCTL);
+                       usleep_range(20000, 40000);
+
+                       hprt0 = dwc2_read_hprt0(hsotg);
+                       hprt0 |= HPRT0_RES;
+                       writel(hprt0, hsotg->regs + HPRT0);
+                       hprt0 &= ~HPRT0_SUSP;
+                       usleep_range(100000, 150000);
+
+                       hprt0 &= ~HPRT0_RES;
+                       writel(hprt0, hsotg->regs + HPRT0);
+                       break;
+
+               case USB_PORT_FEAT_POWER:
+                       dev_dbg(hsotg->dev,
+                               "ClearPortFeature USB_PORT_FEAT_POWER\n");
+                       hprt0 = dwc2_read_hprt0(hsotg);
+                       hprt0 &= ~HPRT0_PWR;
+                       writel(hprt0, hsotg->regs + HPRT0);
+                       break;
+
+               case USB_PORT_FEAT_INDICATOR:
+                       dev_dbg(hsotg->dev,
+                               "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
+                       /* Port indicator not supported */
+                       break;
+
+               case USB_PORT_FEAT_C_CONNECTION:
+                       /*
+                        * Clears driver's internal Connect Status Change flag
+                        */
+                       dev_dbg(hsotg->dev,
+                               "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
+                       hsotg->flags.b.port_connect_status_change = 0;
+                       break;
+
+               case USB_PORT_FEAT_C_RESET:
+                       /* Clears driver's internal Port Reset Change flag */
+                       dev_dbg(hsotg->dev,
+                               "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
+                       hsotg->flags.b.port_reset_change = 0;
+                       break;
+
+               case USB_PORT_FEAT_C_ENABLE:
+                       /*
+                        * Clears the driver's internal Port Enable/Disable
+                        * Change flag
+                        */
+                       dev_dbg(hsotg->dev,
+                               "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
+                       hsotg->flags.b.port_enable_change = 0;
+                       break;
+
+               case USB_PORT_FEAT_C_SUSPEND:
+                       /*
+                        * Clears the driver's internal Port Suspend Change
+                        * flag, which is set when resume signaling on the host
+                        * port is complete
+                        */
+                       dev_dbg(hsotg->dev,
+                               "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
+                       hsotg->flags.b.port_suspend_change = 0;
+                       break;
+
+               case USB_PORT_FEAT_C_PORT_L1:
+                       dev_dbg(hsotg->dev,
+                               "ClearPortFeature USB_PORT_FEAT_C_PORT_L1\n");
+                       hsotg->flags.b.port_l1_change = 0;
+                       break;
+
+               case USB_PORT_FEAT_C_OVER_CURRENT:
+                       dev_dbg(hsotg->dev,
+                               "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
+                       hsotg->flags.b.port_over_current_change = 0;
+                       break;
+
+               default:
+                       retval = -EINVAL;
+                       dev_err(hsotg->dev,
+                               "ClearPortFeature request %1xh unknown or unsupported\n",
+                               wvalue);
+               }
+               break;
+
+       case GetHubDescriptor:
+               dev_dbg(hsotg->dev, "GetHubDescriptor\n");
+               hub_desc = (struct usb_hub_descriptor *)buf;
+               hub_desc->bDescLength = 9;
+               hub_desc->bDescriptorType = 0x29;
+               hub_desc->bNbrPorts = 1;
+               hub_desc->wHubCharacteristics = cpu_to_le16(0x08);
+               hub_desc->bPwrOn2PwrGood = 1;
+               hub_desc->bHubContrCurrent = 0;
+               hub_desc->u.hs.DeviceRemovable[0] = 0;
+               hub_desc->u.hs.DeviceRemovable[1] = 0xff;
+               break;
+
+       case GetHubStatus:
+               dev_dbg(hsotg->dev, "GetHubStatus\n");
+               memset(buf, 0, 4);
+               break;
+
+       case GetPortStatus:
+               dev_vdbg(hsotg->dev,
+                        "GetPortStatus wIndex=0x%04x flags=0x%08x\n", windex,
+                        hsotg->flags.d32);
+               if (!windex || windex > 1)
+                       goto error;
+
+               port_status = 0;
+               if (hsotg->flags.b.port_connect_status_change)
+                       port_status |= USB_PORT_STAT_C_CONNECTION << 16;
+               if (hsotg->flags.b.port_enable_change)
+                       port_status |= USB_PORT_STAT_C_ENABLE << 16;
+               if (hsotg->flags.b.port_suspend_change)
+                       port_status |= USB_PORT_STAT_C_SUSPEND << 16;
+               if (hsotg->flags.b.port_l1_change)
+                       port_status |= USB_PORT_STAT_C_L1 << 16;
+               if (hsotg->flags.b.port_reset_change)
+                       port_status |= USB_PORT_STAT_C_RESET << 16;
+               if (hsotg->flags.b.port_over_current_change) {
+                       dev_warn(hsotg->dev, "Overcurrent change detected\n");
+                       port_status |= USB_PORT_STAT_C_OVERCURRENT << 16;
+               }
+
+               if (!hsotg->flags.b.port_connect_status) {
+                       /*
+                        * The port is disconnected, which means the core is
+                        * either in device mode or it soon will be. Just
+                        * return 0's for the remainder of the port status
+                        * since the port register can't be read if the core
+                        * is in device mode.
+                        */
+                       *(__le32 *)buf = cpu_to_le32(port_status);
+                       break;
+               }
+
+               hprt0 = readl(hsotg->regs + HPRT0);
+               dev_vdbg(hsotg->dev, "  HPRT0: 0x%08x\n", hprt0);
+
+               if (hprt0 & HPRT0_CONNSTS)
+                       port_status |= USB_PORT_STAT_CONNECTION;
+               if (hprt0 & HPRT0_ENA)
+                       port_status |= USB_PORT_STAT_ENABLE;
+               if (hprt0 & HPRT0_SUSP)
+                       port_status |= USB_PORT_STAT_SUSPEND;
+               if (hprt0 & HPRT0_OVRCURRACT)
+                       port_status |= USB_PORT_STAT_OVERCURRENT;
+               if (hprt0 & HPRT0_RST)
+                       port_status |= USB_PORT_STAT_RESET;
+               if (hprt0 & HPRT0_PWR)
+                       port_status |= USB_PORT_STAT_POWER;
+
+               speed = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
+               if (speed == HPRT0_SPD_HIGH_SPEED)
+                       port_status |= USB_PORT_STAT_HIGH_SPEED;
+               else if (speed == HPRT0_SPD_LOW_SPEED)
+                       port_status |= USB_PORT_STAT_LOW_SPEED;
+
+               if (hprt0 & HPRT0_TSTCTL_MASK)
+                       port_status |= USB_PORT_STAT_TEST;
+               /* USB_PORT_FEAT_INDICATOR unsupported always 0 */
+
+               dev_vdbg(hsotg->dev, "port_status=%08x\n", port_status);
+               *(__le32 *)buf = cpu_to_le32(port_status);
+               break;
+
+       case SetHubFeature:
+               dev_dbg(hsotg->dev, "SetHubFeature\n");
+               /* No HUB features supported */
+               break;
+
+       case SetPortFeature:
+               dev_dbg(hsotg->dev, "SetPortFeature\n");
+               if (wvalue != USB_PORT_FEAT_TEST && (!windex || windex > 1))
+                       goto error;
+
+               if (!hsotg->flags.b.port_connect_status) {
+                       /*
+                        * The port is disconnected, which means the core is
+                        * either in device mode or it soon will be. Just
+                        * return without doing anything since the port
+                        * register can't be written if the core is in device
+                        * mode.
+                        */
+                       break;
+               }
+
+               switch (wvalue) {
+               case USB_PORT_FEAT_SUSPEND:
+                       dev_dbg(hsotg->dev,
+                               "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
+                       if (windex != hsotg->otg_port)
+                               goto error;
+                       dwc2_port_suspend(hsotg, windex);
+                       break;
+
+               case USB_PORT_FEAT_POWER:
+                       dev_dbg(hsotg->dev,
+                               "SetPortFeature - USB_PORT_FEAT_POWER\n");
+                       hprt0 = dwc2_read_hprt0(hsotg);
+                       hprt0 |= HPRT0_PWR;
+                       writel(hprt0, hsotg->regs + HPRT0);
+                       break;
+
+               case USB_PORT_FEAT_RESET:
+                       hprt0 = dwc2_read_hprt0(hsotg);
+                       dev_dbg(hsotg->dev,
+                               "SetPortFeature - USB_PORT_FEAT_RESET\n");
+                       pcgctl = readl(hsotg->regs + PCGCTL);
+                       pcgctl &= ~(PCGCTL_ENBL_SLEEP_GATING | PCGCTL_STOPPCLK);
+                       writel(pcgctl, hsotg->regs + PCGCTL);
+                       /* ??? Original driver does this */
+                       writel(0, hsotg->regs + PCGCTL);
+
+                       hprt0 = dwc2_read_hprt0(hsotg);
+                       /* Clear suspend bit if resetting from suspend state */
+                       hprt0 &= ~HPRT0_SUSP;
+
+                       /*
+                        * When B-Host the Port reset bit is set in the Start
+                        * HCD Callback function, so that the reset is started
+                        * within 1ms of the HNP success interrupt
+                        */
+                       if (!dwc2_hcd_is_b_host(hsotg)) {
+                               hprt0 |= HPRT0_PWR | HPRT0_RST;
+                               dev_dbg(hsotg->dev,
+                                       "In host mode, hprt0=%08x\n", hprt0);
+                               writel(hprt0, hsotg->regs + HPRT0);
+                       }
+
+                       /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
+                       usleep_range(50000, 70000);
+                       hprt0 &= ~HPRT0_RST;
+                       writel(hprt0, hsotg->regs + HPRT0);
+                       hsotg->lx_state = DWC2_L0; /* Now back to On state */
+                       break;
+
+               case USB_PORT_FEAT_INDICATOR:
+                       dev_dbg(hsotg->dev,
+                               "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
+                       /* Not supported */
+                       break;
+
+               default:
+                       retval = -EINVAL;
+                       dev_err(hsotg->dev,
+                               "SetPortFeature %1xh unknown or unsupported\n",
+                               wvalue);
+                       break;
+               }
+               break;
+
+       default:
+error:
+               retval = -EINVAL;
+               dev_dbg(hsotg->dev,
+                       "Unknown hub control request: %1xh wIndex: %1xh wValue: %1xh\n",
+                       typereq, windex, wvalue);
+               break;
+       }
+
+       return retval;
+}
+
+static int dwc2_hcd_is_status_changed(struct dwc2_hsotg *hsotg, int port)
+{
+       int retval;
+
+       if (port != 1)
+               return -EINVAL;
+
+       retval = (hsotg->flags.b.port_connect_status_change ||
+                 hsotg->flags.b.port_reset_change ||
+                 hsotg->flags.b.port_enable_change ||
+                 hsotg->flags.b.port_suspend_change ||
+                 hsotg->flags.b.port_over_current_change);
+
+       if (retval) {
+               dev_dbg(hsotg->dev,
+                       "DWC OTG HCD HUB STATUS DATA: Root port status changed\n");
+               dev_dbg(hsotg->dev, "  port_connect_status_change: %d\n",
+                       hsotg->flags.b.port_connect_status_change);
+               dev_dbg(hsotg->dev, "  port_reset_change: %d\n",
+                       hsotg->flags.b.port_reset_change);
+               dev_dbg(hsotg->dev, "  port_enable_change: %d\n",
+                       hsotg->flags.b.port_enable_change);
+               dev_dbg(hsotg->dev, "  port_suspend_change: %d\n",
+                       hsotg->flags.b.port_suspend_change);
+               dev_dbg(hsotg->dev, "  port_over_current_change: %d\n",
+                       hsotg->flags.b.port_over_current_change);
+       }
+
+       return retval;
+}
+
+int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
+{
+       u32 hfnum = readl(hsotg->regs + HFNUM);
+
+#ifdef DWC2_DEBUG_SOF
+       dev_vdbg(hsotg->dev, "DWC OTG HCD GET FRAME NUMBER %d\n",
+                (hfnum & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT);
+#endif
+       return (hfnum & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT;
+}
+
+int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg)
+{
+       return hsotg->op_state == OTG_STATE_B_HOST;
+}
+
+static struct dwc2_hcd_urb *dwc2_hcd_urb_alloc(struct dwc2_hsotg *hsotg,
+                                              int iso_desc_count,
+                                              gfp_t mem_flags)
+{
+       struct dwc2_hcd_urb *urb;
+       u32 size = sizeof(*urb) + iso_desc_count *
+                  sizeof(struct dwc2_hcd_iso_packet_desc);
+
+       urb = kzalloc(size, mem_flags);
+       if (urb)
+               urb->packet_count = iso_desc_count;
+       return urb;
+}
+
+static void dwc2_hcd_urb_set_pipeinfo(struct dwc2_hsotg *hsotg,
+                                     struct dwc2_hcd_urb *urb, u8 dev_addr,
+                                     u8 ep_num, u8 ep_type, u8 ep_dir, u16 mps)
+{
+       if (dbg_perio() ||
+           ep_type == USB_ENDPOINT_XFER_BULK ||
+           ep_type == USB_ENDPOINT_XFER_CONTROL)
+               dev_vdbg(hsotg->dev,
+                        "addr=%d, ep_num=%d, ep_dir=%1x, ep_type=%1x, mps=%d\n",
+                        dev_addr, ep_num, ep_dir, ep_type, mps);
+       urb->pipe_info.dev_addr = dev_addr;
+       urb->pipe_info.ep_num = ep_num;
+       urb->pipe_info.pipe_type = ep_type;
+       urb->pipe_info.pipe_dir = ep_dir;
+       urb->pipe_info.mps = mps;
+}
+
+/*
+ * NOTE: This function will be removed once the peripheral controller code
+ * is integrated and the driver is stable
+ */
+void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg)
+{
+#ifdef DEBUG
+       struct dwc2_host_chan *chan;
+       struct dwc2_hcd_urb *urb;
+       struct dwc2_qtd *qtd;
+       int num_channels;
+       u32 np_tx_status;
+       u32 p_tx_status;
+       int i;
+
+       num_channels = hsotg->core_params->host_channels;
+       dev_dbg(hsotg->dev, "\n");
+       dev_dbg(hsotg->dev,
+               "************************************************************\n");
+       dev_dbg(hsotg->dev, "HCD State:\n");
+       dev_dbg(hsotg->dev, "  Num channels: %d\n", num_channels);
+
+       for (i = 0; i < num_channels; i++) {
+               chan = hsotg->hc_ptr_array[i];
+               dev_dbg(hsotg->dev, "  Channel %d:\n", i);
+               dev_dbg(hsotg->dev,
+                       "    dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
+                       chan->dev_addr, chan->ep_num, chan->ep_is_in);
+               dev_dbg(hsotg->dev, "    speed: %d\n", chan->speed);
+               dev_dbg(hsotg->dev, "    ep_type: %d\n", chan->ep_type);
+               dev_dbg(hsotg->dev, "    max_packet: %d\n", chan->max_packet);
+               dev_dbg(hsotg->dev, "    data_pid_start: %d\n",
+                       chan->data_pid_start);
+               dev_dbg(hsotg->dev, "    multi_count: %d\n", chan->multi_count);
+               dev_dbg(hsotg->dev, "    xfer_started: %d\n",
+                       chan->xfer_started);
+               dev_dbg(hsotg->dev, "    xfer_buf: %p\n", chan->xfer_buf);
+               dev_dbg(hsotg->dev, "    xfer_dma: %08lx\n",
+                       (unsigned long)chan->xfer_dma);
+               dev_dbg(hsotg->dev, "    xfer_len: %d\n", chan->xfer_len);
+               dev_dbg(hsotg->dev, "    xfer_count: %d\n", chan->xfer_count);
+               dev_dbg(hsotg->dev, "    halt_on_queue: %d\n",
+                       chan->halt_on_queue);
+               dev_dbg(hsotg->dev, "    halt_pending: %d\n",
+                       chan->halt_pending);
+               dev_dbg(hsotg->dev, "    halt_status: %d\n", chan->halt_status);
+               dev_dbg(hsotg->dev, "    do_split: %d\n", chan->do_split);
+               dev_dbg(hsotg->dev, "    complete_split: %d\n",
+                       chan->complete_split);
+               dev_dbg(hsotg->dev, "    hub_addr: %d\n", chan->hub_addr);
+               dev_dbg(hsotg->dev, "    hub_port: %d\n", chan->hub_port);
+               dev_dbg(hsotg->dev, "    xact_pos: %d\n", chan->xact_pos);
+               dev_dbg(hsotg->dev, "    requests: %d\n", chan->requests);
+               dev_dbg(hsotg->dev, "    qh: %p\n", chan->qh);
+
+               if (chan->xfer_started) {
+                       u32 hfnum, hcchar, hctsiz, hcint, hcintmsk;
+
+                       hfnum = readl(hsotg->regs + HFNUM);
+                       hcchar = readl(hsotg->regs + HCCHAR(i));
+                       hctsiz = readl(hsotg->regs + HCTSIZ(i));
+                       hcint = readl(hsotg->regs + HCINT(i));
+                       hcintmsk = readl(hsotg->regs + HCINTMSK(i));
+                       dev_dbg(hsotg->dev, "    hfnum: 0x%08x\n", hfnum);
+                       dev_dbg(hsotg->dev, "    hcchar: 0x%08x\n", hcchar);
+                       dev_dbg(hsotg->dev, "    hctsiz: 0x%08x\n", hctsiz);
+                       dev_dbg(hsotg->dev, "    hcint: 0x%08x\n", hcint);
+                       dev_dbg(hsotg->dev, "    hcintmsk: 0x%08x\n", hcintmsk);
+               }
+
+               if (!(chan->xfer_started && chan->qh))
+                       continue;
+
+               list_for_each_entry(qtd, &chan->qh->qtd_list, qtd_list_entry) {
+                       if (!qtd->in_process)
+                               break;
+                       urb = qtd->urb;
+                       dev_dbg(hsotg->dev, "    URB Info:\n");
+                       dev_dbg(hsotg->dev, "      qtd: %p, urb: %p\n",
+                               qtd, urb);
+                       if (urb) {
+                               dev_dbg(hsotg->dev,
+                                       "      Dev: %d, EP: %d %s\n",
+                                       dwc2_hcd_get_dev_addr(&urb->pipe_info),
+                                       dwc2_hcd_get_ep_num(&urb->pipe_info),
+                                       dwc2_hcd_is_pipe_in(&urb->pipe_info) ?
+                                       "IN" : "OUT");
+                               dev_dbg(hsotg->dev,
+                                       "      Max packet size: %d\n",
+                                       dwc2_hcd_get_mps(&urb->pipe_info));
+                               dev_dbg(hsotg->dev,
+                                       "      transfer_buffer: %p\n",
+                                       urb->buf);
+                               dev_dbg(hsotg->dev,
+                                       "      transfer_dma: %08lx\n",
+                                       (unsigned long)urb->dma);
+                               dev_dbg(hsotg->dev,
+                                       "      transfer_buffer_length: %d\n",
+                                       urb->length);
+                               dev_dbg(hsotg->dev, "      actual_length: %d\n",
+                                       urb->actual_length);
+                       }
+               }
+       }
+
+       dev_dbg(hsotg->dev, "  non_periodic_channels: %d\n",
+               hsotg->non_periodic_channels);
+       dev_dbg(hsotg->dev, "  periodic_channels: %d\n",
+               hsotg->periodic_channels);
+       dev_dbg(hsotg->dev, "  periodic_usecs: %d\n", hsotg->periodic_usecs);
+       np_tx_status = readl(hsotg->regs + GNPTXSTS);
+       dev_dbg(hsotg->dev, "  NP Tx Req Queue Space Avail: %d\n",
+               (np_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT);
+       dev_dbg(hsotg->dev, "  NP Tx FIFO Space Avail: %d\n",
+               (np_tx_status & TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT);
+       p_tx_status = readl(hsotg->regs + HPTXSTS);
+       dev_dbg(hsotg->dev, "  P Tx Req Queue Space Avail: %d\n",
+               (p_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT);
+       dev_dbg(hsotg->dev, "  P Tx FIFO Space Avail: %d\n",
+               (p_tx_status & TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT);
+       dwc2_hcd_dump_frrem(hsotg);
+       dwc2_dump_global_registers(hsotg);
+       dwc2_dump_host_registers(hsotg);
+       dev_dbg(hsotg->dev,
+               "************************************************************\n");
+       dev_dbg(hsotg->dev, "\n");
+#endif
+}
+
+/*
+ * NOTE: This function will be removed once the peripheral controller code
+ * is integrated and the driver is stable
+ */
+void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg)
+{
+#ifdef DWC2_DUMP_FRREM
+       dev_dbg(hsotg->dev, "Frame remaining at SOF:\n");
+       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
+               hsotg->frrem_samples, hsotg->frrem_accum,
+               hsotg->frrem_samples > 0 ?
+               hsotg->frrem_accum / hsotg->frrem_samples : 0);
+       dev_dbg(hsotg->dev, "\n");
+       dev_dbg(hsotg->dev, "Frame remaining at start_transfer (uframe 7):\n");
+       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
+               hsotg->hfnum_7_samples,
+               hsotg->hfnum_7_frrem_accum,
+               hsotg->hfnum_7_samples > 0 ?
+               hsotg->hfnum_7_frrem_accum / hsotg->hfnum_7_samples : 0);
+       dev_dbg(hsotg->dev, "Frame remaining at start_transfer (uframe 0):\n");
+       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
+               hsotg->hfnum_0_samples,
+               hsotg->hfnum_0_frrem_accum,
+               hsotg->hfnum_0_samples > 0 ?
+               hsotg->hfnum_0_frrem_accum / hsotg->hfnum_0_samples : 0);
+       dev_dbg(hsotg->dev, "Frame remaining at start_transfer (uframe 1-6):\n");
+       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
+               hsotg->hfnum_other_samples,
+               hsotg->hfnum_other_frrem_accum,
+               hsotg->hfnum_other_samples > 0 ?
+               hsotg->hfnum_other_frrem_accum / hsotg->hfnum_other_samples :
+               0);
+       dev_dbg(hsotg->dev, "\n");
+       dev_dbg(hsotg->dev, "Frame remaining at sample point A (uframe 7):\n");
+       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
+               hsotg->hfnum_7_samples_a, hsotg->hfnum_7_frrem_accum_a,
+               hsotg->hfnum_7_samples_a > 0 ?
+               hsotg->hfnum_7_frrem_accum_a / hsotg->hfnum_7_samples_a : 0);
+       dev_dbg(hsotg->dev, "Frame remaining at sample point A (uframe 0):\n");
+       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
+               hsotg->hfnum_0_samples_a, hsotg->hfnum_0_frrem_accum_a,
+               hsotg->hfnum_0_samples_a > 0 ?
+               hsotg->hfnum_0_frrem_accum_a / hsotg->hfnum_0_samples_a : 0);
+       dev_dbg(hsotg->dev, "Frame remaining at sample point A (uframe 1-6):\n");
+       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
+               hsotg->hfnum_other_samples_a, hsotg->hfnum_other_frrem_accum_a,
+               hsotg->hfnum_other_samples_a > 0 ?
+               hsotg->hfnum_other_frrem_accum_a / hsotg->hfnum_other_samples_a
+               : 0);
+       dev_dbg(hsotg->dev, "\n");
+       dev_dbg(hsotg->dev, "Frame remaining at sample point B (uframe 7):\n");
+       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
+               hsotg->hfnum_7_samples_b, hsotg->hfnum_7_frrem_accum_b,
+               hsotg->hfnum_7_samples_b > 0 ?
+               hsotg->hfnum_7_frrem_accum_b / hsotg->hfnum_7_samples_b : 0);
+       dev_dbg(hsotg->dev, "Frame remaining at sample point B (uframe 0):\n");
+       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
+               hsotg->hfnum_0_samples_b, hsotg->hfnum_0_frrem_accum_b,
+               (hsotg->hfnum_0_samples_b > 0) ?
+               hsotg->hfnum_0_frrem_accum_b / hsotg->hfnum_0_samples_b : 0);
+       dev_dbg(hsotg->dev, "Frame remaining at sample point B (uframe 1-6):\n");
+       dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n",
+               hsotg->hfnum_other_samples_b, hsotg->hfnum_other_frrem_accum_b,
+               (hsotg->hfnum_other_samples_b > 0) ?
+               hsotg->hfnum_other_frrem_accum_b / hsotg->hfnum_other_samples_b
+               : 0);
+#endif
+}
+
+struct wrapper_priv_data {
+       struct dwc2_hsotg *hsotg;
+};
+
+/* Gets the dwc2_hsotg from a usb_hcd */
+static struct dwc2_hsotg *dwc2_hcd_to_hsotg(struct usb_hcd *hcd)
+{
+       struct wrapper_priv_data *p;
+
+       p = (struct wrapper_priv_data *) &hcd->hcd_priv;
+       return p->hsotg;
+}
+
+static int _dwc2_hcd_start(struct usb_hcd *hcd);
+
+void dwc2_host_start(struct dwc2_hsotg *hsotg)
+{
+       struct usb_hcd *hcd = dwc2_hsotg_to_hcd(hsotg);
+
+       hcd->self.is_b_host = dwc2_hcd_is_b_host(hsotg);
+       _dwc2_hcd_start(hcd);
+}
+
+void dwc2_host_disconnect(struct dwc2_hsotg *hsotg)
+{
+       struct usb_hcd *hcd = dwc2_hsotg_to_hcd(hsotg);
+
+       hcd->self.is_b_host = 0;
+}
+
+void dwc2_host_hub_info(struct dwc2_hsotg *hsotg, void *context, int *hub_addr,
+                       int *hub_port)
+{
+       struct urb *urb = context;
+
+       if (urb->dev->tt)
+               *hub_addr = urb->dev->tt->hub->devnum;
+       else
+               *hub_addr = 0;
+       *hub_port = urb->dev->ttport;
+}
+
+int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context)
+{
+       struct urb *urb = context;
+
+       return urb->dev->speed;
+}
+
+static void dwc2_allocate_bus_bandwidth(struct usb_hcd *hcd, u16 bw,
+                                       struct urb *urb)
+{
+       struct usb_bus *bus = hcd_to_bus(hcd);
+
+       if (urb->interval)
+               bus->bandwidth_allocated += bw / urb->interval;
+       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
+               bus->bandwidth_isoc_reqs++;
+       else
+               bus->bandwidth_int_reqs++;
+}
+
+static void dwc2_free_bus_bandwidth(struct usb_hcd *hcd, u16 bw,
+                                   struct urb *urb)
+{
+       struct usb_bus *bus = hcd_to_bus(hcd);
+
+       if (urb->interval)
+               bus->bandwidth_allocated -= bw / urb->interval;
+       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
+               bus->bandwidth_isoc_reqs--;
+       else
+               bus->bandwidth_int_reqs--;
+}
+
+/*
+ * Sets the final status of an URB and returns it to the upper layer. Any
+ * required cleanup of the URB is performed.
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
+                       int status)
+{
+       struct urb *urb;
+       int i;
+
+       if (!qtd) {
+               dev_dbg(hsotg->dev, "## %s: qtd is NULL ##\n", __func__);
+               return;
+       }
+
+       if (!qtd->urb) {
+               dev_dbg(hsotg->dev, "## %s: qtd->urb is NULL ##\n", __func__);
+               return;
+       }
+
+       urb = qtd->urb->priv;
+       if (!urb) {
+               dev_dbg(hsotg->dev, "## %s: urb->priv is NULL ##\n", __func__);
+               return;
+       }
+
+       urb->actual_length = dwc2_hcd_urb_get_actual_length(qtd->urb);
+
+       if (dbg_urb(urb))
+               dev_vdbg(hsotg->dev,
+                        "%s: urb %p device %d ep %d-%s status %d actual %d\n",
+                        __func__, urb, usb_pipedevice(urb->pipe),
+                        usb_pipeendpoint(urb->pipe),
+                        usb_pipein(urb->pipe) ? "IN" : "OUT", status,
+                        urb->actual_length);
+
+       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS && dbg_perio()) {
+               for (i = 0; i < urb->number_of_packets; i++)
+                       dev_vdbg(hsotg->dev, " ISO Desc %d status %d\n",
+                                i, urb->iso_frame_desc[i].status);
+       }
+
+       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+               urb->error_count = dwc2_hcd_urb_get_error_count(qtd->urb);
+               for (i = 0; i < urb->number_of_packets; ++i) {
+                       urb->iso_frame_desc[i].actual_length =
+                               dwc2_hcd_urb_get_iso_desc_actual_length(
+                                               qtd->urb, i);
+                       urb->iso_frame_desc[i].status =
+                               dwc2_hcd_urb_get_iso_desc_status(qtd->urb, i);
+               }
+       }
+
+       urb->status = status;
+       if (!status) {
+               if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+                   urb->actual_length < urb->transfer_buffer_length)
+                       urb->status = -EREMOTEIO;
+       }
+
+       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS ||
+           usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+               struct usb_host_endpoint *ep = urb->ep;
+
+               if (ep)
+                       dwc2_free_bus_bandwidth(dwc2_hsotg_to_hcd(hsotg),
+                                       dwc2_hcd_get_ep_bandwidth(hsotg, ep),
+                                       urb);
+       }
+
+       usb_hcd_unlink_urb_from_ep(dwc2_hsotg_to_hcd(hsotg), urb);
+       urb->hcpriv = NULL;
+       kfree(qtd->urb);
+       qtd->urb = NULL;
+
+       spin_unlock(&hsotg->lock);
+       usb_hcd_giveback_urb(dwc2_hsotg_to_hcd(hsotg), urb, status);
+       spin_lock(&hsotg->lock);
+}
+
+/*
+ * Work queue function for starting the HCD when A-Cable is connected
+ */
+static void dwc2_hcd_start_func(struct work_struct *work)
+{
+       struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg,
+                                               start_work.work);
+
+       dev_dbg(hsotg->dev, "%s() %p\n", __func__, hsotg);
+       dwc2_host_start(hsotg);
+}
+
+/*
+ * Reset work queue function
+ */
+static void dwc2_hcd_reset_func(struct work_struct *work)
+{
+       struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg,
+                                               reset_work.work);
+       u32 hprt0;
+
+       dev_dbg(hsotg->dev, "USB RESET function called\n");
+       hprt0 = dwc2_read_hprt0(hsotg);
+       hprt0 &= ~HPRT0_RST;
+       writel(hprt0, hsotg->regs + HPRT0);
+       hsotg->flags.b.port_reset_change = 1;
+}
+
+/*
+ * =========================================================================
+ *  Linux HC Driver Functions
+ * =========================================================================
+ */
+
+/*
+ * Initializes the DWC_otg controller and its root hub and prepares it for host
+ * mode operation. Activates the root port. Returns 0 on success and a negative
+ * error code on failure.
+ */
+static int _dwc2_hcd_start(struct usb_hcd *hcd)
+{
+       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+       struct usb_bus *bus = hcd_to_bus(hcd);
+       unsigned long flags;
+
+       dev_dbg(hsotg->dev, "DWC OTG HCD START\n");
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+
+       hcd->state = HC_STATE_RUNNING;
+
+       if (dwc2_is_device_mode(hsotg)) {
+               spin_unlock_irqrestore(&hsotg->lock, flags);
+               return 0;       /* why 0 ?? */
+       }
+
+       dwc2_hcd_reinit(hsotg);
+
+       /* Initialize and connect root hub if one is not already attached */
+       if (bus->root_hub) {
+               dev_dbg(hsotg->dev, "DWC OTG HCD Has Root Hub\n");
+               /* Inform the HUB driver to resume */
+               usb_hcd_resume_root_hub(hcd);
+       }
+
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+       return 0;
+}
+
+/*
+ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
+ * stopped.
+ */
+static void _dwc2_hcd_stop(struct usb_hcd *hcd)
+{
+       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+       unsigned long flags;
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+       dwc2_hcd_stop(hsotg);
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+
+       usleep_range(1000, 3000);
+}
+
+/* Returns the current frame number */
+static int _dwc2_hcd_get_frame_number(struct usb_hcd *hcd)
+{
+       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+       return dwc2_hcd_get_frame_number(hsotg);
+}
+
+static void dwc2_dump_urb_info(struct usb_hcd *hcd, struct urb *urb,
+                              char *fn_name)
+{
+#ifdef VERBOSE_DEBUG
+       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+       char *pipetype;
+       char *speed;
+
+       dev_vdbg(hsotg->dev, "%s, urb %p\n", fn_name, urb);
+       dev_vdbg(hsotg->dev, "  Device address: %d\n",
+                usb_pipedevice(urb->pipe));
+       dev_vdbg(hsotg->dev, "  Endpoint: %d, %s\n",
+                usb_pipeendpoint(urb->pipe),
+                usb_pipein(urb->pipe) ? "IN" : "OUT");
+
+       switch (usb_pipetype(urb->pipe)) {
+       case PIPE_CONTROL:
+               pipetype = "CONTROL";
+               break;
+       case PIPE_BULK:
+               pipetype = "BULK";
+               break;
+       case PIPE_INTERRUPT:
+               pipetype = "INTERRUPT";
+               break;
+       case PIPE_ISOCHRONOUS:
+               pipetype = "ISOCHRONOUS";
+               break;
+       default:
+               pipetype = "UNKNOWN";
+               break;
+       }
+
+       dev_vdbg(hsotg->dev, "  Endpoint type: %s %s (%s)\n", pipetype,
+                usb_urb_dir_in(urb) ? "IN" : "OUT", usb_pipein(urb->pipe) ?
+                "IN" : "OUT");
+
+       switch (urb->dev->speed) {
+       case USB_SPEED_HIGH:
+               speed = "HIGH";
+               break;
+       case USB_SPEED_FULL:
+               speed = "FULL";
+               break;
+       case USB_SPEED_LOW:
+               speed = "LOW";
+               break;
+       default:
+               speed = "UNKNOWN";
+               break;
+       }
+
+       dev_vdbg(hsotg->dev, "  Speed: %s\n", speed);
+       dev_vdbg(hsotg->dev, "  Max packet size: %d\n",
+                usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
+       dev_vdbg(hsotg->dev, "  Data buffer length: %d\n",
+                urb->transfer_buffer_length);
+       dev_vdbg(hsotg->dev, "  Transfer buffer: %p, Transfer DMA: %08lx\n",
+                urb->transfer_buffer, (unsigned long)urb->transfer_dma);
+       dev_vdbg(hsotg->dev, "  Setup buffer: %p, Setup DMA: %08lx\n",
+                urb->setup_packet, (unsigned long)urb->setup_dma);
+       dev_vdbg(hsotg->dev, "  Interval: %d\n", urb->interval);
+
+       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+               int i;
+
+               for (i = 0; i < urb->number_of_packets; i++) {
+                       dev_vdbg(hsotg->dev, "  ISO Desc %d:\n", i);
+                       dev_vdbg(hsotg->dev, "    offset: %d, length %d\n",
+                                urb->iso_frame_desc[i].offset,
+                                urb->iso_frame_desc[i].length);
+               }
+       }
+#endif
+}
+
+/*
+ * Starts processing a USB transfer request specified by a USB Request Block
+ * (URB). mem_flags indicates the type of memory allocation to use while
+ * processing this URB.
+ */
+static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+                                gfp_t mem_flags)
+{
+       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+       struct usb_host_endpoint *ep = urb->ep;
+       struct dwc2_hcd_urb *dwc2_urb;
+       int i;
+       int retval;
+       int alloc_bandwidth = 0;
+       u8 ep_type = 0;
+       u32 tflags = 0;
+       void *buf;
+       unsigned long flags;
+
+       if (dbg_urb(urb)) {
+               dev_vdbg(hsotg->dev, "DWC OTG HCD URB Enqueue\n");
+               dwc2_dump_urb_info(hcd, urb, "urb_enqueue");
+       }
+
+       if (ep == NULL)
+               return -EINVAL;
+
+       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS ||
+           usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+               spin_lock_irqsave(&hsotg->lock, flags);
+               if (!dwc2_hcd_is_bandwidth_allocated(hsotg, ep))
+                       alloc_bandwidth = 1;
+               spin_unlock_irqrestore(&hsotg->lock, flags);
+       }
+
+       switch (usb_pipetype(urb->pipe)) {
+       case PIPE_CONTROL:
+               ep_type = USB_ENDPOINT_XFER_CONTROL;
+               break;
+       case PIPE_ISOCHRONOUS:
+               ep_type = USB_ENDPOINT_XFER_ISOC;
+               break;
+       case PIPE_BULK:
+               ep_type = USB_ENDPOINT_XFER_BULK;
+               break;
+       case PIPE_INTERRUPT:
+               ep_type = USB_ENDPOINT_XFER_INT;
+               break;
+       default:
+               dev_warn(hsotg->dev, "Wrong ep type\n");
+       }
+
+       dwc2_urb = dwc2_hcd_urb_alloc(hsotg, urb->number_of_packets,
+                                     mem_flags);
+       if (!dwc2_urb)
+               return -ENOMEM;
+
+       dwc2_hcd_urb_set_pipeinfo(hsotg, dwc2_urb, usb_pipedevice(urb->pipe),
+                                 usb_pipeendpoint(urb->pipe), ep_type,
+                                 usb_pipein(urb->pipe),
+                                 usb_maxpacket(urb->dev, urb->pipe,
+                                               !(usb_pipein(urb->pipe))));
+
+       buf = urb->transfer_buffer;
+
+       if (hcd->self.uses_dma) {
+               if (!buf && (urb->transfer_dma & 3)) {
+                       dev_err(hsotg->dev,
+                               "%s: unaligned transfer with no transfer_buffer",
+                               __func__);
+                       retval = -EINVAL;
+                       goto fail1;
+               }
+       }
+
+       if (!(urb->transfer_flags & URB_NO_INTERRUPT))
+               tflags |= URB_GIVEBACK_ASAP;
+       if (urb->transfer_flags & URB_ZERO_PACKET)
+               tflags |= URB_SEND_ZERO_PACKET;
+
+       dwc2_urb->priv = urb;
+       dwc2_urb->buf = buf;
+       dwc2_urb->dma = urb->transfer_dma;
+       dwc2_urb->length = urb->transfer_buffer_length;
+       dwc2_urb->setup_packet = urb->setup_packet;
+       dwc2_urb->setup_dma = urb->setup_dma;
+       dwc2_urb->flags = tflags;
+       dwc2_urb->interval = urb->interval;
+       dwc2_urb->status = -EINPROGRESS;
+
+       for (i = 0; i < urb->number_of_packets; ++i)
+               dwc2_hcd_urb_set_iso_desc_params(dwc2_urb, i,
+                                                urb->iso_frame_desc[i].offset,
+                                                urb->iso_frame_desc[i].length);
+
+       urb->hcpriv = dwc2_urb;
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+       retval = usb_hcd_link_urb_to_ep(hcd, urb);
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+       if (retval)
+               goto fail1;
+
+       retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, &ep->hcpriv, mem_flags);
+       if (retval)
+               goto fail2;
+
+       if (alloc_bandwidth) {
+               spin_lock_irqsave(&hsotg->lock, flags);
+               dwc2_allocate_bus_bandwidth(hcd,
+                               dwc2_hcd_get_ep_bandwidth(hsotg, ep),
+                               urb);
+               spin_unlock_irqrestore(&hsotg->lock, flags);
+       }
+
+       return 0;
+
+fail2:
+       spin_lock_irqsave(&hsotg->lock, flags);
+       dwc2_urb->priv = NULL;
+       usb_hcd_unlink_urb_from_ep(hcd, urb);
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+fail1:
+       urb->hcpriv = NULL;
+       kfree(dwc2_urb);
+
+       return retval;
+}
+
+/*
+ * Aborts/cancels a USB transfer request. Always returns 0 to indicate success.
+ */
+static int _dwc2_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+                                int status)
+{
+       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+       int rc;
+       unsigned long flags;
+
+       dev_dbg(hsotg->dev, "DWC OTG HCD URB Dequeue\n");
+       dwc2_dump_urb_info(hcd, urb, "urb_dequeue");
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (rc)
+               goto out;
+
+       if (!urb->hcpriv) {
+               dev_dbg(hsotg->dev, "## urb->hcpriv is NULL ##\n");
+               goto out;
+       }
+
+       rc = dwc2_hcd_urb_dequeue(hsotg, urb->hcpriv);
+
+       usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+       kfree(urb->hcpriv);
+       urb->hcpriv = NULL;
+
+       /* Higher layer software sets URB status */
+       spin_unlock(&hsotg->lock);
+       usb_hcd_giveback_urb(hcd, urb, status);
+       spin_lock(&hsotg->lock);
+
+       dev_dbg(hsotg->dev, "Called usb_hcd_giveback_urb()\n");
+       dev_dbg(hsotg->dev, "  urb->status = %d\n", urb->status);
+out:
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+
+       return rc;
+}
+
+/*
+ * Frees resources in the DWC_otg controller related to a given endpoint. Also
+ * clears state in the HCD related to the endpoint. Any URBs for the endpoint
+ * must already be dequeued.
+ */
+static void _dwc2_hcd_endpoint_disable(struct usb_hcd *hcd,
+                                      struct usb_host_endpoint *ep)
+{
+       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+       dev_dbg(hsotg->dev,
+               "DWC OTG HCD EP DISABLE: bEndpointAddress=0x%02x, ep->hcpriv=%p\n",
+               ep->desc.bEndpointAddress, ep->hcpriv);
+       dwc2_hcd_endpoint_disable(hsotg, ep, 250);
+}
+
+/*
+ * Resets endpoint specific parameter values, in current version used to reset
+ * the data toggle (as a WA). This function can be called from usb_clear_halt
+ * routine.
+ */
+static void _dwc2_hcd_endpoint_reset(struct usb_hcd *hcd,
+                                    struct usb_host_endpoint *ep)
+{
+       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+       int is_control = usb_endpoint_xfer_control(&ep->desc);
+       int is_out = usb_endpoint_dir_out(&ep->desc);
+       int epnum = usb_endpoint_num(&ep->desc);
+       struct usb_device *udev;
+       unsigned long flags;
+
+       dev_dbg(hsotg->dev,
+               "DWC OTG HCD EP RESET: bEndpointAddress=0x%02x\n",
+               ep->desc.bEndpointAddress);
+
+       udev = to_usb_device(hsotg->dev);
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+
+       usb_settoggle(udev, epnum, is_out, 0);
+       if (is_control)
+               usb_settoggle(udev, epnum, !is_out, 0);
+       dwc2_hcd_endpoint_reset(hsotg, ep);
+
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+}
+
+/*
+ * Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if
+ * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid
+ * interrupt.
+ *
+ * This function is called by the USB core when an interrupt occurs
+ */
+static irqreturn_t _dwc2_hcd_irq(struct usb_hcd *hcd)
+{
+       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+       return dwc2_handle_hcd_intr(hsotg);
+}
+
+/*
+ * Creates Status Change bitmap for the root hub and root port. The bitmap is
+ * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1
+ * is the status change indicator for the single root port. Returns 1 if either
+ * change indicator is 1, otherwise returns 0.
+ */
+static int _dwc2_hcd_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+       buf[0] = dwc2_hcd_is_status_changed(hsotg, 1) << 1;
+       return buf[0] != 0;
+}
+
+/* Handles hub class-specific requests */
+static int _dwc2_hcd_hub_control(struct usb_hcd *hcd, u16 typereq, u16 wvalue,
+                                u16 windex, char *buf, u16 wlength)
+{
+       int retval = dwc2_hcd_hub_control(dwc2_hcd_to_hsotg(hcd), typereq,
+                                         wvalue, windex, buf, wlength);
+       return retval;
+}
+
+/* Handles hub TT buffer clear completions */
+static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd,
+                                              struct usb_host_endpoint *ep)
+{
+       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+       struct dwc2_qh *qh;
+       unsigned long flags;
+
+       qh = ep->hcpriv;
+       if (!qh)
+               return;
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+       qh->tt_buffer_dirty = 0;
+
+       if (hsotg->flags.b.port_connect_status)
+               dwc2_hcd_queue_transactions(hsotg, DWC2_TRANSACTION_ALL);
+
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+}
+
+static struct hc_driver dwc2_hc_driver = {
+       .description = "dwc2_hsotg",
+       .product_desc = "DWC OTG Controller",
+       .hcd_priv_size = sizeof(struct wrapper_priv_data),
+
+       .irq = _dwc2_hcd_irq,
+       .flags = HCD_MEMORY | HCD_USB2,
+
+       .start = _dwc2_hcd_start,
+       .stop = _dwc2_hcd_stop,
+       .urb_enqueue = _dwc2_hcd_urb_enqueue,
+       .urb_dequeue = _dwc2_hcd_urb_dequeue,
+       .endpoint_disable = _dwc2_hcd_endpoint_disable,
+       .endpoint_reset = _dwc2_hcd_endpoint_reset,
+       .get_frame_number = _dwc2_hcd_get_frame_number,
+
+       .hub_status_data = _dwc2_hcd_hub_status_data,
+       .hub_control = _dwc2_hcd_hub_control,
+       .clear_tt_buffer_complete = _dwc2_hcd_clear_tt_buffer_complete,
+};
+
+/*
+ * Frees secondary storage associated with the dwc2_hsotg structure contained
+ * in the struct usb_hcd field
+ */
+static void dwc2_hcd_free(struct dwc2_hsotg *hsotg)
+{
+       u32 ahbcfg;
+       u32 dctl;
+       int i;
+
+       dev_dbg(hsotg->dev, "DWC OTG HCD FREE\n");
+
+       /* Free memory for QH/QTD lists */
+       dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_inactive);
+       dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_active);
+       dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_inactive);
+       dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_ready);
+       dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_assigned);
+       dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_queued);
+
+       /* Free memory for the host channels */
+       for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+               struct dwc2_host_chan *chan = hsotg->hc_ptr_array[i];
+
+               if (chan != NULL) {
+                       dev_dbg(hsotg->dev, "HCD Free channel #%i, chan=%p\n",
+                               i, chan);
+                       hsotg->hc_ptr_array[i] = NULL;
+                       kfree(chan);
+               }
+       }
+
+       if (hsotg->core_params->dma_enable > 0) {
+               if (hsotg->status_buf) {
+                       dma_free_coherent(hsotg->dev, DWC2_HCD_STATUS_BUF_SIZE,
+                                         hsotg->status_buf,
+                                         hsotg->status_buf_dma);
+                       hsotg->status_buf = NULL;
+               }
+       } else {
+               kfree(hsotg->status_buf);
+               hsotg->status_buf = NULL;
+       }
+
+       ahbcfg = readl(hsotg->regs + GAHBCFG);
+
+       /* Disable all interrupts */
+       ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
+       writel(ahbcfg, hsotg->regs + GAHBCFG);
+       writel(0, hsotg->regs + GINTMSK);
+
+       if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a) {
+               dctl = readl(hsotg->regs + DCTL);
+               dctl |= DCTL_SFTDISCON;
+               writel(dctl, hsotg->regs + DCTL);
+       }
+
+       if (hsotg->wq_otg) {
+               if (!cancel_work_sync(&hsotg->wf_otg))
+                       flush_workqueue(hsotg->wq_otg);
+               destroy_workqueue(hsotg->wq_otg);
+       }
+
+       kfree(hsotg->core_params);
+       hsotg->core_params = NULL;
+       del_timer(&hsotg->wkp_timer);
+}
+
+static void dwc2_hcd_release(struct dwc2_hsotg *hsotg)
+{
+       /* Turn off all host-specific interrupts */
+       dwc2_disable_host_interrupts(hsotg);
+
+       dwc2_hcd_free(hsotg);
+}
+
+/*
+ * Sets all parameters to the given value.
+ *
+ * Assumes that the dwc2_core_params struct contains only integers.
+ */
+void dwc2_set_all_params(struct dwc2_core_params *params, int value)
+{
+       int *p = (int *)params;
+       size_t size = sizeof(*params) / sizeof(*p);
+       int i;
+
+       for (i = 0; i < size; i++)
+               p[i] = value;
+}
+EXPORT_SYMBOL_GPL(dwc2_set_all_params);
+
+/*
+ * Initializes the HCD. This function allocates memory for and initializes the
+ * static parts of the usb_hcd and dwc2_hsotg structures. It also registers the
+ * USB bus with the core and calls the hc_driver->start() function. It returns
+ * a negative error on failure.
+ */
+int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
+                 const struct dwc2_core_params *params)
+{
+       struct usb_hcd *hcd;
+       struct dwc2_host_chan *channel;
+       u32 hcfg;
+       int i, num_channels;
+       int retval;
+
+       dev_dbg(hsotg->dev, "DWC OTG HCD INIT\n");
+
+       /* Detect config values from hardware */
+       retval = dwc2_get_hwparams(hsotg);
+
+       if (retval)
+               return retval;
+
+       retval = -ENOMEM;
+
+       hcfg = readl(hsotg->regs + HCFG);
+       dev_dbg(hsotg->dev, "hcfg=%08x\n", hcfg);
+
+#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
+       hsotg->frame_num_array = kzalloc(sizeof(*hsotg->frame_num_array) *
+                                        FRAME_NUM_ARRAY_SIZE, GFP_KERNEL);
+       if (!hsotg->frame_num_array)
+               goto error1;
+       hsotg->last_frame_num_array = kzalloc(
+                       sizeof(*hsotg->last_frame_num_array) *
+                       FRAME_NUM_ARRAY_SIZE, GFP_KERNEL);
+       if (!hsotg->last_frame_num_array)
+               goto error1;
+       hsotg->last_frame_num = HFNUM_MAX_FRNUM;
+#endif
+
+       hsotg->core_params = kzalloc(sizeof(*hsotg->core_params), GFP_KERNEL);
+       if (!hsotg->core_params)
+               goto error1;
+
+       dwc2_set_all_params(hsotg->core_params, -1);
+
+       /* Validate parameter values */
+       dwc2_set_parameters(hsotg, params);
+
+       /* Check if the bus driver or platform code has setup a dma_mask */
+       if (hsotg->core_params->dma_enable > 0 &&
+           hsotg->dev->dma_mask == NULL) {
+               dev_warn(hsotg->dev,
+                        "dma_mask not set, disabling DMA\n");
+               hsotg->core_params->dma_enable = 0;
+               hsotg->core_params->dma_desc_enable = 0;
+       }
+
+       /* Set device flags indicating whether the HCD supports DMA */
+       if (hsotg->core_params->dma_enable > 0) {
+               if (dma_set_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0)
+                       dev_warn(hsotg->dev, "can't set DMA mask\n");
+               if (dma_set_coherent_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0)
+                       dev_warn(hsotg->dev, "can't set coherent DMA mask\n");
+       }
+
+       hcd = usb_create_hcd(&dwc2_hc_driver, hsotg->dev, dev_name(hsotg->dev));
+       if (!hcd)
+               goto error1;
+
+       if (hsotg->core_params->dma_enable <= 0)
+               hcd->self.uses_dma = 0;
+
+       hcd->has_tt = 1;
+
+       spin_lock_init(&hsotg->lock);
+       ((struct wrapper_priv_data *) &hcd->hcd_priv)->hsotg = hsotg;
+       hsotg->priv = hcd;
+
+       /*
+        * Disable the global interrupt until all the interrupt handlers are
+        * installed
+        */
+       dwc2_disable_global_interrupts(hsotg);
+
+       /* Initialize the DWC_otg core, and select the Phy type */
+       retval = dwc2_core_init(hsotg, true, irq);
+       if (retval)
+               goto error2;
+
+       /* Create new workqueue and init work */
+       retval = -ENOMEM;
+       hsotg->wq_otg = create_singlethread_workqueue("dwc2");
+       if (!hsotg->wq_otg) {
+               dev_err(hsotg->dev, "Failed to create workqueue\n");
+               goto error2;
+       }
+       INIT_WORK(&hsotg->wf_otg, dwc2_conn_id_status_change);
+
+       setup_timer(&hsotg->wkp_timer, dwc2_wakeup_detected,
+                   (unsigned long)hsotg);
+
+       /* Initialize the non-periodic schedule */
+       INIT_LIST_HEAD(&hsotg->non_periodic_sched_inactive);
+       INIT_LIST_HEAD(&hsotg->non_periodic_sched_active);
+
+       /* Initialize the periodic schedule */
+       INIT_LIST_HEAD(&hsotg->periodic_sched_inactive);
+       INIT_LIST_HEAD(&hsotg->periodic_sched_ready);
+       INIT_LIST_HEAD(&hsotg->periodic_sched_assigned);
+       INIT_LIST_HEAD(&hsotg->periodic_sched_queued);
+
+       /*
+        * Create a host channel descriptor for each host channel implemented
+        * in the controller. Initialize the channel descriptor array.
+        */
+       INIT_LIST_HEAD(&hsotg->free_hc_list);
+       num_channels = hsotg->core_params->host_channels;
+       memset(&hsotg->hc_ptr_array[0], 0, sizeof(hsotg->hc_ptr_array));
+
+       for (i = 0; i < num_channels; i++) {
+               channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+               if (channel == NULL)
+                       goto error3;
+               channel->hc_num = i;
+               hsotg->hc_ptr_array[i] = channel;
+       }
+
+       if (hsotg->core_params->uframe_sched > 0)
+               dwc2_hcd_init_usecs(hsotg);
+
+       /* Initialize hsotg start work */
+       INIT_DELAYED_WORK(&hsotg->start_work, dwc2_hcd_start_func);
+
+       /* Initialize port reset work */
+       INIT_DELAYED_WORK(&hsotg->reset_work, dwc2_hcd_reset_func);
+
+       /*
+        * Allocate space for storing data on status transactions. Normally no
+        * data is sent, but this space acts as a bit bucket. This must be
+        * done after usb_add_hcd since that function allocates the DMA buffer
+        * pool.
+        */
+       if (hsotg->core_params->dma_enable > 0)
+               hsotg->status_buf = dma_alloc_coherent(hsotg->dev,
+                                       DWC2_HCD_STATUS_BUF_SIZE,
+                                       &hsotg->status_buf_dma, GFP_KERNEL);
+       else
+               hsotg->status_buf = kzalloc(DWC2_HCD_STATUS_BUF_SIZE,
+                                         GFP_KERNEL);
+
+       if (!hsotg->status_buf)
+               goto error3;
+
+       hsotg->otg_port = 1;
+       hsotg->frame_list = NULL;
+       hsotg->frame_list_dma = 0;
+       hsotg->periodic_qh_count = 0;
+
+       /* Initiate lx_state to L3 disconnected state */
+       hsotg->lx_state = DWC2_L3;
+
+       hcd->self.otg_port = hsotg->otg_port;
+
+       /* Don't support SG list at this point */
+       hcd->self.sg_tablesize = 0;
+
+       /*
+        * Finish generic HCD initialization and start the HCD. This function
+        * allocates the DMA buffer pool, registers the USB bus, requests the
+        * IRQ line, and calls hcd_start method.
+        */
+       retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
+       if (retval < 0)
+               goto error3;
+
+       dwc2_hcd_dump_state(hsotg);
+
+       dwc2_enable_global_interrupts(hsotg);
+
+       return 0;
+
+error3:
+       dwc2_hcd_release(hsotg);
+error2:
+       usb_put_hcd(hcd);
+error1:
+       kfree(hsotg->core_params);
+
+#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
+       kfree(hsotg->last_frame_num_array);
+       kfree(hsotg->frame_num_array);
+#endif
+
+       dev_err(hsotg->dev, "%s() FAILED, returning %d\n", __func__, retval);
+       return retval;
+}
+EXPORT_SYMBOL_GPL(dwc2_hcd_init);
+
+/*
+ * Removes the HCD.
+ * Frees memory and resources associated with the HCD and deregisters the bus.
+ */
+void dwc2_hcd_remove(struct dwc2_hsotg *hsotg)
+{
+       struct usb_hcd *hcd;
+
+       dev_dbg(hsotg->dev, "DWC OTG HCD REMOVE\n");
+
+       hcd = dwc2_hsotg_to_hcd(hsotg);
+       dev_dbg(hsotg->dev, "hsotg->hcd = %p\n", hcd);
+
+       if (!hcd) {
+               dev_dbg(hsotg->dev, "%s: dwc2_hsotg_to_hcd(hsotg) NULL!\n",
+                       __func__);
+               return;
+       }
+
+       usb_remove_hcd(hcd);
+       hsotg->priv = NULL;
+       dwc2_hcd_release(hsotg);
+       usb_put_hcd(hcd);
+
+#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
+       kfree(hsotg->last_frame_num_array);
+       kfree(hsotg->frame_num_array);
+#endif
+}
+EXPORT_SYMBOL_GPL(dwc2_hcd_remove);
diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h
new file mode 100644 (file)
index 0000000..fdc6d48
--- /dev/null
@@ -0,0 +1,769 @@
+/*
+ * hcd.h - DesignWare HS OTG Controller host-mode declarations
+ *
+ * Copyright (C) 2004-2013 Synopsys, Inc.
+ *
+ * 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") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * 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 __DWC2_HCD_H__
+#define __DWC2_HCD_H__
+
+/*
+ * This file contains the structures, constants, and interfaces for the
+ * Host Contoller Driver (HCD)
+ *
+ * The Host Controller Driver (HCD) is responsible for translating requests
+ * from the USB Driver into the appropriate actions on the DWC_otg controller.
+ * It isolates the USBD from the specifics of the controller by providing an
+ * API to the USBD.
+ */
+
+struct dwc2_qh;
+
+/**
+ * struct dwc2_host_chan - Software host channel descriptor
+ *
+ * @hc_num:             Host channel number, used for register address lookup
+ * @dev_addr:           Address of the device
+ * @ep_num:             Endpoint of the device
+ * @ep_is_in:           Endpoint direction
+ * @speed:              Device speed. One of the following values:
+ *                       - USB_SPEED_LOW
+ *                       - USB_SPEED_FULL
+ *                       - USB_SPEED_HIGH
+ * @ep_type:            Endpoint type. One of the following values:
+ *                       - USB_ENDPOINT_XFER_CONTROL: 0
+ *                       - USB_ENDPOINT_XFER_ISOC:    1
+ *                       - USB_ENDPOINT_XFER_BULK:    2
+ *                       - USB_ENDPOINT_XFER_INTR:    3
+ * @max_packet:         Max packet size in bytes
+ * @data_pid_start:     PID for initial transaction.
+ *                       0: DATA0
+ *                       1: DATA2
+ *                       2: DATA1
+ *                       3: MDATA (non-Control EP),
+ *                          SETUP (Control EP)
+ * @multi_count:        Number of additional periodic transactions per
+ *                      (micro)frame
+ * @xfer_buf:           Pointer to current transfer buffer position
+ * @xfer_dma:           DMA address of xfer_buf
+ * @align_buf:          In Buffer DMA mode this will be used if xfer_buf is not
+ *                      DWORD aligned
+ * @xfer_len:           Total number of bytes to transfer
+ * @xfer_count:         Number of bytes transferred so far
+ * @start_pkt_count:    Packet count at start of transfer
+ * @xfer_started:       True if the transfer has been started
+ * @ping:               True if a PING request should be issued on this channel
+ * @error_state:        True if the error count for this transaction is non-zero
+ * @halt_on_queue:      True if this channel should be halted the next time a
+ *                      request is queued for the channel. This is necessary in
+ *                      slave mode if no request queue space is available when
+ *                      an attempt is made to halt the channel.
+ * @halt_pending:       True if the host channel has been halted, but the core
+ *                      is not finished flushing queued requests
+ * @do_split:           Enable split for the channel
+ * @complete_split:     Enable complete split
+ * @hub_addr:           Address of high speed hub for the split
+ * @hub_port:           Port of the low/full speed device for the split
+ * @xact_pos:           Split transaction position. One of the following values:
+ *                       - DWC2_HCSPLT_XACTPOS_MID
+ *                       - DWC2_HCSPLT_XACTPOS_BEGIN
+ *                       - DWC2_HCSPLT_XACTPOS_END
+ *                       - DWC2_HCSPLT_XACTPOS_ALL
+ * @requests:           Number of requests issued for this channel since it was
+ *                      assigned to the current transfer (not counting PINGs)
+ * @schinfo:            Scheduling micro-frame bitmap
+ * @ntd:                Number of transfer descriptors for the transfer
+ * @halt_status:        Reason for halting the host channel
+ * @hcint               Contents of the HCINT register when the interrupt came
+ * @qh:                 QH for the transfer being processed by this channel
+ * @hc_list_entry:      For linking to list of host channels
+ * @desc_list_addr:     Current QH's descriptor list DMA address
+ *
+ * This structure represents the state of a single host channel when acting in
+ * host mode. It contains the data items needed to transfer packets to an
+ * endpoint via a host channel.
+ */
+struct dwc2_host_chan {
+       u8 hc_num;
+
+       unsigned dev_addr:7;
+       unsigned ep_num:4;
+       unsigned ep_is_in:1;
+       unsigned speed:4;
+       unsigned ep_type:2;
+       unsigned max_packet:11;
+       unsigned data_pid_start:2;
+#define DWC2_HC_PID_DATA0      TSIZ_SC_MC_PID_DATA0
+#define DWC2_HC_PID_DATA2      TSIZ_SC_MC_PID_DATA2
+#define DWC2_HC_PID_DATA1      TSIZ_SC_MC_PID_DATA1
+#define DWC2_HC_PID_MDATA      TSIZ_SC_MC_PID_MDATA
+#define DWC2_HC_PID_SETUP      TSIZ_SC_MC_PID_SETUP
+
+       unsigned multi_count:2;
+
+       u8 *xfer_buf;
+       dma_addr_t xfer_dma;
+       dma_addr_t align_buf;
+       u32 xfer_len;
+       u32 xfer_count;
+       u16 start_pkt_count;
+       u8 xfer_started;
+       u8 do_ping;
+       u8 error_state;
+       u8 halt_on_queue;
+       u8 halt_pending;
+       u8 do_split;
+       u8 complete_split;
+       u8 hub_addr;
+       u8 hub_port;
+       u8 xact_pos;
+#define DWC2_HCSPLT_XACTPOS_MID        HCSPLT_XACTPOS_MID
+#define DWC2_HCSPLT_XACTPOS_END        HCSPLT_XACTPOS_END
+#define DWC2_HCSPLT_XACTPOS_BEGIN HCSPLT_XACTPOS_BEGIN
+#define DWC2_HCSPLT_XACTPOS_ALL        HCSPLT_XACTPOS_ALL
+
+       u8 requests;
+       u8 schinfo;
+       u16 ntd;
+       enum dwc2_halt_status halt_status;
+       u32 hcint;
+       struct dwc2_qh *qh;
+       struct list_head hc_list_entry;
+       dma_addr_t desc_list_addr;
+};
+
+struct dwc2_hcd_pipe_info {
+       u8 dev_addr;
+       u8 ep_num;
+       u8 pipe_type;
+       u8 pipe_dir;
+       u16 mps;
+};
+
+struct dwc2_hcd_iso_packet_desc {
+       u32 offset;
+       u32 length;
+       u32 actual_length;
+       u32 status;
+};
+
+struct dwc2_qtd;
+
+struct dwc2_hcd_urb {
+       void *priv;
+       struct dwc2_qtd *qtd;
+       void *buf;
+       dma_addr_t dma;
+       void *setup_packet;
+       dma_addr_t setup_dma;
+       u32 length;
+       u32 actual_length;
+       u32 status;
+       u32 error_count;
+       u32 packet_count;
+       u32 flags;
+       u16 interval;
+       struct dwc2_hcd_pipe_info pipe_info;
+       struct dwc2_hcd_iso_packet_desc iso_descs[0];
+};
+
+/* Phases for control transfers */
+enum dwc2_control_phase {
+       DWC2_CONTROL_SETUP,
+       DWC2_CONTROL_DATA,
+       DWC2_CONTROL_STATUS,
+};
+
+/* Transaction types */
+enum dwc2_transaction_type {
+       DWC2_TRANSACTION_NONE,
+       DWC2_TRANSACTION_PERIODIC,
+       DWC2_TRANSACTION_NON_PERIODIC,
+       DWC2_TRANSACTION_ALL,
+};
+
+/**
+ * struct dwc2_qh - Software queue head structure
+ *
+ * @ep_type:            Endpoint type. One of the following values:
+ *                       - USB_ENDPOINT_XFER_CONTROL
+ *                       - USB_ENDPOINT_XFER_BULK
+ *                       - USB_ENDPOINT_XFER_INT
+ *                       - USB_ENDPOINT_XFER_ISOC
+ * @ep_is_in:           Endpoint direction
+ * @maxp:               Value from wMaxPacketSize field of Endpoint Descriptor
+ * @dev_speed:          Device speed. One of the following values:
+ *                       - USB_SPEED_LOW
+ *                       - USB_SPEED_FULL
+ *                       - USB_SPEED_HIGH
+ * @data_toggle:        Determines the PID of the next data packet for
+ *                      non-controltransfers. Ignored for control transfers.
+ *                      One of the following values:
+ *                       - DWC2_HC_PID_DATA0
+ *                       - DWC2_HC_PID_DATA1
+ * @ping_state:         Ping state
+ * @do_split:           Full/low speed endpoint on high-speed hub requires split
+ * @td_first:           Index of first activated isochronous transfer descriptor
+ * @td_last:            Index of last activated isochronous transfer descriptor
+ * @usecs:              Bandwidth in microseconds per (micro)frame
+ * @interval:           Interval between transfers in (micro)frames
+ * @sched_frame:        (Micro)frame to initialize a periodic transfer.
+ *                      The transfer executes in the following (micro)frame.
+ * @frame_usecs:        Internal variable used by the microframe scheduler
+ * @start_split_frame:  (Micro)frame at which last start split was initialized
+ * @ntd:                Actual number of transfer descriptors in a list
+ * @dw_align_buf:       Used instead of original buffer if its physical address
+ *                      is not dword-aligned
+ * @dw_align_buf_dma:   DMA address for align_buf
+ * @qtd_list:           List of QTDs for this QH
+ * @channel:            Host channel currently processing transfers for this QH
+ * @qh_list_entry:      Entry for QH in either the periodic or non-periodic
+ *                      schedule
+ * @desc_list:          List of transfer descriptors
+ * @desc_list_dma:      Physical address of desc_list
+ * @n_bytes:            Xfer Bytes array. Each element corresponds to a transfer
+ *                      descriptor and indicates original XferSize value for the
+ *                      descriptor
+ * @tt_buffer_dirty     True if clear_tt_buffer_complete is pending
+ *
+ * A Queue Head (QH) holds the static characteristics of an endpoint and
+ * maintains a list of transfers (QTDs) for that endpoint. A QH structure may
+ * be entered in either the non-periodic or periodic schedule.
+ */
+struct dwc2_qh {
+       u8 ep_type;
+       u8 ep_is_in;
+       u16 maxp;
+       u8 dev_speed;
+       u8 data_toggle;
+       u8 ping_state;
+       u8 do_split;
+       u8 td_first;
+       u8 td_last;
+       u16 usecs;
+       u16 interval;
+       u16 sched_frame;
+       u16 frame_usecs[8];
+       u16 start_split_frame;
+       u16 ntd;
+       u8 *dw_align_buf;
+       dma_addr_t dw_align_buf_dma;
+       struct list_head qtd_list;
+       struct dwc2_host_chan *channel;
+       struct list_head qh_list_entry;
+       struct dwc2_hcd_dma_desc *desc_list;
+       dma_addr_t desc_list_dma;
+       u32 *n_bytes;
+       unsigned tt_buffer_dirty:1;
+};
+
+/**
+ * struct dwc2_qtd - Software queue transfer descriptor (QTD)
+ *
+ * @control_phase:      Current phase for control transfers (Setup, Data, or
+ *                      Status)
+ * @in_process:         Indicates if this QTD is currently processed by HW
+ * @data_toggle:        Determines the PID of the next data packet for the
+ *                      data phase of control transfers. Ignored for other
+ *                      transfer types. One of the following values:
+ *                       - DWC2_HC_PID_DATA0
+ *                       - DWC2_HC_PID_DATA1
+ * @complete_split:     Keeps track of the current split type for FS/LS
+ *                      endpoints on a HS Hub
+ * @isoc_split_pos:     Position of the ISOC split in full/low speed
+ * @isoc_frame_index:   Index of the next frame descriptor for an isochronous
+ *                      transfer. A frame descriptor describes the buffer
+ *                      position and length of the data to be transferred in the
+ *                      next scheduled (micro)frame of an isochronous transfer.
+ *                      It also holds status for that transaction. The frame
+ *                      index starts at 0.
+ * @isoc_split_offset:  Position of the ISOC split in the buffer for the
+ *                      current frame
+ * @ssplit_out_xfer_count: How many bytes transferred during SSPLIT OUT
+ * @error_count:        Holds the number of bus errors that have occurred for
+ *                      a transaction within this transfer
+ * @n_desc:             Number of DMA descriptors for this QTD
+ * @isoc_frame_index_last: Last activated frame (packet) index, used in
+ *                      descriptor DMA mode only
+ * @urb:                URB for this transfer
+ * @qh:                 Queue head for this QTD
+ * @qtd_list_entry:     For linking to the QH's list of QTDs
+ *
+ * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control,
+ * interrupt, or isochronous transfer. A single QTD is created for each URB
+ * (of one of these types) submitted to the HCD. The transfer associated with
+ * a QTD may require one or multiple transactions.
+ *
+ * A QTD is linked to a Queue Head, which is entered in either the
+ * non-periodic or periodic schedule for execution. When a QTD is chosen for
+ * execution, some or all of its transactions may be executed. After
+ * execution, the state of the QTD is updated. The QTD may be retired if all
+ * its transactions are complete or if an error occurred. Otherwise, it
+ * remains in the schedule so more transactions can be executed later.
+ */
+struct dwc2_qtd {
+       enum dwc2_control_phase control_phase;
+       u8 in_process;
+       u8 data_toggle;
+       u8 complete_split;
+       u8 isoc_split_pos;
+       u16 isoc_frame_index;
+       u16 isoc_split_offset;
+       u32 ssplit_out_xfer_count;
+       u8 error_count;
+       u8 n_desc;
+       u16 isoc_frame_index_last;
+       struct dwc2_hcd_urb *urb;
+       struct dwc2_qh *qh;
+       struct list_head qtd_list_entry;
+};
+
+#ifdef DEBUG
+struct hc_xfer_info {
+       struct dwc2_hsotg *hsotg;
+       struct dwc2_host_chan *chan;
+};
+#endif
+
+/* Gets the struct usb_hcd that contains a struct dwc2_hsotg */
+static inline struct usb_hcd *dwc2_hsotg_to_hcd(struct dwc2_hsotg *hsotg)
+{
+       return (struct usb_hcd *)hsotg->priv;
+}
+
+/*
+ * Inline used to disable one channel interrupt. Channel interrupts are
+ * disabled when the channel is halted or released by the interrupt handler.
+ * There is no need to handle further interrupts of that type until the
+ * channel is re-assigned. In fact, subsequent handling may cause crashes
+ * because the channel structures are cleaned up when the channel is released.
+ */
+static inline void disable_hc_int(struct dwc2_hsotg *hsotg, int chnum, u32 intr)
+{
+       u32 mask = readl(hsotg->regs + HCINTMSK(chnum));
+
+       mask &= ~intr;
+       writel(mask, hsotg->regs + HCINTMSK(chnum));
+}
+
+/*
+ * Returns the mode of operation, host or device
+ */
+static inline int dwc2_is_host_mode(struct dwc2_hsotg *hsotg)
+{
+       return (readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) != 0;
+}
+static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg)
+{
+       return (readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) == 0;
+}
+
+/*
+ * Reads HPRT0 in preparation to modify. It keeps the WC bits 0 so that if they
+ * are read as 1, they won't clear when written back.
+ */
+static inline u32 dwc2_read_hprt0(struct dwc2_hsotg *hsotg)
+{
+       u32 hprt0 = readl(hsotg->regs + HPRT0);
+
+       hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG | HPRT0_OVRCURRCHG);
+       return hprt0;
+}
+
+static inline u8 dwc2_hcd_get_ep_num(struct dwc2_hcd_pipe_info *pipe)
+{
+       return pipe->ep_num;
+}
+
+static inline u8 dwc2_hcd_get_pipe_type(struct dwc2_hcd_pipe_info *pipe)
+{
+       return pipe->pipe_type;
+}
+
+static inline u16 dwc2_hcd_get_mps(struct dwc2_hcd_pipe_info *pipe)
+{
+       return pipe->mps;
+}
+
+static inline u8 dwc2_hcd_get_dev_addr(struct dwc2_hcd_pipe_info *pipe)
+{
+       return pipe->dev_addr;
+}
+
+static inline u8 dwc2_hcd_is_pipe_isoc(struct dwc2_hcd_pipe_info *pipe)
+{
+       return pipe->pipe_type == USB_ENDPOINT_XFER_ISOC;
+}
+
+static inline u8 dwc2_hcd_is_pipe_int(struct dwc2_hcd_pipe_info *pipe)
+{
+       return pipe->pipe_type == USB_ENDPOINT_XFER_INT;
+}
+
+static inline u8 dwc2_hcd_is_pipe_bulk(struct dwc2_hcd_pipe_info *pipe)
+{
+       return pipe->pipe_type == USB_ENDPOINT_XFER_BULK;
+}
+
+static inline u8 dwc2_hcd_is_pipe_control(struct dwc2_hcd_pipe_info *pipe)
+{
+       return pipe->pipe_type == USB_ENDPOINT_XFER_CONTROL;
+}
+
+static inline u8 dwc2_hcd_is_pipe_in(struct dwc2_hcd_pipe_info *pipe)
+{
+       return pipe->pipe_dir == USB_DIR_IN;
+}
+
+static inline u8 dwc2_hcd_is_pipe_out(struct dwc2_hcd_pipe_info *pipe)
+{
+       return !dwc2_hcd_is_pipe_in(pipe);
+}
+
+extern int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
+                        const struct dwc2_core_params *params);
+extern void dwc2_hcd_remove(struct dwc2_hsotg *hsotg);
+extern void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
+                               const struct dwc2_core_params *params);
+extern void dwc2_set_all_params(struct dwc2_core_params *params, int value);
+extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
+
+/* Transaction Execution Functions */
+extern enum dwc2_transaction_type dwc2_hcd_select_transactions(
+                                               struct dwc2_hsotg *hsotg);
+extern void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
+                                       enum dwc2_transaction_type tr_type);
+
+/* Schedule Queue Functions */
+/* Implemented in hcd_queue.c */
+extern void dwc2_hcd_init_usecs(struct dwc2_hsotg *hsotg);
+extern void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
+extern int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
+extern void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
+extern void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+                                  int sched_csplit);
+
+extern void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb);
+extern int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
+                           struct dwc2_qh **qh, gfp_t mem_flags);
+
+/* Unlinks and frees a QTD */
+static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
+                                               struct dwc2_qtd *qtd,
+                                               struct dwc2_qh *qh)
+{
+       list_del(&qtd->qtd_list_entry);
+       kfree(qtd);
+}
+
+/* Descriptor DMA support functions */
+extern void dwc2_hcd_start_xfer_ddma(struct dwc2_hsotg *hsotg,
+                                    struct dwc2_qh *qh);
+extern void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg,
+                                       struct dwc2_host_chan *chan, int chnum,
+                                       enum dwc2_halt_status halt_status);
+
+extern int dwc2_hcd_qh_init_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+                                gfp_t mem_flags);
+extern void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
+
+/* Check if QH is non-periodic */
+#define dwc2_qh_is_non_per(_qh_ptr_) \
+       ((_qh_ptr_)->ep_type == USB_ENDPOINT_XFER_BULK || \
+        (_qh_ptr_)->ep_type == USB_ENDPOINT_XFER_CONTROL)
+
+#ifdef CONFIG_USB_DWC2_DEBUG_PERIODIC
+static inline bool dbg_hc(struct dwc2_host_chan *hc) { return true; }
+static inline bool dbg_qh(struct dwc2_qh *qh) { return true; }
+static inline bool dbg_urb(struct urb *urb) { return true; }
+static inline bool dbg_perio(void) { return true; }
+#else /* !CONFIG_USB_DWC2_DEBUG_PERIODIC */
+static inline bool dbg_hc(struct dwc2_host_chan *hc)
+{
+       return hc->ep_type == USB_ENDPOINT_XFER_BULK ||
+              hc->ep_type == USB_ENDPOINT_XFER_CONTROL;
+}
+
+static inline bool dbg_qh(struct dwc2_qh *qh)
+{
+       return qh->ep_type == USB_ENDPOINT_XFER_BULK ||
+              qh->ep_type == USB_ENDPOINT_XFER_CONTROL;
+}
+
+static inline bool dbg_urb(struct urb *urb)
+{
+       return usb_pipetype(urb->pipe) == PIPE_BULK ||
+              usb_pipetype(urb->pipe) == PIPE_CONTROL;
+}
+
+static inline bool dbg_perio(void) { return false; }
+#endif
+
+/* High bandwidth multiplier as encoded in highspeed endpoint descriptors */
+#define dwc2_hb_mult(wmaxpacketsize) (1 + (((wmaxpacketsize) >> 11) & 0x03))
+
+/* Packet size for any kind of endpoint descriptor */
+#define dwc2_max_packet(wmaxpacketsize) ((wmaxpacketsize) & 0x07ff)
+
+/*
+ * Returns true if frame1 is less than or equal to frame2. The comparison is
+ * done modulo HFNUM_MAX_FRNUM. This accounts for the rollover of the
+ * frame number when the max frame number is reached.
+ */
+static inline int dwc2_frame_num_le(u16 frame1, u16 frame2)
+{
+       return ((frame2 - frame1) & HFNUM_MAX_FRNUM) <= (HFNUM_MAX_FRNUM >> 1);
+}
+
+/*
+ * Returns true if frame1 is greater than frame2. The comparison is done
+ * modulo HFNUM_MAX_FRNUM. This accounts for the rollover of the frame
+ * number when the max frame number is reached.
+ */
+static inline int dwc2_frame_num_gt(u16 frame1, u16 frame2)
+{
+       return (frame1 != frame2) &&
+              ((frame1 - frame2) & HFNUM_MAX_FRNUM) < (HFNUM_MAX_FRNUM >> 1);
+}
+
+/*
+ * Increments frame by the amount specified by inc. The addition is done
+ * modulo HFNUM_MAX_FRNUM. Returns the incremented value.
+ */
+static inline u16 dwc2_frame_num_inc(u16 frame, u16 inc)
+{
+       return (frame + inc) & HFNUM_MAX_FRNUM;
+}
+
+static inline u16 dwc2_full_frame_num(u16 frame)
+{
+       return (frame & HFNUM_MAX_FRNUM) >> 3;
+}
+
+static inline u16 dwc2_micro_frame_num(u16 frame)
+{
+       return frame & 0x7;
+}
+
+/*
+ * Returns the Core Interrupt Status register contents, ANDed with the Core
+ * Interrupt Mask register contents
+ */
+static inline u32 dwc2_read_core_intr(struct dwc2_hsotg *hsotg)
+{
+       return readl(hsotg->regs + GINTSTS) & readl(hsotg->regs + GINTMSK);
+}
+
+static inline u32 dwc2_hcd_urb_get_status(struct dwc2_hcd_urb *dwc2_urb)
+{
+       return dwc2_urb->status;
+}
+
+static inline u32 dwc2_hcd_urb_get_actual_length(
+               struct dwc2_hcd_urb *dwc2_urb)
+{
+       return dwc2_urb->actual_length;
+}
+
+static inline u32 dwc2_hcd_urb_get_error_count(struct dwc2_hcd_urb *dwc2_urb)
+{
+       return dwc2_urb->error_count;
+}
+
+static inline void dwc2_hcd_urb_set_iso_desc_params(
+               struct dwc2_hcd_urb *dwc2_urb, int desc_num, u32 offset,
+               u32 length)
+{
+       dwc2_urb->iso_descs[desc_num].offset = offset;
+       dwc2_urb->iso_descs[desc_num].length = length;
+}
+
+static inline u32 dwc2_hcd_urb_get_iso_desc_status(
+               struct dwc2_hcd_urb *dwc2_urb, int desc_num)
+{
+       return dwc2_urb->iso_descs[desc_num].status;
+}
+
+static inline u32 dwc2_hcd_urb_get_iso_desc_actual_length(
+               struct dwc2_hcd_urb *dwc2_urb, int desc_num)
+{
+       return dwc2_urb->iso_descs[desc_num].actual_length;
+}
+
+static inline int dwc2_hcd_is_bandwidth_allocated(struct dwc2_hsotg *hsotg,
+                                                 struct usb_host_endpoint *ep)
+{
+       struct dwc2_qh *qh = ep->hcpriv;
+
+       if (qh && !list_empty(&qh->qh_list_entry))
+               return 1;
+
+       return 0;
+}
+
+static inline u16 dwc2_hcd_get_ep_bandwidth(struct dwc2_hsotg *hsotg,
+                                           struct usb_host_endpoint *ep)
+{
+       struct dwc2_qh *qh = ep->hcpriv;
+
+       if (!qh) {
+               WARN_ON(1);
+               return 0;
+       }
+
+       return qh->usecs;
+}
+
+extern void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg,
+                                     struct dwc2_host_chan *chan, int chnum,
+                                     struct dwc2_qtd *qtd);
+
+/* HCD Core API */
+
+/**
+ * dwc2_handle_hcd_intr() - Called on every hardware interrupt
+ *
+ * @hsotg: The DWC2 HCD
+ *
+ * Returns IRQ_HANDLED if interrupt is handled
+ * Return IRQ_NONE if interrupt is not handled
+ */
+extern irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg);
+
+/**
+ * dwc2_hcd_stop() - Halts the DWC_otg host mode operation
+ *
+ * @hsotg: The DWC2 HCD
+ */
+extern void dwc2_hcd_stop(struct dwc2_hsotg *hsotg);
+
+extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
+extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg);
+
+/**
+ * dwc2_hcd_is_b_host() - Returns 1 if core currently is acting as B host,
+ * and 0 otherwise
+ *
+ * @hsotg: The DWC2 HCD
+ */
+extern int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg);
+
+/**
+ * dwc2_hcd_get_frame_number() - Returns current frame number
+ *
+ * @hsotg: The DWC2 HCD
+ */
+extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg);
+
+/**
+ * dwc2_hcd_dump_state() - Dumps hsotg state
+ *
+ * @hsotg: The DWC2 HCD
+ *
+ * NOTE: This function will be removed once the peripheral controller code
+ * is integrated and the driver is stable
+ */
+extern void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg);
+
+/**
+ * dwc2_hcd_dump_frrem() - Dumps the average frame remaining at SOF
+ *
+ * @hsotg: The DWC2 HCD
+ *
+ * This can be used to determine average interrupt latency. Frame remaining is
+ * also shown for start transfer and two additional sample points.
+ *
+ * NOTE: This function will be removed once the peripheral controller code
+ * is integrated and the driver is stable
+ */
+extern void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg);
+
+/* URB interface */
+
+/* Transfer flags */
+#define URB_GIVEBACK_ASAP      0x1
+#define URB_SEND_ZERO_PACKET   0x2
+
+/* Host driver callbacks */
+
+extern void dwc2_host_start(struct dwc2_hsotg *hsotg);
+extern void dwc2_host_disconnect(struct dwc2_hsotg *hsotg);
+extern void dwc2_host_hub_info(struct dwc2_hsotg *hsotg, void *context,
+                              int *hub_addr, int *hub_port);
+extern int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context);
+extern void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
+                              int status);
+
+#ifdef DEBUG
+/*
+ * Macro to sample the remaining PHY clocks left in the current frame. This
+ * may be used during debugging to determine the average time it takes to
+ * execute sections of code. There are two possible sample points, "a" and
+ * "b", so the _letter_ argument must be one of these values.
+ *
+ * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For
+ * example, "cat /sys/devices/lm0/hcd_frrem".
+ */
+#define dwc2_sample_frrem(_hcd_, _qh_, _letter_)                       \
+do {                                                                   \
+       struct hfnum_data _hfnum_;                                      \
+       struct dwc2_qtd *_qtd_;                                         \
+                                                                       \
+       _qtd_ = list_entry((_qh_)->qtd_list.next, struct dwc2_qtd,      \
+                          qtd_list_entry);                             \
+       if (usb_pipeint(_qtd_->urb->pipe) &&                            \
+           (_qh_)->start_split_frame != 0 && !_qtd_->complete_split) { \
+               _hfnum_.d32 = readl((_hcd_)->regs + HFNUM);             \
+               switch (_hfnum_.b.frnum & 0x7) {                        \
+               case 7:                                                 \
+                       (_hcd_)->hfnum_7_samples_##_letter_++;          \
+                       (_hcd_)->hfnum_7_frrem_accum_##_letter_ +=      \
+                               _hfnum_.b.frrem;                        \
+                       break;                                          \
+               case 0:                                                 \
+                       (_hcd_)->hfnum_0_samples_##_letter_++;          \
+                       (_hcd_)->hfnum_0_frrem_accum_##_letter_ +=      \
+                               _hfnum_.b.frrem;                        \
+                       break;                                          \
+               default:                                                \
+                       (_hcd_)->hfnum_other_samples_##_letter_++;      \
+                       (_hcd_)->hfnum_other_frrem_accum_##_letter_ +=  \
+                               _hfnum_.b.frrem;                        \
+                       break;                                          \
+               }                                                       \
+       }                                                               \
+} while (0)
+#else
+#define dwc2_sample_frrem(_hcd_, _qh_, _letter_)       do {} while (0)
+#endif
+
+#endif /* __DWC2_HCD_H__ */
diff --git a/drivers/usb/dwc2/hcd_ddma.c b/drivers/usb/dwc2/hcd_ddma.c
new file mode 100644 (file)
index 0000000..3376177
--- /dev/null
@@ -0,0 +1,1212 @@
+/*
+ * hcd_ddma.c - DesignWare HS OTG Controller descriptor DMA routines
+ *
+ * Copyright (C) 2004-2013 Synopsys, Inc.
+ *
+ * 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") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * 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.
+ */
+
+/*
+ * This file contains the Descriptor DMA implementation for Host mode
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <linux/usb/hcd.h>
+#include <linux/usb/ch11.h>
+
+#include "core.h"
+#include "hcd.h"
+
+static u16 dwc2_frame_list_idx(u16 frame)
+{
+       return frame & (FRLISTEN_64_SIZE - 1);
+}
+
+static u16 dwc2_desclist_idx_inc(u16 idx, u16 inc, u8 speed)
+{
+       return (idx + inc) &
+               ((speed == USB_SPEED_HIGH ? MAX_DMA_DESC_NUM_HS_ISOC :
+                 MAX_DMA_DESC_NUM_GENERIC) - 1);
+}
+
+static u16 dwc2_desclist_idx_dec(u16 idx, u16 inc, u8 speed)
+{
+       return (idx - inc) &
+               ((speed == USB_SPEED_HIGH ? MAX_DMA_DESC_NUM_HS_ISOC :
+                 MAX_DMA_DESC_NUM_GENERIC) - 1);
+}
+
+static u16 dwc2_max_desc_num(struct dwc2_qh *qh)
+{
+       return (qh->ep_type == USB_ENDPOINT_XFER_ISOC &&
+               qh->dev_speed == USB_SPEED_HIGH) ?
+               MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC;
+}
+
+static u16 dwc2_frame_incr_val(struct dwc2_qh *qh)
+{
+       return qh->dev_speed == USB_SPEED_HIGH ?
+              (qh->interval + 8 - 1) / 8 : qh->interval;
+}
+
+static int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+                               gfp_t flags)
+{
+       qh->desc_list = dma_alloc_coherent(hsotg->dev,
+                               sizeof(struct dwc2_hcd_dma_desc) *
+                               dwc2_max_desc_num(qh), &qh->desc_list_dma,
+                               flags);
+
+       if (!qh->desc_list)
+               return -ENOMEM;
+
+       memset(qh->desc_list, 0,
+              sizeof(struct dwc2_hcd_dma_desc) * dwc2_max_desc_num(qh));
+
+       qh->n_bytes = kzalloc(sizeof(u32) * dwc2_max_desc_num(qh), flags);
+       if (!qh->n_bytes) {
+               dma_free_coherent(hsotg->dev, sizeof(struct dwc2_hcd_dma_desc)
+                                 * dwc2_max_desc_num(qh), qh->desc_list,
+                                 qh->desc_list_dma);
+               qh->desc_list = NULL;
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void dwc2_desc_list_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+       if (qh->desc_list) {
+               dma_free_coherent(hsotg->dev, sizeof(struct dwc2_hcd_dma_desc)
+                                 * dwc2_max_desc_num(qh), qh->desc_list,
+                                 qh->desc_list_dma);
+               qh->desc_list = NULL;
+       }
+
+       kfree(qh->n_bytes);
+       qh->n_bytes = NULL;
+}
+
+static int dwc2_frame_list_alloc(struct dwc2_hsotg *hsotg, gfp_t mem_flags)
+{
+       if (hsotg->frame_list)
+               return 0;
+
+       hsotg->frame_list = dma_alloc_coherent(hsotg->dev,
+                                              4 * FRLISTEN_64_SIZE,
+                                              &hsotg->frame_list_dma,
+                                              mem_flags);
+       if (!hsotg->frame_list)
+               return -ENOMEM;
+
+       memset(hsotg->frame_list, 0, 4 * FRLISTEN_64_SIZE);
+       return 0;
+}
+
+static void dwc2_frame_list_free(struct dwc2_hsotg *hsotg)
+{
+       u32 *frame_list;
+       dma_addr_t frame_list_dma;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+
+       if (!hsotg->frame_list) {
+               spin_unlock_irqrestore(&hsotg->lock, flags);
+               return;
+       }
+
+       frame_list = hsotg->frame_list;
+       frame_list_dma = hsotg->frame_list_dma;
+       hsotg->frame_list = NULL;
+
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+
+       dma_free_coherent(hsotg->dev, 4 * FRLISTEN_64_SIZE, frame_list,
+                         frame_list_dma);
+}
+
+static void dwc2_per_sched_enable(struct dwc2_hsotg *hsotg, u32 fr_list_en)
+{
+       u32 hcfg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+
+       hcfg = readl(hsotg->regs + HCFG);
+       if (hcfg & HCFG_PERSCHEDENA) {
+               /* already enabled */
+               spin_unlock_irqrestore(&hsotg->lock, flags);
+               return;
+       }
+
+       writel(hsotg->frame_list_dma, hsotg->regs + HFLBADDR);
+
+       hcfg &= ~HCFG_FRLISTEN_MASK;
+       hcfg |= fr_list_en | HCFG_PERSCHEDENA;
+       dev_vdbg(hsotg->dev, "Enabling Periodic schedule\n");
+       writel(hcfg, hsotg->regs + HCFG);
+
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+}
+
+static void dwc2_per_sched_disable(struct dwc2_hsotg *hsotg)
+{
+       u32 hcfg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+
+       hcfg = readl(hsotg->regs + HCFG);
+       if (!(hcfg & HCFG_PERSCHEDENA)) {
+               /* already disabled */
+               spin_unlock_irqrestore(&hsotg->lock, flags);
+               return;
+       }
+
+       hcfg &= ~HCFG_PERSCHEDENA;
+       dev_vdbg(hsotg->dev, "Disabling Periodic schedule\n");
+       writel(hcfg, hsotg->regs + HCFG);
+
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+}
+
+/*
+ * Activates/Deactivates FrameList entries for the channel based on endpoint
+ * servicing period
+ */
+static void dwc2_update_frame_list(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+                                  int enable)
+{
+       struct dwc2_host_chan *chan;
+       u16 i, j, inc;
+
+       if (!hsotg) {
+               pr_err("hsotg = %p\n", hsotg);
+               return;
+       }
+
+       if (!qh->channel) {
+               dev_err(hsotg->dev, "qh->channel = %p\n", qh->channel);
+               return;
+       }
+
+       if (!hsotg->frame_list) {
+               dev_err(hsotg->dev, "hsotg->frame_list = %p\n",
+                       hsotg->frame_list);
+               return;
+       }
+
+       chan = qh->channel;
+       inc = dwc2_frame_incr_val(qh);
+       if (qh->ep_type == USB_ENDPOINT_XFER_ISOC)
+               i = dwc2_frame_list_idx(qh->sched_frame);
+       else
+               i = 0;
+
+       j = i;
+       do {
+               if (enable)
+                       hsotg->frame_list[j] |= 1 << chan->hc_num;
+               else
+                       hsotg->frame_list[j] &= ~(1 << chan->hc_num);
+               j = (j + inc) & (FRLISTEN_64_SIZE - 1);
+       } while (j != i);
+
+       if (!enable)
+               return;
+
+       chan->schinfo = 0;
+       if (chan->speed == USB_SPEED_HIGH && qh->interval) {
+               j = 1;
+               /* TODO - check this */
+               inc = (8 + qh->interval - 1) / qh->interval;
+               for (i = 0; i < inc; i++) {
+                       chan->schinfo |= j;
+                       j = j << qh->interval;
+               }
+       } else {
+               chan->schinfo = 0xff;
+       }
+}
+
+static void dwc2_release_channel_ddma(struct dwc2_hsotg *hsotg,
+                                     struct dwc2_qh *qh)
+{
+       struct dwc2_host_chan *chan = qh->channel;
+
+       if (dwc2_qh_is_non_per(qh)) {
+               if (hsotg->core_params->uframe_sched > 0)
+                       hsotg->available_host_channels++;
+               else
+                       hsotg->non_periodic_channels--;
+       } else {
+               dwc2_update_frame_list(hsotg, qh, 0);
+       }
+
+       /*
+        * The condition is added to prevent double cleanup try in case of
+        * device disconnect. See channel cleanup in dwc2_hcd_disconnect().
+        */
+       if (chan->qh) {
+               if (!list_empty(&chan->hc_list_entry))
+                       list_del(&chan->hc_list_entry);
+               dwc2_hc_cleanup(hsotg, chan);
+               list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list);
+               chan->qh = NULL;
+       }
+
+       qh->channel = NULL;
+       qh->ntd = 0;
+
+       if (qh->desc_list)
+               memset(qh->desc_list, 0, sizeof(struct dwc2_hcd_dma_desc) *
+                      dwc2_max_desc_num(qh));
+}
+
+/**
+ * dwc2_hcd_qh_init_ddma() - Initializes a QH structure's Descriptor DMA
+ * related members
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh:    The QH to init
+ *
+ * Return: 0 if successful, negative error code otherwise
+ *
+ * Allocates memory for the descriptor list. For the first periodic QH,
+ * allocates memory for the FrameList and enables periodic scheduling.
+ */
+int dwc2_hcd_qh_init_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+                         gfp_t mem_flags)
+{
+       int retval;
+
+       if (qh->do_split) {
+               dev_err(hsotg->dev,
+                       "SPLIT Transfers are not supported in Descriptor DMA mode.\n");
+               retval = -EINVAL;
+               goto err0;
+       }
+
+       retval = dwc2_desc_list_alloc(hsotg, qh, mem_flags);
+       if (retval)
+               goto err0;
+
+       if (qh->ep_type == USB_ENDPOINT_XFER_ISOC ||
+           qh->ep_type == USB_ENDPOINT_XFER_INT) {
+               if (!hsotg->frame_list) {
+                       retval = dwc2_frame_list_alloc(hsotg, mem_flags);
+                       if (retval)
+                               goto err1;
+                       /* Enable periodic schedule on first periodic QH */
+                       dwc2_per_sched_enable(hsotg, HCFG_FRLISTEN_64);
+               }
+       }
+
+       qh->ntd = 0;
+       return 0;
+
+err1:
+       dwc2_desc_list_free(hsotg, qh);
+err0:
+       return retval;
+}
+
+/**
+ * dwc2_hcd_qh_free_ddma() - Frees a QH structure's Descriptor DMA related
+ * members
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh:    The QH to free
+ *
+ * Frees descriptor list memory associated with the QH. If QH is periodic and
+ * the last, frees FrameList memory and disables periodic scheduling.
+ */
+void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+       dwc2_desc_list_free(hsotg, qh);
+
+       /*
+        * Channel still assigned due to some reasons.
+        * Seen on Isoc URB dequeue. Channel halted but no subsequent
+        * ChHalted interrupt to release the channel. Afterwards
+        * when it comes here from endpoint disable routine
+        * channel remains assigned.
+        */
+       if (qh->channel)
+               dwc2_release_channel_ddma(hsotg, qh);
+
+       if ((qh->ep_type == USB_ENDPOINT_XFER_ISOC ||
+            qh->ep_type == USB_ENDPOINT_XFER_INT) &&
+           (hsotg->core_params->uframe_sched > 0 ||
+            !hsotg->periodic_channels) && hsotg->frame_list) {
+               dwc2_per_sched_disable(hsotg);
+               dwc2_frame_list_free(hsotg);
+       }
+}
+
+static u8 dwc2_frame_to_desc_idx(struct dwc2_qh *qh, u16 frame_idx)
+{
+       if (qh->dev_speed == USB_SPEED_HIGH)
+               /* Descriptor set (8 descriptors) index which is 8-aligned */
+               return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8;
+       else
+               return frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1);
+}
+
+/*
+ * Determine starting frame for Isochronous transfer.
+ * Few frames skipped to prevent race condition with HC.
+ */
+static u16 dwc2_calc_starting_frame(struct dwc2_hsotg *hsotg,
+                                   struct dwc2_qh *qh, u16 *skip_frames)
+{
+       u16 frame;
+
+       hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
+
+       /* sched_frame is always frame number (not uFrame) both in FS and HS! */
+
+       /*
+        * skip_frames is used to limit activated descriptors number
+        * to avoid the situation when HC services the last activated
+        * descriptor firstly.
+        * Example for FS:
+        * Current frame is 1, scheduled frame is 3. Since HC always fetches
+        * the descriptor corresponding to curr_frame+1, the descriptor
+        * corresponding to frame 2 will be fetched. If the number of
+        * descriptors is max=64 (or greather) the list will be fully programmed
+        * with Active descriptors and it is possible case (rare) that the
+        * latest descriptor(considering rollback) corresponding to frame 2 will
+        * be serviced first. HS case is more probable because, in fact, up to
+        * 11 uframes (16 in the code) may be skipped.
+        */
+       if (qh->dev_speed == USB_SPEED_HIGH) {
+               /*
+                * Consider uframe counter also, to start xfer asap. If half of
+                * the frame elapsed skip 2 frames otherwise just 1 frame.
+                * Starting descriptor index must be 8-aligned, so if the
+                * current frame is near to complete the next one is skipped as
+                * well.
+                */
+               if (dwc2_micro_frame_num(hsotg->frame_number) >= 5) {
+                       *skip_frames = 2 * 8;
+                       frame = dwc2_frame_num_inc(hsotg->frame_number,
+                                                  *skip_frames);
+               } else {
+                       *skip_frames = 1 * 8;
+                       frame = dwc2_frame_num_inc(hsotg->frame_number,
+                                                  *skip_frames);
+               }
+
+               frame = dwc2_full_frame_num(frame);
+       } else {
+               /*
+                * Two frames are skipped for FS - the current and the next.
+                * But for descriptor programming, 1 frame (descriptor) is
+                * enough, see example above.
+                */
+               *skip_frames = 1;
+               frame = dwc2_frame_num_inc(hsotg->frame_number, 2);
+       }
+
+       return frame;
+}
+
+/*
+ * Calculate initial descriptor index for isochronous transfer based on
+ * scheduled frame
+ */
+static u16 dwc2_recalc_initial_desc_idx(struct dwc2_hsotg *hsotg,
+                                       struct dwc2_qh *qh)
+{
+       u16 frame, fr_idx, fr_idx_tmp, skip_frames;
+
+       /*
+        * With current ISOC processing algorithm the channel is being released
+        * when no more QTDs in the list (qh->ntd == 0). Thus this function is
+        * called only when qh->ntd == 0 and qh->channel == 0.
+        *
+        * So qh->channel != NULL branch is not used and just not removed from
+        * the source file. It is required for another possible approach which
+        * is, do not disable and release the channel when ISOC session
+        * completed, just move QH to inactive schedule until new QTD arrives.
+        * On new QTD, the QH moved back to 'ready' schedule, starting frame and
+        * therefore starting desc_index are recalculated. In this case channel
+        * is released only on ep_disable.
+        */
+
+       /*
+        * Calculate starting descriptor index. For INTERRUPT endpoint it is
+        * always 0.
+        */
+       if (qh->channel) {
+               frame = dwc2_calc_starting_frame(hsotg, qh, &skip_frames);
+               /*
+                * Calculate initial descriptor index based on FrameList current
+                * bitmap and servicing period
+                */
+               fr_idx_tmp = dwc2_frame_list_idx(frame);
+               fr_idx = (FRLISTEN_64_SIZE +
+                         dwc2_frame_list_idx(qh->sched_frame) - fr_idx_tmp)
+                        % dwc2_frame_incr_val(qh);
+               fr_idx = (fr_idx + fr_idx_tmp) % FRLISTEN_64_SIZE;
+       } else {
+               qh->sched_frame = dwc2_calc_starting_frame(hsotg, qh,
+                                                          &skip_frames);
+               fr_idx = dwc2_frame_list_idx(qh->sched_frame);
+       }
+
+       qh->td_first = qh->td_last = dwc2_frame_to_desc_idx(qh, fr_idx);
+
+       return skip_frames;
+}
+
+#define ISOC_URB_GIVEBACK_ASAP
+
+#define MAX_ISOC_XFER_SIZE_FS  1023
+#define MAX_ISOC_XFER_SIZE_HS  3072
+#define DESCNUM_THRESHOLD      4
+
+static void dwc2_fill_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
+                                        struct dwc2_qtd *qtd,
+                                        struct dwc2_qh *qh, u32 max_xfer_size,
+                                        u16 idx)
+{
+       struct dwc2_hcd_dma_desc *dma_desc = &qh->desc_list[idx];
+       struct dwc2_hcd_iso_packet_desc *frame_desc;
+
+       memset(dma_desc, 0, sizeof(*dma_desc));
+       frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
+
+       if (frame_desc->length > max_xfer_size)
+               qh->n_bytes[idx] = max_xfer_size;
+       else
+               qh->n_bytes[idx] = frame_desc->length;
+
+       dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset);
+       dma_desc->status = qh->n_bytes[idx] << HOST_DMA_ISOC_NBYTES_SHIFT &
+                          HOST_DMA_ISOC_NBYTES_MASK;
+
+#ifdef ISOC_URB_GIVEBACK_ASAP
+       /* Set IOC for each descriptor corresponding to last frame of URB */
+       if (qtd->isoc_frame_index_last == qtd->urb->packet_count)
+               dma_desc->status |= HOST_DMA_IOC;
+#endif
+
+       qh->ntd++;
+       qtd->isoc_frame_index_last++;
+}
+
+static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg,
+                                   struct dwc2_qh *qh, u16 skip_frames)
+{
+       struct dwc2_qtd *qtd;
+       u32 max_xfer_size;
+       u16 idx, inc, n_desc, ntd_max = 0;
+
+       idx = qh->td_last;
+       inc = qh->interval;
+       n_desc = 0;
+
+       if (qh->interval) {
+               ntd_max = (dwc2_max_desc_num(qh) + qh->interval - 1) /
+                               qh->interval;
+               if (skip_frames && !qh->channel)
+                       ntd_max -= skip_frames / qh->interval;
+       }
+
+       max_xfer_size = qh->dev_speed == USB_SPEED_HIGH ?
+                       MAX_ISOC_XFER_SIZE_HS : MAX_ISOC_XFER_SIZE_FS;
+
+       list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) {
+               while (qh->ntd < ntd_max && qtd->isoc_frame_index_last <
+                                               qtd->urb->packet_count) {
+                       if (n_desc > 1)
+                               qh->desc_list[n_desc - 1].status |= HOST_DMA_A;
+                       dwc2_fill_host_isoc_dma_desc(hsotg, qtd, qh,
+                                                    max_xfer_size, idx);
+                       idx = dwc2_desclist_idx_inc(idx, inc, qh->dev_speed);
+                       n_desc++;
+               }
+               qtd->in_process = 1;
+       }
+
+       qh->td_last = idx;
+
+#ifdef ISOC_URB_GIVEBACK_ASAP
+       /* Set IOC for last descriptor if descriptor list is full */
+       if (qh->ntd == ntd_max) {
+               idx = dwc2_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
+               qh->desc_list[idx].status |= HOST_DMA_IOC;
+       }
+#else
+       /*
+        * Set IOC bit only for one descriptor. Always try to be ahead of HW
+        * processing, i.e. on IOC generation driver activates next descriptor
+        * but core continues to process descriptors following the one with IOC
+        * set.
+        */
+
+       if (n_desc > DESCNUM_THRESHOLD)
+               /*
+                * Move IOC "up". Required even if there is only one QTD
+                * in the list, because QTDs might continue to be queued,
+                * but during the activation it was only one queued.
+                * Actually more than one QTD might be in the list if this
+                * function called from XferCompletion - QTDs was queued during
+                * HW processing of the previous descriptor chunk.
+                */
+               idx = dwc2_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2),
+                                           qh->dev_speed);
+       else
+               /*
+                * Set the IOC for the latest descriptor if either number of
+                * descriptors is not greater than threshold or no more new
+                * descriptors activated
+                */
+               idx = dwc2_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
+
+       qh->desc_list[idx].status |= HOST_DMA_IOC;
+#endif
+
+       if (n_desc) {
+               qh->desc_list[n_desc - 1].status |= HOST_DMA_A;
+               if (n_desc > 1)
+                       qh->desc_list[0].status |= HOST_DMA_A;
+       }
+}
+
+static void dwc2_fill_host_dma_desc(struct dwc2_hsotg *hsotg,
+                                   struct dwc2_host_chan *chan,
+                                   struct dwc2_qtd *qtd, struct dwc2_qh *qh,
+                                   int n_desc)
+{
+       struct dwc2_hcd_dma_desc *dma_desc = &qh->desc_list[n_desc];
+       int len = chan->xfer_len;
+
+       if (len > MAX_DMA_DESC_SIZE - (chan->max_packet - 1))
+               len = MAX_DMA_DESC_SIZE - (chan->max_packet - 1);
+
+       if (chan->ep_is_in) {
+               int num_packets;
+
+               if (len > 0 && chan->max_packet)
+                       num_packets = (len + chan->max_packet - 1)
+                                       / chan->max_packet;
+               else
+                       /* Need 1 packet for transfer length of 0 */
+                       num_packets = 1;
+
+               /* Always program an integral # of packets for IN transfers */
+               len = num_packets * chan->max_packet;
+       }
+
+       dma_desc->status = len << HOST_DMA_NBYTES_SHIFT & HOST_DMA_NBYTES_MASK;
+       qh->n_bytes[n_desc] = len;
+
+       if (qh->ep_type == USB_ENDPOINT_XFER_CONTROL &&
+           qtd->control_phase == DWC2_CONTROL_SETUP)
+               dma_desc->status |= HOST_DMA_SUP;
+
+       dma_desc->buf = (u32)chan->xfer_dma;
+
+       /*
+        * Last (or only) descriptor of IN transfer with actual size less
+        * than MaxPacket
+        */
+       if (len > chan->xfer_len) {
+               chan->xfer_len = 0;
+       } else {
+               chan->xfer_dma += len;
+               chan->xfer_len -= len;
+       }
+}
+
+static void dwc2_init_non_isoc_dma_desc(struct dwc2_hsotg *hsotg,
+                                       struct dwc2_qh *qh)
+{
+       struct dwc2_qtd *qtd;
+       struct dwc2_host_chan *chan = qh->channel;
+       int n_desc = 0;
+
+       dev_vdbg(hsotg->dev, "%s(): qh=%p dma=%08lx len=%d\n", __func__, qh,
+                (unsigned long)chan->xfer_dma, chan->xfer_len);
+
+       /*
+        * Start with chan->xfer_dma initialized in assign_and_init_hc(), then
+        * if SG transfer consists of multiple URBs, this pointer is re-assigned
+        * to the buffer of the currently processed QTD. For non-SG request
+        * there is always one QTD active.
+        */
+
+       list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) {
+               dev_vdbg(hsotg->dev, "qtd=%p\n", qtd);
+
+               if (n_desc) {
+                       /* SG request - more than 1 QTD */
+                       chan->xfer_dma = qtd->urb->dma +
+                                       qtd->urb->actual_length;
+                       chan->xfer_len = qtd->urb->length -
+                                       qtd->urb->actual_length;
+                       dev_vdbg(hsotg->dev, "buf=%08lx len=%d\n",
+                                (unsigned long)chan->xfer_dma, chan->xfer_len);
+               }
+
+               qtd->n_desc = 0;
+               do {
+                       if (n_desc > 1) {
+                               qh->desc_list[n_desc - 1].status |= HOST_DMA_A;
+                               dev_vdbg(hsotg->dev,
+                                        "set A bit in desc %d (%p)\n",
+                                        n_desc - 1,
+                                        &qh->desc_list[n_desc - 1]);
+                       }
+                       dwc2_fill_host_dma_desc(hsotg, chan, qtd, qh, n_desc);
+                       dev_vdbg(hsotg->dev,
+                                "desc %d (%p) buf=%08x status=%08x\n",
+                                n_desc, &qh->desc_list[n_desc],
+                                qh->desc_list[n_desc].buf,
+                                qh->desc_list[n_desc].status);
+                       qtd->n_desc++;
+                       n_desc++;
+               } while (chan->xfer_len > 0 &&
+                        n_desc != MAX_DMA_DESC_NUM_GENERIC);
+
+               dev_vdbg(hsotg->dev, "n_desc=%d\n", n_desc);
+               qtd->in_process = 1;
+               if (qh->ep_type == USB_ENDPOINT_XFER_CONTROL)
+                       break;
+               if (n_desc == MAX_DMA_DESC_NUM_GENERIC)
+                       break;
+       }
+
+       if (n_desc) {
+               qh->desc_list[n_desc - 1].status |=
+                               HOST_DMA_IOC | HOST_DMA_EOL | HOST_DMA_A;
+               dev_vdbg(hsotg->dev, "set IOC/EOL/A bits in desc %d (%p)\n",
+                        n_desc - 1, &qh->desc_list[n_desc - 1]);
+               if (n_desc > 1) {
+                       qh->desc_list[0].status |= HOST_DMA_A;
+                       dev_vdbg(hsotg->dev, "set A bit in desc 0 (%p)\n",
+                                &qh->desc_list[0]);
+               }
+               chan->ntd = n_desc;
+       }
+}
+
+/**
+ * dwc2_hcd_start_xfer_ddma() - Starts a transfer in Descriptor DMA mode
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh:    The QH to init
+ *
+ * Return: 0 if successful, negative error code otherwise
+ *
+ * For Control and Bulk endpoints, initializes descriptor list and starts the
+ * transfer. For Interrupt and Isochronous endpoints, initializes descriptor
+ * list then updates FrameList, marking appropriate entries as active.
+ *
+ * For Isochronous endpoints the starting descriptor index is calculated based
+ * on the scheduled frame, but only on the first transfer descriptor within a
+ * session. Then the transfer is started via enabling the channel.
+ *
+ * For Isochronous endpoints the channel is not halted on XferComplete
+ * interrupt so remains assigned to the endpoint(QH) until session is done.
+ */
+void dwc2_hcd_start_xfer_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+       /* Channel is already assigned */
+       struct dwc2_host_chan *chan = qh->channel;
+       u16 skip_frames = 0;
+
+       switch (chan->ep_type) {
+       case USB_ENDPOINT_XFER_CONTROL:
+       case USB_ENDPOINT_XFER_BULK:
+               dwc2_init_non_isoc_dma_desc(hsotg, qh);
+               dwc2_hc_start_transfer_ddma(hsotg, chan);
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               dwc2_init_non_isoc_dma_desc(hsotg, qh);
+               dwc2_update_frame_list(hsotg, qh, 1);
+               dwc2_hc_start_transfer_ddma(hsotg, chan);
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               if (!qh->ntd)
+                       skip_frames = dwc2_recalc_initial_desc_idx(hsotg, qh);
+               dwc2_init_isoc_dma_desc(hsotg, qh, skip_frames);
+
+               if (!chan->xfer_started) {
+                       dwc2_update_frame_list(hsotg, qh, 1);
+
+                       /*
+                        * Always set to max, instead of actual size. Otherwise
+                        * ntd will be changed with channel being enabled. Not
+                        * recommended.
+                        */
+                       chan->ntd = dwc2_max_desc_num(qh);
+
+                       /* Enable channel only once for ISOC */
+                       dwc2_hc_start_transfer_ddma(hsotg, chan);
+               }
+
+               break;
+       default:
+               break;
+       }
+}
+
+#define DWC2_CMPL_DONE         1
+#define DWC2_CMPL_STOP         2
+
+static int dwc2_cmpl_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
+                                       struct dwc2_host_chan *chan,
+                                       struct dwc2_qtd *qtd,
+                                       struct dwc2_qh *qh, u16 idx)
+{
+       struct dwc2_hcd_dma_desc *dma_desc = &qh->desc_list[idx];
+       struct dwc2_hcd_iso_packet_desc *frame_desc;
+       u16 remain = 0;
+       int rc = 0;
+
+       if (!qtd->urb)
+               return -EINVAL;
+
+       frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
+       dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset);
+       if (chan->ep_is_in)
+               remain = (dma_desc->status & HOST_DMA_ISOC_NBYTES_MASK) >>
+                        HOST_DMA_ISOC_NBYTES_SHIFT;
+
+       if ((dma_desc->status & HOST_DMA_STS_MASK) == HOST_DMA_STS_PKTERR) {
+               /*
+                * XactError, or unable to complete all the transactions
+                * in the scheduled micro-frame/frame, both indicated by
+                * HOST_DMA_STS_PKTERR
+                */
+               qtd->urb->error_count++;
+               frame_desc->actual_length = qh->n_bytes[idx] - remain;
+               frame_desc->status = -EPROTO;
+       } else {
+               /* Success */
+               frame_desc->actual_length = qh->n_bytes[idx] - remain;
+               frame_desc->status = 0;
+       }
+
+       if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
+               /*
+                * urb->status is not used for isoc transfers here. The
+                * individual frame_desc status are used instead.
+                */
+               dwc2_host_complete(hsotg, qtd, 0);
+               dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
+
+               /*
+                * This check is necessary because urb_dequeue can be called
+                * from urb complete callback (sound driver for example). All
+                * pending URBs are dequeued there, so no need for further
+                * processing.
+                */
+               if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE)
+                       return -1;
+               rc = DWC2_CMPL_DONE;
+       }
+
+       qh->ntd--;
+
+       /* Stop if IOC requested descriptor reached */
+       if (dma_desc->status & HOST_DMA_IOC)
+               rc = DWC2_CMPL_STOP;
+
+       return rc;
+}
+
+static void dwc2_complete_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
+                                        struct dwc2_host_chan *chan,
+                                        enum dwc2_halt_status halt_status)
+{
+       struct dwc2_hcd_iso_packet_desc *frame_desc;
+       struct dwc2_qtd *qtd, *qtd_tmp;
+       struct dwc2_qh *qh;
+       u16 idx;
+       int rc;
+
+       qh = chan->qh;
+       idx = qh->td_first;
+
+       if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) {
+               list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry)
+                       qtd->in_process = 0;
+               return;
+       }
+
+       if (halt_status == DWC2_HC_XFER_AHB_ERR ||
+           halt_status == DWC2_HC_XFER_BABBLE_ERR) {
+               /*
+                * Channel is halted in these error cases, considered as serious
+                * issues.
+                * Complete all URBs marking all frames as failed, irrespective
+                * whether some of the descriptors (frames) succeeded or not.
+                * Pass error code to completion routine as well, to update
+                * urb->status, some of class drivers might use it to stop
+                * queing transfer requests.
+                */
+               int err = halt_status == DWC2_HC_XFER_AHB_ERR ?
+                         -EIO : -EOVERFLOW;
+
+               list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
+                                        qtd_list_entry) {
+                       if (qtd->urb) {
+                               for (idx = 0; idx < qtd->urb->packet_count;
+                                    idx++) {
+                                       frame_desc = &qtd->urb->iso_descs[idx];
+                                       frame_desc->status = err;
+                               }
+
+                               dwc2_host_complete(hsotg, qtd, err);
+                       }
+
+                       dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
+               }
+
+               return;
+       }
+
+       list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
+               if (!qtd->in_process)
+                       break;
+               do {
+                       rc = dwc2_cmpl_host_isoc_dma_desc(hsotg, chan, qtd, qh,
+                                                         idx);
+                       if (rc < 0)
+                               return;
+                       idx = dwc2_desclist_idx_inc(idx, qh->interval,
+                                                   chan->speed);
+                       if (rc == DWC2_CMPL_STOP)
+                               goto stop_scan;
+                       if (rc == DWC2_CMPL_DONE)
+                               break;
+               } while (idx != qh->td_first);
+       }
+
+stop_scan:
+       qh->td_first = idx;
+}
+
+static int dwc2_update_non_isoc_urb_state_ddma(struct dwc2_hsotg *hsotg,
+                                       struct dwc2_host_chan *chan,
+                                       struct dwc2_qtd *qtd,
+                                       struct dwc2_hcd_dma_desc *dma_desc,
+                                       enum dwc2_halt_status halt_status,
+                                       u32 n_bytes, int *xfer_done)
+{
+       struct dwc2_hcd_urb *urb = qtd->urb;
+       u16 remain = 0;
+
+       if (chan->ep_is_in)
+               remain = (dma_desc->status & HOST_DMA_NBYTES_MASK) >>
+                        HOST_DMA_NBYTES_SHIFT;
+
+       dev_vdbg(hsotg->dev, "remain=%d dwc2_urb=%p\n", remain, urb);
+
+       if (halt_status == DWC2_HC_XFER_AHB_ERR) {
+               dev_err(hsotg->dev, "EIO\n");
+               urb->status = -EIO;
+               return 1;
+       }
+
+       if ((dma_desc->status & HOST_DMA_STS_MASK) == HOST_DMA_STS_PKTERR) {
+               switch (halt_status) {
+               case DWC2_HC_XFER_STALL:
+                       dev_vdbg(hsotg->dev, "Stall\n");
+                       urb->status = -EPIPE;
+                       break;
+               case DWC2_HC_XFER_BABBLE_ERR:
+                       dev_err(hsotg->dev, "Babble\n");
+                       urb->status = -EOVERFLOW;
+                       break;
+               case DWC2_HC_XFER_XACT_ERR:
+                       dev_err(hsotg->dev, "XactErr\n");
+                       urb->status = -EPROTO;
+                       break;
+               default:
+                       dev_err(hsotg->dev,
+                               "%s: Unhandled descriptor error status (%d)\n",
+                               __func__, halt_status);
+                       break;
+               }
+               return 1;
+       }
+
+       if (dma_desc->status & HOST_DMA_A) {
+               dev_vdbg(hsotg->dev,
+                        "Active descriptor encountered on channel %d\n",
+                        chan->hc_num);
+               return 0;
+       }
+
+       if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL) {
+               if (qtd->control_phase == DWC2_CONTROL_DATA) {
+                       urb->actual_length += n_bytes - remain;
+                       if (remain || urb->actual_length >= urb->length) {
+                               /*
+                                * For Control Data stage do not set urb->status
+                                * to 0, to prevent URB callback. Set it when
+                                * Status phase is done. See below.
+                                */
+                               *xfer_done = 1;
+                       }
+               } else if (qtd->control_phase == DWC2_CONTROL_STATUS) {
+                       urb->status = 0;
+                       *xfer_done = 1;
+               }
+               /* No handling for SETUP stage */
+       } else {
+               /* BULK and INTR */
+               urb->actual_length += n_bytes - remain;
+               dev_vdbg(hsotg->dev, "length=%d actual=%d\n", urb->length,
+                        urb->actual_length);
+               if (remain || urb->actual_length >= urb->length) {
+                       urb->status = 0;
+                       *xfer_done = 1;
+               }
+       }
+
+       return 0;
+}
+
+static int dwc2_process_non_isoc_desc(struct dwc2_hsotg *hsotg,
+                                     struct dwc2_host_chan *chan,
+                                     int chnum, struct dwc2_qtd *qtd,
+                                     int desc_num,
+                                     enum dwc2_halt_status halt_status,
+                                     int *xfer_done)
+{
+       struct dwc2_qh *qh = chan->qh;
+       struct dwc2_hcd_urb *urb = qtd->urb;
+       struct dwc2_hcd_dma_desc *dma_desc;
+       u32 n_bytes;
+       int failed;
+
+       dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+       if (!urb)
+               return -EINVAL;
+
+       dma_desc = &qh->desc_list[desc_num];
+       n_bytes = qh->n_bytes[desc_num];
+       dev_vdbg(hsotg->dev,
+                "qtd=%p dwc2_urb=%p desc_num=%d desc=%p n_bytes=%d\n",
+                qtd, urb, desc_num, dma_desc, n_bytes);
+       failed = dwc2_update_non_isoc_urb_state_ddma(hsotg, chan, qtd, dma_desc,
+                                                    halt_status, n_bytes,
+                                                    xfer_done);
+       if (failed || (*xfer_done && urb->status != -EINPROGRESS)) {
+               dwc2_host_complete(hsotg, qtd, urb->status);
+               dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
+               dev_vdbg(hsotg->dev, "failed=%1x xfer_done=%1x status=%08x\n",
+                        failed, *xfer_done, urb->status);
+               return failed;
+       }
+
+       if (qh->ep_type == USB_ENDPOINT_XFER_CONTROL) {
+               switch (qtd->control_phase) {
+               case DWC2_CONTROL_SETUP:
+                       if (urb->length > 0)
+                               qtd->control_phase = DWC2_CONTROL_DATA;
+                       else
+                               qtd->control_phase = DWC2_CONTROL_STATUS;
+                       dev_vdbg(hsotg->dev,
+                                "  Control setup transaction done\n");
+                       break;
+               case DWC2_CONTROL_DATA:
+                       if (*xfer_done) {
+                               qtd->control_phase = DWC2_CONTROL_STATUS;
+                               dev_vdbg(hsotg->dev,
+                                        "  Control data transfer done\n");
+                       } else if (desc_num + 1 == qtd->n_desc) {
+                               /*
+                                * Last descriptor for Control data stage which
+                                * is not completed yet
+                                */
+                               dwc2_hcd_save_data_toggle(hsotg, chan, chnum,
+                                                         qtd);
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static void dwc2_complete_non_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
+                                            struct dwc2_host_chan *chan,
+                                            int chnum,
+                                            enum dwc2_halt_status halt_status)
+{
+       struct list_head *qtd_item, *qtd_tmp;
+       struct dwc2_qh *qh = chan->qh;
+       struct dwc2_qtd *qtd = NULL;
+       int xfer_done;
+       int desc_num = 0;
+
+       if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) {
+               list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry)
+                       qtd->in_process = 0;
+               return;
+       }
+
+       list_for_each_safe(qtd_item, qtd_tmp, &qh->qtd_list) {
+               int i;
+
+               qtd = list_entry(qtd_item, struct dwc2_qtd, qtd_list_entry);
+               xfer_done = 0;
+
+               for (i = 0; i < qtd->n_desc; i++) {
+                       if (dwc2_process_non_isoc_desc(hsotg, chan, chnum, qtd,
+                                                      desc_num, halt_status,
+                                                      &xfer_done)) {
+                               qtd = NULL;
+                               break;
+                       }
+                       desc_num++;
+               }
+       }
+
+       if (qh->ep_type != USB_ENDPOINT_XFER_CONTROL) {
+               /*
+                * Resetting the data toggle for bulk and interrupt endpoints
+                * in case of stall. See handle_hc_stall_intr().
+                */
+               if (halt_status == DWC2_HC_XFER_STALL)
+                       qh->data_toggle = DWC2_HC_PID_DATA0;
+               else if (qtd)
+                       dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
+       }
+
+       if (halt_status == DWC2_HC_XFER_COMPLETE) {
+               if (chan->hcint & HCINTMSK_NYET) {
+                       /*
+                        * Got a NYET on the last transaction of the transfer.
+                        * It means that the endpoint should be in the PING
+                        * state at the beginning of the next transfer.
+                        */
+                       qh->ping_state = 1;
+               }
+       }
+}
+
+/**
+ * dwc2_hcd_complete_xfer_ddma() - Scans the descriptor list, updates URB's
+ * status and calls completion routine for the URB if it's done. Called from
+ * interrupt handlers.
+ *
+ * @hsotg:       The HCD state structure for the DWC OTG controller
+ * @chan:        Host channel the transfer is completed on
+ * @chnum:       Index of Host channel registers
+ * @halt_status: Reason the channel is being halted or just XferComplete
+ *               for isochronous transfers
+ *
+ * Releases the channel to be used by other transfers.
+ * In case of Isochronous endpoint the channel is not halted until the end of
+ * the session, i.e. QTD list is empty.
+ * If periodic channel released the FrameList is updated accordingly.
+ * Calls transaction selection routines to activate pending transfers.
+ */
+void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg,
+                                struct dwc2_host_chan *chan, int chnum,
+                                enum dwc2_halt_status halt_status)
+{
+       struct dwc2_qh *qh = chan->qh;
+       int continue_isoc_xfer = 0;
+       enum dwc2_transaction_type tr_type;
+
+       if (chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
+               dwc2_complete_isoc_xfer_ddma(hsotg, chan, halt_status);
+
+               /* Release the channel if halted or session completed */
+               if (halt_status != DWC2_HC_XFER_COMPLETE ||
+                   list_empty(&qh->qtd_list)) {
+                       /* Halt the channel if session completed */
+                       if (halt_status == DWC2_HC_XFER_COMPLETE)
+                               dwc2_hc_halt(hsotg, chan, halt_status);
+                       dwc2_release_channel_ddma(hsotg, qh);
+                       dwc2_hcd_qh_unlink(hsotg, qh);
+               } else {
+                       /* Keep in assigned schedule to continue transfer */
+                       list_move(&qh->qh_list_entry,
+                                 &hsotg->periodic_sched_assigned);
+                       continue_isoc_xfer = 1;
+               }
+               /*
+                * Todo: Consider the case when period exceeds FrameList size.
+                * Frame Rollover interrupt should be used.
+                */
+       } else {
+               /*
+                * Scan descriptor list to complete the URB(s), then release
+                * the channel
+                */
+               dwc2_complete_non_isoc_xfer_ddma(hsotg, chan, chnum,
+                                                halt_status);
+               dwc2_release_channel_ddma(hsotg, qh);
+               dwc2_hcd_qh_unlink(hsotg, qh);
+
+               if (!list_empty(&qh->qtd_list)) {
+                       /*
+                        * Add back to inactive non-periodic schedule on normal
+                        * completion
+                        */
+                       dwc2_hcd_qh_add(hsotg, qh);
+               }
+       }
+
+       tr_type = dwc2_hcd_select_transactions(hsotg);
+       if (tr_type != DWC2_TRANSACTION_NONE || continue_isoc_xfer) {
+               if (continue_isoc_xfer) {
+                       if (tr_type == DWC2_TRANSACTION_NONE)
+                               tr_type = DWC2_TRANSACTION_PERIODIC;
+                       else if (tr_type == DWC2_TRANSACTION_NON_PERIODIC)
+                               tr_type = DWC2_TRANSACTION_ALL;
+               }
+               dwc2_hcd_queue_transactions(hsotg, tr_type);
+       }
+}
diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c
new file mode 100644 (file)
index 0000000..012f17e
--- /dev/null
@@ -0,0 +1,2119 @@
+/*
+ * hcd_intr.c - DesignWare HS OTG Controller host-mode interrupt handling
+ *
+ * Copyright (C) 2004-2013 Synopsys, Inc.
+ *
+ * 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") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * 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.
+ */
+
+/*
+ * This file contains the interrupt handlers for Host mode
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <linux/usb/hcd.h>
+#include <linux/usb/ch11.h>
+
+#include "core.h"
+#include "hcd.h"
+
+/* This function is for debug only */
+static void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg)
+{
+#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
+       u16 curr_frame_number = hsotg->frame_number;
+
+       if (hsotg->frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
+               if (((hsotg->last_frame_num + 1) & HFNUM_MAX_FRNUM) !=
+                   curr_frame_number) {
+                       hsotg->frame_num_array[hsotg->frame_num_idx] =
+                                       curr_frame_number;
+                       hsotg->last_frame_num_array[hsotg->frame_num_idx] =
+                                       hsotg->last_frame_num;
+                       hsotg->frame_num_idx++;
+               }
+       } else if (!hsotg->dumped_frame_num_array) {
+               int i;
+
+               dev_info(hsotg->dev, "Frame     Last Frame\n");
+               dev_info(hsotg->dev, "-----     ----------\n");
+               for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) {
+                       dev_info(hsotg->dev, "0x%04x    0x%04x\n",
+                                hsotg->frame_num_array[i],
+                                hsotg->last_frame_num_array[i]);
+               }
+               hsotg->dumped_frame_num_array = 1;
+       }
+       hsotg->last_frame_num = curr_frame_number;
+#endif
+}
+
+static void dwc2_hc_handle_tt_clear(struct dwc2_hsotg *hsotg,
+                                   struct dwc2_host_chan *chan,
+                                   struct dwc2_qtd *qtd)
+{
+       struct urb *usb_urb;
+
+       if (!chan->qh)
+               return;
+
+       if (chan->qh->dev_speed == USB_SPEED_HIGH)
+               return;
+
+       if (!qtd->urb)
+               return;
+
+       usb_urb = qtd->urb->priv;
+       if (!usb_urb || !usb_urb->dev || !usb_urb->dev->tt)
+               return;
+
+       if (qtd->urb->status != -EPIPE && qtd->urb->status != -EREMOTEIO) {
+               chan->qh->tt_buffer_dirty = 1;
+               if (usb_hub_clear_tt_buffer(usb_urb))
+                       /* Clear failed; let's hope things work anyway */
+                       chan->qh->tt_buffer_dirty = 0;
+       }
+}
+
+/*
+ * Handles the start-of-frame interrupt in host mode. Non-periodic
+ * transactions may be queued to the DWC_otg controller for the current
+ * (micro)frame. Periodic transactions may be queued to the controller
+ * for the next (micro)frame.
+ */
+static void dwc2_sof_intr(struct dwc2_hsotg *hsotg)
+{
+       struct list_head *qh_entry;
+       struct dwc2_qh *qh;
+       enum dwc2_transaction_type tr_type;
+
+#ifdef DEBUG_SOF
+       dev_vdbg(hsotg->dev, "--Start of Frame Interrupt--\n");
+#endif
+
+       hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
+
+       dwc2_track_missed_sofs(hsotg);
+
+       /* Determine whether any periodic QHs should be executed */
+       qh_entry = hsotg->periodic_sched_inactive.next;
+       while (qh_entry != &hsotg->periodic_sched_inactive) {
+               qh = list_entry(qh_entry, struct dwc2_qh, qh_list_entry);
+               qh_entry = qh_entry->next;
+               if (dwc2_frame_num_le(qh->sched_frame, hsotg->frame_number))
+                       /*
+                        * Move QH to the ready list to be executed next
+                        * (micro)frame
+                        */
+                       list_move(&qh->qh_list_entry,
+                                 &hsotg->periodic_sched_ready);
+       }
+       tr_type = dwc2_hcd_select_transactions(hsotg);
+       if (tr_type != DWC2_TRANSACTION_NONE)
+               dwc2_hcd_queue_transactions(hsotg, tr_type);
+
+       /* Clear interrupt */
+       writel(GINTSTS_SOF, hsotg->regs + GINTSTS);
+}
+
+/*
+ * Handles the Rx FIFO Level Interrupt, which indicates that there is
+ * at least one packet in the Rx FIFO. The packets are moved from the FIFO to
+ * memory if the DWC_otg controller is operating in Slave mode.
+ */
+static void dwc2_rx_fifo_level_intr(struct dwc2_hsotg *hsotg)
+{
+       u32 grxsts, chnum, bcnt, dpid, pktsts;
+       struct dwc2_host_chan *chan;
+
+       if (dbg_perio())
+               dev_vdbg(hsotg->dev, "--RxFIFO Level Interrupt--\n");
+
+       grxsts = readl(hsotg->regs + GRXSTSP);
+       chnum = (grxsts & GRXSTS_HCHNUM_MASK) >> GRXSTS_HCHNUM_SHIFT;
+       chan = hsotg->hc_ptr_array[chnum];
+       if (!chan) {
+               dev_err(hsotg->dev, "Unable to get corresponding channel\n");
+               return;
+       }
+
+       bcnt = (grxsts & GRXSTS_BYTECNT_MASK) >> GRXSTS_BYTECNT_SHIFT;
+       dpid = (grxsts & GRXSTS_DPID_MASK) >> GRXSTS_DPID_SHIFT;
+       pktsts = (grxsts & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT;
+
+       /* Packet Status */
+       if (dbg_perio()) {
+               dev_vdbg(hsotg->dev, "    Ch num = %d\n", chnum);
+               dev_vdbg(hsotg->dev, "    Count = %d\n", bcnt);
+               dev_vdbg(hsotg->dev, "    DPID = %d, chan.dpid = %d\n", dpid,
+                        chan->data_pid_start);
+               dev_vdbg(hsotg->dev, "    PStatus = %d\n", pktsts);
+       }
+
+       switch (pktsts) {
+       case GRXSTS_PKTSTS_HCHIN:
+               /* Read the data into the host buffer */
+               if (bcnt > 0) {
+                       dwc2_read_packet(hsotg, chan->xfer_buf, bcnt);
+
+                       /* Update the HC fields for the next packet received */
+                       chan->xfer_count += bcnt;
+                       chan->xfer_buf += bcnt;
+               }
+               break;
+       case GRXSTS_PKTSTS_HCHIN_XFER_COMP:
+       case GRXSTS_PKTSTS_DATATOGGLEERR:
+       case GRXSTS_PKTSTS_HCHHALTED:
+               /* Handled in interrupt, just ignore data */
+               break;
+       default:
+               dev_err(hsotg->dev,
+                       "RxFIFO Level Interrupt: Unknown status %d\n", pktsts);
+               break;
+       }
+}
+
+/*
+ * This interrupt occurs when the non-periodic Tx FIFO is half-empty. More
+ * data packets may be written to the FIFO for OUT transfers. More requests
+ * may be written to the non-periodic request queue for IN transfers. This
+ * interrupt is enabled only in Slave mode.
+ */
+static void dwc2_np_tx_fifo_empty_intr(struct dwc2_hsotg *hsotg)
+{
+       dev_vdbg(hsotg->dev, "--Non-Periodic TxFIFO Empty Interrupt--\n");
+       dwc2_hcd_queue_transactions(hsotg, DWC2_TRANSACTION_NON_PERIODIC);
+}
+
+/*
+ * This interrupt occurs when the periodic Tx FIFO is half-empty. More data
+ * packets may be written to the FIFO for OUT transfers. More requests may be
+ * written to the periodic request queue for IN transfers. This interrupt is
+ * enabled only in Slave mode.
+ */
+static void dwc2_perio_tx_fifo_empty_intr(struct dwc2_hsotg *hsotg)
+{
+       if (dbg_perio())
+               dev_vdbg(hsotg->dev, "--Periodic TxFIFO Empty Interrupt--\n");
+       dwc2_hcd_queue_transactions(hsotg, DWC2_TRANSACTION_PERIODIC);
+}
+
+static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
+                             u32 *hprt0_modify)
+{
+       struct dwc2_core_params *params = hsotg->core_params;
+       int do_reset = 0;
+       u32 usbcfg;
+       u32 prtspd;
+       u32 hcfg;
+       u32 fslspclksel;
+       u32 hfir;
+
+       dev_vdbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
+
+       /* Every time when port enables calculate HFIR.FrInterval */
+       hfir = readl(hsotg->regs + HFIR);
+       hfir &= ~HFIR_FRINT_MASK;
+       hfir |= dwc2_calc_frame_interval(hsotg) << HFIR_FRINT_SHIFT &
+               HFIR_FRINT_MASK;
+       writel(hfir, hsotg->regs + HFIR);
+
+       /* Check if we need to adjust the PHY clock speed for low power */
+       if (!params->host_support_fs_ls_low_power) {
+               /* Port has been enabled, set the reset change flag */
+               hsotg->flags.b.port_reset_change = 1;
+               return;
+       }
+
+       usbcfg = readl(hsotg->regs + GUSBCFG);
+       prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
+
+       if (prtspd == HPRT0_SPD_LOW_SPEED || prtspd == HPRT0_SPD_FULL_SPEED) {
+               /* Low power */
+               if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL)) {
+                       /* Set PHY low power clock select for FS/LS devices */
+                       usbcfg |= GUSBCFG_PHY_LP_CLK_SEL;
+                       writel(usbcfg, hsotg->regs + GUSBCFG);
+                       do_reset = 1;
+               }
+
+               hcfg = readl(hsotg->regs + HCFG);
+               fslspclksel = (hcfg & HCFG_FSLSPCLKSEL_MASK) >>
+                             HCFG_FSLSPCLKSEL_SHIFT;
+
+               if (prtspd == HPRT0_SPD_LOW_SPEED &&
+                   params->host_ls_low_power_phy_clk ==
+                   DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ) {
+                       /* 6 MHZ */
+                       dev_vdbg(hsotg->dev,
+                                "FS_PHY programming HCFG to 6 MHz\n");
+                       if (fslspclksel != HCFG_FSLSPCLKSEL_6_MHZ) {
+                               fslspclksel = HCFG_FSLSPCLKSEL_6_MHZ;
+                               hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
+                               hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
+                               writel(hcfg, hsotg->regs + HCFG);
+                               do_reset = 1;
+                       }
+               } else {
+                       /* 48 MHZ */
+                       dev_vdbg(hsotg->dev,
+                                "FS_PHY programming HCFG to 48 MHz\n");
+                       if (fslspclksel != HCFG_FSLSPCLKSEL_48_MHZ) {
+                               fslspclksel = HCFG_FSLSPCLKSEL_48_MHZ;
+                               hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
+                               hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
+                               writel(hcfg, hsotg->regs + HCFG);
+                               do_reset = 1;
+                       }
+               }
+       } else {
+               /* Not low power */
+               if (usbcfg & GUSBCFG_PHY_LP_CLK_SEL) {
+                       usbcfg &= ~GUSBCFG_PHY_LP_CLK_SEL;
+                       writel(usbcfg, hsotg->regs + GUSBCFG);
+                       do_reset = 1;
+               }
+       }
+
+       if (do_reset) {
+               *hprt0_modify |= HPRT0_RST;
+               queue_delayed_work(hsotg->wq_otg, &hsotg->reset_work,
+                                  msecs_to_jiffies(60));
+       } else {
+               /* Port has been enabled, set the reset change flag */
+               hsotg->flags.b.port_reset_change = 1;
+       }
+}
+
+/*
+ * There are multiple conditions that can cause a port interrupt. This function
+ * determines which interrupt conditions have occurred and handles them
+ * appropriately.
+ */
+static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
+{
+       u32 hprt0;
+       u32 hprt0_modify;
+
+       dev_vdbg(hsotg->dev, "--Port Interrupt--\n");
+
+       hprt0 = readl(hsotg->regs + HPRT0);
+       hprt0_modify = hprt0;
+
+       /*
+        * Clear appropriate bits in HPRT0 to clear the interrupt bit in
+        * GINTSTS
+        */
+       hprt0_modify &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG |
+                         HPRT0_OVRCURRCHG);
+
+       /*
+        * Port Connect Detected
+        * Set flag and clear if detected
+        */
+       if (hprt0 & HPRT0_CONNDET) {
+               dev_vdbg(hsotg->dev,
+                        "--Port Interrupt HPRT0=0x%08x Port Connect Detected--\n",
+                        hprt0);
+               hsotg->flags.b.port_connect_status_change = 1;
+               hsotg->flags.b.port_connect_status = 1;
+               hprt0_modify |= HPRT0_CONNDET;
+
+               /*
+                * The Hub driver asserts a reset when it sees port connect
+                * status change flag
+                */
+       }
+
+       /*
+        * Port Enable Changed
+        * Clear if detected - Set internal flag if disabled
+        */
+       if (hprt0 & HPRT0_ENACHG) {
+               dev_vdbg(hsotg->dev,
+                        "  --Port Interrupt HPRT0=0x%08x Port Enable Changed (now %d)--\n",
+                        hprt0, !!(hprt0 & HPRT0_ENA));
+               hprt0_modify |= HPRT0_ENACHG;
+               if (hprt0 & HPRT0_ENA)
+                       dwc2_hprt0_enable(hsotg, hprt0, &hprt0_modify);
+               else
+                       hsotg->flags.b.port_enable_change = 1;
+       }
+
+       /* Overcurrent Change Interrupt */
+       if (hprt0 & HPRT0_OVRCURRCHG) {
+               dev_vdbg(hsotg->dev,
+                        "  --Port Interrupt HPRT0=0x%08x Port Overcurrent Changed--\n",
+                        hprt0);
+               hsotg->flags.b.port_over_current_change = 1;
+               hprt0_modify |= HPRT0_OVRCURRCHG;
+       }
+
+       /* Clear Port Interrupts */
+       writel(hprt0_modify, hsotg->regs + HPRT0);
+}
+
+/*
+ * Gets the actual length of a transfer after the transfer halts. halt_status
+ * holds the reason for the halt.
+ *
+ * For IN transfers where halt_status is DWC2_HC_XFER_COMPLETE, *short_read
+ * is set to 1 upon return if less than the requested number of bytes were
+ * transferred. short_read may also be NULL on entry, in which case it remains
+ * unchanged.
+ */
+static u32 dwc2_get_actual_xfer_length(struct dwc2_hsotg *hsotg,
+                                      struct dwc2_host_chan *chan, int chnum,
+                                      struct dwc2_qtd *qtd,
+                                      enum dwc2_halt_status halt_status,
+                                      int *short_read)
+{
+       u32 hctsiz, count, length;
+
+       hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+
+       if (halt_status == DWC2_HC_XFER_COMPLETE) {
+               if (chan->ep_is_in) {
+                       count = (hctsiz & TSIZ_XFERSIZE_MASK) >>
+                               TSIZ_XFERSIZE_SHIFT;
+                       length = chan->xfer_len - count;
+                       if (short_read != NULL)
+                               *short_read = (count != 0);
+               } else if (chan->qh->do_split) {
+                       length = qtd->ssplit_out_xfer_count;
+               } else {
+                       length = chan->xfer_len;
+               }
+       } else {
+               /*
+                * Must use the hctsiz.pktcnt field to determine how much data
+                * has been transferred. This field reflects the number of
+                * packets that have been transferred via the USB. This is
+                * always an integral number of packets if the transfer was
+                * halted before its normal completion. (Can't use the
+                * hctsiz.xfersize field because that reflects the number of
+                * bytes transferred via the AHB, not the USB).
+                */
+               count = (hctsiz & TSIZ_PKTCNT_MASK) >> TSIZ_PKTCNT_SHIFT;
+               length = (chan->start_pkt_count - count) * chan->max_packet;
+       }
+
+       return length;
+}
+
+/**
+ * dwc2_update_urb_state() - Updates the state of the URB after a Transfer
+ * Complete interrupt on the host channel. Updates the actual_length field
+ * of the URB based on the number of bytes transferred via the host channel.
+ * Sets the URB status if the data transfer is finished.
+ *
+ * Return: 1 if the data transfer specified by the URB is completely finished,
+ * 0 otherwise
+ */
+static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
+                                struct dwc2_host_chan *chan, int chnum,
+                                struct dwc2_hcd_urb *urb,
+                                struct dwc2_qtd *qtd)
+{
+       u32 hctsiz;
+       int xfer_done = 0;
+       int short_read = 0;
+       int xfer_length = dwc2_get_actual_xfer_length(hsotg, chan, chnum, qtd,
+                                                     DWC2_HC_XFER_COMPLETE,
+                                                     &short_read);
+
+       if (urb->actual_length + xfer_length > urb->length) {
+               dev_warn(hsotg->dev, "%s(): trimming xfer length\n", __func__);
+               xfer_length = urb->length - urb->actual_length;
+       }
+
+       /* Non DWORD-aligned buffer case handling */
+       if (chan->align_buf && xfer_length && chan->ep_is_in) {
+               dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
+               dma_sync_single_for_cpu(hsotg->dev, urb->dma, urb->length,
+                                       DMA_FROM_DEVICE);
+               memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
+                      xfer_length);
+               dma_sync_single_for_device(hsotg->dev, urb->dma, urb->length,
+                                          DMA_FROM_DEVICE);
+       }
+
+       dev_vdbg(hsotg->dev, "urb->actual_length=%d xfer_length=%d\n",
+                urb->actual_length, xfer_length);
+       urb->actual_length += xfer_length;
+
+       if (xfer_length && chan->ep_type == USB_ENDPOINT_XFER_BULK &&
+           (urb->flags & URB_SEND_ZERO_PACKET) &&
+           urb->actual_length >= urb->length &&
+           !(urb->length % chan->max_packet)) {
+               xfer_done = 0;
+       } else if (short_read || urb->actual_length >= urb->length) {
+               xfer_done = 1;
+               urb->status = 0;
+       }
+
+       hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+       dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
+                __func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
+       dev_vdbg(hsotg->dev, "  chan->xfer_len %d\n", chan->xfer_len);
+       dev_vdbg(hsotg->dev, "  hctsiz.xfersize %d\n",
+                (hctsiz & TSIZ_XFERSIZE_MASK) >> TSIZ_XFERSIZE_SHIFT);
+       dev_vdbg(hsotg->dev, "  urb->transfer_buffer_length %d\n", urb->length);
+       dev_vdbg(hsotg->dev, "  urb->actual_length %d\n", urb->actual_length);
+       dev_vdbg(hsotg->dev, "  short_read %d, xfer_done %d\n", short_read,
+                xfer_done);
+
+       return xfer_done;
+}
+
+/*
+ * Save the starting data toggle for the next transfer. The data toggle is
+ * saved in the QH for non-control transfers and it's saved in the QTD for
+ * control transfers.
+ */
+void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg,
+                              struct dwc2_host_chan *chan, int chnum,
+                              struct dwc2_qtd *qtd)
+{
+       u32 hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+       u32 pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT;
+
+       if (chan->ep_type != USB_ENDPOINT_XFER_CONTROL) {
+               if (pid == TSIZ_SC_MC_PID_DATA0)
+                       chan->qh->data_toggle = DWC2_HC_PID_DATA0;
+               else
+                       chan->qh->data_toggle = DWC2_HC_PID_DATA1;
+       } else {
+               if (pid == TSIZ_SC_MC_PID_DATA0)
+                       qtd->data_toggle = DWC2_HC_PID_DATA0;
+               else
+                       qtd->data_toggle = DWC2_HC_PID_DATA1;
+       }
+}
+
+/**
+ * dwc2_update_isoc_urb_state() - Updates the state of an Isochronous URB when
+ * the transfer is stopped for any reason. The fields of the current entry in
+ * the frame descriptor array are set based on the transfer state and the input
+ * halt_status. Completes the Isochronous URB if all the URB frames have been
+ * completed.
+ *
+ * Return: DWC2_HC_XFER_COMPLETE if there are more frames remaining to be
+ * transferred in the URB. Otherwise return DWC2_HC_XFER_URB_COMPLETE.
+ */
+static enum dwc2_halt_status dwc2_update_isoc_urb_state(
+               struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
+               int chnum, struct dwc2_qtd *qtd,
+               enum dwc2_halt_status halt_status)
+{
+       struct dwc2_hcd_iso_packet_desc *frame_desc;
+       struct dwc2_hcd_urb *urb = qtd->urb;
+
+       if (!urb)
+               return DWC2_HC_XFER_NO_HALT_STATUS;
+
+       frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
+
+       switch (halt_status) {
+       case DWC2_HC_XFER_COMPLETE:
+               frame_desc->status = 0;
+               frame_desc->actual_length = dwc2_get_actual_xfer_length(hsotg,
+                                       chan, chnum, qtd, halt_status, NULL);
+
+               /* Non DWORD-aligned buffer case handling */
+               if (chan->align_buf && frame_desc->actual_length &&
+                   chan->ep_is_in) {
+                       dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
+                                __func__);
+                       dma_sync_single_for_cpu(hsotg->dev, urb->dma,
+                                               urb->length, DMA_FROM_DEVICE);
+                       memcpy(urb->buf + frame_desc->offset +
+                              qtd->isoc_split_offset, chan->qh->dw_align_buf,
+                              frame_desc->actual_length);
+                       dma_sync_single_for_device(hsotg->dev, urb->dma,
+                                                  urb->length,
+                                                  DMA_FROM_DEVICE);
+               }
+               break;
+       case DWC2_HC_XFER_FRAME_OVERRUN:
+               urb->error_count++;
+               if (chan->ep_is_in)
+                       frame_desc->status = -ENOSR;
+               else
+                       frame_desc->status = -ECOMM;
+               frame_desc->actual_length = 0;
+               break;
+       case DWC2_HC_XFER_BABBLE_ERR:
+               urb->error_count++;
+               frame_desc->status = -EOVERFLOW;
+               /* Don't need to update actual_length in this case */
+               break;
+       case DWC2_HC_XFER_XACT_ERR:
+               urb->error_count++;
+               frame_desc->status = -EPROTO;
+               frame_desc->actual_length = dwc2_get_actual_xfer_length(hsotg,
+                                       chan, chnum, qtd, halt_status, NULL);
+
+               /* Non DWORD-aligned buffer case handling */
+               if (chan->align_buf && frame_desc->actual_length &&
+                   chan->ep_is_in) {
+                       dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
+                                __func__);
+                       dma_sync_single_for_cpu(hsotg->dev, urb->dma,
+                                               urb->length, DMA_FROM_DEVICE);
+                       memcpy(urb->buf + frame_desc->offset +
+                              qtd->isoc_split_offset, chan->qh->dw_align_buf,
+                              frame_desc->actual_length);
+                       dma_sync_single_for_device(hsotg->dev, urb->dma,
+                                                  urb->length,
+                                                  DMA_FROM_DEVICE);
+               }
+
+               /* Skip whole frame */
+               if (chan->qh->do_split &&
+                   chan->ep_type == USB_ENDPOINT_XFER_ISOC && chan->ep_is_in &&
+                   hsotg->core_params->dma_enable > 0) {
+                       qtd->complete_split = 0;
+                       qtd->isoc_split_offset = 0;
+               }
+
+               break;
+       default:
+               dev_err(hsotg->dev, "Unhandled halt_status (%d)\n",
+                       halt_status);
+               break;
+       }
+
+       if (++qtd->isoc_frame_index == urb->packet_count) {
+               /*
+                * urb->status is not used for isoc transfers. The individual
+                * frame_desc statuses are used instead.
+                */
+               dwc2_host_complete(hsotg, qtd, 0);
+               halt_status = DWC2_HC_XFER_URB_COMPLETE;
+       } else {
+               halt_status = DWC2_HC_XFER_COMPLETE;
+       }
+
+       return halt_status;
+}
+
+/*
+ * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic
+ * QHs, removes the QH from the active non-periodic schedule. If any QTDs are
+ * still linked to the QH, the QH is added to the end of the inactive
+ * non-periodic schedule. For periodic QHs, removes the QH from the periodic
+ * schedule if no more QTDs are linked to the QH.
+ */
+static void dwc2_deactivate_qh(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+                              int free_qtd)
+{
+       int continue_split = 0;
+       struct dwc2_qtd *qtd;
+
+       if (dbg_qh(qh))
+               dev_vdbg(hsotg->dev, "  %s(%p,%p,%d)\n", __func__,
+                        hsotg, qh, free_qtd);
+
+       if (list_empty(&qh->qtd_list)) {
+               dev_dbg(hsotg->dev, "## QTD list empty ##\n");
+               goto no_qtd;
+       }
+
+       qtd = list_first_entry(&qh->qtd_list, struct dwc2_qtd, qtd_list_entry);
+
+       if (qtd->complete_split)
+               continue_split = 1;
+       else if (qtd->isoc_split_pos == DWC2_HCSPLT_XACTPOS_MID ||
+                qtd->isoc_split_pos == DWC2_HCSPLT_XACTPOS_END)
+               continue_split = 1;
+
+       if (free_qtd) {
+               dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
+               continue_split = 0;
+       }
+
+no_qtd:
+       if (qh->channel)
+               qh->channel->align_buf = 0;
+       qh->channel = NULL;
+       dwc2_hcd_qh_deactivate(hsotg, qh, continue_split);
+}
+
+/**
+ * dwc2_release_channel() - Releases a host channel for use by other transfers
+ *
+ * @hsotg:       The HCD state structure
+ * @chan:        The host channel to release
+ * @qtd:         The QTD associated with the host channel. This QTD may be
+ *               freed if the transfer is complete or an error has occurred.
+ * @halt_status: Reason the channel is being released. This status
+ *               determines the actions taken by this function.
+ *
+ * Also attempts to select and queue more transactions since at least one host
+ * channel is available.
+ */
+static void dwc2_release_channel(struct dwc2_hsotg *hsotg,
+                                struct dwc2_host_chan *chan,
+                                struct dwc2_qtd *qtd,
+                                enum dwc2_halt_status halt_status)
+{
+       enum dwc2_transaction_type tr_type;
+       u32 haintmsk;
+       int free_qtd = 0;
+
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "  %s: channel %d, halt_status %d\n",
+                        __func__, chan->hc_num, halt_status);
+
+       switch (halt_status) {
+       case DWC2_HC_XFER_URB_COMPLETE:
+               free_qtd = 1;
+               break;
+       case DWC2_HC_XFER_AHB_ERR:
+       case DWC2_HC_XFER_STALL:
+       case DWC2_HC_XFER_BABBLE_ERR:
+               free_qtd = 1;
+               break;
+       case DWC2_HC_XFER_XACT_ERR:
+               if (qtd && qtd->error_count >= 3) {
+                       dev_vdbg(hsotg->dev,
+                                "  Complete URB with transaction error\n");
+                       free_qtd = 1;
+                       dwc2_host_complete(hsotg, qtd, -EPROTO);
+               }
+               break;
+       case DWC2_HC_XFER_URB_DEQUEUE:
+               /*
+                * The QTD has already been removed and the QH has been
+                * deactivated. Don't want to do anything except release the
+                * host channel and try to queue more transfers.
+                */
+               goto cleanup;
+       case DWC2_HC_XFER_PERIODIC_INCOMPLETE:
+               dev_vdbg(hsotg->dev, "  Complete URB with I/O error\n");
+               free_qtd = 1;
+               dwc2_host_complete(hsotg, qtd, -EIO);
+               break;
+       case DWC2_HC_XFER_NO_HALT_STATUS:
+       default:
+               break;
+       }
+
+       dwc2_deactivate_qh(hsotg, chan->qh, free_qtd);
+
+cleanup:
+       /*
+        * Release the host channel for use by other transfers. The cleanup
+        * function clears the channel interrupt enables and conditions, so
+        * there's no need to clear the Channel Halted interrupt separately.
+        */
+       if (!list_empty(&chan->hc_list_entry))
+               list_del(&chan->hc_list_entry);
+       dwc2_hc_cleanup(hsotg, chan);
+       list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list);
+
+       if (hsotg->core_params->uframe_sched > 0) {
+               hsotg->available_host_channels++;
+       } else {
+               switch (chan->ep_type) {
+               case USB_ENDPOINT_XFER_CONTROL:
+               case USB_ENDPOINT_XFER_BULK:
+                       hsotg->non_periodic_channels--;
+                       break;
+               default:
+                       /*
+                        * Don't release reservations for periodic channels
+                        * here. That's done when a periodic transfer is
+                        * descheduled (i.e. when the QH is removed from the
+                        * periodic schedule).
+                        */
+                       break;
+               }
+       }
+
+       haintmsk = readl(hsotg->regs + HAINTMSK);
+       haintmsk &= ~(1 << chan->hc_num);
+       writel(haintmsk, hsotg->regs + HAINTMSK);
+
+       /* Try to queue more transfers now that there's a free channel */
+       tr_type = dwc2_hcd_select_transactions(hsotg);
+       if (tr_type != DWC2_TRANSACTION_NONE)
+               dwc2_hcd_queue_transactions(hsotg, tr_type);
+}
+
+/*
+ * Halts a host channel. If the channel cannot be halted immediately because
+ * the request queue is full, this function ensures that the FIFO empty
+ * interrupt for the appropriate queue is enabled so that the halt request can
+ * be queued when there is space in the request queue.
+ *
+ * This function may also be called in DMA mode. In that case, the channel is
+ * simply released since the core always halts the channel automatically in
+ * DMA mode.
+ */
+static void dwc2_halt_channel(struct dwc2_hsotg *hsotg,
+                             struct dwc2_host_chan *chan, struct dwc2_qtd *qtd,
+                             enum dwc2_halt_status halt_status)
+{
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+       if (hsotg->core_params->dma_enable > 0) {
+               if (dbg_hc(chan))
+                       dev_vdbg(hsotg->dev, "DMA enabled\n");
+               dwc2_release_channel(hsotg, chan, qtd, halt_status);
+               return;
+       }
+
+       /* Slave mode processing */
+       dwc2_hc_halt(hsotg, chan, halt_status);
+
+       if (chan->halt_on_queue) {
+               u32 gintmsk;
+
+               dev_vdbg(hsotg->dev, "Halt on queue\n");
+               if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL ||
+                   chan->ep_type == USB_ENDPOINT_XFER_BULK) {
+                       dev_vdbg(hsotg->dev, "control/bulk\n");
+                       /*
+                        * Make sure the Non-periodic Tx FIFO empty interrupt
+                        * is enabled so that the non-periodic schedule will
+                        * be processed
+                        */
+                       gintmsk = readl(hsotg->regs + GINTMSK);
+                       gintmsk |= GINTSTS_NPTXFEMP;
+                       writel(gintmsk, hsotg->regs + GINTMSK);
+               } else {
+                       dev_vdbg(hsotg->dev, "isoc/intr\n");
+                       /*
+                        * Move the QH from the periodic queued schedule to
+                        * the periodic assigned schedule. This allows the
+                        * halt to be queued when the periodic schedule is
+                        * processed.
+                        */
+                       list_move(&chan->qh->qh_list_entry,
+                                 &hsotg->periodic_sched_assigned);
+
+                       /*
+                        * Make sure the Periodic Tx FIFO Empty interrupt is
+                        * enabled so that the periodic schedule will be
+                        * processed
+                        */
+                       gintmsk = readl(hsotg->regs + GINTMSK);
+                       gintmsk |= GINTSTS_PTXFEMP;
+                       writel(gintmsk, hsotg->regs + GINTMSK);
+               }
+       }
+}
+
+/*
+ * Performs common cleanup for non-periodic transfers after a Transfer
+ * Complete interrupt. This function should be called after any endpoint type
+ * specific handling is finished to release the host channel.
+ */
+static void dwc2_complete_non_periodic_xfer(struct dwc2_hsotg *hsotg,
+                                           struct dwc2_host_chan *chan,
+                                           int chnum, struct dwc2_qtd *qtd,
+                                           enum dwc2_halt_status halt_status)
+{
+       dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+       qtd->error_count = 0;
+
+       if (chan->hcint & HCINTMSK_NYET) {
+               /*
+                * Got a NYET on the last transaction of the transfer. This
+                * means that the endpoint should be in the PING state at the
+                * beginning of the next transfer.
+                */
+               dev_vdbg(hsotg->dev, "got NYET\n");
+               chan->qh->ping_state = 1;
+       }
+
+       /*
+        * Always halt and release the host channel to make it available for
+        * more transfers. There may still be more phases for a control
+        * transfer or more data packets for a bulk transfer at this point,
+        * but the host channel is still halted. A channel will be reassigned
+        * to the transfer when the non-periodic schedule is processed after
+        * the channel is released. This allows transactions to be queued
+        * properly via dwc2_hcd_queue_transactions, which also enables the
+        * Tx FIFO Empty interrupt if necessary.
+        */
+       if (chan->ep_is_in) {
+               /*
+                * IN transfers in Slave mode require an explicit disable to
+                * halt the channel. (In DMA mode, this call simply releases
+                * the channel.)
+                */
+               dwc2_halt_channel(hsotg, chan, qtd, halt_status);
+       } else {
+               /*
+                * The channel is automatically disabled by the core for OUT
+                * transfers in Slave mode
+                */
+               dwc2_release_channel(hsotg, chan, qtd, halt_status);
+       }
+}
+
+/*
+ * Performs common cleanup for periodic transfers after a Transfer Complete
+ * interrupt. This function should be called after any endpoint type specific
+ * handling is finished to release the host channel.
+ */
+static void dwc2_complete_periodic_xfer(struct dwc2_hsotg *hsotg,
+                                       struct dwc2_host_chan *chan, int chnum,
+                                       struct dwc2_qtd *qtd,
+                                       enum dwc2_halt_status halt_status)
+{
+       u32 hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+
+       qtd->error_count = 0;
+
+       if (!chan->ep_is_in || (hctsiz & TSIZ_PKTCNT_MASK) == 0)
+               /* Core halts channel in these cases */
+               dwc2_release_channel(hsotg, chan, qtd, halt_status);
+       else
+               /* Flush any outstanding requests from the Tx queue */
+               dwc2_halt_channel(hsotg, chan, qtd, halt_status);
+}
+
+static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg,
+                                      struct dwc2_host_chan *chan, int chnum,
+                                      struct dwc2_qtd *qtd)
+{
+       struct dwc2_hcd_iso_packet_desc *frame_desc;
+       u32 len;
+
+       if (!qtd->urb)
+               return 0;
+
+       frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
+       len = dwc2_get_actual_xfer_length(hsotg, chan, chnum, qtd,
+                                         DWC2_HC_XFER_COMPLETE, NULL);
+       if (!len) {
+               qtd->complete_split = 0;
+               qtd->isoc_split_offset = 0;
+               return 0;
+       }
+
+       frame_desc->actual_length += len;
+
+       if (chan->align_buf) {
+               dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
+               dma_sync_single_for_cpu(hsotg->dev, qtd->urb->dma,
+                                       qtd->urb->length, DMA_FROM_DEVICE);
+               memcpy(qtd->urb->buf + frame_desc->offset +
+                      qtd->isoc_split_offset, chan->qh->dw_align_buf, len);
+               dma_sync_single_for_device(hsotg->dev, qtd->urb->dma,
+                                          qtd->urb->length, DMA_FROM_DEVICE);
+       }
+
+       qtd->isoc_split_offset += len;
+
+       if (frame_desc->actual_length >= frame_desc->length) {
+               frame_desc->status = 0;
+               qtd->isoc_frame_index++;
+               qtd->complete_split = 0;
+               qtd->isoc_split_offset = 0;
+       }
+
+       if (qtd->isoc_frame_index == qtd->urb->packet_count) {
+               dwc2_host_complete(hsotg, qtd, 0);
+               dwc2_release_channel(hsotg, chan, qtd,
+                                    DWC2_HC_XFER_URB_COMPLETE);
+       } else {
+               dwc2_release_channel(hsotg, chan, qtd,
+                                    DWC2_HC_XFER_NO_HALT_STATUS);
+       }
+
+       return 1;       /* Indicates that channel released */
+}
+
+/*
+ * Handles a host channel Transfer Complete interrupt. This handler may be
+ * called in either DMA mode or Slave mode.
+ */
+static void dwc2_hc_xfercomp_intr(struct dwc2_hsotg *hsotg,
+                                 struct dwc2_host_chan *chan, int chnum,
+                                 struct dwc2_qtd *qtd)
+{
+       struct dwc2_hcd_urb *urb = qtd->urb;
+       int pipe_type = dwc2_hcd_get_pipe_type(&urb->pipe_info);
+       enum dwc2_halt_status halt_status = DWC2_HC_XFER_COMPLETE;
+       int urb_xfer_done;
+
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev,
+                        "--Host Channel %d Interrupt: Transfer Complete--\n",
+                        chnum);
+
+       if (hsotg->core_params->dma_desc_enable > 0) {
+               dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, halt_status);
+               if (pipe_type == USB_ENDPOINT_XFER_ISOC)
+                       /* Do not disable the interrupt, just clear it */
+                       return;
+               goto handle_xfercomp_done;
+       }
+
+       /* Handle xfer complete on CSPLIT */
+       if (chan->qh->do_split) {
+               if (chan->ep_type == USB_ENDPOINT_XFER_ISOC && chan->ep_is_in &&
+                   hsotg->core_params->dma_enable > 0) {
+                       if (qtd->complete_split &&
+                           dwc2_xfercomp_isoc_split_in(hsotg, chan, chnum,
+                                                       qtd))
+                               goto handle_xfercomp_done;
+               } else {
+                       qtd->complete_split = 0;
+               }
+       }
+
+       if (!urb)
+               goto handle_xfercomp_done;
+
+       /* Update the QTD and URB states */
+       switch (pipe_type) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               switch (qtd->control_phase) {
+               case DWC2_CONTROL_SETUP:
+                       if (urb->length > 0)
+                               qtd->control_phase = DWC2_CONTROL_DATA;
+                       else
+                               qtd->control_phase = DWC2_CONTROL_STATUS;
+                       dev_vdbg(hsotg->dev,
+                                "  Control setup transaction done\n");
+                       halt_status = DWC2_HC_XFER_COMPLETE;
+                       break;
+               case DWC2_CONTROL_DATA:
+                       urb_xfer_done = dwc2_update_urb_state(hsotg, chan,
+                                                             chnum, urb, qtd);
+                       if (urb_xfer_done) {
+                               qtd->control_phase = DWC2_CONTROL_STATUS;
+                               dev_vdbg(hsotg->dev,
+                                        "  Control data transfer done\n");
+                       } else {
+                               dwc2_hcd_save_data_toggle(hsotg, chan, chnum,
+                                                         qtd);
+                       }
+                       halt_status = DWC2_HC_XFER_COMPLETE;
+                       break;
+               case DWC2_CONTROL_STATUS:
+                       dev_vdbg(hsotg->dev, "  Control transfer complete\n");
+                       if (urb->status == -EINPROGRESS)
+                               urb->status = 0;
+                       dwc2_host_complete(hsotg, qtd, urb->status);
+                       halt_status = DWC2_HC_XFER_URB_COMPLETE;
+                       break;
+               }
+
+               dwc2_complete_non_periodic_xfer(hsotg, chan, chnum, qtd,
+                                               halt_status);
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               dev_vdbg(hsotg->dev, "  Bulk transfer complete\n");
+               urb_xfer_done = dwc2_update_urb_state(hsotg, chan, chnum, urb,
+                                                     qtd);
+               if (urb_xfer_done) {
+                       dwc2_host_complete(hsotg, qtd, urb->status);
+                       halt_status = DWC2_HC_XFER_URB_COMPLETE;
+               } else {
+                       halt_status = DWC2_HC_XFER_COMPLETE;
+               }
+
+               dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
+               dwc2_complete_non_periodic_xfer(hsotg, chan, chnum, qtd,
+                                               halt_status);
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               dev_vdbg(hsotg->dev, "  Interrupt transfer complete\n");
+               urb_xfer_done = dwc2_update_urb_state(hsotg, chan, chnum, urb,
+                                                     qtd);
+
+               /*
+                * Interrupt URB is done on the first transfer complete
+                * interrupt
+                */
+               if (urb_xfer_done) {
+                       dwc2_host_complete(hsotg, qtd, urb->status);
+                       halt_status = DWC2_HC_XFER_URB_COMPLETE;
+               } else {
+                       halt_status = DWC2_HC_XFER_COMPLETE;
+               }
+
+               dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
+               dwc2_complete_periodic_xfer(hsotg, chan, chnum, qtd,
+                                           halt_status);
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               if (dbg_perio())
+                       dev_vdbg(hsotg->dev, "  Isochronous transfer complete\n");
+               if (qtd->isoc_split_pos == DWC2_HCSPLT_XACTPOS_ALL)
+                       halt_status = dwc2_update_isoc_urb_state(hsotg, chan,
+                                       chnum, qtd, DWC2_HC_XFER_COMPLETE);
+               dwc2_complete_periodic_xfer(hsotg, chan, chnum, qtd,
+                                           halt_status);
+               break;
+       }
+
+handle_xfercomp_done:
+       disable_hc_int(hsotg, chnum, HCINTMSK_XFERCOMPL);
+}
+
+/*
+ * Handles a host channel STALL interrupt. This handler may be called in
+ * either DMA mode or Slave mode.
+ */
+static void dwc2_hc_stall_intr(struct dwc2_hsotg *hsotg,
+                              struct dwc2_host_chan *chan, int chnum,
+                              struct dwc2_qtd *qtd)
+{
+       struct dwc2_hcd_urb *urb = qtd->urb;
+       int pipe_type = dwc2_hcd_get_pipe_type(&urb->pipe_info);
+
+       dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: STALL Received--\n",
+               chnum);
+
+       if (hsotg->core_params->dma_desc_enable > 0) {
+               dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
+                                           DWC2_HC_XFER_STALL);
+               goto handle_stall_done;
+       }
+
+       if (!urb)
+               goto handle_stall_halt;
+
+       if (pipe_type == USB_ENDPOINT_XFER_CONTROL)
+               dwc2_host_complete(hsotg, qtd, -EPIPE);
+
+       if (pipe_type == USB_ENDPOINT_XFER_BULK ||
+           pipe_type == USB_ENDPOINT_XFER_INT) {
+               dwc2_host_complete(hsotg, qtd, -EPIPE);
+               /*
+                * USB protocol requires resetting the data toggle for bulk
+                * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT)
+                * setup command is issued to the endpoint. Anticipate the
+                * CLEAR_FEATURE command since a STALL has occurred and reset
+                * the data toggle now.
+                */
+               chan->qh->data_toggle = 0;
+       }
+
+handle_stall_halt:
+       dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_STALL);
+
+handle_stall_done:
+       disable_hc_int(hsotg, chnum, HCINTMSK_STALL);
+}
+
+/*
+ * Updates the state of the URB when a transfer has been stopped due to an
+ * abnormal condition before the transfer completes. Modifies the
+ * actual_length field of the URB to reflect the number of bytes that have
+ * actually been transferred via the host channel.
+ */
+static void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg,
+                                     struct dwc2_host_chan *chan, int chnum,
+                                     struct dwc2_hcd_urb *urb,
+                                     struct dwc2_qtd *qtd,
+                                     enum dwc2_halt_status halt_status)
+{
+       u32 xfer_length = dwc2_get_actual_xfer_length(hsotg, chan, chnum,
+                                                     qtd, halt_status, NULL);
+       u32 hctsiz;
+
+       if (urb->actual_length + xfer_length > urb->length) {
+               dev_warn(hsotg->dev, "%s(): trimming xfer length\n", __func__);
+               xfer_length = urb->length - urb->actual_length;
+       }
+
+       /* Non DWORD-aligned buffer case handling */
+       if (chan->align_buf && xfer_length && chan->ep_is_in) {
+               dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
+               dma_sync_single_for_cpu(hsotg->dev, urb->dma, urb->length,
+                                       DMA_FROM_DEVICE);
+               memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
+                      xfer_length);
+               dma_sync_single_for_device(hsotg->dev, urb->dma, urb->length,
+                                          DMA_FROM_DEVICE);
+       }
+
+       urb->actual_length += xfer_length;
+
+       hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+       dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
+                __func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
+       dev_vdbg(hsotg->dev, "  chan->start_pkt_count %d\n",
+                chan->start_pkt_count);
+       dev_vdbg(hsotg->dev, "  hctsiz.pktcnt %d\n",
+                (hctsiz & TSIZ_PKTCNT_MASK) >> TSIZ_PKTCNT_SHIFT);
+       dev_vdbg(hsotg->dev, "  chan->max_packet %d\n", chan->max_packet);
+       dev_vdbg(hsotg->dev, "  bytes_transferred %d\n",
+                xfer_length);
+       dev_vdbg(hsotg->dev, "  urb->actual_length %d\n",
+                urb->actual_length);
+       dev_vdbg(hsotg->dev, "  urb->transfer_buffer_length %d\n",
+                urb->length);
+}
+
+/*
+ * Handles a host channel NAK interrupt. This handler may be called in either
+ * DMA mode or Slave mode.
+ */
+static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg,
+                            struct dwc2_host_chan *chan, int chnum,
+                            struct dwc2_qtd *qtd)
+{
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: NAK Received--\n",
+                        chnum);
+
+       /*
+        * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
+        * interrupt. Re-start the SSPLIT transfer.
+        */
+       if (chan->do_split) {
+               if (chan->complete_split)
+                       qtd->error_count = 0;
+               qtd->complete_split = 0;
+               dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK);
+               goto handle_nak_done;
+       }
+
+       switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
+       case USB_ENDPOINT_XFER_CONTROL:
+       case USB_ENDPOINT_XFER_BULK:
+               if (hsotg->core_params->dma_enable > 0 && chan->ep_is_in) {
+                       /*
+                        * NAK interrupts are enabled on bulk/control IN
+                        * transfers in DMA mode for the sole purpose of
+                        * resetting the error count after a transaction error
+                        * occurs. The core will continue transferring data.
+                        */
+                       qtd->error_count = 0;
+                       break;
+               }
+
+               /*
+                * NAK interrupts normally occur during OUT transfers in DMA
+                * or Slave mode. For IN transfers, more requests will be
+                * queued as request queue space is available.
+                */
+               qtd->error_count = 0;
+
+               if (!chan->qh->ping_state) {
+                       dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb,
+                                                 qtd, DWC2_HC_XFER_NAK);
+                       dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
+
+                       if (chan->speed == USB_SPEED_HIGH)
+                               chan->qh->ping_state = 1;
+               }
+
+               /*
+                * Halt the channel so the transfer can be re-started from
+                * the appropriate point or the PING protocol will
+                * start/continue
+                */
+               dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK);
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               qtd->error_count = 0;
+               dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK);
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               /* Should never get called for isochronous transfers */
+               dev_err(hsotg->dev, "NACK interrupt for ISOC transfer\n");
+               break;
+       }
+
+handle_nak_done:
+       disable_hc_int(hsotg, chnum, HCINTMSK_NAK);
+}
+
+/*
+ * Handles a host channel ACK interrupt. This interrupt is enabled when
+ * performing the PING protocol in Slave mode, when errors occur during
+ * either Slave mode or DMA mode, and during Start Split transactions.
+ */
+static void dwc2_hc_ack_intr(struct dwc2_hsotg *hsotg,
+                            struct dwc2_host_chan *chan, int chnum,
+                            struct dwc2_qtd *qtd)
+{
+       struct dwc2_hcd_iso_packet_desc *frame_desc;
+
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: ACK Received--\n",
+                        chnum);
+
+       if (chan->do_split) {
+               /* Handle ACK on SSPLIT. ACK should not occur in CSPLIT. */
+               if (!chan->ep_is_in &&
+                   chan->data_pid_start != DWC2_HC_PID_SETUP)
+                       qtd->ssplit_out_xfer_count = chan->xfer_len;
+
+               if (chan->ep_type != USB_ENDPOINT_XFER_ISOC || chan->ep_is_in) {
+                       qtd->complete_split = 1;
+                       dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_ACK);
+               } else {
+                       /* ISOC OUT */
+                       switch (chan->xact_pos) {
+                       case DWC2_HCSPLT_XACTPOS_ALL:
+                               break;
+                       case DWC2_HCSPLT_XACTPOS_END:
+                               qtd->isoc_split_pos = DWC2_HCSPLT_XACTPOS_ALL;
+                               qtd->isoc_split_offset = 0;
+                               break;
+                       case DWC2_HCSPLT_XACTPOS_BEGIN:
+                       case DWC2_HCSPLT_XACTPOS_MID:
+                               /*
+                                * For BEGIN or MID, calculate the length for
+                                * the next microframe to determine the correct
+                                * SSPLIT token, either MID or END
+                                */
+                               frame_desc = &qtd->urb->iso_descs[
+                                               qtd->isoc_frame_index];
+                               qtd->isoc_split_offset += 188;
+
+                               if (frame_desc->length - qtd->isoc_split_offset
+                                                       <= 188)
+                                       qtd->isoc_split_pos =
+                                                       DWC2_HCSPLT_XACTPOS_END;
+                               else
+                                       qtd->isoc_split_pos =
+                                                       DWC2_HCSPLT_XACTPOS_MID;
+                               break;
+                       }
+               }
+       } else {
+               qtd->error_count = 0;
+
+               if (chan->qh->ping_state) {
+                       chan->qh->ping_state = 0;
+                       /*
+                        * Halt the channel so the transfer can be re-started
+                        * from the appropriate point. This only happens in
+                        * Slave mode. In DMA mode, the ping_state is cleared
+                        * when the transfer is started because the core
+                        * automatically executes the PING, then the transfer.
+                        */
+                       dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_ACK);
+               }
+       }
+
+       /*
+        * If the ACK occurred when _not_ in the PING state, let the channel
+        * continue transferring data after clearing the error count
+        */
+       disable_hc_int(hsotg, chnum, HCINTMSK_ACK);
+}
+
+/*
+ * Handles a host channel NYET interrupt. This interrupt should only occur on
+ * Bulk and Control OUT endpoints and for complete split transactions. If a
+ * NYET occurs at the same time as a Transfer Complete interrupt, it is
+ * handled in the xfercomp interrupt handler, not here. This handler may be
+ * called in either DMA mode or Slave mode.
+ */
+static void dwc2_hc_nyet_intr(struct dwc2_hsotg *hsotg,
+                             struct dwc2_host_chan *chan, int chnum,
+                             struct dwc2_qtd *qtd)
+{
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: NYET Received--\n",
+                        chnum);
+
+       /*
+        * NYET on CSPLIT
+        * re-do the CSPLIT immediately on non-periodic
+        */
+       if (chan->do_split && chan->complete_split) {
+               if (chan->ep_is_in && chan->ep_type == USB_ENDPOINT_XFER_ISOC &&
+                   hsotg->core_params->dma_enable > 0) {
+                       qtd->complete_split = 0;
+                       qtd->isoc_split_offset = 0;
+                       qtd->isoc_frame_index++;
+                       if (qtd->urb &&
+                           qtd->isoc_frame_index == qtd->urb->packet_count) {
+                               dwc2_host_complete(hsotg, qtd, 0);
+                               dwc2_release_channel(hsotg, chan, qtd,
+                                                    DWC2_HC_XFER_URB_COMPLETE);
+                       } else {
+                               dwc2_release_channel(hsotg, chan, qtd,
+                                               DWC2_HC_XFER_NO_HALT_STATUS);
+                       }
+                       goto handle_nyet_done;
+               }
+
+               if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+                   chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
+                       int frnum = dwc2_hcd_get_frame_number(hsotg);
+
+                       if (dwc2_full_frame_num(frnum) !=
+                           dwc2_full_frame_num(chan->qh->sched_frame)) {
+                               /*
+                                * No longer in the same full speed frame.
+                                * Treat this as a transaction error.
+                                */
+#if 0
+                               /*
+                                * Todo: Fix system performance so this can
+                                * be treated as an error. Right now complete
+                                * splits cannot be scheduled precisely enough
+                                * due to other system activity, so this error
+                                * occurs regularly in Slave mode.
+                                */
+                               qtd->error_count++;
+#endif
+                               qtd->complete_split = 0;
+                               dwc2_halt_channel(hsotg, chan, qtd,
+                                                 DWC2_HC_XFER_XACT_ERR);
+                               /* Todo: add support for isoc release */
+                               goto handle_nyet_done;
+                       }
+               }
+
+               dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NYET);
+               goto handle_nyet_done;
+       }
+
+       chan->qh->ping_state = 1;
+       qtd->error_count = 0;
+
+       dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb, qtd,
+                                 DWC2_HC_XFER_NYET);
+       dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
+
+       /*
+        * Halt the channel and re-start the transfer so the PING protocol
+        * will start
+        */
+       dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NYET);
+
+handle_nyet_done:
+       disable_hc_int(hsotg, chnum, HCINTMSK_NYET);
+}
+
+/*
+ * Handles a host channel babble interrupt. This handler may be called in
+ * either DMA mode or Slave mode.
+ */
+static void dwc2_hc_babble_intr(struct dwc2_hsotg *hsotg,
+                               struct dwc2_host_chan *chan, int chnum,
+                               struct dwc2_qtd *qtd)
+{
+       dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: Babble Error--\n",
+               chnum);
+
+       dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+
+       if (hsotg->core_params->dma_desc_enable > 0) {
+               dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
+                                           DWC2_HC_XFER_BABBLE_ERR);
+               goto disable_int;
+       }
+
+       if (chan->ep_type != USB_ENDPOINT_XFER_ISOC) {
+               dwc2_host_complete(hsotg, qtd, -EOVERFLOW);
+               dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_BABBLE_ERR);
+       } else {
+               enum dwc2_halt_status halt_status;
+
+               halt_status = dwc2_update_isoc_urb_state(hsotg, chan, chnum,
+                                               qtd, DWC2_HC_XFER_BABBLE_ERR);
+               dwc2_halt_channel(hsotg, chan, qtd, halt_status);
+       }
+
+disable_int:
+       disable_hc_int(hsotg, chnum, HCINTMSK_BBLERR);
+}
+
+/*
+ * Handles a host channel AHB error interrupt. This handler is only called in
+ * DMA mode.
+ */
+static void dwc2_hc_ahberr_intr(struct dwc2_hsotg *hsotg,
+                               struct dwc2_host_chan *chan, int chnum,
+                               struct dwc2_qtd *qtd)
+{
+       struct dwc2_hcd_urb *urb = qtd->urb;
+       char *pipetype, *speed;
+       u32 hcchar;
+       u32 hcsplt;
+       u32 hctsiz;
+       u32 hc_dma;
+
+       dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: AHB Error--\n",
+               chnum);
+
+       if (!urb)
+               goto handle_ahberr_halt;
+
+       dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+
+       hcchar = readl(hsotg->regs + HCCHAR(chnum));
+       hcsplt = readl(hsotg->regs + HCSPLT(chnum));
+       hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+       hc_dma = readl(hsotg->regs + HCDMA(chnum));
+
+       dev_err(hsotg->dev, "AHB ERROR, Channel %d\n", chnum);
+       dev_err(hsotg->dev, "  hcchar 0x%08x, hcsplt 0x%08x\n", hcchar, hcsplt);
+       dev_err(hsotg->dev, "  hctsiz 0x%08x, hc_dma 0x%08x\n", hctsiz, hc_dma);
+       dev_err(hsotg->dev, "  Device address: %d\n",
+               dwc2_hcd_get_dev_addr(&urb->pipe_info));
+       dev_err(hsotg->dev, "  Endpoint: %d, %s\n",
+               dwc2_hcd_get_ep_num(&urb->pipe_info),
+               dwc2_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
+
+       switch (dwc2_hcd_get_pipe_type(&urb->pipe_info)) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               pipetype = "CONTROL";
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               pipetype = "BULK";
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               pipetype = "INTERRUPT";
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               pipetype = "ISOCHRONOUS";
+               break;
+       default:
+               pipetype = "UNKNOWN";
+               break;
+       }
+
+       dev_err(hsotg->dev, "  Endpoint type: %s\n", pipetype);
+
+       switch (chan->speed) {
+       case USB_SPEED_HIGH:
+               speed = "HIGH";
+               break;
+       case USB_SPEED_FULL:
+               speed = "FULL";
+               break;
+       case USB_SPEED_LOW:
+               speed = "LOW";
+               break;
+       default:
+               speed = "UNKNOWN";
+               break;
+       }
+
+       dev_err(hsotg->dev, "  Speed: %s\n", speed);
+
+       dev_err(hsotg->dev, "  Max packet size: %d\n",
+               dwc2_hcd_get_mps(&urb->pipe_info));
+       dev_err(hsotg->dev, "  Data buffer length: %d\n", urb->length);
+       dev_err(hsotg->dev, "  Transfer buffer: %p, Transfer DMA: %08lx\n",
+               urb->buf, (unsigned long)urb->dma);
+       dev_err(hsotg->dev, "  Setup buffer: %p, Setup DMA: %08lx\n",
+               urb->setup_packet, (unsigned long)urb->setup_dma);
+       dev_err(hsotg->dev, "  Interval: %d\n", urb->interval);
+
+       /* Core halts the channel for Descriptor DMA mode */
+       if (hsotg->core_params->dma_desc_enable > 0) {
+               dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
+                                           DWC2_HC_XFER_AHB_ERR);
+               goto handle_ahberr_done;
+       }
+
+       dwc2_host_complete(hsotg, qtd, -EIO);
+
+handle_ahberr_halt:
+       /*
+        * Force a channel halt. Don't call dwc2_halt_channel because that won't
+        * write to the HCCHARn register in DMA mode to force the halt.
+        */
+       dwc2_hc_halt(hsotg, chan, DWC2_HC_XFER_AHB_ERR);
+
+handle_ahberr_done:
+       disable_hc_int(hsotg, chnum, HCINTMSK_AHBERR);
+}
+
+/*
+ * Handles a host channel transaction error interrupt. This handler may be
+ * called in either DMA mode or Slave mode.
+ */
+static void dwc2_hc_xacterr_intr(struct dwc2_hsotg *hsotg,
+                                struct dwc2_host_chan *chan, int chnum,
+                                struct dwc2_qtd *qtd)
+{
+       dev_dbg(hsotg->dev,
+               "--Host Channel %d Interrupt: Transaction Error--\n", chnum);
+
+       dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+
+       if (hsotg->core_params->dma_desc_enable > 0) {
+               dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
+                                           DWC2_HC_XFER_XACT_ERR);
+               goto handle_xacterr_done;
+       }
+
+       switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
+       case USB_ENDPOINT_XFER_CONTROL:
+       case USB_ENDPOINT_XFER_BULK:
+               qtd->error_count++;
+               if (!chan->qh->ping_state) {
+
+                       dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb,
+                                                 qtd, DWC2_HC_XFER_XACT_ERR);
+                       dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
+                       if (!chan->ep_is_in && chan->speed == USB_SPEED_HIGH)
+                               chan->qh->ping_state = 1;
+               }
+
+               /*
+                * Halt the channel so the transfer can be re-started from
+                * the appropriate point or the PING protocol will start
+                */
+               dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_XACT_ERR);
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               qtd->error_count++;
+               if (chan->do_split && chan->complete_split)
+                       qtd->complete_split = 0;
+               dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_XACT_ERR);
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               {
+                       enum dwc2_halt_status halt_status;
+
+                       halt_status = dwc2_update_isoc_urb_state(hsotg, chan,
+                                       chnum, qtd, DWC2_HC_XFER_XACT_ERR);
+                       dwc2_halt_channel(hsotg, chan, qtd, halt_status);
+               }
+               break;
+       }
+
+handle_xacterr_done:
+       disable_hc_int(hsotg, chnum, HCINTMSK_XACTERR);
+}
+
+/*
+ * Handles a host channel frame overrun interrupt. This handler may be called
+ * in either DMA mode or Slave mode.
+ */
+static void dwc2_hc_frmovrun_intr(struct dwc2_hsotg *hsotg,
+                                 struct dwc2_host_chan *chan, int chnum,
+                                 struct dwc2_qtd *qtd)
+{
+       enum dwc2_halt_status halt_status;
+
+       if (dbg_hc(chan))
+               dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: Frame Overrun--\n",
+                       chnum);
+
+       dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+
+       switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
+       case USB_ENDPOINT_XFER_CONTROL:
+       case USB_ENDPOINT_XFER_BULK:
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_FRAME_OVERRUN);
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               halt_status = dwc2_update_isoc_urb_state(hsotg, chan, chnum,
+                                       qtd, DWC2_HC_XFER_FRAME_OVERRUN);
+               dwc2_halt_channel(hsotg, chan, qtd, halt_status);
+               break;
+       }
+
+       disable_hc_int(hsotg, chnum, HCINTMSK_FRMOVRUN);
+}
+
+/*
+ * Handles a host channel data toggle error interrupt. This handler may be
+ * called in either DMA mode or Slave mode.
+ */
+static void dwc2_hc_datatglerr_intr(struct dwc2_hsotg *hsotg,
+                                   struct dwc2_host_chan *chan, int chnum,
+                                   struct dwc2_qtd *qtd)
+{
+       dev_dbg(hsotg->dev,
+               "--Host Channel %d Interrupt: Data Toggle Error--\n", chnum);
+
+       if (chan->ep_is_in)
+               qtd->error_count = 0;
+       else
+               dev_err(hsotg->dev,
+                       "Data Toggle Error on OUT transfer, channel %d\n",
+                       chnum);
+
+       dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+       disable_hc_int(hsotg, chnum, HCINTMSK_DATATGLERR);
+}
+
+/*
+ * For debug only. It checks that a valid halt status is set and that
+ * HCCHARn.chdis is clear. If there's a problem, corrective action is
+ * taken and a warning is issued.
+ *
+ * Return: true if halt status is ok, false otherwise
+ */
+static bool dwc2_halt_status_ok(struct dwc2_hsotg *hsotg,
+                               struct dwc2_host_chan *chan, int chnum,
+                               struct dwc2_qtd *qtd)
+{
+#ifdef DEBUG
+       u32 hcchar;
+       u32 hctsiz;
+       u32 hcintmsk;
+       u32 hcsplt;
+
+       if (chan->halt_status == DWC2_HC_XFER_NO_HALT_STATUS) {
+               /*
+                * This code is here only as a check. This condition should
+                * never happen. Ignore the halt if it does occur.
+                */
+               hcchar = readl(hsotg->regs + HCCHAR(chnum));
+               hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+               hcintmsk = readl(hsotg->regs + HCINTMSK(chnum));
+               hcsplt = readl(hsotg->regs + HCSPLT(chnum));
+               dev_dbg(hsotg->dev,
+                       "%s: chan->halt_status DWC2_HC_XFER_NO_HALT_STATUS,\n",
+                        __func__);
+               dev_dbg(hsotg->dev,
+                       "channel %d, hcchar 0x%08x, hctsiz 0x%08x,\n",
+                       chnum, hcchar, hctsiz);
+               dev_dbg(hsotg->dev,
+                       "hcint 0x%08x, hcintmsk 0x%08x, hcsplt 0x%08x,\n",
+                       chan->hcint, hcintmsk, hcsplt);
+               if (qtd)
+                       dev_dbg(hsotg->dev, "qtd->complete_split %d\n",
+                               qtd->complete_split);
+               dev_warn(hsotg->dev,
+                        "%s: no halt status, channel %d, ignoring interrupt\n",
+                        __func__, chnum);
+               return false;
+       }
+
+       /*
+        * This code is here only as a check. hcchar.chdis should never be set
+        * when the halt interrupt occurs. Halt the channel again if it does
+        * occur.
+        */
+       hcchar = readl(hsotg->regs + HCCHAR(chnum));
+       if (hcchar & HCCHAR_CHDIS) {
+               dev_warn(hsotg->dev,
+                        "%s: hcchar.chdis set unexpectedly, hcchar 0x%08x, trying to halt again\n",
+                        __func__, hcchar);
+               chan->halt_pending = 0;
+               dwc2_halt_channel(hsotg, chan, qtd, chan->halt_status);
+               return false;
+       }
+#endif
+
+       return true;
+}
+
+/*
+ * Handles a host Channel Halted interrupt in DMA mode. This handler
+ * determines the reason the channel halted and proceeds accordingly.
+ */
+static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg,
+                                   struct dwc2_host_chan *chan, int chnum,
+                                   struct dwc2_qtd *qtd)
+{
+       u32 hcintmsk;
+       int out_nak_enh = 0;
+
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev,
+                        "--Host Channel %d Interrupt: DMA Channel Halted--\n",
+                        chnum);
+
+       /*
+        * For core with OUT NAK enhancement, the flow for high-speed
+        * CONTROL/BULK OUT is handled a little differently
+        */
+       if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_71a) {
+               if (chan->speed == USB_SPEED_HIGH && !chan->ep_is_in &&
+                   (chan->ep_type == USB_ENDPOINT_XFER_CONTROL ||
+                    chan->ep_type == USB_ENDPOINT_XFER_BULK)) {
+                       out_nak_enh = 1;
+               }
+       }
+
+       if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE ||
+           (chan->halt_status == DWC2_HC_XFER_AHB_ERR &&
+            hsotg->core_params->dma_desc_enable <= 0)) {
+               if (hsotg->core_params->dma_desc_enable > 0)
+                       dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
+                                                   chan->halt_status);
+               else
+                       /*
+                        * Just release the channel. A dequeue can happen on a
+                        * transfer timeout. In the case of an AHB Error, the
+                        * channel was forced to halt because there's no way to
+                        * gracefully recover.
+                        */
+                       dwc2_release_channel(hsotg, chan, qtd,
+                                            chan->halt_status);
+               return;
+       }
+
+       hcintmsk = readl(hsotg->regs + HCINTMSK(chnum));
+
+       if (chan->hcint & HCINTMSK_XFERCOMPL) {
+               /*
+                * Todo: This is here because of a possible hardware bug. Spec
+                * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT
+                * interrupt w/ACK bit set should occur, but I only see the
+                * XFERCOMP bit, even with it masked out. This is a workaround
+                * for that behavior. Should fix this when hardware is fixed.
+                */
+               if (chan->ep_type == USB_ENDPOINT_XFER_ISOC && !chan->ep_is_in)
+                       dwc2_hc_ack_intr(hsotg, chan, chnum, qtd);
+               dwc2_hc_xfercomp_intr(hsotg, chan, chnum, qtd);
+       } else if (chan->hcint & HCINTMSK_STALL) {
+               dwc2_hc_stall_intr(hsotg, chan, chnum, qtd);
+       } else if ((chan->hcint & HCINTMSK_XACTERR) &&
+                  hsotg->core_params->dma_desc_enable <= 0) {
+               if (out_nak_enh) {
+                       if (chan->hcint &
+                           (HCINTMSK_NYET | HCINTMSK_NAK | HCINTMSK_ACK)) {
+                               dev_vdbg(hsotg->dev,
+                                        "XactErr with NYET/NAK/ACK\n");
+                               qtd->error_count = 0;
+                       } else {
+                               dev_vdbg(hsotg->dev,
+                                        "XactErr without NYET/NAK/ACK\n");
+                       }
+               }
+
+               /*
+                * Must handle xacterr before nak or ack. Could get a xacterr
+                * at the same time as either of these on a BULK/CONTROL OUT
+                * that started with a PING. The xacterr takes precedence.
+                */
+               dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd);
+       } else if ((chan->hcint & HCINTMSK_XCS_XACT) &&
+                  hsotg->core_params->dma_desc_enable > 0) {
+               dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd);
+       } else if ((chan->hcint & HCINTMSK_AHBERR) &&
+                  hsotg->core_params->dma_desc_enable > 0) {
+               dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd);
+       } else if (chan->hcint & HCINTMSK_BBLERR) {
+               dwc2_hc_babble_intr(hsotg, chan, chnum, qtd);
+       } else if (chan->hcint & HCINTMSK_FRMOVRUN) {
+               dwc2_hc_frmovrun_intr(hsotg, chan, chnum, qtd);
+       } else if (!out_nak_enh) {
+               if (chan->hcint & HCINTMSK_NYET) {
+                       /*
+                        * Must handle nyet before nak or ack. Could get a nyet
+                        * at the same time as either of those on a BULK/CONTROL
+                        * OUT that started with a PING. The nyet takes
+                        * precedence.
+                        */
+                       dwc2_hc_nyet_intr(hsotg, chan, chnum, qtd);
+               } else if ((chan->hcint & HCINTMSK_NAK) &&
+                          !(hcintmsk & HCINTMSK_NAK)) {
+                       /*
+                        * If nak is not masked, it's because a non-split IN
+                        * transfer is in an error state. In that case, the nak
+                        * is handled by the nak interrupt handler, not here.
+                        * Handle nak here for BULK/CONTROL OUT transfers, which
+                        * halt on a NAK to allow rewinding the buffer pointer.
+                        */
+                       dwc2_hc_nak_intr(hsotg, chan, chnum, qtd);
+               } else if ((chan->hcint & HCINTMSK_ACK) &&
+                          !(hcintmsk & HCINTMSK_ACK)) {
+                       /*
+                        * If ack is not masked, it's because a non-split IN
+                        * transfer is in an error state. In that case, the ack
+                        * is handled by the ack interrupt handler, not here.
+                        * Handle ack here for split transfers. Start splits
+                        * halt on ACK.
+                        */
+                       dwc2_hc_ack_intr(hsotg, chan, chnum, qtd);
+               } else {
+                       if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+                           chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
+                               /*
+                                * A periodic transfer halted with no other
+                                * channel interrupts set. Assume it was halted
+                                * by the core because it could not be completed
+                                * in its scheduled (micro)frame.
+                                */
+                               dev_dbg(hsotg->dev,
+                                       "%s: Halt channel %d (assume incomplete periodic transfer)\n",
+                                       __func__, chnum);
+                               dwc2_halt_channel(hsotg, chan, qtd,
+                                       DWC2_HC_XFER_PERIODIC_INCOMPLETE);
+                       } else {
+                               dev_err(hsotg->dev,
+                                       "%s: Channel %d - ChHltd set, but reason is unknown\n",
+                                       __func__, chnum);
+                               dev_err(hsotg->dev,
+                                       "hcint 0x%08x, intsts 0x%08x\n",
+                                       chan->hcint,
+                                       readl(hsotg->regs + GINTSTS));
+                       }
+               }
+       } else {
+               dev_info(hsotg->dev,
+                        "NYET/NAK/ACK/other in non-error case, 0x%08x\n",
+                        chan->hcint);
+       }
+}
+
+/*
+ * Handles a host channel Channel Halted interrupt
+ *
+ * In slave mode, this handler is called only when the driver specifically
+ * requests a halt. This occurs during handling other host channel interrupts
+ * (e.g. nak, xacterr, stall, nyet, etc.).
+ *
+ * In DMA mode, this is the interrupt that occurs when the core has finished
+ * processing a transfer on a channel. Other host channel interrupts (except
+ * ahberr) are disabled in DMA mode.
+ */
+static void dwc2_hc_chhltd_intr(struct dwc2_hsotg *hsotg,
+                               struct dwc2_host_chan *chan, int chnum,
+                               struct dwc2_qtd *qtd)
+{
+       if (dbg_hc(chan))
+               dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: Channel Halted--\n",
+                        chnum);
+
+       if (hsotg->core_params->dma_enable > 0) {
+               dwc2_hc_chhltd_intr_dma(hsotg, chan, chnum, qtd);
+       } else {
+               if (!dwc2_halt_status_ok(hsotg, chan, chnum, qtd))
+                       return;
+               dwc2_release_channel(hsotg, chan, qtd, chan->halt_status);
+       }
+}
+
+/* Handles interrupt for a specific Host Channel */
+static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
+{
+       struct dwc2_qtd *qtd;
+       struct dwc2_host_chan *chan;
+       u32 hcint, hcintmsk;
+
+       chan = hsotg->hc_ptr_array[chnum];
+
+       hcint = readl(hsotg->regs + HCINT(chnum));
+       hcintmsk = readl(hsotg->regs + HCINTMSK(chnum));
+       if (!chan) {
+               dev_err(hsotg->dev, "## hc_ptr_array for channel is NULL ##\n");
+               writel(hcint, hsotg->regs + HCINT(chnum));
+               return;
+       }
+
+       if (dbg_hc(chan)) {
+               dev_vdbg(hsotg->dev, "--Host Channel Interrupt--, Channel %d\n",
+                        chnum);
+               dev_vdbg(hsotg->dev,
+                        "  hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
+                        hcint, hcintmsk, hcint & hcintmsk);
+       }
+
+       writel(hcint, hsotg->regs + HCINT(chnum));
+       chan->hcint = hcint;
+       hcint &= hcintmsk;
+
+       /*
+        * If the channel was halted due to a dequeue, the qtd list might
+        * be empty or at least the first entry will not be the active qtd.
+        * In this case, take a shortcut and just release the channel.
+        */
+       if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) {
+               /*
+                * If the channel was halted, this should be the only
+                * interrupt unmasked
+                */
+               WARN_ON(hcint != HCINTMSK_CHHLTD);
+               if (hsotg->core_params->dma_desc_enable > 0)
+                       dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
+                                                   chan->halt_status);
+               else
+                       dwc2_release_channel(hsotg, chan, NULL,
+                                            chan->halt_status);
+               return;
+       }
+
+       if (list_empty(&chan->qh->qtd_list)) {
+               /*
+                * TODO: Will this ever happen with the
+                * DWC2_HC_XFER_URB_DEQUEUE handling above?
+                */
+               dev_dbg(hsotg->dev, "## no QTD queued for channel %d ##\n",
+                       chnum);
+               dev_dbg(hsotg->dev,
+                       "  hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
+                       chan->hcint, hcintmsk, hcint);
+               chan->halt_status = DWC2_HC_XFER_NO_HALT_STATUS;
+               disable_hc_int(hsotg, chnum, HCINTMSK_CHHLTD);
+               chan->hcint = 0;
+               return;
+       }
+
+       qtd = list_first_entry(&chan->qh->qtd_list, struct dwc2_qtd,
+                              qtd_list_entry);
+
+       if (hsotg->core_params->dma_enable <= 0) {
+               if ((hcint & HCINTMSK_CHHLTD) && hcint != HCINTMSK_CHHLTD)
+                       hcint &= ~HCINTMSK_CHHLTD;
+       }
+
+       if (hcint & HCINTMSK_XFERCOMPL) {
+               dwc2_hc_xfercomp_intr(hsotg, chan, chnum, qtd);
+               /*
+                * If NYET occurred at same time as Xfer Complete, the NYET is
+                * handled by the Xfer Complete interrupt handler. Don't want
+                * to call the NYET interrupt handler in this case.
+                */
+               hcint &= ~HCINTMSK_NYET;
+       }
+       if (hcint & HCINTMSK_CHHLTD)
+               dwc2_hc_chhltd_intr(hsotg, chan, chnum, qtd);
+       if (hcint & HCINTMSK_AHBERR)
+               dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd);
+       if (hcint & HCINTMSK_STALL)
+               dwc2_hc_stall_intr(hsotg, chan, chnum, qtd);
+       if (hcint & HCINTMSK_NAK)
+               dwc2_hc_nak_intr(hsotg, chan, chnum, qtd);
+       if (hcint & HCINTMSK_ACK)
+               dwc2_hc_ack_intr(hsotg, chan, chnum, qtd);
+       if (hcint & HCINTMSK_NYET)
+               dwc2_hc_nyet_intr(hsotg, chan, chnum, qtd);
+       if (hcint & HCINTMSK_XACTERR)
+               dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd);
+       if (hcint & HCINTMSK_BBLERR)
+               dwc2_hc_babble_intr(hsotg, chan, chnum, qtd);
+       if (hcint & HCINTMSK_FRMOVRUN)
+               dwc2_hc_frmovrun_intr(hsotg, chan, chnum, qtd);
+       if (hcint & HCINTMSK_DATATGLERR)
+               dwc2_hc_datatglerr_intr(hsotg, chan, chnum, qtd);
+
+       chan->hcint = 0;
+}
+
+/*
+ * This interrupt indicates that one or more host channels has a pending
+ * interrupt. There are multiple conditions that can cause each host channel
+ * interrupt. This function determines which conditions have occurred for each
+ * host channel interrupt and handles them appropriately.
+ */
+static void dwc2_hc_intr(struct dwc2_hsotg *hsotg)
+{
+       u32 haint;
+       int i;
+
+       haint = readl(hsotg->regs + HAINT);
+       if (dbg_perio()) {
+               dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+               dev_vdbg(hsotg->dev, "HAINT=%08x\n", haint);
+       }
+
+       for (i = 0; i < hsotg->core_params->host_channels; i++) {
+               if (haint & (1 << i))
+                       dwc2_hc_n_intr(hsotg, i);
+       }
+}
+
+/* This function handles interrupts for the HCD */
+irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg)
+{
+       u32 gintsts, dbg_gintsts;
+       irqreturn_t retval = IRQ_NONE;
+
+       if (!dwc2_is_controller_alive(hsotg)) {
+               dev_warn(hsotg->dev, "Controller is dead\n");
+               return retval;
+       }
+
+       spin_lock(&hsotg->lock);
+
+       /* Check if HOST Mode */
+       if (dwc2_is_host_mode(hsotg)) {
+               gintsts = dwc2_read_core_intr(hsotg);
+               if (!gintsts) {
+                       spin_unlock(&hsotg->lock);
+                       return retval;
+               }
+
+               retval = IRQ_HANDLED;
+
+               dbg_gintsts = gintsts;
+#ifndef DEBUG_SOF
+               dbg_gintsts &= ~GINTSTS_SOF;
+#endif
+               if (!dbg_perio())
+                       dbg_gintsts &= ~(GINTSTS_HCHINT | GINTSTS_RXFLVL |
+                                        GINTSTS_PTXFEMP);
+
+               /* Only print if there are any non-suppressed interrupts left */
+               if (dbg_gintsts)
+                       dev_vdbg(hsotg->dev,
+                                "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x\n",
+                                gintsts);
+
+               if (gintsts & GINTSTS_SOF)
+                       dwc2_sof_intr(hsotg);
+               if (gintsts & GINTSTS_RXFLVL)
+                       dwc2_rx_fifo_level_intr(hsotg);
+               if (gintsts & GINTSTS_NPTXFEMP)
+                       dwc2_np_tx_fifo_empty_intr(hsotg);
+               if (gintsts & GINTSTS_PRTINT)
+                       dwc2_port_intr(hsotg);
+               if (gintsts & GINTSTS_HCHINT)
+                       dwc2_hc_intr(hsotg);
+               if (gintsts & GINTSTS_PTXFEMP)
+                       dwc2_perio_tx_fifo_empty_intr(hsotg);
+
+               if (dbg_gintsts) {
+                       dev_vdbg(hsotg->dev,
+                                "DWC OTG HCD Finished Servicing Interrupts\n");
+                       dev_vdbg(hsotg->dev,
+                                "DWC OTG HCD gintsts=0x%08x gintmsk=0x%08x\n",
+                                readl(hsotg->regs + GINTSTS),
+                                readl(hsotg->regs + GINTMSK));
+               }
+       }
+
+       spin_unlock(&hsotg->lock);
+
+       return retval;
+}
diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
new file mode 100644 (file)
index 0000000..9540f7e
--- /dev/null
@@ -0,0 +1,835 @@
+/*
+ * hcd_queue.c - DesignWare HS OTG Controller host queuing routines
+ *
+ * Copyright (C) 2004-2013 Synopsys, Inc.
+ *
+ * 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") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * 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.
+ */
+
+/*
+ * This file contains the functions to manage Queue Heads and Queue
+ * Transfer Descriptors for Host mode
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <linux/usb/hcd.h>
+#include <linux/usb/ch11.h>
+
+#include "core.h"
+#include "hcd.h"
+
+/**
+ * dwc2_qh_init() - Initializes a QH structure
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh:    The QH to init
+ * @urb:   Holds the information about the device/endpoint needed to initialize
+ *         the QH
+ */
+#define SCHEDULE_SLOP 10
+static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+                        struct dwc2_hcd_urb *urb)
+{
+       int dev_speed, hub_addr, hub_port;
+       char *speed, *type;
+
+       dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+       /* Initialize QH */
+       qh->ep_type = dwc2_hcd_get_pipe_type(&urb->pipe_info);
+       qh->ep_is_in = dwc2_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
+
+       qh->data_toggle = DWC2_HC_PID_DATA0;
+       qh->maxp = dwc2_hcd_get_mps(&urb->pipe_info);
+       INIT_LIST_HEAD(&qh->qtd_list);
+       INIT_LIST_HEAD(&qh->qh_list_entry);
+
+       /* FS/LS Endpoint on HS Hub, NOT virtual root hub */
+       dev_speed = dwc2_host_get_speed(hsotg, urb->priv);
+
+       dwc2_host_hub_info(hsotg, urb->priv, &hub_addr, &hub_port);
+
+       if ((dev_speed == USB_SPEED_LOW || dev_speed == USB_SPEED_FULL) &&
+           hub_addr != 0 && hub_addr != 1) {
+               dev_vdbg(hsotg->dev,
+                        "QH init: EP %d: TT found at hub addr %d, for port %d\n",
+                        dwc2_hcd_get_ep_num(&urb->pipe_info), hub_addr,
+                        hub_port);
+               qh->do_split = 1;
+       }
+
+       if (qh->ep_type == USB_ENDPOINT_XFER_INT ||
+           qh->ep_type == USB_ENDPOINT_XFER_ISOC) {
+               /* Compute scheduling parameters once and save them */
+               u32 hprt, prtspd;
+
+               /* Todo: Account for split transfers in the bus time */
+               int bytecount =
+                       dwc2_hb_mult(qh->maxp) * dwc2_max_packet(qh->maxp);
+
+               qh->usecs = NS_TO_US(usb_calc_bus_time(qh->do_split ?
+                               USB_SPEED_HIGH : dev_speed, qh->ep_is_in,
+                               qh->ep_type == USB_ENDPOINT_XFER_ISOC,
+                               bytecount));
+               /* Start in a slightly future (micro)frame */
+               qh->sched_frame = dwc2_frame_num_inc(hsotg->frame_number,
+                                                    SCHEDULE_SLOP);
+               qh->interval = urb->interval;
+#if 0
+               /* Increase interrupt polling rate for debugging */
+               if (qh->ep_type == USB_ENDPOINT_XFER_INT)
+                       qh->interval = 8;
+#endif
+               hprt = readl(hsotg->regs + HPRT0);
+               prtspd = (hprt & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
+               if (prtspd == HPRT0_SPD_HIGH_SPEED &&
+                   (dev_speed == USB_SPEED_LOW ||
+                    dev_speed == USB_SPEED_FULL)) {
+                       qh->interval *= 8;
+                       qh->sched_frame |= 0x7;
+                       qh->start_split_frame = qh->sched_frame;
+               }
+               dev_dbg(hsotg->dev, "interval=%d\n", qh->interval);
+       }
+
+       dev_vdbg(hsotg->dev, "DWC OTG HCD QH Initialized\n");
+       dev_vdbg(hsotg->dev, "DWC OTG HCD QH - qh = %p\n", qh);
+       dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Device Address = %d\n",
+                dwc2_hcd_get_dev_addr(&urb->pipe_info));
+       dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Endpoint %d, %s\n",
+                dwc2_hcd_get_ep_num(&urb->pipe_info),
+                dwc2_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
+
+       qh->dev_speed = dev_speed;
+
+       switch (dev_speed) {
+       case USB_SPEED_LOW:
+               speed = "low";
+               break;
+       case USB_SPEED_FULL:
+               speed = "full";
+               break;
+       case USB_SPEED_HIGH:
+               speed = "high";
+               break;
+       default:
+               speed = "?";
+               break;
+       }
+       dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Speed = %s\n", speed);
+
+       switch (qh->ep_type) {
+       case USB_ENDPOINT_XFER_ISOC:
+               type = "isochronous";
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               type = "interrupt";
+               break;
+       case USB_ENDPOINT_XFER_CONTROL:
+               type = "control";
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               type = "bulk";
+               break;
+       default:
+               type = "?";
+               break;
+       }
+
+       dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Type = %s\n", type);
+
+       if (qh->ep_type == USB_ENDPOINT_XFER_INT) {
+               dev_vdbg(hsotg->dev, "DWC OTG HCD QH - usecs = %d\n",
+                        qh->usecs);
+               dev_vdbg(hsotg->dev, "DWC OTG HCD QH - interval = %d\n",
+                        qh->interval);
+       }
+}
+
+/**
+ * dwc2_hcd_qh_create() - Allocates and initializes a QH
+ *
+ * @hsotg:        The HCD state structure for the DWC OTG controller
+ * @urb:          Holds the information about the device/endpoint needed
+ *                to initialize the QH
+ * @atomic_alloc: Flag to do atomic allocation if needed
+ *
+ * Return: Pointer to the newly allocated QH, or NULL on error
+ */
+static struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
+                                         struct dwc2_hcd_urb *urb,
+                                         gfp_t mem_flags)
+{
+       struct dwc2_qh *qh;
+
+       if (!urb->priv)
+               return NULL;
+
+       /* Allocate memory */
+       qh = kzalloc(sizeof(*qh), mem_flags);
+       if (!qh)
+               return NULL;
+
+       dwc2_qh_init(hsotg, qh, urb);
+
+       if (hsotg->core_params->dma_desc_enable > 0 &&
+           dwc2_hcd_qh_init_ddma(hsotg, qh, mem_flags) < 0) {
+               dwc2_hcd_qh_free(hsotg, qh);
+               return NULL;
+       }
+
+       return qh;
+}
+
+/**
+ * dwc2_hcd_qh_free() - Frees the QH
+ *
+ * @hsotg: HCD instance
+ * @qh:    The QH to free
+ *
+ * QH should already be removed from the list. QTD list should already be empty
+ * if called from URB Dequeue.
+ *
+ * Must NOT be called with interrupt disabled or spinlock held
+ */
+void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+       u32 buf_size;
+
+       if (hsotg->core_params->dma_desc_enable > 0) {
+               dwc2_hcd_qh_free_ddma(hsotg, qh);
+       } else if (qh->dw_align_buf) {
+               if (qh->ep_type == USB_ENDPOINT_XFER_ISOC)
+                       buf_size = 4096;
+               else
+                       buf_size = hsotg->core_params->max_transfer_size;
+               dma_free_coherent(hsotg->dev, buf_size, qh->dw_align_buf,
+                                 qh->dw_align_buf_dma);
+       }
+
+       kfree(qh);
+}
+
+/**
+ * dwc2_periodic_channel_available() - Checks that a channel is available for a
+ * periodic transfer
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ *
+ * Return: 0 if successful, negative error code otherwise
+ */
+static int dwc2_periodic_channel_available(struct dwc2_hsotg *hsotg)
+{
+       /*
+        * Currently assuming that there is a dedicated host channel for
+        * each periodic transaction plus at least one host channel for
+        * non-periodic transactions
+        */
+       int status;
+       int num_channels;
+
+       num_channels = hsotg->core_params->host_channels;
+       if (hsotg->periodic_channels + hsotg->non_periodic_channels <
+                                                               num_channels
+           && hsotg->periodic_channels < num_channels - 1) {
+               status = 0;
+       } else {
+               dev_dbg(hsotg->dev,
+                       "%s: Total channels: %d, Periodic: %d, "
+                       "Non-periodic: %d\n", __func__, num_channels,
+                       hsotg->periodic_channels, hsotg->non_periodic_channels);
+               status = -ENOSPC;
+       }
+
+       return status;
+}
+
+/**
+ * dwc2_check_periodic_bandwidth() - Checks that there is sufficient bandwidth
+ * for the specified QH in the periodic schedule
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh:    QH containing periodic bandwidth required
+ *
+ * Return: 0 if successful, negative error code otherwise
+ *
+ * For simplicity, this calculation assumes that all the transfers in the
+ * periodic schedule may occur in the same (micro)frame
+ */
+static int dwc2_check_periodic_bandwidth(struct dwc2_hsotg *hsotg,
+                                        struct dwc2_qh *qh)
+{
+       int status;
+       s16 max_claimed_usecs;
+
+       status = 0;
+
+       if (qh->dev_speed == USB_SPEED_HIGH || qh->do_split) {
+               /*
+                * High speed mode
+                * Max periodic usecs is 80% x 125 usec = 100 usec
+                */
+               max_claimed_usecs = 100 - qh->usecs;
+       } else {
+               /*
+                * Full speed mode
+                * Max periodic usecs is 90% x 1000 usec = 900 usec
+                */
+               max_claimed_usecs = 900 - qh->usecs;
+       }
+
+       if (hsotg->periodic_usecs > max_claimed_usecs) {
+               dev_err(hsotg->dev,
+                       "%s: already claimed usecs %d, required usecs %d\n",
+                       __func__, hsotg->periodic_usecs, qh->usecs);
+               status = -ENOSPC;
+       }
+
+       return status;
+}
+
+/**
+ * Microframe scheduler
+ * track the total use in hsotg->frame_usecs
+ * keep each qh use in qh->frame_usecs
+ * when surrendering the qh then donate the time back
+ */
+static const unsigned short max_uframe_usecs[] = {
+       100, 100, 100, 100, 100, 100, 30, 0
+};
+
+void dwc2_hcd_init_usecs(struct dwc2_hsotg *hsotg)
+{
+       int i;
+
+       for (i = 0; i < 8; i++)
+               hsotg->frame_usecs[i] = max_uframe_usecs[i];
+}
+
+static int dwc2_find_single_uframe(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+       unsigned short utime = qh->usecs;
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               /* At the start hsotg->frame_usecs[i] = max_uframe_usecs[i] */
+               if (utime <= hsotg->frame_usecs[i]) {
+                       hsotg->frame_usecs[i] -= utime;
+                       qh->frame_usecs[i] += utime;
+                       return i;
+               }
+       }
+       return -ENOSPC;
+}
+
+/*
+ * use this for FS apps that can span multiple uframes
+ */
+static int dwc2_find_multi_uframe(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+       unsigned short utime = qh->usecs;
+       unsigned short xtime;
+       int t_left;
+       int i;
+       int j;
+       int k;
+
+       for (i = 0; i < 8; i++) {
+               if (hsotg->frame_usecs[i] <= 0)
+                       continue;
+
+               /*
+                * we need n consecutive slots so use j as a start slot
+                * j plus j+1 must be enough time (for now)
+                */
+               xtime = hsotg->frame_usecs[i];
+               for (j = i + 1; j < 8; j++) {
+                       /*
+                        * if we add this frame remaining time to xtime we may
+                        * be OK, if not we need to test j for a complete frame
+                        */
+                       if (xtime + hsotg->frame_usecs[j] < utime) {
+                               if (hsotg->frame_usecs[j] <
+                                                       max_uframe_usecs[j])
+                                       continue;
+                       }
+                       if (xtime >= utime) {
+                               t_left = utime;
+                               for (k = i; k < 8; k++) {
+                                       t_left -= hsotg->frame_usecs[k];
+                                       if (t_left <= 0) {
+                                               qh->frame_usecs[k] +=
+                                                       hsotg->frame_usecs[k]
+                                                               + t_left;
+                                               hsotg->frame_usecs[k] = -t_left;
+                                               return i;
+                                       } else {
+                                               qh->frame_usecs[k] +=
+                                                       hsotg->frame_usecs[k];
+                                               hsotg->frame_usecs[k] = 0;
+                                       }
+                               }
+                       }
+                       /* add the frame time to x time */
+                       xtime += hsotg->frame_usecs[j];
+                       /* we must have a fully available next frame or break */
+                       if (xtime < utime &&
+                          hsotg->frame_usecs[j] == max_uframe_usecs[j])
+                               continue;
+               }
+       }
+       return -ENOSPC;
+}
+
+static int dwc2_find_uframe(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+       int ret;
+
+       if (qh->dev_speed == USB_SPEED_HIGH) {
+               /* if this is a hs transaction we need a full frame */
+               ret = dwc2_find_single_uframe(hsotg, qh);
+       } else {
+               /*
+                * if this is a fs transaction we may need a sequence
+                * of frames
+                */
+               ret = dwc2_find_multi_uframe(hsotg, qh);
+       }
+       return ret;
+}
+
+/**
+ * dwc2_check_max_xfer_size() - Checks that the max transfer size allowed in a
+ * host channel is large enough to handle the maximum data transfer in a single
+ * (micro)frame for a periodic transfer
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh:    QH for a periodic endpoint
+ *
+ * Return: 0 if successful, negative error code otherwise
+ */
+static int dwc2_check_max_xfer_size(struct dwc2_hsotg *hsotg,
+                                   struct dwc2_qh *qh)
+{
+       u32 max_xfer_size;
+       u32 max_channel_xfer_size;
+       int status = 0;
+
+       max_xfer_size = dwc2_max_packet(qh->maxp) * dwc2_hb_mult(qh->maxp);
+       max_channel_xfer_size = hsotg->core_params->max_transfer_size;
+
+       if (max_xfer_size > max_channel_xfer_size) {
+               dev_err(hsotg->dev,
+                       "%s: Periodic xfer length %d > max xfer length for channel %d\n",
+                       __func__, max_xfer_size, max_channel_xfer_size);
+               status = -ENOSPC;
+       }
+
+       return status;
+}
+
+/**
+ * dwc2_schedule_periodic() - Schedules an interrupt or isochronous transfer in
+ * the periodic schedule
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh:    QH for the periodic transfer. The QH should already contain the
+ *         scheduling information.
+ *
+ * Return: 0 if successful, negative error code otherwise
+ */
+static int dwc2_schedule_periodic(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+       int status;
+
+       if (hsotg->core_params->uframe_sched > 0) {
+               int frame = -1;
+
+               status = dwc2_find_uframe(hsotg, qh);
+               if (status == 0)
+                       frame = 7;
+               else if (status > 0)
+                       frame = status - 1;
+
+               /* Set the new frame up */
+               if (frame >= 0) {
+                       qh->sched_frame &= ~0x7;
+                       qh->sched_frame |= (frame & 7);
+               }
+
+               if (status > 0)
+                       status = 0;
+       } else {
+               status = dwc2_periodic_channel_available(hsotg);
+               if (status) {
+                       dev_info(hsotg->dev,
+                                "%s: No host channel available for periodic transfer\n",
+                                __func__);
+                       return status;
+               }
+
+               status = dwc2_check_periodic_bandwidth(hsotg, qh);
+       }
+
+       if (status) {
+               dev_dbg(hsotg->dev,
+                       "%s: Insufficient periodic bandwidth for periodic transfer\n",
+                       __func__);
+               return status;
+       }
+
+       status = dwc2_check_max_xfer_size(hsotg, qh);
+       if (status) {
+               dev_dbg(hsotg->dev,
+                       "%s: Channel max transfer size too small for periodic transfer\n",
+                       __func__);
+               return status;
+       }
+
+       if (hsotg->core_params->dma_desc_enable > 0)
+               /* Don't rely on SOF and start in ready schedule */
+               list_add_tail(&qh->qh_list_entry, &hsotg->periodic_sched_ready);
+       else
+               /* Always start in inactive schedule */
+               list_add_tail(&qh->qh_list_entry,
+                             &hsotg->periodic_sched_inactive);
+
+       if (hsotg->core_params->uframe_sched <= 0)
+               /* Reserve periodic channel */
+               hsotg->periodic_channels++;
+
+       /* Update claimed usecs per (micro)frame */
+       hsotg->periodic_usecs += qh->usecs;
+
+       return status;
+}
+
+/**
+ * dwc2_deschedule_periodic() - Removes an interrupt or isochronous transfer
+ * from the periodic schedule
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh:           QH for the periodic transfer
+ */
+static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg,
+                                    struct dwc2_qh *qh)
+{
+       int i;
+
+       list_del_init(&qh->qh_list_entry);
+
+       /* Update claimed usecs per (micro)frame */
+       hsotg->periodic_usecs -= qh->usecs;
+
+       if (hsotg->core_params->uframe_sched > 0) {
+               for (i = 0; i < 8; i++) {
+                       hsotg->frame_usecs[i] += qh->frame_usecs[i];
+                       qh->frame_usecs[i] = 0;
+               }
+       } else {
+               /* Release periodic channel reservation */
+               hsotg->periodic_channels--;
+       }
+}
+
+/**
+ * dwc2_hcd_qh_add() - Adds a QH to either the non periodic or periodic
+ * schedule if it is not already in the schedule. If the QH is already in
+ * the schedule, no action is taken.
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh:    The QH to add
+ *
+ * Return: 0 if successful, negative error code otherwise
+ */
+int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+       int status;
+       u32 intr_mask;
+
+       if (dbg_qh(qh))
+               dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+       if (!list_empty(&qh->qh_list_entry))
+               /* QH already in a schedule */
+               return 0;
+
+       /* Add the new QH to the appropriate schedule */
+       if (dwc2_qh_is_non_per(qh)) {
+               /* Always start in inactive schedule */
+               list_add_tail(&qh->qh_list_entry,
+                             &hsotg->non_periodic_sched_inactive);
+               return 0;
+       }
+
+       status = dwc2_schedule_periodic(hsotg, qh);
+       if (status)
+               return status;
+       if (!hsotg->periodic_qh_count) {
+               intr_mask = readl(hsotg->regs + GINTMSK);
+               intr_mask |= GINTSTS_SOF;
+               writel(intr_mask, hsotg->regs + GINTMSK);
+       }
+       hsotg->periodic_qh_count++;
+
+       return 0;
+}
+
+/**
+ * dwc2_hcd_qh_unlink() - Removes a QH from either the non-periodic or periodic
+ * schedule. Memory is not freed.
+ *
+ * @hsotg: The HCD state structure
+ * @qh:    QH to remove from schedule
+ */
+void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+       u32 intr_mask;
+
+       dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+       if (list_empty(&qh->qh_list_entry))
+               /* QH is not in a schedule */
+               return;
+
+       if (dwc2_qh_is_non_per(qh)) {
+               if (hsotg->non_periodic_qh_ptr == &qh->qh_list_entry)
+                       hsotg->non_periodic_qh_ptr =
+                                       hsotg->non_periodic_qh_ptr->next;
+               list_del_init(&qh->qh_list_entry);
+               return;
+       }
+
+       dwc2_deschedule_periodic(hsotg, qh);
+       hsotg->periodic_qh_count--;
+       if (!hsotg->periodic_qh_count) {
+               intr_mask = readl(hsotg->regs + GINTMSK);
+               intr_mask &= ~GINTSTS_SOF;
+               writel(intr_mask, hsotg->regs + GINTMSK);
+       }
+}
+
+/*
+ * Schedule the next continuing periodic split transfer
+ */
+static void dwc2_sched_periodic_split(struct dwc2_hsotg *hsotg,
+                                     struct dwc2_qh *qh, u16 frame_number,
+                                     int sched_next_periodic_split)
+{
+       u16 incr;
+
+       if (sched_next_periodic_split) {
+               qh->sched_frame = frame_number;
+               incr = dwc2_frame_num_inc(qh->start_split_frame, 1);
+               if (dwc2_frame_num_le(frame_number, incr)) {
+                       /*
+                        * Allow one frame to elapse after start split
+                        * microframe before scheduling complete split, but
+                        * DON'T if we are doing the next start split in the
+                        * same frame for an ISOC out
+                        */
+                       if (qh->ep_type != USB_ENDPOINT_XFER_ISOC ||
+                           qh->ep_is_in != 0) {
+                               qh->sched_frame =
+                                       dwc2_frame_num_inc(qh->sched_frame, 1);
+                       }
+               }
+       } else {
+               qh->sched_frame = dwc2_frame_num_inc(qh->start_split_frame,
+                                                    qh->interval);
+               if (dwc2_frame_num_le(qh->sched_frame, frame_number))
+                       qh->sched_frame = frame_number;
+               qh->sched_frame |= 0x7;
+               qh->start_split_frame = qh->sched_frame;
+       }
+}
+
+/*
+ * Deactivates a QH. For non-periodic QHs, removes the QH from the active
+ * non-periodic schedule. The QH is added to the inactive non-periodic
+ * schedule if any QTDs are still attached to the QH.
+ *
+ * For periodic QHs, the QH is removed from the periodic queued schedule. If
+ * there are any QTDs still attached to the QH, the QH is added to either the
+ * periodic inactive schedule or the periodic ready schedule and its next
+ * scheduled frame is calculated. The QH is placed in the ready schedule if
+ * the scheduled frame has been reached already. Otherwise it's placed in the
+ * inactive schedule. If there are no QTDs attached to the QH, the QH is
+ * completely removed from the periodic schedule.
+ */
+void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+                           int sched_next_periodic_split)
+{
+       u16 frame_number;
+
+       if (dbg_qh(qh))
+               dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+       if (dwc2_qh_is_non_per(qh)) {
+               dwc2_hcd_qh_unlink(hsotg, qh);
+               if (!list_empty(&qh->qtd_list))
+                       /* Add back to inactive non-periodic schedule */
+                       dwc2_hcd_qh_add(hsotg, qh);
+               return;
+       }
+
+       frame_number = dwc2_hcd_get_frame_number(hsotg);
+
+       if (qh->do_split) {
+               dwc2_sched_periodic_split(hsotg, qh, frame_number,
+                                         sched_next_periodic_split);
+       } else {
+               qh->sched_frame = dwc2_frame_num_inc(qh->sched_frame,
+                                                    qh->interval);
+               if (dwc2_frame_num_le(qh->sched_frame, frame_number))
+                       qh->sched_frame = frame_number;
+       }
+
+       if (list_empty(&qh->qtd_list)) {
+               dwc2_hcd_qh_unlink(hsotg, qh);
+               return;
+       }
+       /*
+        * Remove from periodic_sched_queued and move to
+        * appropriate queue
+        */
+       if ((hsotg->core_params->uframe_sched > 0 &&
+            dwc2_frame_num_le(qh->sched_frame, frame_number)) ||
+           (hsotg->core_params->uframe_sched <= 0 &&
+            qh->sched_frame == frame_number))
+               list_move(&qh->qh_list_entry, &hsotg->periodic_sched_ready);
+       else
+               list_move(&qh->qh_list_entry, &hsotg->periodic_sched_inactive);
+}
+
+/**
+ * dwc2_hcd_qtd_init() - Initializes a QTD structure
+ *
+ * @qtd: The QTD to initialize
+ * @urb: The associated URB
+ */
+void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb)
+{
+       qtd->urb = urb;
+       if (dwc2_hcd_get_pipe_type(&urb->pipe_info) ==
+                       USB_ENDPOINT_XFER_CONTROL) {
+               /*
+                * The only time the QTD data toggle is used is on the data
+                * phase of control transfers. This phase always starts with
+                * DATA1.
+                */
+               qtd->data_toggle = DWC2_HC_PID_DATA1;
+               qtd->control_phase = DWC2_CONTROL_SETUP;
+       }
+
+       /* Start split */
+       qtd->complete_split = 0;
+       qtd->isoc_split_pos = DWC2_HCSPLT_XACTPOS_ALL;
+       qtd->isoc_split_offset = 0;
+       qtd->in_process = 0;
+
+       /* Store the qtd ptr in the urb to reference the QTD */
+       urb->qtd = qtd;
+}
+
+/**
+ * dwc2_hcd_qtd_add() - Adds a QTD to the QTD-list of a QH
+ *
+ * @hsotg:        The DWC HCD structure
+ * @qtd:          The QTD to add
+ * @qh:           Out parameter to return queue head
+ * @atomic_alloc: Flag to do atomic alloc if needed
+ *
+ * Return: 0 if successful, negative error code otherwise
+ *
+ * Finds the correct QH to place the QTD into. If it does not find a QH, it
+ * will create a new QH. If the QH to which the QTD is added is not currently
+ * scheduled, it is placed into the proper schedule based on its EP type.
+ */
+int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
+                    struct dwc2_qh **qh, gfp_t mem_flags)
+{
+       struct dwc2_hcd_urb *urb = qtd->urb;
+       unsigned long flags;
+       int allocated = 0;
+       int retval;
+
+       /*
+        * Get the QH which holds the QTD-list to insert to. Create QH if it
+        * doesn't exist.
+        */
+       if (*qh == NULL) {
+               *qh = dwc2_hcd_qh_create(hsotg, urb, mem_flags);
+               if (*qh == NULL)
+                       return -ENOMEM;
+               allocated = 1;
+       }
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+
+       retval = dwc2_hcd_qh_add(hsotg, *qh);
+       if (retval)
+               goto fail;
+
+       qtd->qh = *qh;
+       list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list);
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+
+       return 0;
+
+fail:
+       if (allocated) {
+               struct dwc2_qtd *qtd2, *qtd2_tmp;
+               struct dwc2_qh *qh_tmp = *qh;
+
+               *qh = NULL;
+               dwc2_hcd_qh_unlink(hsotg, qh_tmp);
+
+               /* Free each QTD in the QH's QTD list */
+               list_for_each_entry_safe(qtd2, qtd2_tmp, &qh_tmp->qtd_list,
+                                        qtd_list_entry)
+                       dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh_tmp);
+
+               spin_unlock_irqrestore(&hsotg->lock, flags);
+               dwc2_hcd_qh_free(hsotg, qh_tmp);
+       } else {
+               spin_unlock_irqrestore(&hsotg->lock, flags);
+       }
+
+       return retval;
+}
diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h
new file mode 100644 (file)
index 0000000..9c92a3c
--- /dev/null
@@ -0,0 +1,809 @@
+/*
+ * hw.h - DesignWare HS OTG Controller hardware definitions
+ *
+ * Copyright 2004-2013 Synopsys, Inc.
+ *
+ * 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") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * 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 __DWC2_HW_H__
+#define __DWC2_HW_H__
+
+#define HSOTG_REG(x)   (x)
+
+#define GOTGCTL                                HSOTG_REG(0x000)
+#define GOTGCTL_CHIRPEN                        (1 << 27)
+#define GOTGCTL_MULT_VALID_BC_MASK     (0x1f << 22)
+#define GOTGCTL_MULT_VALID_BC_SHIFT    22
+#define GOTGCTL_OTGVER                 (1 << 20)
+#define GOTGCTL_BSESVLD                        (1 << 19)
+#define GOTGCTL_ASESVLD                        (1 << 18)
+#define GOTGCTL_DBNC_SHORT             (1 << 17)
+#define GOTGCTL_CONID_B                        (1 << 16)
+#define GOTGCTL_DEVHNPEN               (1 << 11)
+#define GOTGCTL_HSTSETHNPEN            (1 << 10)
+#define GOTGCTL_HNPREQ                 (1 << 9)
+#define GOTGCTL_HSTNEGSCS              (1 << 8)
+#define GOTGCTL_SESREQ                 (1 << 1)
+#define GOTGCTL_SESREQSCS              (1 << 0)
+
+#define GOTGINT                                HSOTG_REG(0x004)
+#define GOTGINT_DBNCE_DONE             (1 << 19)
+#define GOTGINT_A_DEV_TOUT_CHG         (1 << 18)
+#define GOTGINT_HST_NEG_DET            (1 << 17)
+#define GOTGINT_HST_NEG_SUC_STS_CHNG   (1 << 9)
+#define GOTGINT_SES_REQ_SUC_STS_CHNG   (1 << 8)
+#define GOTGINT_SES_END_DET            (1 << 2)
+
+#define GAHBCFG                                HSOTG_REG(0x008)
+#define GAHBCFG_AHB_SINGLE             (1 << 23)
+#define GAHBCFG_NOTI_ALL_DMA_WRIT      (1 << 22)
+#define GAHBCFG_REM_MEM_SUPP           (1 << 21)
+#define GAHBCFG_P_TXF_EMP_LVL          (1 << 8)
+#define GAHBCFG_NP_TXF_EMP_LVL         (1 << 7)
+#define GAHBCFG_DMA_EN                 (1 << 5)
+#define GAHBCFG_HBSTLEN_MASK           (0xf << 1)
+#define GAHBCFG_HBSTLEN_SHIFT          1
+#define GAHBCFG_HBSTLEN_SINGLE         0
+#define GAHBCFG_HBSTLEN_INCR           1
+#define GAHBCFG_HBSTLEN_INCR4          3
+#define GAHBCFG_HBSTLEN_INCR8          5
+#define GAHBCFG_HBSTLEN_INCR16         7
+#define GAHBCFG_GLBL_INTR_EN           (1 << 0)
+#define GAHBCFG_CTRL_MASK              (GAHBCFG_P_TXF_EMP_LVL | \
+                                        GAHBCFG_NP_TXF_EMP_LVL | \
+                                        GAHBCFG_DMA_EN | \
+                                        GAHBCFG_GLBL_INTR_EN)
+
+#define GUSBCFG                                HSOTG_REG(0x00C)
+#define GUSBCFG_FORCEDEVMODE           (1 << 30)
+#define GUSBCFG_FORCEHOSTMODE          (1 << 29)
+#define GUSBCFG_TXENDDELAY             (1 << 28)
+#define GUSBCFG_ICTRAFFICPULLREMOVE    (1 << 27)
+#define GUSBCFG_ICUSBCAP               (1 << 26)
+#define GUSBCFG_ULPI_INT_PROT_DIS      (1 << 25)
+#define GUSBCFG_INDICATORPASSTHROUGH   (1 << 24)
+#define GUSBCFG_INDICATORCOMPLEMENT    (1 << 23)
+#define GUSBCFG_TERMSELDLPULSE         (1 << 22)
+#define GUSBCFG_ULPI_INT_VBUS_IND      (1 << 21)
+#define GUSBCFG_ULPI_EXT_VBUS_DRV      (1 << 20)
+#define GUSBCFG_ULPI_CLK_SUSP_M                (1 << 19)
+#define GUSBCFG_ULPI_AUTO_RES          (1 << 18)
+#define GUSBCFG_ULPI_FS_LS             (1 << 17)
+#define GUSBCFG_OTG_UTMI_FS_SEL                (1 << 16)
+#define GUSBCFG_PHY_LP_CLK_SEL         (1 << 15)
+#define GUSBCFG_USBTRDTIM_MASK         (0xf << 10)
+#define GUSBCFG_USBTRDTIM_SHIFT                10
+#define GUSBCFG_HNPCAP                 (1 << 9)
+#define GUSBCFG_SRPCAP                 (1 << 8)
+#define GUSBCFG_DDRSEL                 (1 << 7)
+#define GUSBCFG_PHYSEL                 (1 << 6)
+#define GUSBCFG_FSINTF                 (1 << 5)
+#define GUSBCFG_ULPI_UTMI_SEL          (1 << 4)
+#define GUSBCFG_PHYIF16                        (1 << 3)
+#define GUSBCFG_TOUTCAL_MASK           (0x7 << 0)
+#define GUSBCFG_TOUTCAL_SHIFT          0
+#define GUSBCFG_TOUTCAL_LIMIT          0x7
+#define GUSBCFG_TOUTCAL(_x)            ((_x) << 0)
+
+#define GRSTCTL                                HSOTG_REG(0x010)
+#define GRSTCTL_AHBIDLE                        (1 << 31)
+#define GRSTCTL_DMAREQ                 (1 << 30)
+#define GRSTCTL_TXFNUM_MASK            (0x1f << 6)
+#define GRSTCTL_TXFNUM_SHIFT           6
+#define GRSTCTL_TXFNUM_LIMIT           0x1f
+#define GRSTCTL_TXFNUM(_x)             ((_x) << 6)
+#define GRSTCTL_TXFFLSH                        (1 << 5)
+#define GRSTCTL_RXFFLSH                        (1 << 4)
+#define GRSTCTL_IN_TKNQ_FLSH           (1 << 3)
+#define GRSTCTL_FRMCNTRRST             (1 << 2)
+#define GRSTCTL_HSFTRST                        (1 << 1)
+#define GRSTCTL_CSFTRST                        (1 << 0)
+
+#define GINTSTS                                HSOTG_REG(0x014)
+#define GINTMSK                                HSOTG_REG(0x018)
+#define GINTSTS_WKUPINT                        (1 << 31)
+#define GINTSTS_SESSREQINT             (1 << 30)
+#define GINTSTS_DISCONNINT             (1 << 29)
+#define GINTSTS_CONIDSTSCHNG           (1 << 28)
+#define GINTSTS_LPMTRANRCVD            (1 << 27)
+#define GINTSTS_PTXFEMP                        (1 << 26)
+#define GINTSTS_HCHINT                 (1 << 25)
+#define GINTSTS_PRTINT                 (1 << 24)
+#define GINTSTS_RESETDET               (1 << 23)
+#define GINTSTS_FET_SUSP               (1 << 22)
+#define GINTSTS_INCOMPL_IP             (1 << 21)
+#define GINTSTS_INCOMPL_SOIN           (1 << 20)
+#define GINTSTS_OEPINT                 (1 << 19)
+#define GINTSTS_IEPINT                 (1 << 18)
+#define GINTSTS_EPMIS                  (1 << 17)
+#define GINTSTS_RESTOREDONE            (1 << 16)
+#define GINTSTS_EOPF                   (1 << 15)
+#define GINTSTS_ISOUTDROP              (1 << 14)
+#define GINTSTS_ENUMDONE               (1 << 13)
+#define GINTSTS_USBRST                 (1 << 12)
+#define GINTSTS_USBSUSP                        (1 << 11)
+#define GINTSTS_ERLYSUSP               (1 << 10)
+#define GINTSTS_I2CINT                 (1 << 9)
+#define GINTSTS_ULPI_CK_INT            (1 << 8)
+#define GINTSTS_GOUTNAKEFF             (1 << 7)
+#define GINTSTS_GINNAKEFF              (1 << 6)
+#define GINTSTS_NPTXFEMP               (1 << 5)
+#define GINTSTS_RXFLVL                 (1 << 4)
+#define GINTSTS_SOF                    (1 << 3)
+#define GINTSTS_OTGINT                 (1 << 2)
+#define GINTSTS_MODEMIS                        (1 << 1)
+#define GINTSTS_CURMODE_HOST           (1 << 0)
+
+#define GRXSTSR                                HSOTG_REG(0x01C)
+#define GRXSTSP                                HSOTG_REG(0x020)
+#define GRXSTS_FN_MASK                 (0x7f << 25)
+#define GRXSTS_FN_SHIFT                        25
+#define GRXSTS_PKTSTS_MASK             (0xf << 17)
+#define GRXSTS_PKTSTS_SHIFT            17
+#define GRXSTS_PKTSTS_GLOBALOUTNAK     1
+#define GRXSTS_PKTSTS_OUTRX            2
+#define GRXSTS_PKTSTS_HCHIN            2
+#define GRXSTS_PKTSTS_OUTDONE          3
+#define GRXSTS_PKTSTS_HCHIN_XFER_COMP  3
+#define GRXSTS_PKTSTS_SETUPDONE                4
+#define GRXSTS_PKTSTS_DATATOGGLEERR    5
+#define GRXSTS_PKTSTS_SETUPRX          6
+#define GRXSTS_PKTSTS_HCHHALTED                7
+#define GRXSTS_HCHNUM_MASK             (0xf << 0)
+#define GRXSTS_HCHNUM_SHIFT            0
+#define GRXSTS_DPID_MASK               (0x3 << 15)
+#define GRXSTS_DPID_SHIFT              15
+#define GRXSTS_BYTECNT_MASK            (0x7ff << 4)
+#define GRXSTS_BYTECNT_SHIFT           4
+#define GRXSTS_EPNUM_MASK              (0xf << 0)
+#define GRXSTS_EPNUM_SHIFT             0
+
+#define GRXFSIZ                                HSOTG_REG(0x024)
+#define GRXFSIZ_DEPTH_MASK             (0xffff << 0)
+#define GRXFSIZ_DEPTH_SHIFT            0
+
+#define GNPTXFSIZ                      HSOTG_REG(0x028)
+/* Use FIFOSIZE_* constants to access this register */
+
+#define GNPTXSTS                       HSOTG_REG(0x02C)
+#define GNPTXSTS_NP_TXQ_TOP_MASK               (0x7f << 24)
+#define GNPTXSTS_NP_TXQ_TOP_SHIFT              24
+#define GNPTXSTS_NP_TXQ_SPC_AVAIL_MASK         (0xff << 16)
+#define GNPTXSTS_NP_TXQ_SPC_AVAIL_SHIFT                16
+#define GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(_v)      (((_v) >> 16) & 0xff)
+#define GNPTXSTS_NP_TXF_SPC_AVAIL_MASK         (0xffff << 0)
+#define GNPTXSTS_NP_TXF_SPC_AVAIL_SHIFT                0
+#define GNPTXSTS_NP_TXF_SPC_AVAIL_GET(_v)      (((_v) >> 0) & 0xffff)
+
+#define GI2CCTL                                HSOTG_REG(0x0030)
+#define GI2CCTL_BSYDNE                 (1 << 31)
+#define GI2CCTL_RW                     (1 << 30)
+#define GI2CCTL_I2CDATSE0              (1 << 28)
+#define GI2CCTL_I2CDEVADDR_MASK                (0x3 << 26)
+#define GI2CCTL_I2CDEVADDR_SHIFT       26
+#define GI2CCTL_I2CSUSPCTL             (1 << 25)
+#define GI2CCTL_ACK                    (1 << 24)
+#define GI2CCTL_I2CEN                  (1 << 23)
+#define GI2CCTL_ADDR_MASK              (0x7f << 16)
+#define GI2CCTL_ADDR_SHIFT             16
+#define GI2CCTL_REGADDR_MASK           (0xff << 8)
+#define GI2CCTL_REGADDR_SHIFT          8
+#define GI2CCTL_RWDATA_MASK            (0xff << 0)
+#define GI2CCTL_RWDATA_SHIFT           0
+
+#define GPVNDCTL                       HSOTG_REG(0x0034)
+#define GGPIO                          HSOTG_REG(0x0038)
+#define GUID                           HSOTG_REG(0x003c)
+#define GSNPSID                                HSOTG_REG(0x0040)
+#define GHWCFG1                                HSOTG_REG(0x0044)
+
+#define GHWCFG2                                HSOTG_REG(0x0048)
+#define GHWCFG2_OTG_ENABLE_IC_USB              (1 << 31)
+#define GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK         (0x1f << 26)
+#define GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT                26
+#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK     (0x3 << 24)
+#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT    24
+#define GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK       (0x3 << 22)
+#define GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT      22
+#define GHWCFG2_MULTI_PROC_INT                 (1 << 20)
+#define GHWCFG2_DYNAMIC_FIFO                   (1 << 19)
+#define GHWCFG2_PERIO_EP_SUPPORTED             (1 << 18)
+#define GHWCFG2_NUM_HOST_CHAN_MASK             (0xf << 14)
+#define GHWCFG2_NUM_HOST_CHAN_SHIFT            14
+#define GHWCFG2_NUM_DEV_EP_MASK                        (0xf << 10)
+#define GHWCFG2_NUM_DEV_EP_SHIFT               10
+#define GHWCFG2_FS_PHY_TYPE_MASK               (0x3 << 8)
+#define GHWCFG2_FS_PHY_TYPE_SHIFT              8
+#define GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED      0
+#define GHWCFG2_FS_PHY_TYPE_DEDICATED          1
+#define GHWCFG2_FS_PHY_TYPE_SHARED_UTMI                2
+#define GHWCFG2_FS_PHY_TYPE_SHARED_ULPI                3
+#define GHWCFG2_HS_PHY_TYPE_MASK               (0x3 << 6)
+#define GHWCFG2_HS_PHY_TYPE_SHIFT              6
+#define GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED      0
+#define GHWCFG2_HS_PHY_TYPE_UTMI               1
+#define GHWCFG2_HS_PHY_TYPE_ULPI               2
+#define GHWCFG2_HS_PHY_TYPE_UTMI_ULPI          3
+#define GHWCFG2_POINT2POINT                    (1 << 5)
+#define GHWCFG2_ARCHITECTURE_MASK              (0x3 << 3)
+#define GHWCFG2_ARCHITECTURE_SHIFT             3
+#define GHWCFG2_SLAVE_ONLY_ARCH                        0
+#define GHWCFG2_EXT_DMA_ARCH                   1
+#define GHWCFG2_INT_DMA_ARCH                   2
+#define GHWCFG2_OP_MODE_MASK                   (0x7 << 0)
+#define GHWCFG2_OP_MODE_SHIFT                  0
+#define GHWCFG2_OP_MODE_HNP_SRP_CAPABLE                0
+#define GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE       1
+#define GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE     2
+#define GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE     3
+#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE  4
+#define GHWCFG2_OP_MODE_SRP_CAPABLE_HOST       5
+#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST    6
+#define GHWCFG2_OP_MODE_UNDEFINED              7
+
+#define GHWCFG3                                HSOTG_REG(0x004c)
+#define GHWCFG3_DFIFO_DEPTH_MASK               (0xffff << 16)
+#define GHWCFG3_DFIFO_DEPTH_SHIFT              16
+#define GHWCFG3_OTG_LPM_EN                     (1 << 15)
+#define GHWCFG3_BC_SUPPORT                     (1 << 14)
+#define GHWCFG3_OTG_ENABLE_HSIC                        (1 << 13)
+#define GHWCFG3_ADP_SUPP                       (1 << 12)
+#define GHWCFG3_SYNCH_RESET_TYPE               (1 << 11)
+#define GHWCFG3_OPTIONAL_FEATURES              (1 << 10)
+#define GHWCFG3_VENDOR_CTRL_IF                 (1 << 9)
+#define GHWCFG3_I2C                            (1 << 8)
+#define GHWCFG3_OTG_FUNC                       (1 << 7)
+#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK    (0x7 << 4)
+#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT   4
+#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK      (0xf << 0)
+#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT     0
+
+#define GHWCFG4                                HSOTG_REG(0x0050)
+#define GHWCFG4_DESC_DMA_DYN                   (1 << 31)
+#define GHWCFG4_DESC_DMA                       (1 << 30)
+#define GHWCFG4_NUM_IN_EPS_MASK                        (0xf << 26)
+#define GHWCFG4_NUM_IN_EPS_SHIFT               26
+#define GHWCFG4_DED_FIFO_EN                    (1 << 25)
+#define GHWCFG4_SESSION_END_FILT_EN            (1 << 24)
+#define GHWCFG4_B_VALID_FILT_EN                        (1 << 23)
+#define GHWCFG4_A_VALID_FILT_EN                        (1 << 22)
+#define GHWCFG4_VBUS_VALID_FILT_EN             (1 << 21)
+#define GHWCFG4_IDDIG_FILT_EN                  (1 << 20)
+#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_MASK      (0xf << 16)
+#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT     16
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK       (0x3 << 14)
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT      14
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8          0
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16         1
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16    2
+#define GHWCFG4_XHIBER                         (1 << 7)
+#define GHWCFG4_HIBER                          (1 << 6)
+#define GHWCFG4_MIN_AHB_FREQ                   (1 << 5)
+#define GHWCFG4_POWER_OPTIMIZ                  (1 << 4)
+#define GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK       (0xf << 0)
+#define GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT      0
+
+#define GLPMCFG                                HSOTG_REG(0x0054)
+#define GLPMCFG_INV_SEL_HSIC           (1 << 31)
+#define GLPMCFG_HSIC_CONNECT           (1 << 30)
+#define GLPMCFG_RETRY_COUNT_STS_MASK   (0x7 << 25)
+#define GLPMCFG_RETRY_COUNT_STS_SHIFT  25
+#define GLPMCFG_SEND_LPM               (1 << 24)
+#define GLPMCFG_RETRY_COUNT_MASK       (0x7 << 21)
+#define GLPMCFG_RETRY_COUNT_SHIFT      21
+#define GLPMCFG_LPM_CHAN_INDEX_MASK    (0xf << 17)
+#define GLPMCFG_LPM_CHAN_INDEX_SHIFT   17
+#define GLPMCFG_SLEEP_STATE_RESUMEOK   (1 << 16)
+#define GLPMCFG_PRT_SLEEP_STS          (1 << 15)
+#define GLPMCFG_LPM_RESP_MASK          (0x3 << 13)
+#define GLPMCFG_LPM_RESP_SHIFT         13
+#define GLPMCFG_HIRD_THRES_MASK                (0x1f << 8)
+#define GLPMCFG_HIRD_THRES_SHIFT       8
+#define GLPMCFG_HIRD_THRES_EN                  (0x10 << 8)
+#define GLPMCFG_EN_UTMI_SLEEP          (1 << 7)
+#define GLPMCFG_REM_WKUP_EN            (1 << 6)
+#define GLPMCFG_HIRD_MASK              (0xf << 2)
+#define GLPMCFG_HIRD_SHIFT             2
+#define GLPMCFG_APPL_RESP              (1 << 1)
+#define GLPMCFG_LPM_CAP_EN             (1 << 0)
+
+#define GPWRDN                         HSOTG_REG(0x0058)
+#define GPWRDN_MULT_VAL_ID_BC_MASK     (0x1f << 24)
+#define GPWRDN_MULT_VAL_ID_BC_SHIFT    24
+#define GPWRDN_ADP_INT                 (1 << 23)
+#define GPWRDN_BSESSVLD                        (1 << 22)
+#define GPWRDN_IDSTS                   (1 << 21)
+#define GPWRDN_LINESTATE_MASK          (0x3 << 19)
+#define GPWRDN_LINESTATE_SHIFT         19
+#define GPWRDN_STS_CHGINT_MSK          (1 << 18)
+#define GPWRDN_STS_CHGINT              (1 << 17)
+#define GPWRDN_SRP_DET_MSK             (1 << 16)
+#define GPWRDN_SRP_DET                 (1 << 15)
+#define GPWRDN_CONNECT_DET_MSK         (1 << 14)
+#define GPWRDN_CONNECT_DET             (1 << 13)
+#define GPWRDN_DISCONN_DET_MSK         (1 << 12)
+#define GPWRDN_DISCONN_DET             (1 << 11)
+#define GPWRDN_RST_DET_MSK             (1 << 10)
+#define GPWRDN_RST_DET                 (1 << 9)
+#define GPWRDN_LNSTSCHG_MSK            (1 << 8)
+#define GPWRDN_LNSTSCHG                        (1 << 7)
+#define GPWRDN_DIS_VBUS                        (1 << 6)
+#define GPWRDN_PWRDNSWTCH              (1 << 5)
+#define GPWRDN_PWRDNRSTN               (1 << 4)
+#define GPWRDN_PWRDNCLMP               (1 << 3)
+#define GPWRDN_RESTORE                 (1 << 2)
+#define GPWRDN_PMUACTV                 (1 << 1)
+#define GPWRDN_PMUINTSEL               (1 << 0)
+
+#define GDFIFOCFG                      HSOTG_REG(0x005c)
+#define GDFIFOCFG_EPINFOBASE_MASK      (0xffff << 16)
+#define GDFIFOCFG_EPINFOBASE_SHIFT     16
+#define GDFIFOCFG_GDFIFOCFG_MASK       (0xffff << 0)
+#define GDFIFOCFG_GDFIFOCFG_SHIFT      0
+
+#define ADPCTL                         HSOTG_REG(0x0060)
+#define ADPCTL_AR_MASK                 (0x3 << 27)
+#define ADPCTL_AR_SHIFT                        27
+#define ADPCTL_ADP_TMOUT_INT_MSK       (1 << 26)
+#define ADPCTL_ADP_SNS_INT_MSK         (1 << 25)
+#define ADPCTL_ADP_PRB_INT_MSK         (1 << 24)
+#define ADPCTL_ADP_TMOUT_INT           (1 << 23)
+#define ADPCTL_ADP_SNS_INT             (1 << 22)
+#define ADPCTL_ADP_PRB_INT             (1 << 21)
+#define ADPCTL_ADPENA                  (1 << 20)
+#define ADPCTL_ADPRES                  (1 << 19)
+#define ADPCTL_ENASNS                  (1 << 18)
+#define ADPCTL_ENAPRB                  (1 << 17)
+#define ADPCTL_RTIM_MASK               (0x7ff << 6)
+#define ADPCTL_RTIM_SHIFT              6
+#define ADPCTL_PRB_PER_MASK            (0x3 << 4)
+#define ADPCTL_PRB_PER_SHIFT           4
+#define ADPCTL_PRB_DELTA_MASK          (0x3 << 2)
+#define ADPCTL_PRB_DELTA_SHIFT         2
+#define ADPCTL_PRB_DSCHRG_MASK         (0x3 << 0)
+#define ADPCTL_PRB_DSCHRG_SHIFT                0
+
+#define HPTXFSIZ                       HSOTG_REG(0x100)
+/* Use FIFOSIZE_* constants to access this register */
+
+#define DPTXFSIZN(_a)                  HSOTG_REG(0x104 + (((_a) - 1) * 4))
+/* Use FIFOSIZE_* constants to access this register */
+
+/* These apply to the GNPTXFSIZ, HPTXFSIZ and DPTXFSIZN registers */
+#define FIFOSIZE_DEPTH_MASK            (0xffff << 16)
+#define FIFOSIZE_DEPTH_SHIFT           16
+#define FIFOSIZE_STARTADDR_MASK                (0xffff << 0)
+#define FIFOSIZE_STARTADDR_SHIFT       0
+
+/* Device mode registers */
+
+#define DCFG                           HSOTG_REG(0x800)
+#define DCFG_EPMISCNT_MASK             (0x1f << 18)
+#define DCFG_EPMISCNT_SHIFT            18
+#define DCFG_EPMISCNT_LIMIT            0x1f
+#define DCFG_EPMISCNT(_x)              ((_x) << 18)
+#define DCFG_PERFRINT_MASK             (0x3 << 11)
+#define DCFG_PERFRINT_SHIFT            11
+#define DCFG_PERFRINT_LIMIT            0x3
+#define DCFG_PERFRINT(_x)              ((_x) << 11)
+#define DCFG_DEVADDR_MASK              (0x7f << 4)
+#define DCFG_DEVADDR_SHIFT             4
+#define DCFG_DEVADDR_LIMIT             0x7f
+#define DCFG_DEVADDR(_x)               ((_x) << 4)
+#define DCFG_NZ_STS_OUT_HSHK           (1 << 2)
+#define DCFG_DEVSPD_MASK               (0x3 << 0)
+#define DCFG_DEVSPD_SHIFT              0
+#define DCFG_DEVSPD_HS                 0
+#define DCFG_DEVSPD_FS                 1
+#define DCFG_DEVSPD_LS                 2
+#define DCFG_DEVSPD_FS48               3
+
+#define DCTL                           HSOTG_REG(0x804)
+#define DCTL_PWRONPRGDONE              (1 << 11)
+#define DCTL_CGOUTNAK                  (1 << 10)
+#define DCTL_SGOUTNAK                  (1 << 9)
+#define DCTL_CGNPINNAK                 (1 << 8)
+#define DCTL_SGNPINNAK                 (1 << 7)
+#define DCTL_TSTCTL_MASK               (0x7 << 4)
+#define DCTL_TSTCTL_SHIFT              4
+#define DCTL_GOUTNAKSTS                        (1 << 3)
+#define DCTL_GNPINNAKSTS               (1 << 2)
+#define DCTL_SFTDISCON                 (1 << 1)
+#define DCTL_RMTWKUPSIG                        (1 << 0)
+
+#define DSTS                           HSOTG_REG(0x808)
+#define DSTS_SOFFN_MASK                        (0x3fff << 8)
+#define DSTS_SOFFN_SHIFT               8
+#define DSTS_SOFFN_LIMIT               0x3fff
+#define DSTS_SOFFN(_x)                 ((_x) << 8)
+#define DSTS_ERRATICERR                        (1 << 3)
+#define DSTS_ENUMSPD_MASK              (0x3 << 1)
+#define DSTS_ENUMSPD_SHIFT             1
+#define DSTS_ENUMSPD_HS                        0
+#define DSTS_ENUMSPD_FS                        1
+#define DSTS_ENUMSPD_LS                        2
+#define DSTS_ENUMSPD_FS48              3
+#define DSTS_SUSPSTS                   (1 << 0)
+
+#define DIEPMSK                                HSOTG_REG(0x810)
+#define DIEPMSK_TXFIFOEMPTY            (1 << 7)
+#define DIEPMSK_INEPNAKEFFMSK          (1 << 6)
+#define DIEPMSK_INTKNEPMISMSK          (1 << 5)
+#define DIEPMSK_INTKNTXFEMPMSK         (1 << 4)
+#define DIEPMSK_TIMEOUTMSK             (1 << 3)
+#define DIEPMSK_AHBERRMSK              (1 << 2)
+#define DIEPMSK_EPDISBLDMSK            (1 << 1)
+#define DIEPMSK_XFERCOMPLMSK           (1 << 0)
+
+#define DOEPMSK                                HSOTG_REG(0x814)
+#define DOEPMSK_BACK2BACKSETUP         (1 << 6)
+#define DOEPMSK_OUTTKNEPDISMSK         (1 << 4)
+#define DOEPMSK_SETUPMSK               (1 << 3)
+#define DOEPMSK_AHBERRMSK              (1 << 2)
+#define DOEPMSK_EPDISBLDMSK            (1 << 1)
+#define DOEPMSK_XFERCOMPLMSK           (1 << 0)
+
+#define DAINT                          HSOTG_REG(0x818)
+#define DAINTMSK                       HSOTG_REG(0x81C)
+#define DAINT_OUTEP_SHIFT              16
+#define DAINT_OUTEP(_x)                        (1 << ((_x) + 16))
+#define DAINT_INEP(_x)                 (1 << (_x))
+
+#define DTKNQR1                                HSOTG_REG(0x820)
+#define DTKNQR2                                HSOTG_REG(0x824)
+#define DTKNQR3                                HSOTG_REG(0x830)
+#define DTKNQR4                                HSOTG_REG(0x834)
+
+#define DVBUSDIS                       HSOTG_REG(0x828)
+#define DVBUSPULSE                     HSOTG_REG(0x82C)
+
+#define DIEPCTL0                       HSOTG_REG(0x900)
+#define DIEPCTL(_a)                    HSOTG_REG(0x900 + ((_a) * 0x20))
+
+#define DOEPCTL0                       HSOTG_REG(0xB00)
+#define DOEPCTL(_a)                    HSOTG_REG(0xB00 + ((_a) * 0x20))
+
+/* EP0 specialness:
+ * bits[29..28] - reserved (no SetD0PID, SetD1PID)
+ * bits[25..22] - should always be zero, this isn't a periodic endpoint
+ * bits[10..0]  - MPS setting different for EP0
+ */
+#define D0EPCTL_MPS_MASK               (0x3 << 0)
+#define D0EPCTL_MPS_SHIFT              0
+#define D0EPCTL_MPS_64                 0
+#define D0EPCTL_MPS_32                 1
+#define D0EPCTL_MPS_16                 2
+#define D0EPCTL_MPS_8                  3
+
+#define DXEPCTL_EPENA                  (1 << 31)
+#define DXEPCTL_EPDIS                  (1 << 30)
+#define DXEPCTL_SETD1PID               (1 << 29)
+#define DXEPCTL_SETODDFR               (1 << 29)
+#define DXEPCTL_SETD0PID               (1 << 28)
+#define DXEPCTL_SETEVENFR              (1 << 28)
+#define DXEPCTL_SNAK                   (1 << 27)
+#define DXEPCTL_CNAK                   (1 << 26)
+#define DXEPCTL_TXFNUM_MASK            (0xf << 22)
+#define DXEPCTL_TXFNUM_SHIFT           22
+#define DXEPCTL_TXFNUM_LIMIT           0xf
+#define DXEPCTL_TXFNUM(_x)             ((_x) << 22)
+#define DXEPCTL_STALL                  (1 << 21)
+#define DXEPCTL_SNP                    (1 << 20)
+#define DXEPCTL_EPTYPE_MASK            (0x3 << 18)
+#define DXEPCTL_EPTYPE_SHIFT           18
+#define DXEPCTL_EPTYPE_CONTROL         0
+#define DXEPCTL_EPTYPE_ISO             1
+#define DXEPCTL_EPTYPE_BULK            2
+#define DXEPCTL_EPTYPE_INTTERUPT       3
+#define DXEPCTL_NAKSTS                 (1 << 17)
+#define DXEPCTL_DPID                   (1 << 16)
+#define DXEPCTL_EOFRNUM                        (1 << 16)
+#define DXEPCTL_USBACTEP               (1 << 15)
+#define DXEPCTL_NEXTEP_MASK            (0xf << 11)
+#define DXEPCTL_NEXTEP_SHIFT           11
+#define DXEPCTL_NEXTEP_LIMIT           0xf
+#define DXEPCTL_NEXTEP(_x)             ((_x) << 11)
+#define DXEPCTL_MPS_MASK               (0x7ff << 0)
+#define DXEPCTL_MPS_SHIFT              0
+#define DXEPCTL_MPS_LIMIT              0x7ff
+#define DXEPCTL_MPS(_x)                        ((_x) << 0)
+
+#define DIEPINT(_a)                    HSOTG_REG(0x908 + ((_a) * 0x20))
+#define DOEPINT(_a)                    HSOTG_REG(0xB08 + ((_a) * 0x20))
+#define DXEPINT_INEPNAKEFF             (1 << 6)
+#define DXEPINT_BACK2BACKSETUP         (1 << 6)
+#define DXEPINT_INTKNEPMIS             (1 << 5)
+#define DXEPINT_INTKNTXFEMP            (1 << 4)
+#define DXEPINT_OUTTKNEPDIS            (1 << 4)
+#define DXEPINT_TIMEOUT                        (1 << 3)
+#define DXEPINT_SETUP                  (1 << 3)
+#define DXEPINT_AHBERR                 (1 << 2)
+#define DXEPINT_EPDISBLD               (1 << 1)
+#define DXEPINT_XFERCOMPL              (1 << 0)
+
+#define DIEPTSIZ0                      HSOTG_REG(0x910)
+#define DIEPTSIZ0_PKTCNT_MASK          (0x3 << 19)
+#define DIEPTSIZ0_PKTCNT_SHIFT         19
+#define DIEPTSIZ0_PKTCNT_LIMIT         0x3
+#define DIEPTSIZ0_PKTCNT(_x)           ((_x) << 19)
+#define DIEPTSIZ0_XFERSIZE_MASK                (0x7f << 0)
+#define DIEPTSIZ0_XFERSIZE_SHIFT       0
+#define DIEPTSIZ0_XFERSIZE_LIMIT       0x7f
+#define DIEPTSIZ0_XFERSIZE(_x)         ((_x) << 0)
+
+#define DOEPTSIZ0                      HSOTG_REG(0xB10)
+#define DOEPTSIZ0_SUPCNT_MASK          (0x3 << 29)
+#define DOEPTSIZ0_SUPCNT_SHIFT         29
+#define DOEPTSIZ0_SUPCNT_LIMIT         0x3
+#define DOEPTSIZ0_SUPCNT(_x)           ((_x) << 29)
+#define DOEPTSIZ0_PKTCNT               (1 << 19)
+#define DOEPTSIZ0_XFERSIZE_MASK                (0x7f << 0)
+#define DOEPTSIZ0_XFERSIZE_SHIFT       0
+
+#define DIEPTSIZ(_a)                   HSOTG_REG(0x910 + ((_a) * 0x20))
+#define DOEPTSIZ(_a)                   HSOTG_REG(0xB10 + ((_a) * 0x20))
+#define DXEPTSIZ_MC_MASK               (0x3 << 29)
+#define DXEPTSIZ_MC_SHIFT              29
+#define DXEPTSIZ_MC_LIMIT              0x3
+#define DXEPTSIZ_MC(_x)                        ((_x) << 29)
+#define DXEPTSIZ_PKTCNT_MASK           (0x3ff << 19)
+#define DXEPTSIZ_PKTCNT_SHIFT          19
+#define DXEPTSIZ_PKTCNT_LIMIT          0x3ff
+#define DXEPTSIZ_PKTCNT_GET(_v)                (((_v) >> 19) & 0x3ff)
+#define DXEPTSIZ_PKTCNT(_x)            ((_x) << 19)
+#define DXEPTSIZ_XFERSIZE_MASK         (0x7ffff << 0)
+#define DXEPTSIZ_XFERSIZE_SHIFT                0
+#define DXEPTSIZ_XFERSIZE_LIMIT                0x7ffff
+#define DXEPTSIZ_XFERSIZE_GET(_v)      (((_v) >> 0) & 0x7ffff)
+#define DXEPTSIZ_XFERSIZE(_x)          ((_x) << 0)
+
+#define DIEPDMA(_a)                    HSOTG_REG(0x914 + ((_a) * 0x20))
+#define DOEPDMA(_a)                    HSOTG_REG(0xB14 + ((_a) * 0x20))
+
+#define DTXFSTS(_a)                    HSOTG_REG(0x918 + ((_a) * 0x20))
+
+#define PCGCTL                         HSOTG_REG(0x0e00)
+#define PCGCTL_IF_DEV_MODE             (1 << 31)
+#define PCGCTL_P2HD_PRT_SPD_MASK       (0x3 << 29)
+#define PCGCTL_P2HD_PRT_SPD_SHIFT      29
+#define PCGCTL_P2HD_DEV_ENUM_SPD_MASK  (0x3 << 27)
+#define PCGCTL_P2HD_DEV_ENUM_SPD_SHIFT 27
+#define PCGCTL_MAC_DEV_ADDR_MASK       (0x7f << 20)
+#define PCGCTL_MAC_DEV_ADDR_SHIFT      20
+#define PCGCTL_MAX_TERMSEL             (1 << 19)
+#define PCGCTL_MAX_XCVRSELECT_MASK     (0x3 << 17)
+#define PCGCTL_MAX_XCVRSELECT_SHIFT    17
+#define PCGCTL_PORT_POWER              (1 << 16)
+#define PCGCTL_PRT_CLK_SEL_MASK                (0x3 << 14)
+#define PCGCTL_PRT_CLK_SEL_SHIFT       14
+#define PCGCTL_ESS_REG_RESTORED                (1 << 13)
+#define PCGCTL_EXTND_HIBER_SWITCH      (1 << 12)
+#define PCGCTL_EXTND_HIBER_PWRCLMP     (1 << 11)
+#define PCGCTL_ENBL_EXTND_HIBER                (1 << 10)
+#define PCGCTL_RESTOREMODE             (1 << 9)
+#define PCGCTL_RESETAFTSUSP            (1 << 8)
+#define PCGCTL_DEEP_SLEEP              (1 << 7)
+#define PCGCTL_PHY_IN_SLEEP            (1 << 6)
+#define PCGCTL_ENBL_SLEEP_GATING       (1 << 5)
+#define PCGCTL_RSTPDWNMODULE           (1 << 3)
+#define PCGCTL_PWRCLMP                 (1 << 2)
+#define PCGCTL_GATEHCLK                        (1 << 1)
+#define PCGCTL_STOPPCLK                        (1 << 0)
+
+#define EPFIFO(_a)                     HSOTG_REG(0x1000 + ((_a) * 0x1000))
+
+/* Host Mode Registers */
+
+#define HCFG                           HSOTG_REG(0x0400)
+#define HCFG_MODECHTIMEN               (1 << 31)
+#define HCFG_PERSCHEDENA               (1 << 26)
+#define HCFG_FRLISTEN_MASK             (0x3 << 24)
+#define HCFG_FRLISTEN_SHIFT            24
+#define HCFG_FRLISTEN_8                                (0 << 24)
+#define FRLISTEN_8_SIZE                                8
+#define HCFG_FRLISTEN_16                       (1 << 24)
+#define FRLISTEN_16_SIZE                       16
+#define HCFG_FRLISTEN_32                       (2 << 24)
+#define FRLISTEN_32_SIZE                       32
+#define HCFG_FRLISTEN_64                       (3 << 24)
+#define FRLISTEN_64_SIZE                       64
+#define HCFG_DESCDMA                   (1 << 23)
+#define HCFG_RESVALID_MASK             (0xff << 8)
+#define HCFG_RESVALID_SHIFT            8
+#define HCFG_ENA32KHZ                  (1 << 7)
+#define HCFG_FSLSSUPP                  (1 << 2)
+#define HCFG_FSLSPCLKSEL_MASK          (0x3 << 0)
+#define HCFG_FSLSPCLKSEL_SHIFT         0
+#define HCFG_FSLSPCLKSEL_30_60_MHZ     0
+#define HCFG_FSLSPCLKSEL_48_MHZ                1
+#define HCFG_FSLSPCLKSEL_6_MHZ         2
+
+#define HFIR                           HSOTG_REG(0x0404)
+#define HFIR_FRINT_MASK                        (0xffff << 0)
+#define HFIR_FRINT_SHIFT               0
+#define HFIR_RLDCTRL                   (1 << 16)
+
+#define HFNUM                          HSOTG_REG(0x0408)
+#define HFNUM_FRREM_MASK               (0xffff << 16)
+#define HFNUM_FRREM_SHIFT              16
+#define HFNUM_FRNUM_MASK               (0xffff << 0)
+#define HFNUM_FRNUM_SHIFT              0
+#define HFNUM_MAX_FRNUM                        0x3fff
+
+#define HPTXSTS                                HSOTG_REG(0x0410)
+#define TXSTS_QTOP_ODD                 (1 << 31)
+#define TXSTS_QTOP_CHNEP_MASK          (0xf << 27)
+#define TXSTS_QTOP_CHNEP_SHIFT         27
+#define TXSTS_QTOP_TOKEN_MASK          (0x3 << 25)
+#define TXSTS_QTOP_TOKEN_SHIFT         25
+#define TXSTS_QTOP_TERMINATE           (1 << 24)
+#define TXSTS_QSPCAVAIL_MASK           (0xff << 16)
+#define TXSTS_QSPCAVAIL_SHIFT          16
+#define TXSTS_FSPCAVAIL_MASK           (0xffff << 0)
+#define TXSTS_FSPCAVAIL_SHIFT          0
+
+#define HAINT                          HSOTG_REG(0x0414)
+#define HAINTMSK                       HSOTG_REG(0x0418)
+#define HFLBADDR                       HSOTG_REG(0x041c)
+
+#define HPRT0                          HSOTG_REG(0x0440)
+#define HPRT0_SPD_MASK                 (0x3 << 17)
+#define HPRT0_SPD_SHIFT                        17
+#define HPRT0_SPD_HIGH_SPEED           0
+#define HPRT0_SPD_FULL_SPEED           1
+#define HPRT0_SPD_LOW_SPEED            2
+#define HPRT0_TSTCTL_MASK              (0xf << 13)
+#define HPRT0_TSTCTL_SHIFT             13
+#define HPRT0_PWR                      (1 << 12)
+#define HPRT0_LNSTS_MASK               (0x3 << 10)
+#define HPRT0_LNSTS_SHIFT              10
+#define HPRT0_RST                      (1 << 8)
+#define HPRT0_SUSP                     (1 << 7)
+#define HPRT0_RES                      (1 << 6)
+#define HPRT0_OVRCURRCHG               (1 << 5)
+#define HPRT0_OVRCURRACT               (1 << 4)
+#define HPRT0_ENACHG                   (1 << 3)
+#define HPRT0_ENA                      (1 << 2)
+#define HPRT0_CONNDET                  (1 << 1)
+#define HPRT0_CONNSTS                  (1 << 0)
+
+#define HCCHAR(_ch)                    HSOTG_REG(0x0500 + 0x20 * (_ch))
+#define HCCHAR_CHENA                   (1 << 31)
+#define HCCHAR_CHDIS                   (1 << 30)
+#define HCCHAR_ODDFRM                  (1 << 29)
+#define HCCHAR_DEVADDR_MASK            (0x7f << 22)
+#define HCCHAR_DEVADDR_SHIFT           22
+#define HCCHAR_MULTICNT_MASK           (0x3 << 20)
+#define HCCHAR_MULTICNT_SHIFT          20
+#define HCCHAR_EPTYPE_MASK             (0x3 << 18)
+#define HCCHAR_EPTYPE_SHIFT            18
+#define HCCHAR_LSPDDEV                 (1 << 17)
+#define HCCHAR_EPDIR                   (1 << 15)
+#define HCCHAR_EPNUM_MASK              (0xf << 11)
+#define HCCHAR_EPNUM_SHIFT             11
+#define HCCHAR_MPS_MASK                        (0x7ff << 0)
+#define HCCHAR_MPS_SHIFT               0
+
+#define HCSPLT(_ch)                    HSOTG_REG(0x0504 + 0x20 * (_ch))
+#define HCSPLT_SPLTENA                 (1 << 31)
+#define HCSPLT_COMPSPLT                        (1 << 16)
+#define HCSPLT_XACTPOS_MASK            (0x3 << 14)
+#define HCSPLT_XACTPOS_SHIFT           14
+#define HCSPLT_XACTPOS_MID             0
+#define HCSPLT_XACTPOS_END             1
+#define HCSPLT_XACTPOS_BEGIN           2
+#define HCSPLT_XACTPOS_ALL             3
+#define HCSPLT_HUBADDR_MASK            (0x7f << 7)
+#define HCSPLT_HUBADDR_SHIFT           7
+#define HCSPLT_PRTADDR_MASK            (0x7f << 0)
+#define HCSPLT_PRTADDR_SHIFT           0
+
+#define HCINT(_ch)                     HSOTG_REG(0x0508 + 0x20 * (_ch))
+#define HCINTMSK(_ch)                  HSOTG_REG(0x050c + 0x20 * (_ch))
+#define HCINTMSK_RESERVED14_31         (0x3ffff << 14)
+#define HCINTMSK_FRM_LIST_ROLL         (1 << 13)
+#define HCINTMSK_XCS_XACT              (1 << 12)
+#define HCINTMSK_BNA                   (1 << 11)
+#define HCINTMSK_DATATGLERR            (1 << 10)
+#define HCINTMSK_FRMOVRUN              (1 << 9)
+#define HCINTMSK_BBLERR                        (1 << 8)
+#define HCINTMSK_XACTERR               (1 << 7)
+#define HCINTMSK_NYET                  (1 << 6)
+#define HCINTMSK_ACK                   (1 << 5)
+#define HCINTMSK_NAK                   (1 << 4)
+#define HCINTMSK_STALL                 (1 << 3)
+#define HCINTMSK_AHBERR                        (1 << 2)
+#define HCINTMSK_CHHLTD                        (1 << 1)
+#define HCINTMSK_XFERCOMPL             (1 << 0)
+
+#define HCTSIZ(_ch)                    HSOTG_REG(0x0510 + 0x20 * (_ch))
+#define TSIZ_DOPNG                     (1 << 31)
+#define TSIZ_SC_MC_PID_MASK            (0x3 << 29)
+#define TSIZ_SC_MC_PID_SHIFT           29
+#define TSIZ_SC_MC_PID_DATA0           0
+#define TSIZ_SC_MC_PID_DATA2           1
+#define TSIZ_SC_MC_PID_DATA1           2
+#define TSIZ_SC_MC_PID_MDATA           3
+#define TSIZ_SC_MC_PID_SETUP           3
+#define TSIZ_PKTCNT_MASK               (0x3ff << 19)
+#define TSIZ_PKTCNT_SHIFT              19
+#define TSIZ_NTD_MASK                  (0xff << 8)
+#define TSIZ_NTD_SHIFT                 8
+#define TSIZ_SCHINFO_MASK              (0xff << 0)
+#define TSIZ_SCHINFO_SHIFT             0
+#define TSIZ_XFERSIZE_MASK             (0x7ffff << 0)
+#define TSIZ_XFERSIZE_SHIFT            0
+
+#define HCDMA(_ch)                     HSOTG_REG(0x0514 + 0x20 * (_ch))
+#define HCDMA_DMA_ADDR_MASK            (0x1fffff << 11)
+#define HCDMA_DMA_ADDR_SHIFT           11
+#define HCDMA_CTD_MASK                 (0xff << 3)
+#define HCDMA_CTD_SHIFT                        3
+
+#define HCDMAB(_ch)                    HSOTG_REG(0x051c + 0x20 * (_ch))
+
+#define HCFIFO(_ch)                    HSOTG_REG(0x1000 + 0x1000 * (_ch))
+
+/**
+ * struct dwc2_hcd_dma_desc - Host-mode DMA descriptor structure
+ *
+ * @status: DMA descriptor status quadlet
+ * @buf:    DMA descriptor data buffer pointer
+ *
+ * DMA Descriptor structure contains two quadlets:
+ * Status quadlet and Data buffer pointer.
+ */
+struct dwc2_hcd_dma_desc {
+       u32 status;
+       u32 buf;
+};
+
+#define HOST_DMA_A                     (1 << 31)
+#define HOST_DMA_STS_MASK              (0x3 << 28)
+#define HOST_DMA_STS_SHIFT             28
+#define HOST_DMA_STS_PKTERR            (1 << 28)
+#define HOST_DMA_EOL                   (1 << 26)
+#define HOST_DMA_IOC                   (1 << 25)
+#define HOST_DMA_SUP                   (1 << 24)
+#define HOST_DMA_ALT_QTD               (1 << 23)
+#define HOST_DMA_QTD_OFFSET_MASK       (0x3f << 17)
+#define HOST_DMA_QTD_OFFSET_SHIFT      17
+#define HOST_DMA_ISOC_NBYTES_MASK      (0xfff << 0)
+#define HOST_DMA_ISOC_NBYTES_SHIFT     0
+#define HOST_DMA_NBYTES_MASK           (0x1ffff << 0)
+#define HOST_DMA_NBYTES_SHIFT          0
+
+#define MAX_DMA_DESC_SIZE              131071
+#define MAX_DMA_DESC_NUM_GENERIC       64
+#define MAX_DMA_DESC_NUM_HS_ISOC       256
+
+#endif /* __DWC2_HW_H__ */
diff --git a/drivers/usb/dwc2/pci.c b/drivers/usb/dwc2/pci.c
new file mode 100644 (file)
index 0000000..c291fca
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * pci.c - DesignWare HS OTG Controller PCI driver
+ *
+ * Copyright (C) 2004-2013 Synopsys, Inc.
+ *
+ * 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") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * 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.
+ */
+
+/*
+ * Provides the initialization and cleanup entry points for the DWC_otg PCI
+ * driver
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/usb.h>
+
+#include <linux/usb/hcd.h>
+#include <linux/usb/ch11.h>
+
+#include "core.h"
+#include "hcd.h"
+
+#define PCI_VENDOR_ID_SYNOPSYS         0x16c3
+#define PCI_PRODUCT_ID_HAPS_HSOTG      0xabc0
+
+static const char dwc2_driver_name[] = "dwc2";
+
+static const struct dwc2_core_params dwc2_module_params = {
+       .otg_cap                        = -1,
+       .otg_ver                        = -1,
+       .dma_enable                     = -1,
+       .dma_desc_enable                = 0,
+       .speed                          = -1,
+       .enable_dynamic_fifo            = -1,
+       .en_multiple_tx_fifo            = -1,
+       .host_rx_fifo_size              = 1024,
+       .host_nperio_tx_fifo_size       = 256,
+       .host_perio_tx_fifo_size        = 1024,
+       .max_transfer_size              = 65535,
+       .max_packet_count               = 511,
+       .host_channels                  = -1,
+       .phy_type                       = -1,
+       .phy_utmi_width                 = -1,
+       .phy_ulpi_ddr                   = -1,
+       .phy_ulpi_ext_vbus              = -1,
+       .i2c_enable                     = -1,
+       .ulpi_fs_ls                     = -1,
+       .host_support_fs_ls_low_power   = -1,
+       .host_ls_low_power_phy_clk      = -1,
+       .ts_dline                       = -1,
+       .reload_ctl                     = -1,
+       .ahbcfg                         = -1,
+       .uframe_sched                   = -1,
+};
+
+/**
+ * dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the
+ * DWC_otg driver
+ *
+ * @dev: Bus device
+ *
+ * This routine is called, for example, when the rmmod command is executed. The
+ * device may or may not be electrically present. If it is present, the driver
+ * stops device processing. Any resources used on behalf of this device are
+ * freed.
+ */
+static void dwc2_driver_remove(struct pci_dev *dev)
+{
+       struct dwc2_hsotg *hsotg = pci_get_drvdata(dev);
+
+       dwc2_hcd_remove(hsotg);
+       pci_disable_device(dev);
+}
+
+/**
+ * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg
+ * driver
+ *
+ * @dev: Bus device
+ *
+ * This routine creates the driver components required to control the device
+ * (core, HCD, and PCD) and initializes the device. The driver components are
+ * stored in a dwc2_hsotg structure. A reference to the dwc2_hsotg is saved
+ * in the device private data. This allows the driver to access the dwc2_hsotg
+ * structure on subsequent calls to driver methods for this device.
+ */
+static int dwc2_driver_probe(struct pci_dev *dev,
+                            const struct pci_device_id *id)
+{
+       struct dwc2_hsotg *hsotg;
+       int retval;
+
+       hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL);
+       if (!hsotg)
+               return -ENOMEM;
+
+       hsotg->dev = &dev->dev;
+       hsotg->regs = devm_ioremap_resource(&dev->dev, &dev->resource[0]);
+       if (IS_ERR(hsotg->regs))
+               return PTR_ERR(hsotg->regs);
+
+       dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
+               (unsigned long)pci_resource_start(dev, 0), hsotg->regs);
+
+       if (pci_enable_device(dev) < 0)
+               return -ENODEV;
+
+       pci_set_master(dev);
+
+       retval = dwc2_hcd_init(hsotg, dev->irq, &dwc2_module_params);
+       if (retval) {
+               pci_disable_device(dev);
+               return retval;
+       }
+
+       pci_set_drvdata(dev, hsotg);
+
+       return retval;
+}
+
+static const struct pci_device_id dwc2_pci_ids[] = {
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, PCI_PRODUCT_ID_HAPS_HSOTG),
+       },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_STMICRO,
+                          PCI_DEVICE_ID_STMICRO_USB_OTG),
+       },
+       { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE(pci, dwc2_pci_ids);
+
+static struct pci_driver dwc2_pci_driver = {
+       .name = dwc2_driver_name,
+       .id_table = dwc2_pci_ids,
+       .probe = dwc2_driver_probe,
+       .remove = dwc2_driver_remove,
+};
+
+module_pci_driver(dwc2_pci_driver);
+
+MODULE_DESCRIPTION("DESIGNWARE HS OTG PCI Bus Glue");
+MODULE_AUTHOR("Synopsys, Inc.");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
new file mode 100644 (file)
index 0000000..d01d0d3
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * platform.c - DesignWare HS OTG Controller platform driver
+ *
+ * Copyright (C) Matthijs Kooijman <matthijs@stdin.nl>
+ *
+ * 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") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * 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/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "core.h"
+#include "hcd.h"
+
+static const char dwc2_driver_name[] = "dwc2";
+
+static const struct dwc2_core_params params_bcm2835 = {
+       .otg_cap                        = 0,    /* HNP/SRP capable */
+       .otg_ver                        = 0,    /* 1.3 */
+       .dma_enable                     = 1,
+       .dma_desc_enable                = 0,
+       .speed                          = 0,    /* High Speed */
+       .enable_dynamic_fifo            = 1,
+       .en_multiple_tx_fifo            = 1,
+       .host_rx_fifo_size              = 774,  /* 774 DWORDs */
+       .host_nperio_tx_fifo_size       = 256,  /* 256 DWORDs */
+       .host_perio_tx_fifo_size        = 512,  /* 512 DWORDs */
+       .max_transfer_size              = 65535,
+       .max_packet_count               = 511,
+       .host_channels                  = 8,
+       .phy_type                       = 1,    /* UTMI */
+       .phy_utmi_width                 = 8,    /* 8 bits */
+       .phy_ulpi_ddr                   = 0,    /* Single */
+       .phy_ulpi_ext_vbus              = 0,
+       .i2c_enable                     = 0,
+       .ulpi_fs_ls                     = 0,
+       .host_support_fs_ls_low_power   = 0,
+       .host_ls_low_power_phy_clk      = 0,    /* 48 MHz */
+       .ts_dline                       = 0,
+       .reload_ctl                     = 0,
+       .ahbcfg                         = 0x10,
+       .uframe_sched                   = 0,
+};
+
+/**
+ * dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the
+ * DWC_otg driver
+ *
+ * @dev: Platform device
+ *
+ * This routine is called, for example, when the rmmod command is executed. The
+ * device may or may not be electrically present. If it is present, the driver
+ * stops device processing. Any resources used on behalf of this device are
+ * freed.
+ */
+static int dwc2_driver_remove(struct platform_device *dev)
+{
+       struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
+
+       dwc2_hcd_remove(hsotg);
+
+       return 0;
+}
+
+static const struct of_device_id dwc2_of_match_table[] = {
+       { .compatible = "brcm,bcm2835-usb", .data = &params_bcm2835 },
+       { .compatible = "snps,dwc2", .data = NULL },
+       {},
+};
+MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
+
+/**
+ * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg
+ * driver
+ *
+ * @dev: Platform device
+ *
+ * This routine creates the driver components required to control the device
+ * (core, HCD, and PCD) and initializes the device. The driver components are
+ * stored in a dwc2_hsotg structure. A reference to the dwc2_hsotg is saved
+ * in the device private data. This allows the driver to access the dwc2_hsotg
+ * structure on subsequent calls to driver methods for this device.
+ */
+static int dwc2_driver_probe(struct platform_device *dev)
+{
+       const struct of_device_id *match;
+       const struct dwc2_core_params *params;
+       struct dwc2_core_params defparams;
+       struct dwc2_hsotg *hsotg;
+       struct resource *res;
+       int retval;
+       int irq;
+
+       match = of_match_device(dwc2_of_match_table, &dev->dev);
+       if (match && match->data) {
+               params = match->data;
+       } else {
+               /* Default all params to autodetect */
+               dwc2_set_all_params(&defparams, -1);
+               params = &defparams;
+       }
+
+       hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL);
+       if (!hsotg)
+               return -ENOMEM;
+
+       hsotg->dev = &dev->dev;
+
+       /*
+        * Use reasonable defaults so platforms don't have to provide these.
+        */
+       if (!dev->dev.dma_mask)
+               dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
+       retval = dma_set_coherent_mask(&dev->dev, DMA_BIT_MASK(32));
+       if (retval)
+               return retval;
+
+       irq = platform_get_irq(dev, 0);
+       if (irq < 0) {
+               dev_err(&dev->dev, "missing IRQ resource\n");
+               return irq;
+       }
+
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       hsotg->regs = devm_ioremap_resource(&dev->dev, res);
+       if (IS_ERR(hsotg->regs))
+               return PTR_ERR(hsotg->regs);
+
+       dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
+               (unsigned long)res->start, hsotg->regs);
+
+       retval = dwc2_hcd_init(hsotg, irq, params);
+       if (retval)
+               return retval;
+
+       platform_set_drvdata(dev, hsotg);
+
+       return retval;
+}
+
+static struct platform_driver dwc2_platform_driver = {
+       .driver = {
+               .name = dwc2_driver_name,
+               .of_match_table = dwc2_of_match_table,
+       },
+       .probe = dwc2_driver_probe,
+       .remove = dwc2_driver_remove,
+};
+
+module_platform_driver(dwc2_platform_driver);
+
+MODULE_DESCRIPTION("DESIGNWARE HS OTG Platform Glue");
+MODULE_AUTHOR("Matthijs Kooijman <matthijs@stdin.nl>");
+MODULE_LICENSE("Dual BSD/GPL");
This page took 0.319996 seconds and 5 git commands to generate.