[PATCH] Au1200 USB Device Controller and device-only OTG

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds support for the USB Device Controller on the Au1200 SOC as
well as basic device-only OTG (On-The-Go) support.  There are some defines and
hooks for future expansion to full OTG support.

This has been tested with the g_zero gadget as well as the g_file_storage
gadget on a DB1250 board.

Signed-off-by: Kevin Hickey <khickey@xxxxxxxxxxx>
---
 arch/mips/configs/db1200_defconfig |   21 +
 drivers/usb/core/Kconfig           |    2 -
 drivers/usb/gadget/Kconfig         |   49 +-
 drivers/usb/gadget/Makefile        |    5 +
 drivers/usb/gadget/au1200_otg.c    |  854 +++++++++++
 drivers/usb/gadget/au1200_otg.h    |  138 ++
 drivers/usb/gadget/au1200_udc.c    | 2862 ++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/au1200_udc.h    |  816 ++++++++++
 drivers/usb/gadget/au1200_uoc.h    | 1021 +++++++++++++
 drivers/usb/gadget/gadget_chips.h  |    6 +
 include/linux/usb/otg.h            |    7 +-
 11 files changed, 5770 insertions(+), 11 deletions(-)
 create mode 100644 drivers/usb/gadget/au1200_otg.c
 create mode 100644 drivers/usb/gadget/au1200_otg.h
 create mode 100644 drivers/usb/gadget/au1200_udc.c
 create mode 100644 drivers/usb/gadget/au1200_udc.h
 create mode 100644 drivers/usb/gadget/au1200_uoc.h

diff --git a/arch/mips/configs/db1200_defconfig b/arch/mips/configs/db1200_defconfig
index ab17973..b69fec3 100644
--- a/arch/mips/configs/db1200_defconfig
+++ b/arch/mips/configs/db1200_defconfig
@@ -914,13 +914,34 @@ CONFIG_USB_ARCH_HAS_EHCI=y
 #
 CONFIG_USB_GADGET=m
 # CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
 # CONFIG_USB_GADGET_NET2280 is not set
 # CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
 # CONFIG_USB_GADGET_GOKU is not set
 # CONFIG_USB_GADGET_LH7A40X is not set
 # CONFIG_USB_GADGET_OMAP is not set
+CONFIG_USB_GADGET_AU1200=y
+CONFIG_USB_AU1200=m
+# CONFIG_USB_GADGET_S3C2410 is not set
 # CONFIG_USB_GADGET_AT91 is not set
 # CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_PORT_AU1200OTG=y
+CONFIG_USB_AU1200OTG=m
+CONFIG_USB_ZERO=m
+# CONFIG_USB_ETH is not set
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
 # CONFIG_USB_GADGET_DUALSPEED is not set
 
 #
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index cc9f397..cc54c55 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -106,8 +106,6 @@ config USB_OTG
 	bool
 	depends on USB && EXPERIMENTAL
 	select USB_SUSPEND
-	default n
-
 
 config USB_OTG_WHITELIST
 	bool "Rely on OTG Targeted Peripherals List"
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index acc95b2..ceb8a17 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -315,16 +315,28 @@ config USB_OMAP
 	default USB_GADGET
 	select USB_GADGET_SELECTED
 
-config USB_OTG
-	boolean "OTG Support"
-	depends on USB_GADGET_OMAP && ARCH_OMAP_OTG && USB_OHCI_HCD
+config USB_GADGET_AU1200
+	boolean "AU1200 USB Device Controller"
+	depends on SOC_AU1200
+	select USB_GADGET_DUALSPEED
 	help
-	   The most notable feature of USB OTG is support for a
-	   "Dual-Role" device, which can act as either a device
-	   or a host.  The initial role choice can be changed
-	   later, when two dual-role devices talk to each other.
+	   The RMI Alchemy Au1200 and Au1250 SOCs include a full On-The-Go port
+	   with USB 1.1 and USB 2.0 support.  The device port supports 4
+	   bidirectional endpoints plus the default endpoint ep0.
+
+	   This driver provides the device mode for the On-The-Go port.  The
+	   port will not be active unless the au1200_otg driver is loaded or
+	   built statically.
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "au1200_udc" and force all
+	   gadget drivers to also be dynamically linked.
 
-	   Select this only if your OMAP board has a Mini-AB connector.
+config USB_AU1200
+	tristate
+	depends on USB_GADGET_AU1200
+	default USB_GADGET
+	select USB_GADGET_SELECTED
 
 config USB_GADGET_S3C2410
 	boolean "S3C2410 USB Device Controller"
@@ -407,6 +419,27 @@ config USB_GADGET_DUALSPEED
 	  Means that gadget drivers should include extra descriptors
 	  and code to handle dual-speed controllers.
 
+config USB_PORT_AU1200OTG
+	boolean "AU1200 USB portmux control (On-The-Go support)"
+	depends on USB_GADGET_AU1200 || USB_EHCI_HCD || USB_OHCI_HCD
+	default n
+	help
+	   The AU1200 and Au1200 USB device port can be used as either a host
+	   port or a device port.  This driver configures the port based on
+	   hardware or software set criteria.  It is required to be loaded for
+	   au1200_udc to be useful.
+
+	   NOTE: Currently, only device-port mode is supported.  Host-port and
+	   other On The Go modes will be supported in a future release.
+
+	   Say "y" to link this driver statically or "m" to build a dynamically
+	   linked module called "au1200_otg".
+
+config USB_AU1200OTG
+	tristate
+	depends on USB_PORT_AU1200OTG
+	default USB_AU1200
+
 #
 # USB Gadget Drivers
 #
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index fcb5cb9..d2af7cd 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_USB_PXA25X)	+= pxa25x_udc.o
 obj-$(CONFIG_USB_PXA27X)	+= pxa27x_udc.o
 obj-$(CONFIG_USB_GOKU)		+= goku_udc.o
 obj-$(CONFIG_USB_OMAP)		+= omap_udc.o
+obj-$(CONFIG_USB_AU1200)	+= au1200_udc.o
 obj-$(CONFIG_USB_LH7A40X)	+= lh7a40x_udc.o
 obj-$(CONFIG_USB_S3C2410)	+= s3c2410_udc.o
 obj-$(CONFIG_USB_AT91)		+= at91_udc.o
@@ -49,3 +50,7 @@ obj-$(CONFIG_USB_G_PRINTER)	+= g_printer.o
 obj-$(CONFIG_USB_MIDI_GADGET)	+= g_midi.o
 obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
 
+#
+# AU1200 USB OTG options
+#
+obj-$(CONFIG_USB_AU1200OTG)	+= au1200_otg.o
diff --git a/drivers/usb/gadget/au1200_otg.c b/drivers/usb/gadget/au1200_otg.c
new file mode 100644
index 0000000..a110aff
--- /dev/null
+++ b/drivers/usb/gadget/au1200_otg.c
@@ -0,0 +1,854 @@
+/*
+ * Au1200 On The Go port driver.
+ */
+
+/*
+ * Copyright (C) 2008 RMI Corporation (http://www.rmicorp.com)
+ * Author: Kevin Hickey (khickey@xxxxxxxxxxx)
+ *
+ * THIS SOFTWARE IS PROVIDED BY RMI Corporation '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 RMI 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 program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*****************************************************************************
+ *  Includes
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+
+#include <asm/byteorder.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+#include <linux/platform_device.h>
+
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1000_gpio.h>
+
+#include <linux/usb.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+
+#define	DRIVER_DESC		"Au1200 USB OTG Controller"
+#define DRIVER_NAME_FOR_PRINT   OTG_DRIVER_NAME
+
+#include "au1200_otg.h"
+#include "au1200_uoc.h"
+
+
+/*****************************************************************************
+ *  Function Declarations
+ *****************************************************************************/
+
+static u32 otg_app_query(int);
+static int au1200otg_set_peripheral(struct otg_transceiver *,
+		struct usb_gadget *);
+
+
+/*****************************************************************************
+ *  Data
+ *****************************************************************************/
+
+static const char driver_name[] = OTG_DRIVER_NAME;
+static const char driver_desc[] = DRIVER_DESC;
+
+static struct otg *the_controller;
+static const char *transceiver_label = "au1200_otg";
+
+static u32 init_state;
+
+struct usb_otg_gadget_extension otg_gadget_extension = {
+	.request = NULL,
+	.query   = otg_app_query,
+	.notify  = NULL
+};
+
+static u32 state_mask;
+u32 otg_tmr_high_count;
+
+/*****************************************************************************
+ *  Function Definitions
+ *****************************************************************************/
+
+/**
+ * \brief
+ * fill OTG transceiver struct
+ *
+ * \param  transceiver  OTG transceiver
+ *
+ * \return              void
+ */
+static inline void otg_init_transceiver(struct otg_transceiver *transceiver)
+{
+	transceiver->dev            = NULL;
+	transceiver->label          = transceiver_label;
+	transceiver->default_a      = 0;
+	transceiver->state          = OTG_STATE_UNDEFINED;
+	transceiver->prv_state      = OTG_STATE_UNDEFINED;
+	transceiver->params         = 0;
+	transceiver->otg_priv       = (void *) &otg_gadget_extension;
+	transceiver->host           = NULL;
+	transceiver->gadget         = NULL;
+	transceiver->port_status    = 0;
+	transceiver->port_change    = 0;
+	transceiver->set_host       = NULL;
+	transceiver->set_peripheral = au1200otg_set_peripheral;
+	transceiver->set_power      = NULL;
+	transceiver->start_srp      = NULL;
+	transceiver->start_hnp      = NULL;
+}
+
+/**
+ * \brief
+ * OTG state change
+ *
+ * subset of OTG states to support the gadget only or
+ * ID pin configuration
+ *
+ * \param  otg          OTG controller info
+ * \param  event_code   event that requested a state change
+ * \param  pEvt_mask
+ *
+ * \return              events that were not handled here
+ */
+u32 otg_change_state(struct otg *otg, u32 _event, u32 *pEvt_mask)
+{
+	u32  event_code = _event;
+	u32  uoc_status = get_status(otg);
+
+	if (GOT_EVENT(OTG_GADGET_READY, event_code) &&
+			((otg->transceiver.state & OTG_STATE_MASK) !=
+			 OTG_STATE_UNDEFINED)) {
+
+		/* Switch from "NO_B_DEVICE" states to normal operation or   */
+		/*       deactivate operations in case gadget was unloaded   */
+
+		CHANGE_STATE(otg, OTG_STATE_UNDEFINED, pEvt_mask);
+	}
+	if ((OTG_INT_TMX & event_code) && otg_tmr_high_count) {
+
+		/* a long timer is running : decrement the high part         */
+
+		restart_timer(otg);
+		otg_tmr_high_count--;
+		RES_EVENT(OTG_INT_TMX, event_code);
+	}
+
+	do {
+		switch (otg->transceiver.state & OTG_STATE_MASK) {
+		/* NOT_ASSIGNED (yet): init state, 1st time after loading     */
+		/* ======================================================     */
+
+		case OTG_STATE_UNDEFINED:
+
+			CHECK_STATE(otg, OTG_STATE_UNDEFINED, pEvt_mask);
+
+			if (IS_FLAG_RES(otg, OTG_FLAGS_ACTIV)) {
+
+				/* seems to be the first time: let it run !   */
+
+				SET_FLAG(otg, OTG_FLAGS_ACTIV);
+			}
+
+			/*      muxer is still neutral                        */
+
+			RES_EVENT((OTG_INT_IDC | OTG_INT_TMX), event_code);
+
+			if (IS_FLAG_RES(otg, OTG_GADGET_READY)) {
+				if (IS_BIT_RES(OTG_STS_ID, uoc_status)) {
+
+					/* ID pin connected: A-device (host)  */
+
+					if (OTG_STATE_NO_B_DEVICE_A !=
+							otg->transceiver.state)
+						CHANGE_STATE(otg,
+							OTG_STATE_NO_B_DEVICE_A,
+							pEvt_mask);
+				} else if (IS_BIT_SET(OTG_STS_ID, uoc_status)) {
+
+					/* ID pin not connected:
+					 * disable(neutral)*/
+
+					if (OTG_STATE_NO_B_DEVICE_B !=
+							otg->transceiver.state)
+						CHANGE_STATE(otg,
+							OTG_STATE_NO_B_DEVICE_B,
+							pEvt_mask);
+				}
+			} else if ((OTG_STATE_NO_B_DEVICE_A ==
+						otg->transceiver.state) ||
+					(OTG_STATE_NO_B_DEVICE_B ==
+					 otg->transceiver.state)) {
+
+				/* Exit "not ready" state                     */
+				/* ----------------------                     */
+
+				RES_EVENT(OTG_GADGET_READY, event_code);
+				CHANGE_STATE(otg, OTG_STATE_UNDEFINED,
+						pEvt_mask);
+			}
+
+			/* ================================================== */
+
+			else {
+
+				/* ID pin is not connected: B-device
+				 * (peripheral)*/
+
+				CHANGE_STATE(otg, OTG_STATE_B_IDLE, pEvt_mask);
+			}
+			break;
+
+		case OTG_STATE_B_IDLE:
+			/* B_IDLE: init state for B-devices                  */
+			/*         monitor VBus, no connection, no activity  */
+
+			CHECK_STATE(otg, OTG_STATE_B_IDLE, pEvt_mask);
+
+			if (IS_BIT_SET(OTG_STS_SESSVLD, uoc_status)) {
+				/* Session valid => B_PERIPHERAL             */
+
+				RES_EVENT(OTG_INT_SVC, event_code);
+				CHANGE_STATE(otg, OTG_STATE_B_PERIPHERAL,
+						pEvt_mask);
+				if (otg_gadget_extension.notify) {
+					otg_gadget_extension.notify(
+							OTG_GADGET_EVT_SVALID);
+				}
+			}
+			break;
+
+		case OTG_STATE_B_PERIPHERAL:
+			/* B_PERIPHERAL: connected to A-host, responding     */
+			/*               VBus driven by A, remote activity   */
+
+			CHECK_STATE(otg, OTG_STATE_B_PERIPHERAL, pEvt_mask);
+
+			if (IS_BIT_RES(OTG_STS_SESSVLD, uoc_status)) {
+				/* ID pin changed | ~Session valid => B_IDLE */
+
+				RES_EVENT((OTG_INT_IDC | OTG_INT_SVC),
+						event_code);
+				CHANGE_STATE(otg, OTG_STATE_B_IDLE, pEvt_mask);
+				if (otg_gadget_extension.notify) {
+					otg_gadget_extension.notify(
+							OTG_GADGET_EVT_SVDROP);
+				}
+			}
+			break;
+
+		default:
+			/* something went wrong */
+			BUG();
+			break;
+	}
+	} while ((otg->transceiver.state ^ otg->transceiver.prv_state) &
+			(OTG_STATE_MASK));
+
+
+	DBG("OTG-state change done\n");
+
+	return event_code;
+}
+
+/**
+ * \brief
+ * OTG state change request
+ *
+ * \param  dev    OTG device info
+ * \param  params
+ *
+ * \return void
+ */
+static inline void otg_req_state_chg(struct otg *otg, u32 params)
+{
+	u32 temp, tmp2;
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	/* disable global OTG interrupt, clear int status:                   */
+	temp = ~((u32) OTG_INT_GLOBAL) & readl(&otg->regs->inten);
+	writel(temp, &otg->regs->inten);
+	tmp2 = readl(&otg->regs->intr);
+	writel(tmp2, &otg->regs->intr);
+	temp &= tmp2;
+
+	/* update OTG state:                                                 */
+	otg_change_state(otg, (params | temp), &temp);
+
+	/* enable global OTG interrupt:                                      */
+	state_mask = ~temp & OTG_INT_ADDS;
+	writel((OTG_INT_ADDS | temp | OTG_INT_GLOBAL), &otg->regs->inten);
+	local_irq_restore(flags);
+}
+
+/**
+ * \brief
+ * OTG set transceiver:
+ *
+ * \param  pointer to transceiver struct
+ *
+ * \return void
+ */
+int otg_set_transceiver(struct otg_transceiver *transceiver)
+{
+	struct otg *otg = the_controller;
+
+	if (unlikely(transceiver != otg_to_transceiver(otg))) {
+		ERR("USB OTG: unknown transceiver\n");
+		return -EINVAL;
+	} else
+		return 0;
+}
+
+/**
+ * \brief
+ * OTG get transceiver: provide info to others
+ *
+ * \param  void
+ *
+ * \return pointer to transceiver struct
+ */
+struct otg_transceiver *otg_get_transceiver(void)
+{
+	return otg_to_transceiver(the_controller);
+}
+
+/**
+ * \brief
+ * Bind/unbind the OTG controller to/from usb gadget
+ *
+ * \param  transceiver  this transceiver
+ * \param  gadget       usb gadget info
+ *
+ * \return error code
+ */
+static int au1200otg_set_peripheral(struct otg_transceiver *transceiver,
+		struct usb_gadget *gadget)
+{
+	struct otg *otg = the_controller;
+	int flag = 0;
+
+	if (unlikely(transceiver != otg_to_transceiver(otg))) {
+		ERR("USB OTG: unknown transceiver\n");
+		return -EINVAL;
+	}
+	if (gadget) {
+		if (transceiver->gadget) {
+			ERR("USB gadget: OTG driver already registered\n");
+			return -EBUSY;
+		}
+		DBG("bind OTG driver to USB gadget\n");
+		transceiver->gadget = gadget;
+		SET_FLAG(otg, OTG_GADGET_READY | OTG_B_BUS_REQ);
+
+		/* Now checking consistence ...                              */
+		/* Depending on the driver loading sequence is possible      */
+		/* that the "Load state defaults" function was already       */
+		/*  called so the state could be inconsistent.               */
+		if (transceiver->host && !transceiver->host->is_b_host)
+			flag |= 1;
+		transceiver->gadget->is_a_peripheral = flag;
+
+		if (IS_FLAG_SET(otg, OTG_FLAGS_ACTIV))
+			otg_req_state_chg(otg, OTG_GADGET_READY);
+
+		if (IS_BIT_SET(OTG_STS_SESSVLD, readl(&otg->regs->sts)) &&
+				(otg->transceiver.state & OTG_STATE_MASK)
+				== OTG_STATE_B_PERIPHERAL) {
+			VDBG("calling gadget: connect\n");
+			otg_gadget_extension.notify(OTG_GADGET_EVT_SVALID);
+		}
+		return 0;
+	} else {
+		DBG("unbind OTG driver from USB gadget\n");
+		RES_FLAG(otg, OTG_GADGET_READY | OTG_B_BUS_REQ);
+		if (IS_FLAG_SET(otg, OTG_FLAGS_ACTIV))
+			otg_req_state_chg(otg, OTG_GADGET_READY);
+
+		transceiver->gadget = NULL;
+		return 0;
+	}
+}
+
+/**
+ * \brief
+ * OTG application query
+ *
+ * \param  index   select status info data
+ *
+ * \return status
+ */
+static u32 otg_app_query(int index)
+{
+	struct otg *otg = the_controller;
+	u32  temp = 0;
+
+	if (index == 0) {
+		temp = otg->transceiver.params |
+			readl(&otg->regs->sts);
+
+		if (((readl(&otg->regs->ctl) & OTG_CTL_MUX_MASK) ==
+					OTG_CTL_ENABLE_UDC) &&
+				((temp & OTG_STS_PSUS) ||
+				 (~temp & OTG_STS_VBUSVLD)))
+			temp |= OTG_FLAGS_UDC_SUSP;
+	} else if (index == 1)
+		temp = otg->transceiver.state;
+
+	return temp;
+}
+
+/**
+ * \brief
+ * OTG ISR calling the main state machine
+ *
+ * \param  irq    IRQ number
+ * \param  _dev
+ * \param  r
+ *
+ * \return IRQ_HANDLED(system code)
+ */
+static irqreturn_t otg_isr(int irq, void *dev)
+{
+	struct otg *otg = (struct otg *) dev;
+	u32         interrupts, int_mask, temp;
+
+	int_mask = readl(&otg->regs->inten);
+	if ((OTG_INT_GLOBAL & int_mask) &&
+			(int_mask &= ~((u32) OTG_INT_GLOBAL)) &&
+			(interrupts = int_mask &
+			 (temp = readl(&otg->regs->intr)))) {
+
+		writel(int_mask, &otg->regs->inten);
+		/* clear interrupt status */
+		writel(temp, &otg->regs->intr);
+		/* filter out additional WA interrupts, they're done         */
+		/*       don't want to see them in the state machine         */
+
+		if (interrupts & ~state_mask) {
+
+			/* events pending for the state machine              */
+
+			otg_change_state(otg, (interrupts & ~state_mask),
+					&int_mask);
+		}
+
+		/* enable interrupts and keep information about WA ints:     */
+
+		state_mask = OTG_INT_ADDS & ~int_mask;
+		writel((OTG_INT_ADDS | int_mask | OTG_INT_GLOBAL),
+				&otg->regs->inten);
+	}
+	return IRQ_HANDLED;
+}
+
+/**
+ * \brief
+ * OTG probe: init hardware, register the driver
+ *
+ * \param  otg   otg controller info
+ *
+ * \return  success
+ */
+static inline int __init otg_probe(struct otg *otg)
+{
+	int         retval;
+	u32         temp;
+	int         i;
+
+	/* initialize the OTG controller */
+
+	VDBG("OTG init ...\n");
+
+#ifdef VERBOSE
+	/* print regs */
+	print_regs(otg);
+#endif
+	/* Make sure we'll remember the initial state                        */
+	init_state = readl(&otg->regs->ctl);
+	VDBG("  OTG init state was %08x\n", init_state);
+
+	/* turn on the OTG controller                                        */
+	writel((init_state | OTG_CTL_PADEN), &otg->regs->ctl);
+
+	/* initialize flags                                                  */
+	otg->transceiver.params = 0;
+
+	/* make sure all interrupts are disabled                             */
+	writel(OTG_INT_DISALL, &otg->regs->inten);
+	writel(OTG_INT_ENALL, &otg->regs->intr);
+
+	/* Set multiplexer to neutral, get power control, drop VBus          */
+
+	if (((init_state & OTG_CTL_MUX_MASK) == OTG_CTL_ENABLE_UHC) &&
+			((((init_state & OTG_CTL_PPO) &&
+			  (init_state & OTG_CTL_PPWR))) ||
+			 ((~init_state & OTG_CTL_PPO) &&
+			  (readl(&otg->regs->sts) & OTG_STS_SESSVLD)))) {
+
+		/* VBus still powered try to discharge VBus and set timer    */
+
+		DBG("Setting init state, trying to discharge VBus ...\n");
+
+		for (i = 0; i < 4; i++) {
+			writel(TIMER_PERIOD, &otg->regs->tmr);
+			writel((OTG_CTL_PADEN | OTG_CTL_IDSNSEN |
+						OTG_CTL_PPO | OTG_CTL_DISCHRG |
+						OTG_CTL_TMR_UNCOND),
+						&otg->regs->ctl);
+			while (!(readl(&otg->regs->sts) & OTG_STS_TMH))
+				udelay(1);
+		}
+		writel((OTG_CTL_PADEN | OTG_CTL_IDSNSEN | OTG_CTL_PPO),
+				&otg->regs->ctl);
+		writel(OTG_INT_ENALL, &otg->regs->intr);
+#ifdef DEBUG
+		if (readl(&otg->regs->sts) & OTG_STS_SESSVLD)
+			DBG("  VBus still high, external host connected\n");
+		else
+			DBG("  VBus discharged\n");
+#endif
+	} else {
+		DBG("Setting init state\n");
+
+		writel((OTG_CTL_PADEN | OTG_CTL_IDSNSEN | OTG_CTL_PPO),
+				&otg->regs->ctl);
+	}
+
+	VDBG("OTG init done\n");
+
+	/* registering to the device driver */
+	if (usb_gadget_register_otg(otg_get_transceiver)) {
+		ERR("gadget driver registration failed\n");
+		retval = -ENODEV;
+		goto err1;
+	}
+
+	/* finally activate OTG functionality */
+	/* Enable timer interrupt, start timer, set state                    */
+
+	SET_OTG_TIMER(otg, IDSNS_WAIT);
+	CHANGE_STATE(otg, OTG_STATE_UNDEFINED, &temp);
+	CHECK_STATE(otg, OTG_STATE_UNDEFINED, &temp);
+
+	/* clear all interrupts before enable */
+	writel(readl(&otg->regs->intr), &otg->regs->intr);
+
+	state_mask = ~temp & OTG_INT_ADDS;
+	writel((OTG_INT_ADDS | temp | OTG_INT_GLOBAL), &otg->regs->inten);
+
+	DBG("OTG-HW initialized, now checking ID ...\n");
+
+	return 0;
+
+	usb_gadget_unregister_otg();
+err1:
+	return retval;
+}
+
+/**
+ * \brief
+ * OTG remove: deregister the driver, clean-up hardware
+ *
+ * \param  otg   otg controller info
+ *
+ * \return void
+ */
+static inline void __exit otg_remove(struct otg *otg)
+{
+	int muxer;
+
+	/* unregistering from the usb gadget */
+	usb_gadget_unregister_otg();
+
+	/* clean up the OTG controller */
+
+	/* Disable all interrupts                                            */
+	writel(OTG_INT_DISALL, &otg->regs->inten);
+	writel(OTG_INT_ENALL, &otg->regs->intr);
+
+	/* reset state, terminate all connections                            */
+	CHANGE_STATE(otg, OTG_STATE_UNDEFINED, &state_mask);
+	CHECK_STATE(otg, OTG_STATE_UNDEFINED, &state_mask);
+	otg->transceiver.params = 0;
+
+	muxer = init_state & (OTG_CTL_ENABLE_UHC | OTG_CTL_ENABLE_UDC);
+
+
+	/* Don't assign the port to the device controller                    */
+
+	if (!(muxer ^ OTG_CTL_ENABLE_UDC)) {
+
+		init_state &= ~((u32)(OTG_CTL_MUX_MASK | OTG_CTL_PUEN));
+		muxer = OTG_CTL_DISABLE_ALL;
+	}
+	VDBG("OTG writing back corrected init state: %08x\n", init_state);
+
+	/* Now, that's the moment to remember                                */
+	/* Set dev muxer and pull up bits, turn off the OTG controller       */
+
+	/* Turn off VBus                                                     */
+	writel(init_state, &otg->regs->ctl);
+
+	if (!(muxer ^ OTG_CTL_ENABLE_UHC))
+		INFO("disabling OTG-HW, port is assigned to host\n");
+	else if (!(muxer ^ OTG_CTL_ENABLE_UDC))
+		INFO("disabling OTG-HW, port is assigned to device\n");
+	else
+		INFO("disabling OTG-HW, port is not assigned\n");
+
+	VDBG("OTG exit: OTG-HW disabled\n");
+
+	if (!muxer)
+		INFO("OTG HW disabled, port is not assigned\n");
+}
+
+/**
+ * \brief
+ * OTG dev probe: enable, init controller hardware
+ *
+ * \param  dev   platform device info
+ *
+ * \return success
+ */
+static int __init otg_drv_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct otg *otg;
+	u32         resource, len, irq;
+	void       *base;
+	int         retval;
+	char        buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, *bufp;
+
+	/* alloc, and start init */
+	otg = kmalloc(sizeof(struct otg), GFP_KERNEL);
+	if (!otg) {
+		ERR("couldn't allocate memory for OTG driver\n");
+		retval = -ENOMEM;
+		goto err1;
+	}
+	DBG("kmalloc: OTG driver: %p\n", otg);
+
+	/* hold global device pointer */
+	the_controller = otg;
+
+	memset(otg, 0, sizeof(struct otg));
+	spin_lock_init(&otg->lock);
+
+	if (pdev->resource[0].flags != IORESOURCE_MEM) {
+		ERR("resource is not IORESOURCE_MEM\n");
+		retval = -ENOMEM;
+		goto err2;
+	}
+	resource = pdev->resource[0].start;
+	len = pdev->resource[0].end + 1 - pdev->resource[0].start;
+	if (pdev->resource[1].flags != IORESOURCE_IRQ) {
+		ERR("resource is not IORESOURCE_IRQ\n");
+		retval = -ENOMEM;
+		goto err2;
+	}
+	irq = pdev->resource[1].start;
+
+	otg->pdev = pdev;
+
+	au_writel((au_readl(USB_MSR_BASE + USB_MSR_MCFG) |
+				(1 << USBMSRMCFG_GMEMEN)),
+				(USB_MSR_BASE + USB_MSR_MCFG));
+	au_readl(USB_MSR_BASE + USB_MSR_MCFG);
+	au_sync();
+
+	otg->enabled = 1;
+
+	if (!request_mem_region(resource, len, driver_name)) {
+		ERR("controller already in use\n");
+		retval = -EBUSY;
+		goto err3;
+	}
+	otg->region = 1;
+
+	base = ioremap_nocache(resource, len);
+	if (!base) {
+		ERR("couldn't map memory\n");
+		retval = -EFAULT;
+		goto err4;
+	}
+	otg->regs = (struct otg_regs *) base;
+	bufp = buf;
+
+	otg->chiprev = (u16) read_c0_prid() & 0xff;
+
+	/* OTG transceiver info */
+	otg->transceiver.dev = dev;
+	otg_init_transceiver(otg_to_transceiver(otg));
+
+	/* make sure all interrupts are disabled */
+	writel(OTG_INT_DISALL, &otg->regs->inten);
+	writel(OTG_INT_ENALL, &otg->regs->intr);
+	readl(&otg->regs->inten);
+
+	/* irq setup after old hardware is cleaned up */
+	if (!irq) {
+		ERR("No IRQ. Check system setup!\n");
+		retval = -ENODEV;
+		goto err5;
+	}
+	snprintf(buf, sizeof buf, "%d", irq);
+	bufp = buf;
+	if (request_irq(irq, otg_isr, IRQF_SHARED,
+				driver_name, otg) != 0) {
+		ERR("request interrupt %s failed\n", bufp);
+		retval = -EBUSY;
+		goto err5;
+	}
+	otg->got_irq = 1;
+
+	/* done */
+	INFO("%s\n", driver_desc);
+	INFO("irq %s, mem %08x, chip rev %02x (Au1200 %s)\n",
+			bufp, resource, otg->chiprev,
+			(otg->chiprev ? "AC" : "AB"));
+
+	retval = otg_probe(otg);
+	if (retval == 0) {
+		dev_set_drvdata(dev, otg);
+		return 0;
+	}
+
+	otg->got_irq = 0;
+	free_irq(irq, otg);
+err5:
+
+	otg->regs = NULL;
+	iounmap(base);
+err4:
+	otg->region = 0;
+	release_mem_region(resource, len);
+err3:
+	otg->enabled = 0;
+	au_writel((au_readl(USB_MSR_BASE + USB_MSR_MCFG) &
+				~((u32)(1 << USBMSRMCFG_GMEMEN))),
+			(USB_MSR_BASE + USB_MSR_MCFG));
+	au_readl(USB_MSR_BASE + USB_MSR_MCFG);
+	/* au_sync(); */
+	udelay(1000);
+err2:
+	otg->pdev = NULL;
+	the_controller = NULL;
+	DBG("kfree: OTG driver: %p\n", otg);
+	kfree(otg);
+err1:
+	otg = NULL;
+
+	return retval;
+}
+
+/**
+ * \brief
+ * OTG dev remove: clean-up, disable controller hardware
+ *
+ * \param  dev   platform device info
+ *
+ * \return void
+ */
+static int __exit otg_drv_remove(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct otg *otg = dev_get_drvdata(dev);
+
+	otg_remove(otg);
+
+	otg->got_irq = 0;
+	free_irq(pdev->resource[1].start, otg);
+	iounmap(otg->regs);
+	otg->regs = NULL;
+	otg->region = 0;
+	release_mem_region(pdev->resource[0].start,
+			pdev->resource[0].end + 1
+			- pdev->resource[0].start);
+	otg->enabled = 0;
+
+	au_readl(USB_MSR_BASE + USB_MSR_MCFG);
+	au_sync();
+
+	otg->pdev = NULL;
+	the_controller = NULL;
+	DBG("kfree: OTG driver: %p\n", otg);
+	kfree(otg);
+	otg = NULL;
+	dev_set_drvdata(dev, NULL);
+	return 0;
+}
+
+
+/*****************************************************************************
+ *  More data
+ *****************************************************************************/
+
+/**
+ * \brief
+ * driver struct to be used for driver registration
+ *
+ */
+static struct device_driver otg_device_driver = {
+	.name =		"au1xxx-uoc",
+	.bus =		&platform_bus_type,
+	.probe =	otg_drv_probe,
+	.remove =	otg_drv_remove,
+	/* 	.suspend =	otg_drv_suspend, */
+	/* 	.resume =	otg_drv_resume, */
+};
+
+/* This comment closes the module definition from above. There can be multiple
+   definitions of this kind in a file. See the doxygen documentation for more
+   information. */
+/** \}*/
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Kevin Hickey");
+MODULE_LICENSE("GPL");
+
+static int __init init(void)
+{
+	return driver_register(&otg_device_driver);
+}
+static void __exit cleanup(void)
+{
+	driver_unregister(&otg_device_driver);
+}
+
+module_init(init);
+module_exit(cleanup);
diff --git a/drivers/usb/gadget/au1200_otg.h b/drivers/usb/gadget/au1200_otg.h
new file mode 100644
index 0000000..8c2e3a5
--- /dev/null
+++ b/drivers/usb/gadget/au1200_otg.h
@@ -0,0 +1,138 @@
+/*
+ * Declarations for the Au1200 On The Go port driver.
+ */
+
+/*
+ * Copyright (C) 2008 RMI Corporation (http://www.rmicorp.com)
+ * Author: Kevin Hickey (khickey@xxxxxxxxxxx)
+ *
+ * THIS SOFTWARE IS PROVIDED BY RMI Corporation '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 RMI 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 program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef AU1200_OTG_H
+#define AU1200_OTG_H
+
+/**********************************
+ * OTG sub-state definitions
+ ***********************************/
+
+#define OTG_STATE_MASK                  0x0F
+
+#define OTG_STATE_NO_B_DEVICE_A         (0x60 | OTG_STATE_UNDEFINED)
+#define OTG_STATE_NO_B_DEVICE_B         (0x40 | OTG_STATE_UNDEFINED)
+
+#define OTG_STATE_B_HOST_WT             (0x10 | OTG_STATE_B_HOST)
+#define OTG_STATE_B_PERIPHERAL_WT       (0x10 | OTG_STATE_B_PERIPHERAL)
+#define OTG_STATE_B_PERIPHERAL_DC       (0x20 | OTG_STATE_B_PERIPHERAL)
+#define OTG_STATE_B_SRP_WAIT_SE0        (0x10 | OTG_STATE_B_SRP_INIT)
+#define OTG_STATE_B_SRP_D_PULSE         (0x20 | OTG_STATE_B_SRP_INIT)
+#define OTG_STATE_B_SRP_V_PULSE         (0x30 | OTG_STATE_B_SRP_INIT)
+#define OTG_STATE_B_SRP_V_DCHRG         (0x40 | OTG_STATE_B_SRP_INIT)
+#define OTG_STATE_B_SRP_WAIT_VBUS       (0x50 | OTG_STATE_B_SRP_INIT)
+
+#define OTG_STATE_A_IDLE_WAIT_DP        (0x10 | OTG_STATE_A_IDLE)
+#define OTG_STATE_A_IDLE_WAIT_VP        (0x20 | OTG_STATE_A_IDLE)
+#define OTG_STATE_A_IDLE_WAIT_MP        (0x30 | OTG_STATE_A_IDLE)
+#define OTG_STATE_A_IDLE_WAIT_DV        (0x40 | OTG_STATE_A_IDLE)
+#define OTG_STATE_A_WAIT_BCON_VB        (0x10 | OTG_STATE_A_WAIT_BCON)
+#define OTG_STATE_A_WAIT_VFALL_DN       (0x10 | OTG_STATE_A_WAIT_VFALL)
+
+
+/**********************************
+ *  typical timer values
+ **********************************/
+
+#define OTG_TMR_WAIT_VFALL     10   /* (  ) A waits for VBus                 */
+#define OTG_TMR_A_WAIT_VRISE   100  /* (  ) A waits for VBus                 */
+#define OTG_TMR_A_WAIT_BCON    200  /* (  ) A waits for B-connect (1.. s)    */
+#define OTG_TMR_A_IDLE_BDIS    250  /* (ms) A waits for B-disc (200.. ms)    */
+#define OTG_TMR_B_WAIT_ADISCON 600  /* (us) B waits for A to disconnect <1ms */
+#define OTG_TMR_B_ACON_BRST    200  /* (us) B waits before starting reset    */
+#define OTG_TMR_B_ASE0_BRST    5    /* (ms) B waits for A-conn (3.125.. ms)  */
+#define OTG_TMR_B_AIDL_BDIS    50   /* (ms) B waits before dc (5..150ms)     */
+#define OTG_TMR_SRP_WAIT_SE0   2    /* (  ) B SRP idle wait                  */
+#define OTG_TMR_SRP_WAIT_DP    7    /* (ms) B SRP D_PULSE (5..10ms)          */
+#define OTG_TMR_SRP_WAIT_VP    80   /* (ms) B SRP V_PULSE (5..100ms)         */
+#define OTG_TMR_SRP_DCHRG_V    30   /* (  ) B SRP VBus discharge             */
+#define OTG_TMR_SRP_WAIT_VRS   5800 /* (ms) B SRP waits for VBus (5..6s)     */
+#define OTG_TMR_ASRP_WAIT_MP   4    /* (  ) A SRP min. pulse                 */
+#define OTG_TMR_ASRP_WAIT_DP   10   /* (ms) A SRP D_PULSE TO                 */
+#define OTG_TMR_ASRP_WAIT_VP   200  /* (ms) A SRP V_PULSE TO                 */
+#define OTG_TMR_ASRP_WAIT_DV   200  /* (  ) A SRP waits for V_PULSE          */
+#define OTG_TMR_A_BCON_VB      50   /* (  ) A waits for VBus after connect   */
+
+#define OTG_TMR_IDSNS_WAIT     10   /* (ms) ID sense wait                    */
+#define TIMER_PERIOD           1000 /* 10 ms, if longer than 10ms            */
+
+/**********************************
+ * OTG state parameters
+ **********************************/
+
+#define OTG_HOST_READY         (1<<20)   /* indicates a USB host driver is   */
+/* running                          */
+#define OTG_GADGET_READY       (1<<21)   /* indicates a USB gadget driver is */
+/* running                          */
+#define OTG_A_BUS_REQ          (1<<22)   /* used by appl-SW to request a     */
+/* VBus rise, auto-reset by driver  */
+#define OTG_A_BUS_DROP         (1<<23)   /* used by appl-SW to request a     */
+/* VBus drop, auto-reset by driver  */
+#define OTG_A_CLR_ERR          (1<<24)   /* used by appl-SW to request VBerr */
+/* clean-up, auto-reset by driver   */
+#define OTG_AB_HNP_REQ         (1<<25)   /* used by appl-SW to initiate      */
+/* HNP, auto-reset by driver        */
+#define OTG_B_BUS_REQ          (1<<26)   /* used by appl-SW to request       */
+/* B-device functionality, ...      */
+#define OTG_B_BUS_DIS          (1<<27)   /* used by appl-SW to request       */
+/* disable B-device functionality   */
+#define OTG_B_aSSN_REQ         (1<<28)   /* used by appl-SW to initiate SRP, */
+/* auto-reset by the driver         */
+#define OTG_B_SRP_ERROR        (1<<29)   /* indicates invalid HW conditions  */
+/* during SRP, reset by writing "1" */
+#define OTG_A_VBUS_FAILED      (1<<30)   /* indicates a VBus error, reset by */
+/* writing "1", when setting        */
+/* CLR_ERR or when leaving A-states */
+#define OTG_UDC_RWK_REQ        (1<<31)   /* call UDC function to force a     */
+/* remote wake-up                   */
+
+#define SW_REQUEST_MASK        (OTG_A_BUS_REQ | OTG_A_BUS_DROP | \
+		OTG_A_CLR_ERR | OTG_B_aSSN_REQ | \
+		OTG_B_BUS_REQ | OTG_B_BUS_DIS | \
+		OTG_UDC_RWK_REQ)
+
+/*********************************************************************/
+
+/*
+ * gadget events for notify function
+ */
+#define OTG_GADGET_EVT_SVDROP  (1<<0)    /* Session valid drop       */
+#define OTG_GADGET_EVT_SVALID  (1<<1)    /* Session valid            */
+#define OTG_GADGET_REQ_WAKE    (1<<2)    /* Request remote wake-up   */
+#define OTG_FLAGS_UDC_SUSP     (1<<17)   /* gadget phy suspended     */
+
+/*****************************************************************************
+ *  Data
+ *****************************************************************************/
+struct usb_otg_gadget_extension {
+	int (*request) (u32);	/* function call for state change requests */
+	u32 (*query) (int);	/* function call to query state            */
+	void (*notify) (u32);   /* filled in by gadget for notification    */
+};
+
+#endif /* AU1200_OTG_H */
diff --git a/drivers/usb/gadget/au1200_udc.c b/drivers/usb/gadget/au1200_udc.c
new file mode 100644
index 0000000..5289181
--- /dev/null
+++ b/drivers/usb/gadget/au1200_udc.c
@@ -0,0 +1,2862 @@
+/*
+ * RMI Au1200 UDC high/full speed USB device controller.
+ */
+
+/*
+ * Copyright (C) 2008 RMI Corporation (http://www.rmicorp.com)
+ * Author: Kevin Hickey (khickey@xxxxxxxxxxx)
+ *
+ * Adapted from the AMD5536 UDC module.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RMI Corporation '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 RMI 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 program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*****************************************************************************
+ * Defines
+ *****************************************************************************/
+
+/* debug control */
+/* #define UDC_DEBUG */
+/* #define UDC_VERBOSE */
+/* #define UDC_REGISTER_DUMP */
+
+/* Driver strings */
+#define UDC_MOD_DESCRIPTION         "RMI Au1200 UDC - USB Device Controller"
+
+/*****************************************************************************
+ *  Includes
+ *****************************************************************************/
+/* system */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/byteorder.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+/* MIPS config */
+#include <asm/mach-au1x00/au1xxx.h>
+
+/* gadget stack */
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+
+/* udc specific */
+#include "au1200_udc.h"
+
+/*****************************************************************************
+ *  Static Function Declarations
+ *****************************************************************************/
+static void udc_tasklet_disconnect(unsigned long);
+static void empty_req_queue(struct udc_ep *);
+static int udc_probe(struct udc *dev);
+static void udc_basic_init(struct udc *dev);
+static void udc_setup_endpoints(struct udc *dev);
+static void udc_soft_reset(struct udc *dev);
+static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq);
+static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req);
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req);
+static inline int startup_registers(struct udc *dev);
+static int udc_remote_wakeup(struct udc *dev);
+static int udc_suspend(struct udc *dev);
+static int udc_resume(struct udc *dev);
+static void udc_clear_NAK(struct udc_ep *ep);
+
+static int execute_bulk_request_with_dma(struct usb_ep *usbep,
+					 struct usb_request *usbreq, gfp_t gfp);
+
+static void udc_tasklet_execute_request(unsigned long);
+
+/*****************************************************************************
+ *  Data
+ *****************************************************************************/
+/* description */
+static const char mod_desc[] = UDC_MOD_DESCRIPTION;
+static const char name[] = DRIVER_NAME_FOR_PRINT;
+
+/* structure to hold endpoint function pointers */
+static struct usb_ep_ops udc_ep_ops;
+
+/* received setup data */
+static union udc_setup_data setup_data;
+
+/* pointer to device object */
+static struct udc       *udc;
+
+/* irq spin lock for soft reset */
+spinlock_t udc_irq_spinlock;
+/* stall spin lock */
+spinlock_t udc_stall_spinlock;
+
+/* this is used for dma chaining */
+static int udc_gfp_flags;
+
+/* count soft resets after suspend to avoid loop */
+static int soft_reset_occured;
+static int soft_reset_after_usbreset_occured;
+
+#ifdef UDC_USE_TIMER
+/* timer */
+static struct timer_list udc_timer;
+static int stop_timer;
+int set_rde = -1;
+DECLARE_COMPLETION(on_exit);
+static struct timer_list udc_pollstall_timer;
+static int stop_pollstall_timer;
+DECLARE_COMPLETION(on_pollstall_exit);
+#endif
+
+/* tasklet for usb disconnect */
+DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
+		(unsigned long)&udc);
+
+/* otg registering count */
+static u32 otg_reg_count;
+
+/* gadget registering count */
+static u32 gadget_bind_count;
+
+/* endpoint names used for print */
+static const char ep0_string[] = "ep0in";
+static const char *ep_string[] = {
+	ep0_string,
+	"ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk",
+	"ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk",
+	"ep11in-bulk", "ep12in-bulk", "ep13in-bulk", "ep14in-bulk",
+	"ep15in-bulk", "ep0out", "ep1out-bulk", "ep2out-bulk", "ep3out-bulk",
+	"ep4out-bulk", "ep5out-bulk", "ep6out-bulk", "ep7out-bulk",
+	"ep8out-bulk", "ep9out-bulk", "ep10out-bulk", "ep11out-bulk",
+	"ep12out-bulk", "ep13out-bulk", "ep14out-bulk", "ep15out-bulk"
+};
+
+
+#ifdef UDC_DEBUG
+/* data for debuging only */
+static unsigned long no_pref_req;
+static unsigned long no_req;
+static u32 same_cfg;
+static u32 num_enums;
+#endif
+
+/****** following flags can be set by module parameters */
+/* DMA usage flag */
+static int use_dma = 1;
+/* packet per buffer dma */
+static int use_dma_ppb = 1;
+/* with per descr. update */
+static int use_dma_ppb_du;
+/* buffer fill mode */
+static int use_dma_bufferfill_mode;
+/* full speed only mode */
+static int use_fullspeed;
+/* tx buffer size for high speed */
+static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE;
+
+/* module parameters */
+module_param(use_dma, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma, "true for DMA");
+module_param(use_dma_ppb, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb, "true for DMA in packet per buffer mode");
+module_param(use_dma_ppb_du, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb_du,
+	"true for DMA in packet per buffer mode with descriptor update");
+module_param(use_fullspeed, bool, S_IRUGO);
+MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only");
+module_param(hs_tx_buf, long, S_IRUGO);
+MODULE_PARM_DESC(hs_tx_buf,
+		 "high speed tx buffer size for data endpoints in dwords");
+
+MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
+MODULE_AUTHOR("Kevin Hickey");
+MODULE_LICENSE("GPL");
+
+/*****************************************************************************
+ *  Function Definitions
+ *****************************************************************************/
+/* printing registers --------------------------------------------------------*/
+/**
+ * Prints UDC device registers and endpoint irq registers
+ *
+ * \param dev pointer to device struct
+ */
+static void print_regs(struct udc *dev)
+{
+	DBG("------- Device registers -------\n");
+	DBG("dev config     = %08lx\n", (unsigned long) dev->regs->cfg);
+	DBG("dev control    = %08lx\n", (unsigned long) dev->regs->ctl);
+	DBG("dev status     = %08lx\n", (unsigned long) dev->regs->sts);
+	DBG("\n");
+	DBG("dev int's      = %08lx\n", (unsigned long) dev->regs->irqsts);
+	DBG("dev intmask    = %08lx\n", (unsigned long) dev->regs->irqmsk);
+	DBG("\n");
+	DBG("dev ep int's   = %08lx\n", (unsigned long) dev->regs->ep_irqsts);
+	DBG("dev ep intmask = %08lx\n", (unsigned long) dev->regs->ep_irqmsk);
+	DBG("\n");
+	DBG("USE DMA        = %d\n", use_dma);
+	if (use_dma) {
+		DBG("DMA mode       = ");
+		if (use_dma_ppb && !use_dma_ppb_du)
+			DBG("PPBNDU (packet per buffer w/o desc. update)\n");
+		else if (use_dma_ppb_du && use_dma_ppb_du)
+			DBG("PPBDU (packet per buffer with desc. update)\n");
+		if (use_dma_bufferfill_mode)
+			DBG("BF (buffer fill mode)\n");
+	}
+
+	if (!use_dma)
+		INFO("FIFO mode\n");
+#ifdef UDC_USE_TIMER
+	INFO("RDE timer is used\n");
+#endif
+	DBG("-------------------------------------------------------\n");
+}
+
+#ifdef UDC_DEBUG
+/**
+ * Prints misc information, to be removed
+ *
+ * \param dev           pointer to device struct
+ */
+static void print_misc(struct udc *dev)
+{
+	print_regs(dev);
+
+	if (use_dma)
+		INFO("no_req=%ld no_pref_req=%ld\n", no_req, no_pref_req);
+}
+#endif
+
+/**
+ * Masks unused interrupts
+ *
+ * \param dev           pointer to device struct
+ * \return 0 if success
+ */
+static int udc_mask_unused_interrupts(struct udc *dev)
+{
+	u32 tmp;
+
+	/* mask all dev interrupts */
+	tmp =   UDC_BIT(UDC_DEVINT_ENUM) |
+		UDC_BIT(UDC_DEVINT_US) |
+		UDC_BIT(UDC_DEVINT_UR) |
+		UDC_BIT(UDC_DEVINT_ES) |
+		UDC_BIT(UDC_DEVINT_SI) |
+		UDC_BIT(UDC_DEVINT_SOF)|
+		UDC_BIT(UDC_DEVINT_SC);
+	iowrite32(tmp, &dev->regs->irqmsk);
+
+	/* mask all ep interrupts */
+	iowrite32(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqmsk);
+
+	return 0;
+}
+
+/**
+ * Enables endpoint 0 interrupts
+ *
+ * \param dev           pointer to device struct
+ * \return 0 if success
+ */
+static int udc_enable_ep0_interrupts(struct udc *dev)
+{
+	u32 tmp;
+
+	tmp = ioread32(&dev->regs->ep_irqmsk);
+	tmp &= ~(UDC_BIT(UDC_EPINT_IN_EP0) | UDC_BIT(UDC_EPINT_OUT_EP0));
+
+	iowrite32(tmp, &dev->regs->ep_irqmsk);
+
+	return 0;
+}
+
+/**
+ * Calculates fifo start of endpoint based on preceeding endpoints
+ *
+ * \param ep           pointer to ep struct
+ * \return 0 if success
+ */
+static u32 *udc_calc_txfifo_addr(const struct udc *dev, unsigned ep_num)
+{
+	u32 tmp;
+	int i;
+	u32 *retval = dev->txfifo;
+
+	/* traverse ep's */
+	for (i = 0; i < ep_num; ++i) {
+		if (dev->ep[i].regs) {
+			/* read fifo size */
+			tmp = ioread32(&dev->ep[i].regs->bufin_framenum);
+			tmp = UDC_GETBITS(tmp, UDC_EPIN_BUFF_SIZE);
+			retval += tmp;
+		}
+	}
+	return retval;
+}
+
+/**
+ * Enables endpoint, is called by gadget driver
+ *
+ * \param usbep         pointer to ep struct
+ * \param desc          pointer to endpoint descriptor
+ * \return 0 if success
+ */
+static int udc_ep_enable(struct usb_ep *usbep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct udc_ep           *ep;
+	struct udc              *dev;
+	u32                     tmp;
+	unsigned long           iflags;
+	u8 udc_csr_epix;
+
+	VDBG("udc_enable()\n");
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (!usbep
+			|| usbep->name == ep0_string
+			|| !desc
+			|| desc->bDescriptorType != USB_DT_ENDPOINT) {
+		ERR("udc_enable: !usbep=%d !desc=%d ep->desc!=NULL=%d \
+				usbep->name==ep0_string=%d \
+				desc->bDescriptorType!=USB_DT_ENDPOINT=%d\n",
+				!usbep, !desc, ep->desc != NULL,
+				usbep->name == ep0_string,
+				desc->bDescriptorType != USB_DT_ENDPOINT);
+		return -EINVAL;
+	}
+
+	dev = ep->dev;
+
+	/* exit on suspend */
+	if (dev->sys_suspended)
+		return -ESHUTDOWN;
+
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	spin_lock_irqsave(&dev->lock, iflags);
+	ep->desc = desc;
+
+	ep->halted = 0;
+
+	/* set traffic type */
+	tmp = ioread32(&ep->regs->ctl);
+	tmp = UDC_ADDBITS(tmp, desc->bmAttributes, UDC_EPCTL_ET);
+	iowrite32(tmp, &ep->regs->ctl);
+
+	/* set max packet size */
+	tmp = ioread32(&ep->regs->bufout_maxpkt);
+	tmp = UDC_ADDBITS(tmp, desc->wMaxPacketSize, UDC_EP_MAX_PKT_SIZE);
+	ep->ep.maxpacket = desc->wMaxPacketSize;
+	iowrite32(tmp, &ep->regs->bufout_maxpkt);
+
+	/* IN ep */
+	if (ep->in) {
+		/* ep ix in UDC CSR register space */
+		udc_csr_epix = ep->num;
+
+		/* set buffer size (tx fifo entries) */
+		tmp = ioread32(&ep->regs->bufin_framenum);
+		/* double buffering: fifo size = 2 x max packet size */
+		tmp = UDC_ADDBITS(
+				tmp,
+				desc->wMaxPacketSize * UDC_EPIN_BUFF_SIZE_MULT /
+				UDC_DWORD_BYTES,
+				UDC_EPIN_BUFF_SIZE);
+		iowrite32(tmp, &ep->regs->bufin_framenum);
+
+		/* calc. tx fifo base addr */
+		ep->txfifo = udc_calc_txfifo_addr(dev, ep->num);
+
+		/* flush fifo */
+		tmp = ioread32(&ep->regs->ctl);
+		tmp |= UDC_BIT(UDC_EPCTL_F);
+		iowrite32(tmp, &ep->regs->ctl);
+
+	} /* OUT ep */
+	else {
+		/* ep ix in UDC CSR register space */
+		udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+
+		if (ep->num != UDC_EP0OUT_IX)
+			dev->data_ep_enabled = 1;
+	}
+
+	/***** UDC CSR reg ****************************/
+	/* set ep values  */
+	tmp = ioread32(&dev->csr->ne[udc_csr_epix]);
+	/* max packet */
+	tmp = UDC_ADDBITS(tmp, desc->wMaxPacketSize, UDC_CSR_NE_MAX_PKT);
+	/* ep number */
+	tmp = UDC_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM);
+	/* ep direction */
+	tmp = UDC_ADDBITS(tmp, ep->in, UDC_CSR_NE_DIR);
+	/* ep type */
+	tmp = UDC_ADDBITS(tmp, desc->bmAttributes, UDC_CSR_NE_TYPE);
+	/* ep config */
+	tmp = UDC_ADDBITS(tmp, dev->cur_config, UDC_CSR_NE_CFG);
+	/* ep interface */
+	tmp = UDC_ADDBITS(tmp, dev->cur_intf, UDC_CSR_NE_INTF);
+	/* ep alt */
+	tmp = UDC_ADDBITS(tmp, dev->cur_alt, UDC_CSR_NE_ALT);
+	/* write reg */
+	iowrite32(tmp, &dev->csr->ne[udc_csr_epix]);
+
+	/* enable ep irq */
+	tmp = ioread32(&dev->regs->ep_irqmsk);
+	tmp &= UDC_UNMASK_BIT(ep->num);
+	iowrite32(tmp, &dev->regs->ep_irqmsk);
+
+	/* clear NAK by writing CNAK */
+	/* avoid BNA for OUT DMA,  dont clear NAK until DMA desc. written */
+	if (ep->in)
+		udc_clear_NAK(ep);
+
+	DBG("%s enabled\n", usbep->name);
+
+	spin_unlock_irqrestore(&dev->lock, iflags);
+	return 0;
+}
+
+/**
+ * Enables device interrupts for SET_INTF and SET_CONFIG
+ *
+ * \param dev           pointer to device struct
+ * \return 0 if success
+ */
+static int udc_enable_dev_setup_interrupts(struct udc *dev)
+{
+	u32 tmp;
+
+	/* read irq mask */
+	tmp = ioread32(&dev->regs->irqmsk);
+
+	/* enable SET_INTERFACE, SET_CONFIG and other needed irq's */
+	tmp &= UDC_UNMASK_BIT(UDC_DEVINT_SI)
+		& UDC_UNMASK_BIT(UDC_DEVINT_SC)
+		& UDC_UNMASK_BIT(UDC_DEVINT_UR)
+		& UDC_UNMASK_BIT(UDC_DEVINT_ENUM);
+	iowrite32(tmp, &dev->regs->irqmsk);
+
+	return 0;
+}
+
+/**
+ * Resets endpoint
+ *
+ * \param regs          pointer to device register struct
+ * \param ep            pointer to endpoint
+ */
+static void ep_init(struct udc_regs *regs, struct udc_ep *ep)
+{
+	u32             tmp;
+
+	VDBG("ep-%d reset\n", ep->num);
+	ep->desc = 0;
+	ep->ep.ops = &udc_ep_ops;
+	INIT_LIST_HEAD(&ep->queue);
+
+	ep->ep.maxpacket = (u16) ~0;
+	if (!(ep->dev->sys_suspended)) {
+		/* set NAK  */
+		tmp = ioread32(&ep->regs->ctl);
+		tmp |= UDC_BIT(UDC_EPCTL_SNAK);
+		iowrite32(tmp, &ep->regs->ctl);
+		ep->naking = 1;
+
+		/* disable interrupt */
+		tmp = ioread32(&regs->ep_irqmsk);
+		tmp |= UDC_BIT(ep->num);
+		iowrite32(tmp, &regs->ep_irqmsk);
+
+		if (ep->in) {
+			/* unset P and IN bit of potential former DMA */
+			tmp = ioread32(&ep->regs->ctl);
+			tmp &= UDC_UNMASK_BIT(UDC_EPCTL_P);
+			iowrite32(tmp, &ep->regs->ctl);
+
+			tmp = ioread32(&ep->regs->sts);
+			tmp |= UDC_BIT(UDC_EPSTS_IN);
+			iowrite32(tmp, &ep->regs->sts);
+
+			/* flush the fifo */
+			tmp = ioread32(&ep->regs->ctl);
+			tmp |= UDC_BIT(UDC_EPCTL_F);
+			iowrite32(tmp, &ep->regs->ctl);
+
+		}
+		/* reset desc pointer */
+		iowrite32(0, &ep->regs->desptr);
+	}
+
+
+}
+
+/**
+ * Disables endpoint, is called by gadget driver
+ *
+ * \param usbep            pointer to ep struct
+ * \return 0 if success
+ */
+static int udc_disable(struct usb_ep *usbep)
+{
+	struct udc_ep   *ep;
+	struct udc	*dev;
+	unsigned long	iflags;
+
+	if (!usbep)
+		return -EINVAL;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	dev = ep->dev;
+
+	if (usbep->name == ep0_string || !ep->desc)
+		return -EINVAL;
+
+	DBG("Disable %s\n", usbep->name);
+
+	spin_lock_irqsave(&dev->lock, iflags);
+	empty_req_queue(ep);
+	ep_init(dev->regs, ep);
+	spin_unlock_irqrestore(&dev->lock, iflags);
+
+	return 0;
+}
+
+/**
+ * Allocates request packet, called by gadget driver
+ */
+static struct usb_request *
+udc_alloc_request(struct usb_ep *usbep, gfp_t gfp)
+{
+	struct udc_request      *req;
+	struct udc_data_dma     *dma_desc;
+	struct udc_ep   	*ep;
+	struct udc		*dev;
+
+	static int		serial;
+
+	VDBG("udc_alloc_req()\n");
+	if (!usbep)
+		return 0;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	dev = ep->dev;
+	udc_gfp_flags = gfp;
+
+	req = kmalloc(sizeof(struct udc_request), gfp);
+	if (!req)
+		return 0;
+
+	memset(req, 0, sizeof *req);
+	req->req.dma = DMA_DONT_USE;
+	INIT_LIST_HEAD(&req->queue);
+	req->ready_for_p_bit = false;
+
+	req->serial_number = serial++;
+
+	/* KH TODO: Extract to function to be used by this
+	 * and prepare_dma_chain. */
+	gfp = GFP_ATOMIC | GFP_DMA;
+	/* ep0 in requests are allocated from data pool here */
+	dma_desc = dma_pool_alloc(dev->data_requests, gfp,
+			&req->td_phys);
+	if (!dma_desc) {
+		kfree(req);
+		return 0;
+	}
+
+	VDBG("udc_alloc_req: req = %lx dma_desc = %lx, \
+			req->td_phys = %lx\n",
+			(unsigned long)req, (unsigned long) dma_desc,
+			(unsigned long)req->td_phys);
+	/* prevent from using desc. - set HOST BUSY */
+	dma_desc->status = UDC_ADDBITS(dma_desc->status,
+			UDC_DMA_STP_STS_BS_HOST_BUSY,
+			UDC_DMA_STP_STS_BS);
+	dma_desc->bufptr = __constant_cpu_to_le32(DMA_DONT_USE);
+	dma_desc->next = req->td_phys;
+	req->td_data = dma_desc;
+	req->chain_len = 1;
+
+	return &req->req;
+}
+
+/**
+ * Frees request packet, called by gadget driver
+ */
+static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+	struct udc_ep   	*ep;
+	struct udc_request      *req;
+
+	if (!usbep || !usbreq)
+		return;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	req = container_of(usbreq, struct udc_request, req);
+
+	WARN_ON(!list_empty(&req->queue));
+	if (req->td_data) {
+		if (req->chain_len > 1)
+			udc_free_dma_chain(ep->dev, req);
+
+		/* Free the first entry, not done by udc_free_dma_chain */
+		dma_pool_free(ep->dev->data_requests, req->td_data,
+			      req->td_phys);
+	}
+	kfree(req);
+}
+
+/**
+ * Completes request packet
+ */
+static void
+complete_req(struct udc_ep *ep, struct udc_request *req, int sts)
+{
+	unsigned                halted;
+
+	/* unmap DMA */
+	if (req->req.dma != DMA_DONT_USE) {
+		dma_unmap_single(0,
+				 req->req.dma,
+				 req->req.length,
+				 ep->in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+		req->req.dma = DMA_DONT_USE;
+	}
+
+	halted = ep->halted;
+	ep->halted = 1;
+
+	/* set new status if pending */
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = sts;
+
+	list_del_init(&req->queue);
+
+	req->req.complete(&ep->ep, &req->req);
+
+	up(&ep->in_use);
+	ep->halted = halted;
+}
+
+/**
+ * Frees pci pool descriptors of a DMA chain
+ */
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req)
+{
+
+	int ret_val = 0;
+	struct udc_data_dma     *td;
+	struct udc_data_dma     *td_last = NULL;
+	unsigned int i;
+
+	/* Do not free first desc., will be done by free for request */
+	td_last = req->td_data;
+	td = phys_to_virt(td_last->next);
+
+	for (i = 1; i < req->chain_len; i++) {
+
+		dma_pool_free(dev->data_requests, td,
+				(dma_addr_t) td_last->next);
+		td_last = td;
+		td = phys_to_virt(td_last->next);
+	}
+
+	return ret_val;
+}
+
+/**
+ * Iterates to the end of a DMA chain and returns last descriptor
+ */
+static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req)
+{
+	struct udc_data_dma     *td;
+
+	td = req->td_data;
+	while (td && !(td->status & UDC_BIT(UDC_DMA_IN_STS_L)))
+		td = phys_to_virt(td->next);
+
+	return td;
+
+}
+
+static inline void udc_set_rde(struct udc *dev)
+{
+	UDC_SET_BIT(UDC_DEVCTL_RDE, &dev->regs->ctl);
+}
+
+/*
+ * Print a single DMA descriptor.  Used by print_descriptor_chain.
+ */
+static void print_dma_descriptor(struct udc_data_dma *desc)
+{
+	INFO("DMA Descriptor:\n");
+	INFO("Address:0x%8.8x\n", (u32)desc);
+	INFO("Status: 0x%8.8x\n", desc->status);
+	INFO("Buffer: 0x%8.8x\n", desc->bufptr);
+	INFO("Next:   0x%8.8x\n", desc->next);
+}
+
+/*
+ * Walk and print a descriptor chain.  Useful for debugging and error output
+ */
+static void print_descriptor_chain(struct udc_ep *ep)
+{
+	struct udc_data_dma *desc = phys_to_virt(ep->regs->desptr);
+
+	INFO("DMA Descriptor Chain (%s: 0x%8.8X)\n", ep->ep.name,
+			ep->regs->desptr);
+	print_dma_descriptor(desc);
+	while (desc && !(desc->status & UDC_BIT(UDC_DMA_IN_STS_L)) &&
+		       (desc->next != ep->regs->desptr)) {
+		desc = (struct udc_data_dma *)(phys_to_virt(desc->next));
+		print_dma_descriptor(desc);
+	}
+
+}
+
+struct udc_data_dma *prepare_dma_chain(struct udc_ep *ep,
+		struct udc_request *req, gfp_t gfp)
+{
+	int i;
+	struct usb_ep *usbep = &ep->ep;
+	struct usb_request *usbreq = &req->req;
+	struct udc_data_dma *td = req->td_data;
+	struct udc_data_dma *next = NULL;
+	dma_addr_t dma_addr;
+
+	td->bufptr = usbreq->dma;
+	td->status = 0;
+	if (ep->in)
+		td->status = UDC_ADDBITS(td->status,
+				ep->ep.maxpacket,
+				UDC_DMA_IN_STS_TXBYTES);
+
+	for (i = usbep->maxpacket; i < usbreq->length; i += usbep->maxpacket) {
+		if (td->next == (u32)req->td_phys) {
+			next = dma_pool_alloc(ep->dev->data_requests,
+					gfp, &dma_addr);
+			if (next == NULL) {
+				ERR("%s allocation failed!\n", __func__);
+				return NULL;
+			}
+
+			++req->chain_len;
+			/* Last points to first */
+			next->next = (u32)req->td_phys;
+			td->next = dma_addr;
+		} else {
+			next = (struct udc_data_dma *)phys_to_virt(td->next);
+		}
+
+		next->bufptr = usbreq->dma + i;
+		next->status = 0;
+		if (ep->in)
+			next->status = UDC_ADDBITS(next->status,
+						   ep->ep.maxpacket,
+						   UDC_DMA_IN_STS_TXBYTES);
+		td = next;
+	}
+
+	return td;
+}
+
+static void udc_clear_NAK(struct udc_ep *ep)
+{
+	u32 tmp = ioread32(&ep->regs->ctl);
+	int i = 0;
+
+	while (tmp & UDC_BIT(UDC_EPCTL_NAK)) {
+		tmp |= UDC_BIT(UDC_EPCTL_CNAK);
+		iowrite32(tmp, &ep->regs->ctl);
+		au_sync();
+
+		udelay(100);
+		tmp = ioread32(&ep->regs->ctl);
+		++i;
+		if (i % 100 == 0)
+			INFO("Tried to CNAK %d times.\n", i);
+	}
+
+	ep->naking = 0;
+}
+
+static int execute_bulk_request_with_dma(struct usb_ep *usbep,
+					  struct usb_request *usbreq, gfp_t gfp)
+{
+	int			retval;
+	struct udc 		*dev;
+	struct udc_ep 		*ep;
+	struct udc_request	*req;
+	unsigned long 		iflags;
+	struct udc_data_dma	*td;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	req = container_of(usbreq, struct udc_request, req);
+	dev = ep->dev;
+	td = req->td_data;		/* For notational convenience */
+
+	/* We don't want the isr to start acting on this request while we're
+	 * setting it up.  */
+	spin_lock_irqsave(&dev->lock, iflags);
+
+	usbreq->actual = 0;
+	usbreq->status = -EINPROGRESS;
+
+	/* Map the buffer allocated for the request into DMA space.
+	 * Remember that the CPU should not access this memory until it is
+	 * unmapped.  */
+	if (usbreq->length > 0 && usbreq->dma == DMA_DONT_USE) {
+		usbreq->dma = dma_map_single(dev->pdev,
+					     usbreq->buf,
+					     usbreq->length,
+			ep->in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+	}
+
+	td = prepare_dma_chain(ep, req, gfp);
+	if (td == NULL) {
+		retval = -ENOMEM;
+		goto finish;
+	}
+
+	if (ep->in && usbreq->length % usbep->maxpacket != 0)
+		td->status = UDC_ADDBITS(td->status,
+					usbreq->length % usbep->maxpacket,
+					UDC_DMA_IN_STS_TXBYTES);
+
+	td->status |= UDC_BIT(UDC_DMA_OUT_STS_L);
+
+	/* Set the endpoint descriptor register to start the transfer */
+	iowrite32((u32)req->td_phys, &ep->regs->desptr);
+	au_sync();
+
+	udc_clear_NAK(ep);
+
+finish:
+	spin_unlock_irqrestore(&dev->lock, iflags);
+	return retval;
+}
+
+static void udc_tasklet_execute_request(unsigned long ep_as_ul)
+{
+	struct udc_ep *ep = (struct udc_ep *)ep_as_ul;
+	struct udc_request *req;
+
+	down(&ep->in_et);
+
+	if (!list_empty(&ep->queue) && !down_trylock(&ep->in_use)) {
+		req = list_entry(ep->queue.next, struct udc_request, queue);
+
+		execute_bulk_request_with_dma(&ep->ep, &req->req,
+				udc_gfp_flags);
+		if (ep->in)
+			UDC_UNSET_BIT(ep->num, &ep->dev->regs->ep_irqmsk);
+		else
+			udc_set_rde(ep->dev);
+
+		/* Harmless to do on out EPs and saves a branch */
+		req->ready_for_p_bit = true;
+	}
+
+	up(&ep->in_et);
+}
+
+/**
+ * Queues a request packet, called by gadget driver
+ */
+static int udc_queue(struct usb_ep *usbep, struct usb_request *usbreq,
+		gfp_t gfp)
+{
+	int retval = 0;
+	unsigned long           iflags = 0;
+	struct udc_ep   	*ep;
+	struct udc_request      *req;
+	struct udc              *dev;
+
+	/* check the inputs */
+
+	if (!usbep || !usbreq || !usbreq->complete || !usbreq->buf)
+		return -EINVAL;
+
+	req = container_of(usbreq, struct udc_request, req);
+	ep = container_of(usbep, struct udc_ep, ep);
+	dev = ep->dev;
+
+	if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+		return -EINVAL;
+
+	/* exit on suspend */
+	if (dev->sys_suspended)
+		return -ESHUTDOWN;
+
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	spin_lock_irqsave(&dev->lock, iflags);
+	if (ep->num != UDC_EP0OUT_IX && ep->num != UDC_EP0IN_IX) {
+		list_add_tail(&req->queue, &ep->queue);
+		tasklet_schedule(&ep->execute_tasklet);
+		goto finished;
+	} else {
+		if (usbreq->length > 0) {
+			list_add_tail(&req->queue, &ep->queue);
+			execute_bulk_request_with_dma(usbep, usbreq, gfp);
+			UDC_UNSET_BIT(ep->num, &dev->regs->ep_irqmsk);
+			goto finished;
+		} else {
+			/* IN zlp's are handled by hardware */
+			complete_req(ep, req, 0);
+			if (dev->set_cfg_not_acked) {
+				UDC_SET_BIT(UDC_DEVCTL_CSR_DONE,
+						&dev->regs->ctl);
+				dev->set_cfg_not_acked = 0;
+			}
+			goto finished;
+		}
+	}
+
+finished:
+	spin_unlock_irqrestore(&dev->lock, iflags);
+	return retval;
+}
+
+/**
+ * Empty request queue of an endpoint
+ */
+static void empty_req_queue(struct udc_ep *ep)
+{
+	struct udc_request      *req;
+
+	ep->halted = 1;
+	while (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next,
+				struct udc_request,
+				queue);
+		complete_req(ep, req, -ESHUTDOWN);
+	}
+}
+
+/**
+ * Dequeues a request packet, called by gadget driver
+ */
+static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+	struct udc_ep   	*ep;
+	struct udc_request      *req;
+	unsigned long           iflags;
+
+	if (!usbep || !usbreq)
+		return -EINVAL;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+		return -EINVAL;
+
+	req = container_of(usbreq, struct udc_request, req);
+
+	spin_lock_irqsave(&ep->dev->lock, iflags);
+	complete_req(ep, req, -ECONNRESET);
+	spin_unlock_irqrestore(&ep->dev->lock, iflags);
+
+	return 0;
+}
+
+/**
+ * Halt or clear halt of endpoint, called by gadget driver
+ */
+static int udc_set_halt(struct usb_ep *usbep, int halt)
+{
+	struct udc_ep   *ep;
+	unsigned long iflags;
+	int retval = 0;
+
+	if (!usbep)
+		return -EINVAL;
+
+	DBG("set_halt %s: halt=%d\n", usbep->name, halt);
+
+	/* TODO: DRY */
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+		return -EINVAL;
+	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+	if (ep->dev->sys_suspended)
+		return -ESHUTDOWN;
+
+	spin_lock_irqsave(&udc_stall_spinlock, iflags);
+	/* halt or clear halt */
+	if (halt) {
+		if (ep->num != 0) {
+			UDC_SET_BIT(UDC_EPCTL_S, &ep->regs->ctl);
+			ep->halted = 1;
+		}
+	} else {
+		if (ep->halted) {
+			UDC_UNSET_BIT(UDC_EPCTL_S, &ep->regs->ctl);
+			udc_clear_NAK(ep);
+			ep->halted = 0;
+		}
+	}
+	spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
+	return retval;
+}
+
+/**
+ * Return fifo fill state, called by gadget driver
+ * This is equivalent to unimplemented
+ */
+static int udc_fifo_status(struct usb_ep *usbep)
+{
+	return 0;
+}
+
+/**
+ * Flush the endpoint fifo, called by gadget driver
+ * This is equivalent to unimplemented
+ */
+static void udc_fifo_flush(struct usb_ep *usbep)
+{
+	return;
+}
+
+static struct usb_ep_ops udc_ep_ops = {
+	.enable         = udc_ep_enable,
+	.disable        = udc_disable,
+
+	.queue          = udc_queue,
+	.dequeue        = udc_dequeue,
+
+	.alloc_request  = udc_alloc_request,
+	.free_request   = udc_free_request,
+
+	.set_halt       = udc_set_halt,
+	.fifo_status    = udc_fifo_status,
+	.fifo_flush     = udc_fifo_flush,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * Get frame count fifo, called by gadget driver
+ * This is equivalent to unimplemented
+ */
+static int udc_get_frame(struct usb_gadget *gadget)
+{
+	return 0;
+}
+
+/**
+ * Remote wakeup gadget interface
+ */
+static int udc_wakeup(struct usb_gadget *gadget)
+{
+	struct udc              *dev;
+
+	if (!gadget)
+		return -EINVAL;
+	dev = container_of(gadget, struct udc, gadget);
+	udc_remote_wakeup(dev);
+
+	return 0;
+}
+
+/**
+ * gadget ioctl, used for OTG support notification
+ * \return 1 if OTG supported, else 0
+ */
+static int udc_gadget_ioctl(struct usb_gadget *gadget, unsigned cmd,
+			     unsigned long par)
+{
+	struct udc              *dev;
+	int                     retval = 0;
+	unsigned long           iflags;
+	u32 tmp;
+
+	if (!gadget)
+		return -ENODEV;
+	dev = container_of(gadget, struct udc, gadget);
+	spin_lock_irqsave(&dev->lock, iflags);
+	tmp = ioread32(&dev->regs->cfg);
+
+	if (tmp & UDC_BIT(UDC_DEVCFG_HNPSFEN))
+		retval = 1;
+	else
+		retval = 0;
+	spin_unlock_irqrestore(&dev->lock, iflags);
+	return retval;
+}
+
+static const struct usb_gadget_ops udc_ops = {
+	.wakeup         = udc_wakeup,
+	.get_frame      = udc_get_frame,
+	.ioctl          = udc_gadget_ioctl,
+};
+
+/**
+ * Setups endpoint parameters, adds endpoints to linked list
+ */
+static void make_ep_lists(struct udc *dev)
+{
+	/* make gadget ep lists */
+	INIT_LIST_HEAD(&dev->gadget.ep_list);
+	list_add_tail(&dev->ep[UDC_EPIN_STATUS_IX].ep.ep_list,
+		      &dev->gadget.ep_list);
+	list_add_tail(&dev->ep[UDC_EPIN_IX].ep.ep_list, &dev->gadget.ep_list);
+	list_add_tail(&dev->ep[UDC_EPOUT_IX].ep.ep_list,
+		       &dev->gadget.ep_list);
+
+	/* fifo config */
+	dev->ep[UDC_EPIN_STATUS_IX].fifo_depth = UDC_EPIN_SMALLINT_BUFF_SIZE;
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		dev->ep[UDC_EPIN_IX].fifo_depth = UDC_FS_EPIN_BUFF_SIZE;
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		dev->ep[UDC_EPIN_IX].fifo_depth = hs_tx_buf;
+	dev->ep[UDC_EPOUT_IX].fifo_depth = UDC_RXFIFO_SIZE;
+}
+
+/**
+ * Init registers at driver load time
+ */
+static int startup_registers(struct udc *dev)
+{
+	u32 tmp;
+	DBG("In startup_registers()\n");
+
+	/* init controller by soft reset */
+	udc_soft_reset(dev);
+
+	/* mask not needed interrupts */
+	udc_mask_unused_interrupts(dev);
+
+	/* put into initial config */
+	udc_basic_init(dev);
+	/* link up all endpoints */
+	udc_setup_endpoints(dev);
+
+	/* program speed */
+	tmp = ioread32(&dev->regs->cfg);
+	if (use_fullspeed)
+		tmp = UDC_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+	else
+		tmp = UDC_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
+	iowrite32(tmp, &dev->regs->cfg);
+
+	DBG("After speed program\n");
+
+	return 0;
+}
+
+/**
+ * Inits UDC context
+ */
+static void udc_basic_init(struct udc *dev)
+{
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+	/* disable DMA */
+	UDC_UNSET_BIT(UDC_DEVCTL_RDE, &dev->regs->ctl);
+	UDC_UNSET_BIT(UDC_DEVCTL_TDE, &dev->regs->ctl);
+
+	/* enable dynamic CSR programming */
+	UDC_SET_BITS((UDC_BIT(UDC_DEVCFG_CSR_PRG) |
+		      UDC_BIT(UDC_DEVCFG_SP) |
+		      UDC_BIT(UDC_DEVCFG_RWKP)),
+		     &dev->regs->cfg);
+
+	make_ep_lists(dev);
+
+	dev->data_ep_enabled = 0;
+	dev->data_ep_queued = 0;
+}
+
+/**
+ * Sets initial endpoint parameters
+ *
+ * \param dev           pointer to device struct
+ */
+static void udc_setup_endpoints(struct udc *dev)
+{
+	struct udc_ep   *ep;
+	u32     tmp;
+
+	DBG("udc_setup_endpoints()\n");
+
+	/* read enum speed */
+	tmp = ioread32(&dev->regs->sts);
+	tmp = UDC_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED);
+	if (tmp ==  UDC_DEVSTS_ENUM_SPEED_HIGH)
+		dev->gadget.speed = USB_SPEED_HIGH;
+	else if (tmp ==  UDC_DEVSTS_ENUM_SPEED_FULL)
+		dev->gadget.speed = USB_SPEED_FULL;
+
+	/* set basic ep parameters */
+	for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+		ep = &dev->ep[tmp];
+		ep->dev = dev;
+		ep->ep.name = ep_string[tmp];
+		ep->num = tmp;
+		/* txfifo size is calculated at enable time */
+		ep->txfifo = dev->txfifo;
+
+		/* fifo size */
+		if (tmp < UDC_EPIN_NUM) {
+			ep->fifo_depth = UDC_TXFIFO_SIZE;
+			ep->in = 1;
+		} else {
+			ep->fifo_depth = UDC_RXFIFO_SIZE;
+			ep->in = 0;
+
+		}
+		ep->regs = &dev->ep_regs[tmp];
+		/* ep will be reset only if ep was not enabled before to avoid
+		   disabling ep interrupts when ENUM interrupt occurs but ep is
+		   not enabled by gadget driver  */
+		if (!ep->desc)
+			ep_init(dev->regs, ep);
+
+		/* nak OUT endpoints until enable - not for ep0*/
+		if (tmp > UDC_EPIN_NUM) {
+			UDC_SET_BIT(UDC_EPCTL_SNAK, &ep->regs->ctl);
+			ep->naking = 1;
+		}
+	}
+
+	DBG("Done setting up ep params\n");
+
+	/* EP0 max packet */
+	if (dev->gadget.speed == USB_SPEED_FULL) {
+		dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_FS_EP0IN_MAX_PKT_SIZE;
+		dev->ep[UDC_EP0OUT_IX].ep.maxpacket =
+			UDC_FS_EP0OUT_MAX_PKT_SIZE;
+	} else if (dev->gadget.speed == USB_SPEED_HIGH) {
+		dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
+		dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
+	}
+
+	DBG("Done setting up EP0 max packet\n");
+
+	/* with suspend bug workaround, ep0 params for gadget driver
+	   are set at gadget driver bind() call */
+	dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+	dev->ep[UDC_EP0IN_IX].halted = 0;
+	INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+
+	/* init cfg/alt/int */
+	dev->cur_config = 0;
+	dev->cur_intf = 0;
+	dev->cur_alt = 0;
+
+	DBG("udc_setup_endpoints done\n");
+}
+
+/**
+ * Bringup after Connect event,
+ * initial bringup to be ready for ep0 events
+ */
+static void usb_connect(struct udc *dev)
+{
+	INFO("USB Connect\n");
+
+	dev->connected = 1;
+
+	/* put into initial config */
+	udc_basic_init(dev);
+
+	/* enable device setup interrupts */
+	udc_enable_dev_setup_interrupts(dev);
+}
+
+/**
+ * Calls gadget with disconnect event and resets the UDC and makes
+ * initial bringup to be ready for ep0 events
+ */
+static void usb_disconnect(struct udc *dev)
+{
+	INFO("USB Disconnect\n");
+
+	dev->connected = 0;
+
+	/* mask interrupts */
+	udc_mask_unused_interrupts(dev);
+
+	tasklet_schedule(&disconnect_tasklet);
+}
+
+/**
+ * Tasklet for disconnect to be outside of interrupt
+ * context
+ */
+static void udc_tasklet_disconnect(unsigned long par)
+{
+	struct udc *dev = (struct udc *)(*((struct udc **) par));
+	u32 tmp;
+
+	DBG("Tasklet disconnect\n");
+	if (dev->driver) {
+		/* call gadget to reset configs etc. */
+		if (spin_is_locked(&dev->lock)) {
+			spin_unlock(&dev->lock);
+			dev->driver->disconnect(&dev->gadget);
+			spin_lock(&dev->lock);
+		} else
+			dev->driver->disconnect(&dev->gadget);
+
+		/* empty queues */
+		for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
+			empty_req_queue(&dev->ep[tmp]);
+	}
+
+	/* disable ep0 */
+	ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+	if (!soft_reset_occured) {
+		/* init controller by soft reset */
+		udc_soft_reset(dev);
+		soft_reset_occured++;
+	}
+	/* re-enable dev interrupts */
+	udc_enable_dev_setup_interrupts(dev);
+	/* back to full speed ? */
+	if (use_fullspeed) {
+		tmp = ioread32(&dev->regs->cfg);
+		tmp = UDC_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+		iowrite32(tmp, &dev->regs->cfg);
+	}
+}
+
+/**
+ * Reset the UDC core
+ */
+static void udc_soft_reset(struct udc *dev)
+{
+	DBG("Soft reset\n");
+	/* reset possible waiting interrupts, because int.
+	   status is lost after soft reset */
+	/* ep int. status reset */
+	iowrite32(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqsts);
+	/* device int. status reset */
+	iowrite32(UDC_DEV_MSK_DISABLE, &dev->regs->irqsts);
+
+	spin_lock_irq(&udc_irq_spinlock);
+	iowrite32(UDC_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+	ioread32(&dev->regs->cfg);
+	spin_unlock_irq(&udc_irq_spinlock);
+
+}
+
+/**
+ * Called by OTG driver to notify us regarding an OTG event
+ *
+ * \param code           notify code
+ */
+void otg_notify(unsigned int code)
+{
+	DBG("OTG notify code=%d\n", code);
+	switch (code) {
+	case OTG_GADGET_EVT_SVDROP:
+		/* disconnect event */
+		usb_disconnect(udc);
+		break;
+	case OTG_GADGET_EVT_SVALID:
+		/* connect event */
+		usb_connect(udc);
+		break;
+	case OTG_GADGET_REQ_WAKE:
+		/* remote wakeup event */
+		udc_remote_wakeup(udc);
+		break;
+	}
+}
+
+/**
+ * Inits endpoint 0 so that SETUP packets are processed
+ *
+ * \param dev           pointer to device struct
+ */
+static void activate_control_endpoints(struct udc *dev)
+{
+	u32 tmp;
+	struct udc_ep 	*ep0in = &dev->ep[UDC_EP0IN_IX];
+	struct udc_ep 	*ep0out = &dev->ep[UDC_EP0OUT_IX];
+
+	DBG("activate_control_endpoints\n");
+
+	/* flush fifo */
+	UDC_SET_BIT(UDC_EPCTL_F, &ep0in->regs->ctl);
+
+	/* set ep0 directions */
+	ep0in->in = 1;
+	ep0out->in = 0;
+
+	/* set buffer size (tx fifo entries) of EP0_IN */
+	tmp = ioread32(&ep0in->regs->bufin_framenum);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp = UDC_ADDBITS(tmp, UDC_FS_EPIN0_BUFF_SIZE,
+		      UDC_EPIN_BUFF_SIZE);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp = UDC_ADDBITS(tmp, UDC_EPIN0_BUFF_SIZE, UDC_EPIN_BUFF_SIZE);
+	iowrite32(tmp, &ep0in->regs->bufin_framenum);
+
+	/* set max packet size of EP0_IN */
+	tmp = ioread32(&ep0in->regs->bufout_maxpkt);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp = UDC_ADDBITS(tmp, UDC_FS_EP0IN_MAX_PKT_SIZE,
+				  UDC_EP_MAX_PKT_SIZE);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp = UDC_ADDBITS(tmp, UDC_EP0IN_MAX_PKT_SIZE,
+				  UDC_EP_MAX_PKT_SIZE);
+	iowrite32(tmp, &ep0in->regs->bufout_maxpkt);
+
+	/* set max packet size of EP0_OUT */
+	tmp = ioread32(&ep0out->regs->bufout_maxpkt);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp = UDC_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+				  UDC_EP_MAX_PKT_SIZE);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp = UDC_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+				  UDC_EP_MAX_PKT_SIZE);
+	iowrite32(tmp, &ep0out->regs->bufout_maxpkt);
+
+	/* set max packet size of EP0 in UDC CSR  */
+	tmp = ioread32(&dev->csr->ne[0]);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp = UDC_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+				  UDC_CSR_NE_MAX_PKT);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp = UDC_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+				  UDC_CSR_NE_MAX_PKT);
+	iowrite32(tmp, &dev->csr->ne[0]);
+
+	ep0out->td->status |= UDC_BIT(UDC_DMA_OUT_STS_L);
+	/* write dma desc address */
+	iowrite32(ep0out->td_stp_dma, &ep0out->regs->subptr);
+	iowrite32(ep0out->td_phys, &ep0out->regs->desptr);
+	/* enable DMA */
+	UDC_SET_BITS((UDC_BIT(UDC_DEVCTL_MODE)
+		      | UDC_BIT(UDC_DEVCTL_RDE)
+		      | UDC_BIT(UDC_DEVCTL_TDE)),
+		     &dev->regs->ctl);
+
+	if (use_dma_bufferfill_mode)
+		UDC_SET_BIT(UDC_DEVCTL_BF, &dev->regs->ctl);
+	else if (use_dma_ppb_du)
+		UDC_SET_BIT(UDC_DEVCTL_DU, &dev->regs->ctl);
+
+	/* clear NAK by writing CNAK for EP0IN */
+	udc_clear_NAK(ep0in);
+	udc_clear_NAK(ep0out);
+}
+
+/**
+ * \brief
+ * Make endpoint 0 ready for control traffic
+ */
+static int setup_ep0(struct udc *dev)
+{
+	activate_control_endpoints(dev);
+	/* enable ep0 interrupts */
+	udc_enable_ep0_interrupts(dev);
+	/* enable device setup interrupts */
+	udc_enable_dev_setup_interrupts(dev);
+
+	return 0;
+}
+
+/**
+ * Called by gadget driver to register itself
+ */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct udc              *dev = udc;
+	int                     retval;
+	u32 tmp;
+
+	DBG("In usb_gadget_register_driver\n");
+
+	DBG("Driver speed is %d\n", driver->speed);
+	if (!driver || !driver->bind
+			|| !driver->unbind
+			|| !driver->setup
+			|| driver->speed != USB_SPEED_HIGH)
+		return -EINVAL;
+	if (!dev)
+		return -ENODEV;
+	if (dev->driver)
+		return -EBUSY;
+
+	driver->driver.bus = 0;
+	dev->driver = driver;
+	dev->gadget.dev.driver = &driver->driver;
+
+	device_create_file(&dev->pdev->dev, &dev_attr_function);
+	device_create_file(&dev->pdev->dev, &dev_attr_queues);
+
+#ifdef CONFIG_USB_OTG
+	DBG("Gadget is OTG\n");
+	dev->gadget.is_otg = 1;
+#endif
+	retval = driver->bind(&dev->gadget);
+	/* e.g. ether gadget needs driver_data on both ep0 endpoints */
+	dev->ep[UDC_EP0OUT_IX].ep.driver_data =
+		dev->ep[UDC_EP0IN_IX].ep.driver_data;
+
+	gadget_bind_count++;
+	if (retval) {
+		DBG("binding to  %s returning %d\n",
+				driver->driver.name, retval);
+		dev->driver = 0;
+		dev->gadget.dev.driver = 0;
+		return retval;
+	} else {
+		DBG("Binding successful\n");
+	}
+
+	/* if otg driver already registered */
+	/* call otg bind() to mux udc to phy */
+	if (dev->otg_transceiver) {
+		dev->otg_transceiver->set_peripheral(
+				dev->otg_transceiver, &dev->gadget);
+		/* clear SD */
+		tmp = ioread32(&dev->regs->ctl);
+		tmp = tmp & UDC_CLEAR_BIT(UDC_DEVCTL_SD);
+		iowrite32(tmp, &dev->regs->ctl);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+/**
+ * Called by OTG driver to register itself
+ */
+int usb_gadget_register_otg(struct otg_transceiver *(*get_transceiver)(void))
+{
+	struct udc              *dev = udc;
+	int                     retval;
+	u32 tmp;
+
+	if (!get_transceiver)
+		return -EINVAL;
+	if (!dev)
+		return -ENODEV;
+	if (dev->otg_transceiver)
+		return -EBUSY;
+
+	dev->otg_transceiver = get_transceiver();
+
+	if (!dev->otg_transceiver->otg_priv)
+		return -EINVAL;
+	dev->otg_driver = (struct usb_otg_gadget_extension *)
+		dev->otg_transceiver->otg_priv;
+
+	/* init registers here first with suspend bug */
+	if (!otg_reg_count) {
+		startup_registers(dev);
+		otg_reg_count++;
+	}
+
+	/* set notify function */
+	dev->otg_driver->notify = otg_notify;
+	DBG("otg_driver->notify set.\n");
+	/* if gadget driver already registered */
+	/* call gadget bind() to switch to mux udc to phy */
+	if (dev->driver) {
+		/* otg driver bind() */
+		retval = dev->otg_transceiver->set_peripheral(
+				dev->otg_transceiver, &dev->gadget);
+		if (retval) {
+			DBG("error bind to uoc driver\n");
+			dev->otg_driver = NULL;
+			dev->otg_transceiver = NULL;
+			return retval;
+		}
+		/* get ready for ep0 traffic */
+		setup_ep0(dev);
+
+		/* clear SD */
+		tmp = ioread32(&dev->regs->ctl);
+		tmp = tmp & UDC_CLEAR_BIT(UDC_DEVCTL_SD);
+		iowrite32(tmp, &dev->regs->ctl);
+	}
+
+	INFO("registered uoc driver\n");
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_register_otg);
+
+/**
+ * Called by OTG driver to unregister itself
+ */
+int usb_gadget_unregister_otg(void)
+{
+	struct udc      *dev = udc;
+	unsigned long   flags;
+
+	if (!dev)
+		return -ENODEV;
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	/* mask not needed interrupts */
+	udc_mask_unused_interrupts(dev);
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	dev->otg_supported = 0;
+	if (dev->otg_transceiver) {
+		dev->otg_transceiver->set_peripheral(dev->otg_transceiver,
+				NULL);
+		dev->otg_transceiver = NULL;
+	}
+	if (dev->otg_driver) {
+		dev->otg_driver->notify = NULL;
+		dev->otg_driver = NULL;
+	}
+
+	/* set SD */
+	UDC_SET_BIT(UDC_DEVCTL_SD, &dev->regs->ctl);
+
+	DBG("unregistered uoc driver\n");
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_otg);
+
+/**
+ *  shutdown requests and disconnect from gadget
+ */
+static void shutdown(struct udc *dev, struct usb_gadget_driver *driver)
+{
+	int tmp;
+
+	/* empty queues and init hardware */
+	udc_basic_init(dev);
+	for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
+		empty_req_queue(&dev->ep[tmp]);
+
+	if (dev->gadget.speed != USB_SPEED_UNKNOWN)
+		driver->disconnect(&dev->gadget);
+	udc_setup_endpoints(dev);
+}
+
+/**
+ * Called by gadget driver to unregister itself
+ */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct udc      *dev = udc;
+	unsigned long   iflags;
+
+	if (!dev)
+		return -ENODEV;
+	if (!driver || driver != dev->driver)
+		return -EINVAL;
+	if (gadget_bind_count) {
+		spin_lock_irqsave(&dev->lock, iflags);
+		shutdown(dev, driver);
+		spin_unlock_irqrestore(&dev->lock, iflags);
+	}
+
+	/* unbind from otg driver first */
+	if (dev->otg_transceiver) {
+		dev->otg_transceiver->set_peripheral(
+				dev->otg_transceiver, NULL);
+	}
+
+	if (gadget_bind_count)
+		driver->unbind(&dev->gadget);
+
+	gadget_bind_count = 0;
+	dev->driver = 0;
+
+	/* set SD */
+	UDC_SET_BIT(UDC_DEVCTL_SD, &dev->regs->ctl);
+	DBG("%s: unregistered\n", driver->driver.name);
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+void update_req_count(struct udc_request *req)
+{
+	struct udc_data_dma *last_desc;
+	unsigned int count;
+	unsigned int tmp;
+
+	last_desc = udc_get_last_dma_desc(req);
+	count = UDC_GETBITS(last_desc->status, UDC_DMA_OUT_STS_RXBYTES);
+	if (count == 0) {
+		/* on 64k packets the RXBYTES field is zero */
+		if (req->req.length == UDC_DMA_MAXPACKET)
+			count = UDC_DMA_MAXPACKET;
+	}
+
+	VDBG("Received %lx bytes\n", (unsigned long) count);
+
+	tmp = req->req.length - req->req.actual;
+	if (count > tmp) {
+		ERR("Buffer overrun!\n");
+		req->req.status = -EOVERFLOW;
+		count = tmp;
+	}
+
+	req->req.actual += count;
+}
+
+/**
+ * Check for and clear BNA and Hardware errors
+ * returns nonzero if any errors were found
+ */
+static inline int check_and_clear_errors(struct udc_ep *ep)
+{
+	u32 				epsts;
+
+	epsts = ioread32(&ep->regs->sts);
+	/* BNA event */
+	if (epsts & UDC_BIT(UDC_EPSTS_BNA)) {
+		ERR("BNA occurred - %s: desptr = 0x%8.8x\n", ep->ep.name,
+		       ep->regs->desptr);
+		UDC_SET_BIT(UDC_EPSTS_BNA, &ep->regs->sts);
+		return 1;
+	}
+
+	/* HE event */
+	if (epsts & UDC_BIT(UDC_EPSTS_HE)) {
+		ERR("HE occured on %s\n", ep->ep.name);
+		UDC_SET_BIT(UDC_EPSTS_HE, &ep->regs->sts);
+		return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * Interrupt handler for data OUT traffic
+ */
+static inline int udc_data_out_isr(struct udc *dev, int ep_ix)
+{
+	int 				ret_val = 0;
+	u32				tmp;
+	struct udc_ep   		*ep;
+	struct udc_request              *req;
+	unsigned long 			iflags;
+	struct udc_data_dma 		*last_desc;
+	unsigned 			dma_done;
+
+	VDBG("ep%d irq\n", ep_ix);
+	ep = &dev->ep[ep_ix];
+
+	spin_lock_irqsave(&dev->lock, iflags);
+
+	tmp = ioread32(&ep->regs->sts);
+	/* BNA event ? */
+	if (tmp & UDC_BIT(UDC_EPSTS_BNA)) {
+		ERR("BNA occurred - %s: desptr = 0x%8.8x\n", ep->ep.name,
+		       ep->regs->desptr);
+		/* clear BNA */
+		ep->regs->sts = UDC_BIT(UDC_EPSTS_BNA);
+		au_sync();
+		goto finished;
+	}
+
+	/* HE event ? */
+	if (tmp & UDC_BIT(UDC_EPSTS_HE)) {
+		ERR("HE occured on %s\n", ep->ep.name);
+
+		/* clear HE */
+		ep->regs->sts = UDC_BIT(UDC_EPSTS_HE);
+		au_sync();
+
+		ret_val = 1;
+		goto finished;
+	}
+
+	/*
+	epsts = ioread32(&ep->regs->sts);
+	if (check_and_clear_errors(ep))
+		goto finished;
+		*/
+
+	if (!list_empty(&ep->queue))
+		req = list_entry(ep->queue.next, struct udc_request, queue);
+	else {
+		INFO("In %s but there is no queued request.\n", __func__);
+		goto finished;
+	}
+
+	/* check for DMA done */
+	last_desc = udc_get_last_dma_desc(req);
+	dma_done = UDC_GETBITS(last_desc->status, UDC_DMA_OUT_STS_BS);
+
+	if (dma_done == UDC_DMA_OUT_STS_BS_DMA_DONE) {
+		update_req_count(req);
+		complete_req(ep, req, 0);
+		tasklet_schedule(&ep->execute_tasklet);
+	} else {
+		INFO("Got a DMA done interrupt but DMA is not done.\n");
+		print_descriptor_chain(ep);
+	}
+
+finished:
+	/* clear OUT bits in ep status */
+	ep->regs->sts = UDC_EPSTS_OUT_CLEAR;
+	au_sync();
+
+	spin_unlock_irqrestore(&dev->lock, iflags);
+	return ret_val;
+}
+
+/**
+ * Interrupt handler for data IN traffic
+ */
+static inline int udc_data_in_isr(struct udc *dev, int ep_ix)
+{
+	int ret_val = 0;
+	u32 epsts;
+	struct udc_ep  *ep;
+	unsigned long 			iflags;
+	struct udc_request *req;
+
+	spin_lock_irqsave(&dev->lock, iflags);
+
+	ep = &dev->ep[ep_ix];
+	epsts = ioread32(&ep->regs->sts);
+
+	/* BNA */
+	if (epsts & UDC_BIT(UDC_EPSTS_BNA)) {
+		ERR("BNA ep%din occured - DESPTR = %08lx \n", ep->num,
+			(long unsigned int)ep->regs->desptr);
+
+		/* clear BNA */
+		ep->regs->sts = UDC_BIT(UDC_EPSTS_BNA);
+		au_sync();
+
+		goto finished;
+	}
+
+	/* HE event */
+	if (epsts & UDC_BIT(UDC_EPSTS_HE)) {
+		ERR("HE occured on %s\n", ep->ep.name);
+
+		/* clear HE */
+		ep->regs->sts = UDC_BIT(UDC_EPSTS_HE);
+		au_sync();
+
+		ret_val = 1;
+		goto finished;
+	}
+	/*
+	epsts = ioread32(&ep->regs->sts);
+	if (check_and_clear_errors(ep))
+		goto finished;
+		*/
+
+	if (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct udc_request, queue);
+	} else {
+		/* This is not all that unusual - the host can be greedy when
+		 * it wants IN data and might beat the gadget to queueing a
+		 * request.
+		 */
+		goto finished;
+	}
+
+	/* DMA completion */
+	if (epsts & UDC_BIT(UDC_EPSTS_TDC)) {
+		/* Disable this IRQ to prevent flooding */
+		dev->regs->ep_irqmsk |= UDC_BIT(ep->num);
+		au_sync();
+
+		complete_req(ep, req, 0);
+		tasklet_schedule(&ep->execute_tasklet);
+	}
+
+	if (epsts & UDC_BIT(UDC_EPSTS_IN)) {
+		/* set poll demand bit */
+		if (req->ready_for_p_bit) {
+			req->ready_for_p_bit = false;
+			ep->regs->ctl |= UDC_BIT(UDC_EPCTL_P);
+			au_sync();
+		}
+	}
+
+finished:
+	/* clear status bits */
+	UDC_SET_BITS(epsts, &ep->regs->sts);
+	spin_unlock_irqrestore(&dev->lock, iflags);
+	return ret_val;
+}
+
+/**
+ * Interrupt handler for Control OUT traffic
+ *
+ * \param dev           pointer to UDC device object
+ * \return 0 if success
+ */
+static inline int udc_control_out_isr(struct udc *dev)
+{
+	int ret_val = 0;
+	u32 tmp;
+	int setup_supported;
+	struct udc_ep   *ep0in;
+	struct udc_ep   *ep0out;
+
+	ep0out = &dev->ep[UDC_EP0OUT_IX];
+	ep0in = &dev->ep[UDC_EP0IN_IX];
+
+	/* clear irq */
+	UDC_SET_BIT(UDC_EPINT_OUT_EP0, &dev->regs->ep_irqsts);
+	if (check_and_clear_errors(ep0out))
+		goto finished;
+
+	tmp = ep0out->regs->sts;
+
+	/* type of data: SETUP or DATA 0 bytes */
+	tmp = UDC_GETBITS(tmp, UDC_EPSTS_OUT);
+	/* setup data */
+	if (tmp == UDC_EPSTS_OUT_SETUP) {
+		dev->waiting_zlp_ack_ep0in = 0;
+
+		ep0out->regs->sts |= UDC_EPSTS_OUT_CLEAR;
+
+		setup_data.data[0] = dev->ep[UDC_EP0OUT_IX].td_stp->data12;
+		setup_data.data[1] = dev->ep[UDC_EP0OUT_IX].td_stp->data34;
+		ep0out->td_stp->status = UDC_DMA_STP_STS_BS_HOST_READY;
+
+		/* determine direction of control data */
+		if ((setup_data.request.bRequestType & USB_DIR_IN) == 0) {
+			dev->gadget.ep0 = &dev->ep[UDC_EP0OUT_IX].ep;
+		} else {
+			dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+			udc_set_rde(dev);
+		}
+
+		setup_supported = dev->driver->setup(&dev->gadget,
+						     &setup_data.request);
+
+		tmp = ioread32(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+		if (setup_supported >= 0 &&
+				setup_supported < UDC_EP0IN_MAXPACKET) {
+			ep0in->regs->ctl |= UDC_BIT(UDC_EPCTL_CNAK);
+		} else if (setup_supported < 0) {
+			/* if unsupported request then stall */
+			ep0in->regs->ctl |= UDC_BIT(UDC_EPCTL_S);
+			au_sync();
+		}
+
+		ep0out->regs->ctl |= UDC_BIT(UDC_EPCTL_CNAK);
+		au_sync();
+	} else if (tmp == UDC_EPSTS_OUT_DATA) {
+		/* no req if 0 packet, just reactivate */
+		if (list_empty(&ep0out->queue)) {
+			ep0out->td->status =
+				UDC_ADDBITS(ep0out->td->status,
+						UDC_DMA_OUT_STS_BS_HOST_READY,
+						UDC_DMA_OUT_STS_BS);
+		} else {
+			udc_data_out_isr(dev, UDC_EP0OUT_IX);
+			ep0out->regs->desptr = ep0out->td_phys;
+		}
+		udc_set_rde(dev);
+	}
+
+finished:
+	ep0out->regs->sts = UDC_EPSTS_OUT_CLEAR;
+	return ret_val;
+}
+
+/**
+ * Interrupt handler for Control IN traffic
+ *
+ * \param dev           pointer to UDC device object
+ * \return 0 if success
+ */
+static inline int udc_control_in_isr(struct udc *dev)
+{
+	int ret_val = 0;
+	u32 tmp;
+	struct udc_ep *ep;
+	struct udc_request *req;
+
+	ep = &dev->ep[UDC_EP0IN_IX];
+
+	UDC_SET_BIT(UDC_EPINT_IN_EP0, &dev->regs->ep_irqsts);
+
+	tmp = ep->regs->sts;
+	if (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct udc_request, queue);
+
+		/* DMA completion */
+		if (tmp & UDC_BIT(UDC_EPSTS_TDC)) {
+			ep->regs->ctl |= UDC_BIT(UDC_EPCTL_CNAK);
+		} else if (tmp & UDC_BIT(UDC_EPSTS_IN)) {
+			ep->regs->desptr = (u32)req->td_phys;
+			req->td_data->status = UDC_ADDBITS(req->td_data->status,
+						UDC_DMA_STP_STS_BS_HOST_READY,
+						UDC_DMA_STP_STS_BS);
+			au_sync();
+
+			ep->regs->ctl |= UDC_BIT(UDC_EPCTL_P);
+
+			/* All bytes are always transferred */
+			req->req.actual = req->req.length;
+			complete_req(ep, req, 0);
+			au_sync();
+		}
+	}
+	ep->regs->sts = ep->regs->sts;
+	au_sync();
+
+	return ret_val;
+}
+
+/**
+ * Interrupt handler for global device events
+ *
+ * \param dev           pointer to UDC device object
+ * \param dev_irq       device interrupt bit of DEVINT register
+ * \return 0 if success
+ */
+static inline int udc_dev_isr(struct udc *dev, u32 dev_irq)
+{
+	int ret_val = 0;
+	u32 tmp;
+	u32 cfg;
+	struct udc_ep *ep;
+	u16 i;
+	u8 udc_csr_epix;
+
+	DBG("Got interrupt.  dev_irq is %8.8X\n", dev_irq);
+
+	/* SET_CONFIG irq ? */
+	if (dev_irq & UDC_BIT(UDC_DEVINT_SC)) {
+
+		/* read config value */
+		tmp = ioread32(&dev->regs->sts);
+		cfg = UDC_GETBITS(tmp, UDC_DEVSTS_CFG);
+#ifdef UDC_DEBUG
+		/* this is needed for debug only */
+		if (cfg == dev->cur_config)
+			same_cfg = 1;
+		else
+			same_cfg = 0;
+		VDBG("same_cfg=%d\n", same_cfg);
+#endif
+		DBG("SET_CONFIG interrupt: config=%d\n", cfg);
+		dev->cur_config = cfg;
+		dev->set_cfg_not_acked = 1;
+
+		/* make usb request for gadget driver */
+		memset(&setup_data, 0 , sizeof(union udc_setup_data));
+		setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION;
+		setup_data.request.wValue = dev->cur_config;
+
+		/* programm the NE registers */
+		for (i = 0; i < UDC_EP_NUM; i++) {
+			ep = &dev->ep[i];
+			if (ep->in) {
+
+				/* ep ix in UDC CSR register space */
+				udc_csr_epix = ep->num;
+
+
+			} /* OUT ep */
+			else {
+				/* ep ix in UDC CSR register space */
+				udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+			}
+
+			tmp = ioread32(&dev->csr->ne[udc_csr_epix]);
+			/* ep cfg */
+			tmp = UDC_ADDBITS(tmp, ep->dev->cur_config,
+					UDC_CSR_NE_CFG);
+			/* write reg */
+			iowrite32(tmp, &dev->csr->ne[udc_csr_epix]);
+
+			/* clear stall bits */
+			ep->halted = 0;
+			tmp = ioread32(&ep->regs->ctl);
+			tmp = tmp & UDC_CLEAR_BIT(UDC_EPCTL_S);
+			iowrite32(tmp, &ep->regs->ctl);
+		}
+		/* call gadget zero with setup data received */
+		spin_unlock(&dev->lock);
+		tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+		spin_lock(&dev->lock);
+
+	} /* SET_INTERFACE ? */
+	if (dev_irq & UDC_BIT(UDC_DEVINT_SI)) {
+		dev->set_cfg_not_acked = 1;
+		/* read interface and alt setting values */
+		tmp = ioread32(&dev->regs->sts);
+		dev->cur_alt = UDC_GETBITS(tmp, UDC_DEVSTS_ALT);
+		dev->cur_intf = UDC_GETBITS(tmp, UDC_DEVSTS_INTF);
+
+		/* make usb request for gadget driver */
+		memset(&setup_data, 0 , sizeof(union udc_setup_data));
+		setup_data.request.bRequest = USB_REQ_SET_INTERFACE;
+		setup_data.request.bRequestType = USB_RECIP_INTERFACE;
+		setup_data.request.wValue = dev->cur_alt;
+		setup_data.request.wIndex = dev->cur_intf;
+
+		DBG("SET_INTERFACE interrupt: alt=%d intf=%d\n",
+				dev->cur_alt, dev->cur_intf);
+
+		for (i = 0; i < UDC_EP_NUM; i++) {
+			ep = &dev->ep[i];
+			if (ep->in) {
+
+				/* ep ix in UDC CSR register space */
+				udc_csr_epix = ep->num;
+
+
+			} /* OUT ep */
+			else {
+				/* ep ix in UDC CSR register space */
+				udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+			}
+
+			/***** UDC CSR reg ****************************/
+			/* set ep values  */
+			tmp = ioread32(&dev->csr->ne[udc_csr_epix]);
+			/* ep interface */
+			tmp = UDC_ADDBITS(tmp, ep->dev->cur_intf,
+					UDC_CSR_NE_INTF);
+			/* ep alt */
+			tmp = UDC_ADDBITS(tmp, ep->dev->cur_alt,
+					UDC_CSR_NE_ALT);
+			/* write reg */
+			iowrite32(tmp, &dev->csr->ne[udc_csr_epix]);
+
+			/* clear stall bits */
+			ep->halted = 0;
+			tmp = ioread32(&ep->regs->ctl);
+			tmp = tmp & UDC_CLEAR_BIT(UDC_EPCTL_S);
+			iowrite32(tmp, &ep->regs->ctl);
+		}
+
+		/* call gadget zero with setup data received */
+		spin_unlock(&dev->lock);
+		tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+		spin_lock(&dev->lock);
+
+	} /* USB reset */
+	if (dev_irq & UDC_BIT(UDC_DEVINT_UR)) {
+		DBG("USB Reset interrupt\n");
+
+		/* allow soft reset when suspend occurs */
+		soft_reset_occured = 0;
+
+		dev->waiting_zlp_ack_ep0in = 0;
+		dev->set_cfg_not_acked = 0;
+
+		/* mask not needed interrupts */
+		udc_mask_unused_interrupts(dev);
+
+		/* call gadget to reset configs etc. */
+		spin_unlock(&dev->lock);
+		dev->driver->disconnect(&dev->gadget);
+		spin_lock(&dev->lock);
+
+		/* disable ep0 to empty req queue */
+		empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+		ep_init(dev->regs,
+				&dev->ep[UDC_EP0IN_IX]);
+
+		/* soft reset when rxfifo not empty */
+		tmp = ioread32(&dev->regs->sts);
+		if (!(tmp & UDC_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) &&
+				!soft_reset_after_usbreset_occured) {
+			udc_soft_reset(dev);
+			soft_reset_after_usbreset_occured++;
+		}
+
+		/* put into initial config */
+		udc_basic_init(dev);
+
+		/* enable device setup interrupts */
+		udc_enable_dev_setup_interrupts(dev);
+
+	} /* USB suspend */
+
+	if (dev_irq & UDC_BIT(UDC_DEVINT_ENUM)) {
+		DBG("ENUM interrupt\n");
+#ifdef UDC_DEBUG
+		num_enums++;
+		DBG("%d enumerations !\n", num_enums);
+#endif
+		soft_reset_after_usbreset_occured = 0;
+
+		/* disable ep0 to empty req queue */
+		empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+		ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+		/* link up all endpoints */
+		udc_setup_endpoints(dev);
+		if (dev->gadget.speed == USB_SPEED_HIGH)
+			INFO("Connect: Speed = HIGH_SPEED\n");
+		else if (dev->gadget.speed == USB_SPEED_FULL)
+			INFO("Connect: Speed = FULL_SPEED\n");
+
+		/* init ep 0 */
+		activate_control_endpoints(dev);
+
+		/* enable ep0 interrupts */
+		udc_enable_ep0_interrupts(dev);
+	}
+
+	return ret_val;
+}
+
+static irqreturn_t udc_irq(int irq, void *pdev)
+{
+	struct udc *dev = pdev;
+	u32 reg;
+	u16 i;
+	u32 ep_irq;
+
+	/* If UDC is suspended, then don't touch any register, otherwise
+	   system hangs in endless retry => possibly hang !!! */
+	if (dev->otg_driver && dev->otg_driver->query) {
+		if (dev->otg_driver->query(0) & OTG_FLAGS_UDC_SUSP)
+			return IRQ_HANDLED;
+	} else {
+		return IRQ_HANDLED;
+	}
+
+	if (dev->sys_suspended)
+		return IRQ_HANDLED;
+
+	spin_lock(&dev->lock);
+
+	/* check for ep irq */
+	reg = ioread32(&dev->regs->ep_irqsts);
+	if (reg) {
+		/* EP0 OUT */
+		if (reg & UDC_BIT(UDC_EPINT_OUT_EP0))
+			udc_control_out_isr(dev);
+
+		if (reg & UDC_BIT(UDC_EPINT_IN_EP0))
+			udc_control_in_isr(dev);
+
+		/* data endpoint */
+		/* iterate ep's */
+		for (i = 1; i < UDC_EP_NUM; i++) {
+			ep_irq = 1 << i;
+			/* irq for out ep ? */
+			if ((reg & ep_irq) && i > UDC_EPIN_NUM) {
+				/* clear irq */
+				iowrite32(ep_irq, &dev->regs->ep_irqsts);
+				udc_data_out_isr(dev, i);
+			} /* irq for in ep ? */
+			if ((reg & ep_irq) && i < UDC_EPIN_NUM && i > 0) {
+				/* clear irq */
+				iowrite32(ep_irq, &dev->regs->ep_irqsts);
+				udc_data_in_isr(dev, i);
+			}
+
+		}
+
+	}
+
+	/* check for dev irq */
+	reg = ioread32(&dev->regs->irqsts);
+	if (reg) {
+		/* clear irq */
+		iowrite32(reg, &dev->regs->irqsts);
+		udc_dev_isr(dev, reg);
+	}
+
+
+	spin_unlock(&dev->lock);
+	return IRQ_HANDLED;
+}
+
+/**
+ * Tears down device
+ *
+ * \param pdev        pointer to device struct
+ */
+static void gadget_release(struct device *pdev)
+{
+	struct udc *dev = dev_get_drvdata(pdev);
+	kfree(dev);
+}
+
+static void udc_remove(struct udc *dev)
+{
+	u32 tmp;
+	/* disable UDC memory, DMA and clock */
+	tmp = ioread32((u32 *) (USB_MSR_BASE + USB_MSR_MCFG));
+	tmp &= UDC_CLEAR_BIT(USBMSRMCFG_DMEMEN)
+		& UDC_CLEAR_BIT(USBMSRMCFG_DBMEN)
+		& UDC_CLEAR_BIT(USBMSRMCFG_UDCCLKEN);
+	iowrite32(tmp, (u32 *)(USB_MSR_BASE + USB_MSR_MCFG));
+
+	device_unregister(&udc->gadget.dev);
+	udc = 0;
+}
+
+static void udc_drv_remove(struct device *_dev)
+{
+	struct platform_device *pdev = to_platform_device(_dev);
+	struct udc *dev = dev_get_drvdata(_dev);
+
+#ifdef UDC_DEBUG
+	print_misc(dev);
+#endif
+	/* gadget driver registered ? */
+	if (dev->driver) {
+		WARN("unregistering %s on driver remove\n",
+				dev->driver->driver.name);
+		usb_gadget_unregister_driver(dev->driver);
+	}
+	/* otg driver registered ? */
+	if (dev->otg_transceiver) {
+		/* should have been done already by driver model core */
+		WARN("uoc driver is still registered\n");
+	}
+	/* dma pool cleanup */
+	if (dev->data_requests)
+		dma_pool_destroy(dev->data_requests);
+	if (dev->stp_requests) {
+		/* cleanup DMA desc's for ep0in */
+		dma_pool_free(dev->stp_requests,
+				dev->ep[UDC_EP0OUT_IX].td_stp,
+				dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+		dma_pool_free(dev->stp_requests,
+				dev->ep[UDC_EP0OUT_IX].td,
+				dev->ep[UDC_EP0OUT_IX].td_phys);
+
+		dma_pool_destroy(dev->stp_requests);
+	}
+
+	/* init controller by soft reset */
+	iowrite32(UDC_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+
+	if (dev->irq_registered)
+		free_irq(pdev->resource[1].start, dev);
+	if (dev->regs)
+		iounmap(dev->regs);
+	if (dev->mem_region)
+		release_mem_region(pdev->resource[0].start,
+				pdev->resource[0].end + 1
+				- pdev->resource[0].start);
+
+	device_remove_file(&pdev->dev, &dev_attr_registers);
+	dev_set_drvdata(_dev, 0);
+	udc_remove(dev);
+}
+
+__init static int init_dma_pools(struct udc *dev)
+{
+	struct udc_stp_dma      *td_stp;
+	struct udc_data_dma     *td_data;
+	int retval;
+
+	/* consistent DMA mode setting ? */
+	if (use_dma_ppb) {
+		use_dma_bufferfill_mode = 0;
+	} else {
+		use_dma_ppb_du = 0;
+		use_dma_bufferfill_mode = 1;
+	}
+
+	/* DMA setup */
+	dev->data_requests = dma_pool_create("data_requests", NULL,
+			sizeof(struct udc_data_dma),
+			UDC_POOL_ALIGN,
+			UDC_POOL_CROSS);
+	if (!dev->data_requests) {
+		DBG("can't get request data pool\n");
+		retval = -ENOMEM;
+		goto finished;
+	}
+
+	/* EP0 in dma regs = dev control regs */
+	dev->ep[UDC_EP0IN_IX].dma = &dev->regs->ctl;
+
+	/* dma desc for setup data */
+	dev->stp_requests = dma_pool_create("setup requests", NULL,
+			sizeof(struct udc_stp_dma),
+			UDC_POOL_ALIGN,
+			UDC_POOL_CROSS);
+	if (!dev->stp_requests) {
+		DBG("can't get stp request pool\n");
+		retval = -ENOMEM;
+		goto finished;
+	}
+	/* setup */
+	td_stp = dma_pool_alloc(dev->stp_requests, UDC_POOL_GFP_STP,
+			&dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+	if (td_stp == NULL) {
+		retval = -ENOMEM;
+		goto finished;
+	}
+	dev->ep[UDC_EP0OUT_IX].td_stp = td_stp;
+	/* data: 0 packets !? */
+	td_data = dma_pool_alloc(dev->stp_requests, UDC_POOL_GFP_STP,
+			&dev->ep[UDC_EP0OUT_IX].td_phys);
+	if (td_data == NULL) {
+		retval = -ENOMEM;
+		goto finished;
+	}
+	dev->ep[UDC_EP0OUT_IX].td = td_data;
+	/* point to itself */
+	dev->ep[UDC_EP0OUT_IX].td->next = dev->ep[UDC_EP0OUT_IX].td_phys;
+	return 0;
+
+finished:
+	return retval;
+}
+
+/**
+ * Called by kernel  init device context
+ */
+static int udc_drv_probe(struct device *_dev)
+{
+	char                    tmp[8];
+	struct udc              *dev;
+	struct platform_device *pdev = to_platform_device(_dev);
+	u32                     resource;
+	u32                     len;
+	u32                     irq;
+	int                     retval = 0;
+	u32                     reg;
+
+	/* basic init */
+	reg = ioread32((u32 *) (USB_MSR_BASE + USB_MSR_MCFG));
+	if (reg == 0) {
+		/* default value */
+		reg = USBMSRMCFG_DEFAULT;
+		iowrite32(reg, (u32 *)(USB_MSR_BASE + USB_MSR_MCFG));
+		ioread32((u32 *)(USB_MSR_BASE + USB_MSR_MCFG));
+		udelay(1000);
+	}
+	/* enable UDC memory, DMA, clock, cacheable memory,
+	 * read combining and prefetch enable */
+	reg |= UDC_BIT(USBMSRMCFG_DMEMEN) | UDC_BIT(USBMSRMCFG_DBMEN)
+		| UDC_BIT(USBMSRMCFG_UDCCLKEN)
+		| UDC_BIT(USBMSRMCFG_PHYPLLEN)
+#ifdef CONFIG_DMA_COHERENT
+		| UDC_BIT(USBMSRMCFG_UCAM)
+#endif
+		| UDC_BIT(USBMSRMCFG_RDCOMB)
+		| UDC_BIT(USBMSRMCFG_PFEN);
+	iowrite32(reg, (u32 *)(USB_MSR_BASE + USB_MSR_MCFG));
+
+	/* one udc only */
+	if (udc) {
+		WARN("already probed.\n");
+		return -EBUSY;
+	}
+
+	/* init */
+	dev = kmalloc(sizeof(struct udc), GFP_KERNEL);
+	if (!dev) {
+		retval = -ENOMEM;
+		goto finished;
+	}
+	memset(dev, 0, sizeof(struct udc));
+
+	dev->pdev = _dev;
+
+	/* check platform resources */
+	if (pdev->resource[0].flags != IORESOURCE_MEM) {
+		ERR("resource[0] must be IORESOURCE_MEM\n");
+		retval = -ENOMEM;
+		goto finished;
+	}
+	resource = pdev->resource[0].start;
+	len = pdev->resource[0].end + 1 - pdev->resource[0].start;
+	if (pdev->resource[1].flags != IORESOURCE_IRQ) {
+		ERR("resource[1] must be IORESOURCE_IRQ\n");
+		retval = -ENOMEM;
+		goto finished;
+	}
+	irq = pdev->resource[1].start;
+
+	/* platform device resource allocation */
+	/* mem */
+	if (!request_mem_region(resource, len, name)) {
+		ERR("controller already in use\n");
+		retval = -EBUSY;
+		goto finished;
+	}
+	dev->mem_region = 1;
+
+	dev->virt_addr = ioremap_nocache(resource, len);
+	if (dev->virt_addr == NULL) {
+		DBG("start address cannot be mapped\n");
+		retval = -EFAULT;
+		goto finished;
+	}
+
+	/* irq */
+	if (!irq) {
+		ERR("irq not set\n");
+		retval = -ENODEV;
+		goto finished;
+	}
+	snprintf(tmp, sizeof tmp, "%d", irq);
+	if (request_irq(irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
+		ERR("error on request_irq() with %s\n", tmp);
+		retval = -EBUSY;
+		goto finished;
+	}
+	dev->irq_registered = 1;
+
+	dev_set_drvdata(_dev, dev);
+
+	/* chip revision */
+	dev->chiprev = 0;
+
+	/* chip rev for Au1200 */
+	dev->chiprev = (u16) read_c0_prid() & 0xff;
+
+	/* init dma pools */
+	if (use_dma) {
+		retval = init_dma_pools(dev);
+		if (retval != 0)
+			goto finished;
+	}
+
+	dev->phys_addr = resource;
+	dev->irq = irq;
+	dev->pdev = _dev;
+	dev->gadget.dev.parent = _dev;
+	dev->gadget.dev.dma_mask = _dev->dma_mask;
+	/* general probing */
+	if (udc_probe(dev) != 0)
+		goto finished;
+	return retval;
+
+finished:
+	if (dev)
+		udc_drv_remove(_dev);
+	return retval;
+}
+
+/**
+ * general probe
+ */
+__init int udc_probe(struct udc *dev)
+{
+	char                    tmp[128];
+	u32 reg;
+	int retval;
+
+	/* device struct setup */
+	spin_lock_init(&dev->lock);
+	spin_lock_init(&udc_irq_spinlock);
+	spin_lock_init(&udc_stall_spinlock);
+	dev->gadget.ops = &udc_ops;
+
+	strcpy(dev->gadget.dev.bus_id, "gadget");
+	dev->gadget.dev.release = gadget_release;
+	dev->gadget.name = name;
+	dev->gadget.is_dualspeed = 1;
+
+	/* udc csr registers base */
+	dev->csr = (struct udc_csrs *)(dev->virt_addr + UDC_CSR_ADDR);
+	/* dev registers base */
+	dev->regs = (struct udc_regs *)(dev->virt_addr + UDC_DEVCFG_ADDR);
+	/* ep registers base */
+	dev->ep_regs = (struct udc_ep_regs *)(dev->virt_addr + UDC_EPREGS_ADDR);
+	/* fifo's base */
+	dev->rxfifo = (u32 *) (dev->virt_addr + UDC_RXFIFO_ADDR);
+	dev->txfifo = (u32 *) (dev->virt_addr + UDC_TXFIFO_ADDR);
+
+	/* init registers, interrupts, ... */
+	{
+		u32 tmp;
+
+		dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+		dev->ep[UDC_EP0IN_IX].halted = 0;
+		INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+		dev->gadget.speed = USB_SPEED_HIGH;
+		make_ep_lists(dev);
+		/* basic endpoint init */
+		for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+			struct udc_ep   *ep = &dev->ep[tmp];
+
+			ep->ep.name = ep_string[tmp];
+			ep->dev = dev;
+			ep->num = tmp;
+			/* txfifo size is calculated at enable time */
+			ep->txfifo = dev->txfifo;
+
+			/* fifo size */
+			if (tmp < UDC_EPIN_NUM) {
+				ep->fifo_depth = UDC_TXFIFO_SIZE;
+				ep->in = 1;
+			} else {
+				ep->fifo_depth = UDC_RXFIFO_SIZE;
+				ep->in = 0;
+
+			}
+
+			ep->regs = &dev->ep_regs[tmp];
+			if (!ep->desc) {
+				ep->desc = 0;
+				INIT_LIST_HEAD(&ep->queue);
+
+				ep->ep.maxpacket = ~0;
+				ep->ep.ops = &udc_ep_ops;
+			}
+
+			tasklet_init(&ep->execute_tasklet,
+					udc_tasklet_execute_request,
+					(unsigned long)ep);
+					init_MUTEX(&ep->in_use);
+					init_MUTEX(&ep->in_et);
+		}
+		dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
+		dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
+	}
+
+
+	INFO("%s\n", mod_desc);
+
+	snprintf(tmp, sizeof tmp, "%d", dev->irq);
+	INFO("irq %s, mem %08lx, chip rev %02x (Au1200 %s)\n",
+			tmp, dev->phys_addr, dev->chiprev,
+			(dev->chiprev == 0) ? "AB" : "AC");
+#ifdef CONFIG_DMA_COHERENT
+	/* coherent DMA not possible with AB silicon */
+	if (dev->chiprev == UDC_AUAB_REV) {
+		ERR("Your chip revision is %s, it must be at least %s to use"
+				" coherent DMA. \nPlease change DMA_COHERENT to"
+				" DMA_NONCOHERENT in arch/mips/Kconfig and"
+				" re-compile .\n", "AB", "AC");
+		retval = -ENODEV;
+		goto finished;
+	}
+#endif
+
+#ifdef CONFIG_DMA_COHERENT
+	INFO("Compiled for coherent memory.\n");
+#endif
+#ifdef CONFIG_DMA_NONCOHERENT
+	INFO("Compiled for non-coherent memory.\n");
+#endif
+	udc = dev;
+
+	retval = device_register(&dev->gadget.dev);
+	if (retval) {
+		ERR("Failed to register gadget device\n");
+		goto finished;
+	}
+	device_create_file(&pdev->dev, &dev_attr_registers);
+
+	/* set SD */
+	reg = ioread32(&dev->regs->ctl);
+	reg |= UDC_BIT(UDC_DEVCTL_SD);
+	iowrite32(reg, &dev->regs->ctl);
+	/* print dev register info */
+	print_regs(dev);
+	return 0;
+
+finished:
+	return retval;
+}
+
+
+/**
+ *  Initiates a remote wakeup
+ *
+ * \return 0 if success
+ */
+/* initiate remote wakeup */
+static int udc_remote_wakeup(struct udc *dev)
+{
+	INFO("UDC initiates remote wakeup\n");
+
+	UDC_SET_BIT(UDC_DEVCTL_RES, &dev->regs->ctl);
+	UDC_UNSET_BIT(UDC_DEVCTL_RES, &dev->regs->ctl);
+
+	return 0;
+}
+
+/**
+ *  Suspends UDC
+ */
+static int udc_suspend(struct udc *dev)
+{
+	int retval = 0;
+
+	u32 tmp;
+	INFO("UDC suspend\n");
+	/* mask interrupts */
+	udc_mask_unused_interrupts(dev);
+
+	if (dev->driver && dev->driver->disconnect) {
+		/* call gadget to reset context */
+		if (spin_is_locked(&dev->lock)) {
+			spin_unlock(&dev->lock);
+			dev->driver->disconnect(&dev->gadget);
+			spin_lock(&dev->lock);
+		} else
+			dev->driver->disconnect(&dev->gadget);
+
+		/* disable ep0 to empty req queue */
+		empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+		ep_init(dev->regs,
+				&dev->ep[UDC_EP0IN_IX]);
+
+		/* init controller by soft reset */
+		udc_soft_reset(dev);
+
+	}
+	if (dev->otg_driver && dev->otg_transceiver
+			&& dev->otg_transceiver->set_peripheral) {
+		/* if UDC is supended by Host or already disconnected then
+		   don't force disconnect by unbind() */
+		if (dev->otg_driver->query) {
+			if (!(dev->otg_driver->query(0) & OTG_FLAGS_UDC_SUSP)) {
+				/* unbind from otg driver -> host disconnect */
+				dev->otg_transceiver->set_peripheral(
+						dev->otg_transceiver, NULL);
+				dev->connected = 0;
+			}
+		} else {
+			/* unbind from otg driver -> host disconnect */
+			dev->otg_transceiver->set_peripheral(
+					dev->otg_transceiver, NULL);
+			dev->connected = 0;
+		}
+	}
+
+	dev->sys_suspended = 1;
+
+	/* switch off UDC clock */
+			tmp = ioread32((u32 *)(USB_MSR_BASE + USB_MSR_MCFG));
+			tmp &= UDC_CLEAR_BIT(USBMSRMCFG_UDCCLKEN);
+			iowrite32(tmp, (u32 *)(USB_MSR_BASE + USB_MSR_MCFG));
+
+	return retval;
+}
+
+static int udc_resume(struct udc *dev)
+{
+	int retval = 0;
+
+	u32 tmp;
+	INFO("UDC resume\n");
+	/* switch on UDC clock */
+	tmp = ioread32((u32 *)(USB_MSR_BASE + USB_MSR_MCFG));
+	tmp |= UDC_BIT(USBMSRMCFG_UDCCLKEN);
+	iowrite32(tmp, (u32 *)(USB_MSR_BASE + USB_MSR_MCFG));
+
+	dev->sys_suspended = 0;
+
+	usb_connect(dev);
+	if (dev->otg_transceiver && dev->otg_transceiver->set_peripheral) {
+		/* bind to otg driver */
+		dev->otg_transceiver->set_peripheral(dev->otg_transceiver,
+						     &dev->gadget);
+	}
+	return retval;
+}
+
+static int udc_au1xxx_drv_probe(struct device *dev)
+{
+	int retval;
+
+	DBG("udc_au1xxx_drv_probe()\n");
+	retval = udc_drv_probe(dev);
+	return retval;
+}
+
+static int udc_au1xxx_drv_remove(struct device *dev)
+{
+	DBG("udc_au1xxx_drv_remove()\n");
+	udc_drv_remove(dev);
+	return 0;
+}
+
+static int udc_au1xxx_drv_suspend(struct device *dev, pm_message_t state)
+{
+	struct udc *udc_dev = dev_get_drvdata(dev);
+	return udc_suspend(udc_dev);
+}
+
+static int udc_au1xxx_drv_resume(struct device *dev)
+{
+	struct udc *udc_dev = dev_get_drvdata(dev);
+	return udc_resume(udc_dev);
+}
+
+static struct device_driver udc_au1xxx_driver = {
+	.name		= "au1xxx-udc",
+	.bus		= &platform_bus_type,
+	.probe		= udc_au1xxx_drv_probe,
+	.remove		= udc_au1xxx_drv_remove,
+	.suspend	= udc_au1xxx_drv_suspend,
+	.resume	    = udc_au1xxx_drv_resume,
+};
+
+
+static int __init init(void)
+{
+	int rc;
+
+	/* probe by device system */
+	rc = driver_register(&udc_au1xxx_driver);
+
+	return rc;
+}
+module_init(init);
+
+static void __exit cleanup(void)
+{
+	/* unregister at device system */
+	driver_unregister(&udc_au1xxx_driver);
+
+}
+module_exit(cleanup);
+
diff --git a/drivers/usb/gadget/au1200_udc.h b/drivers/usb/gadget/au1200_udc.h
new file mode 100644
index 0000000..2a4f7bf
--- /dev/null
+++ b/drivers/usb/gadget/au1200_udc.h
@@ -0,0 +1,816 @@
+/*
+ * Header for driver for RMI Au1200 UDC high/full speed USB device controller
+ */
+/*
+ * Copyright (C) 2008 RMI Corporation (http://www.rmicorp.com)
+ * Author: Kevin Hickey (khickey@xxxxxxxxxxx)
+ *
+ * Adapted from the AMD5536 UDC module.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef AU1200UDC_H
+#define AU1200UDC_H
+
+/*****************************************************************************
+ *  Constants
+ *****************************************************************************/
+
+/* Driver  constants -------------------------------------------------------*/
+#define DRIVER_NAME_FOR_PRINT "au1200_udc"
+
+/* Platform specific -------------------------------------------------------*/
+#define UDC_POOL_ALIGN       32
+#define UDC_POOL_CROSS       4096
+#define UDC_POOL_GFP_STP     (GFP_ATOMIC | GFP_DMA)
+
+#ifndef USBMSRMCFG_UCAM
+#define USBMSRMCFG_UCAM           7
+#endif
+#define USBMSRMCFG_DEFAULT        0x00d02000
+
+/* Au1200 rev. */
+#define UDC_AUAB_REV 0
+#define UDC_AUAC_REV 1
+#define UDC_AUA0 0
+
+/* Global CSR's -------------------------------------------------------------*/
+/* UDC CSR's */
+#define UDC_CSR_ADDR                            0x500
+
+/* EP NE bits */
+/* EP number */
+#define UDC_CSR_NE_NUM_MASK                     0x0000000f
+#define UDC_CSR_NE_NUM_OFS                      0
+/* EP direction */
+#define UDC_CSR_NE_DIR_MASK                     0x00000010
+#define UDC_CSR_NE_DIR_OFS                      4
+/* EP type */
+#define UDC_CSR_NE_TYPE_MASK                    0x00000060
+#define UDC_CSR_NE_TYPE_OFS                     5
+/* EP config number */
+#define UDC_CSR_NE_CFG_MASK                     0x00000780
+#define UDC_CSR_NE_CFG_OFS                      7
+/* EP interface number */
+#define UDC_CSR_NE_INTF_MASK                    0x00007800
+#define UDC_CSR_NE_INTF_OFS                     11
+/* EP alt setting */
+#define UDC_CSR_NE_ALT_MASK                     0x00078000
+#define UDC_CSR_NE_ALT_OFS                      15
+
+/* max pkt */
+#define UDC_CSR_NE_MAX_PKT_MASK                 0x3ff80000
+#define UDC_CSR_NE_MAX_PKT_OFS                  19
+
+/* Device Config Register ---------------------------------------------------*/
+#define UDC_DEVCFG_ADDR                         0x400
+
+#define UDC_DEVCFG_SOFTRESET                    31
+#define UDC_DEVCFG_HNPSFEN                      30
+#define UDC_DEVCFG_DMARST                       29
+#define UDC_DEVCFG_SET_DESC                     18
+#define UDC_DEVCFG_CSR_PRG                      17
+#define UDC_DEVCFG_STATUS                       7
+#define UDC_DEVCFG_DIR                          6
+#define UDC_DEVCFG_PI                           5
+#define UDC_DEVCFG_SS                           4
+#define UDC_DEVCFG_SP                           3
+#define UDC_DEVCFG_RWKP                         2
+
+#define UDC_DEVCFG_SPD_MASK                     0x3
+#define UDC_DEVCFG_SPD_OFS                      0
+#define UDC_DEVCFG_SPD_HS                       0x0
+#define UDC_DEVCFG_SPD_FS                       0x1
+#define UDC_DEVCFG_SPD_LS                       0x2
+/*#define UDC_DEVCFG_SPD_FS                     0x3*/
+
+
+/* Device Control Register --------------------------------------------------*/
+#define UDC_DEVCTL_ADDR                         0x404
+
+#define UDC_DEVCTL_THLEN_MASK                   0xff000000
+#define UDC_DEVCTL_THLEN_OFS                    24
+
+#define UDC_DEVCTL_BRLEN_MASK                   0x00ff0000
+#define UDC_DEVCTL_BRLEN_OFS                    16
+
+#define UDC_DEVCTL_CSR_DONE                     13
+#define UDC_DEVCTL_DEVNAK                       12
+#define UDC_DEVCTL_SD                           10
+#define UDC_DEVCTL_MODE                         9
+#define UDC_DEVCTL_BREN                         8
+#define UDC_DEVCTL_THE                          7
+#define UDC_DEVCTL_BF                           6
+#define UDC_DEVCTL_BE                           5
+#define UDC_DEVCTL_DU                           4
+#define UDC_DEVCTL_TDE                          3
+#define UDC_DEVCTL_RDE                          2
+#define UDC_DEVCTL_RES                          0
+
+
+/* Device Status Register ---------------------------------------------------*/
+#define UDC_DEVSTS_ADDR                         0x408
+
+#define UDC_DEVSTS_TS_MASK                      0xfffc0000
+#define UDC_DEVSTS_TS_OFS                       18
+
+#define UDC_DEVSTS_SESSVLD                      17
+#define UDC_DEVSTS_PHY_ERROR                    16
+#define UDC_DEVSTS_RXFIFO_EMPTY                 15
+
+#define UDC_DEVSTS_ENUM_SPEED_MASK              0x00006000
+#define UDC_DEVSTS_ENUM_SPEED_OFS               13
+#define UDC_DEVSTS_ENUM_SPEED_FULL              1
+#define UDC_DEVSTS_ENUM_SPEED_HIGH              0
+
+#define UDC_DEVSTS_SUSP                         12
+
+#define UDC_DEVSTS_ALT_MASK                     0x00000f00
+#define UDC_DEVSTS_ALT_OFS                      8
+
+#define UDC_DEVSTS_INTF_MASK                    0x000000f0
+#define UDC_DEVSTS_INTF_OFS                     4
+
+#define UDC_DEVSTS_CFG_MASK                     0x0000000f
+#define UDC_DEVSTS_CFG_OFS                      0
+
+
+/* Device Interrupt Register ------------------------------------------------*/
+#define UDC_DEVINT_ADDR                         0x40c
+
+#define UDC_DEVINT_ENUM                         6
+#define UDC_DEVINT_SOF                          5
+#define UDC_DEVINT_US                           4
+#define UDC_DEVINT_UR                           3
+#define UDC_DEVINT_ES                           2
+#define UDC_DEVINT_SI                           1
+#define UDC_DEVINT_SC                           0
+
+/* Device Interrupt Mask Register -------------------------------------------*/
+#define UDC_DEVINT_MSK_ADDR                     0x410
+
+#define UDC_DEVINT_MSK                          0x3f
+
+/* Endpoint Interrupt Register ----------------------------------------------*/
+#define UDC_EPINT_ADDR                          0x414
+
+#define UDC_EPINT_OUT_MASK                      0xffff0000
+#define UDC_EPINT_OUT_OFS                       16
+#define UDC_EPINT_IN_MASK                       0x0000ffff
+#define UDC_EPINT_IN_OFS                        0
+
+#define UDC_EPINT_IN_EP0                        0
+#define UDC_EPINT_IN_EP1                        1
+#define UDC_EPINT_IN_EP2                        2
+#define UDC_EPINT_IN_EP3                        3
+#define UDC_EPINT_OUT_EP0                       16
+#define UDC_EPINT_OUT_EP1                       17
+#define UDC_EPINT_OUT_EP2                       18
+#define UDC_EPINT_OUT_EP3                       19
+
+#define UDC_EPINT_EP0_ENABLE_MSK                0x001e001e
+
+/* Endpoint Interrupt Mask Register -----------------------------------------*/
+#define UDC_EPINT_MSK_ADDR                      0x418
+
+#define UDC_EPINT_OUT_MSK_MASK                  0xffff0000
+#define UDC_EPINT_OUT_MSK_OFS                   16
+#define UDC_EPINT_IN_MSK_MASK                   0x0000ffff
+#define UDC_EPINT_IN_MSK_OFS                    0
+
+#define UDC_EPINT_MSK_DISABLE_ALL               (UDC_EPINT_OUT_MASK |\
+						 UDC_EPINT_IN_MASK)
+/* mask non-EP0 endpoints */
+#define UDC_EPDATAINT_MSK_DISABLE               0xfffefffe
+/* mask all dev interrupts */
+#define UDC_DEV_MSK_DISABLE                     0x7f
+
+/* Endpoint-specific CSR's --------------------------------------------------*/
+/* Endpoint Control Registers -----------------------------------------------*/
+#define UDC_EPREGS_ADDR                         0x0
+#define UDC_EPIN_REGS_ADDR                      0x0
+#define UDC_EPOUT_REGS_ADDR                     0x200
+
+#define UDC_EPCTL_ADDR                          0x0
+
+#define UDC_EPCTL_RRDY                          9
+#define UDC_EPCTL_CNAK                          8
+#define UDC_EPCTL_SNAK                          7
+#define UDC_EPCTL_NAK                           6
+
+#define UDC_EPCTL_ET_MASK                       0x00000030
+#define UDC_EPCTL_ET_OFS                        4
+#define UDC_EPCTL_ET_CONTROL                    0
+#define UDC_EPCTL_ET_ISO                        1
+#define UDC_EPCTL_ET_BULK                       2
+#define UDC_EPCTL_ET_INTERRUPT                  3
+
+#define UDC_EPCTL_P                             3
+#define UDC_EPCTL_SN                            2
+#define UDC_EPCTL_F                             1
+#define UDC_EPCTL_S                             0
+
+/* Endpoint Status Registers ------------------------------------------------*/
+#define UDC_EPSTS_ADDR                          0x4
+
+#define UDC_EPSTS_RX_PKT_SIZE_MASK              0x007ff800
+#define UDC_EPSTS_RX_PKT_SIZE_OFS               11
+
+#define UDC_EPSTS_TDC                           10
+#define UDC_EPSTS_HE                            9
+#define UDC_EPSTS_BNA                           7
+#define UDC_EPSTS_IN                            6
+
+#define UDC_EPSTS_OUT_MASK                      0x00000030
+#define UDC_EPSTS_OUT_OFS                       4
+#define UDC_EPSTS_OUT_DATA                      1
+#define UDC_EPSTS_OUT_DATA_CLEAR                0x10
+#define UDC_EPSTS_OUT_SETUP                     2
+#define UDC_EPSTS_OUT_SETUP_CLEAR               0x20
+#define UDC_EPSTS_OUT_CLEAR                     0x30
+
+/* Endpoint Buffer Size IN/ Receive Packet Frame Number OUT  Registers ------*/
+#define UDC_EPIN_BUFF_SIZE_ADDR                 0x8
+#define UDC_EPOUT_FRAME_NUMBER_ADDR             0x8
+
+#define UDC_EPIN_BUFF_SIZE_MASK                 0x0000ffff
+#define UDC_EPIN_BUFF_SIZE_OFS                  0
+/*  EP0in txfifo = 128 bytes*/
+#define UDC_EPIN0_BUFF_SIZE                     32
+/*  EP0in fullspeed txfifo = 128 bytes*/
+#define UDC_FS_EPIN0_BUFF_SIZE                  32
+
+/* fifo size mult = fifo size / max packet */
+#define UDC_EPIN_BUFF_SIZE_MULT                 2
+
+/* EPin data fifo size = 1024 bytes DOUBLE BUFFERING */
+#define UDC_EPIN_BUFF_SIZE                      256
+/* EPin small INT data fifo size = 128 bytes */
+#define UDC_EPIN_SMALLINT_BUFF_SIZE             32
+
+/* EPin fullspeed data fifo size = 128 bytes DOUBLE BUFFERING */
+#define UDC_FS_EPIN_BUFF_SIZE                   32
+
+#define UDC_EPOUT_FRAME_NUMBER_MASK             0x0000ffff
+#define UDC_EPOUT_FRAME_NUMBER_OFS              0
+
+/* Endpoint Buffer Size OUT/Max Packet Size Registers -----------------------*/
+#define UDC_EPOUT_BUFF_SIZE_ADDR                0x0c
+#define UDC_EP_MAX_PKT_SIZE_ADDR                0x0c
+
+#define UDC_EPOUT_BUFF_SIZE_MASK                0xffff0000
+#define UDC_EPOUT_BUFF_SIZE_OFS                 16
+#define UDC_EP_MAX_PKT_SIZE_MASK                0x0000ffff
+#define UDC_EP_MAX_PKT_SIZE_OFS                 0
+/* EP0in max packet size = 64 bytes */
+#define UDC_EP0IN_MAX_PKT_SIZE                  64
+/* EP0out max packet size = 64 bytes */
+#define UDC_EP0OUT_MAX_PKT_SIZE                 64
+/* EP0in fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0IN_MAX_PKT_SIZE               64
+/* EP0out fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0OUT_MAX_PKT_SIZE              64
+
+/* Endpoint dma descriptors ------------------------------------------------*/
+/* Setup data */
+/* Status dword */
+#define UDC_DMA_STP_STS_CFG_MASK                0x0fff0000
+#define UDC_DMA_STP_STS_CFG_OFS                 16
+#define UDC_DMA_STP_STS_CFG_ALT_MASK            0x000f0000
+#define UDC_DMA_STP_STS_CFG_ALT_OFS             16
+#define UDC_DMA_STP_STS_CFG_INTF_MASK           0x00f00000
+#define UDC_DMA_STP_STS_CFG_INTF_OFS            20
+#define UDC_DMA_STP_STS_CFG_NUM_MASK            0x0f000000
+#define UDC_DMA_STP_STS_CFG_NUM_OFS             24
+#define UDC_DMA_STP_STS_RX_MASK                 0x30000000
+#define UDC_DMA_STP_STS_RX_OFS                  28
+#define UDC_DMA_STP_STS_BS_MASK                 0xc0000000
+#define UDC_DMA_STP_STS_BS_OFS                  30
+#define UDC_DMA_STP_STS_BS_HOST_READY           0
+#define UDC_DMA_STP_STS_BS_DMA_BUSY             1
+#define UDC_DMA_STP_STS_BS_DMA_DONE             2
+#define UDC_DMA_STP_STS_BS_HOST_BUSY            3
+/* IN data */
+/* Status dword */
+#define UDC_DMA_IN_STS_TXBYTES_MASK            0x0000ffff
+#define UDC_DMA_IN_STS_TXBYTES_OFS             0
+#define UDC_DMA_IN_STS_FRAMENUM_MASK           0x07ff0000
+#define UDC_DMA_IN_STS_FRAMENUM_OFS            0
+#define UDC_DMA_IN_STS_L                       27
+#define UDC_DMA_IN_STS_TX_MASK                 0x30000000
+#define UDC_DMA_IN_STS_TX_OFS                  28
+#define UDC_DMA_IN_STS_BS_MASK                 0xc0000000
+#define UDC_DMA_IN_STS_BS_OFS                  30
+#define UDC_DMA_IN_STS_BS_HOST_READY           0
+#define UDC_DMA_IN_STS_BS_DMA_BUSY             1
+#define UDC_DMA_IN_STS_BS_DMA_DONE             2
+#define UDC_DMA_IN_STS_BS_HOST_BUSY            3
+/* OUT data */
+/* Status dword */
+#define UDC_DMA_OUT_STS_RXBYTES_MASK            0x0000ffff
+#define UDC_DMA_OUT_STS_RXBYTES_OFS             0
+#define UDC_DMA_OUT_STS_FRAMENUM_MASK           0x07ff0000
+#define UDC_DMA_OUT_STS_FRAMENUM_OFS            0
+#define UDC_DMA_OUT_STS_L                       27
+#define UDC_DMA_OUT_STS_RX_MASK                 0x30000000
+#define UDC_DMA_OUT_STS_RX_OFS                  28
+#define UDC_DMA_OUT_STS_BS_MASK                 0xc0000000
+#define UDC_DMA_OUT_STS_BS_OFS                  30
+#define UDC_DMA_OUT_STS_BS_HOST_READY           0
+#define UDC_DMA_OUT_STS_BS_DMA_BUSY             1
+#define UDC_DMA_OUT_STS_BS_DMA_DONE             2
+#define UDC_DMA_OUT_STS_BS_HOST_BUSY            3
+/* other constants */
+/* max ep0in packet */
+#define UDC_EP0IN_MAXPACKET                     1000
+/* max dma packet */
+#define UDC_DMA_MAXPACKET                       65536
+/* DMA buffer len for temp request, should be the same as the upper
+   layer gadget is using */
+#define UDC_DMA_TEMP_BUFFER_LEN                 4096
+/* un-usable DMA address */
+#define DMA_DONT_USE                           (~(dma_addr_t)0)
+
+/* other Endpoint register addresses and values-----------------------------*/
+#define UDC_EP_SUBPTR_ADDR                      0x10
+#define UDC_EP_DESPTR_ADDR                      0x14
+#define UDC_EP_WRITE_CONFIRM_ADDR               0x1c
+
+/* EP number as layouted in AHB space */
+#define UDC_EP_NUM                              32
+#define UDC_EPIN_NUM                            16
+#define UDC_EPIN_NUM_USED                       5
+#define UDC_EPOUT_NUM                           16
+/* EP number of EP's really used = EP0 + 8 data EP's */
+#define UDC_USED_EP_NUM                         9
+/* UDC CSR regs are aligned but AHB regs not - offset for OUT EP's */
+#define UDC_CSR_EP_OUT_IX_OFS                   12
+
+#define UDC_EP0OUT_IX                           16
+#define UDC_EP0IN_IX                            0
+
+/* max packet */
+#define UDC_HS_BULK_MAXPKT                      512
+
+/* Rx fifo address and size = 1k -------------------------------------------*/
+#define UDC_RXFIFO_ADDR                         0x800
+#define UDC_RXFIFO_SIZE                         0x400
+
+/* Tx fifo address and size = 1.5k -----------------------------------------*/
+#define UDC_TXFIFO_ADDR                         0xc00
+#define UDC_TXFIFO_SIZE                         0x600
+
+/* default data endpoints --------------------------------------------------*/
+#define UDC_EPIN_STATUS_IX                      1
+#define UDC_EPIN_IX                             2
+#define UDC_EPOUT_IX                            18
+
+/* general constants -------------------------------------------------------*/
+#define UDC_DWORD_BYTES                         4
+#define UDC_BITS_PER_BYTE_SHIFT                 3
+#define UDC_BYTE_MASK                           0xff
+#define UDC_BITS_PER_BYTE                       8
+
+/* char device constants ---------------------------------------------------*/
+/* names */
+#ifdef UDC_DEBUG
+#ifdef UDC_DRIVER_NAME
+#define UDC_DEVICE_NAME UDC_DRIVER_NAME
+#else
+#define UDC_DEVICE_NAME "amd5536udc"
+#endif
+#define UDC_DEVICE_FILE_NAME "amd5536udc_dev"
+#define UDC_DEVICE_FILE_INODE "/dev/amd5536udc_dev"
+/* major number */
+#define UDC_MAJOR_NUM   240
+#endif
+
+#ifdef __KERNEL__
+/* kernel wrappers */
+#define device_create_file(x, y) do {} while (0)
+#define device_remove_file device_create_file
+
+#ifndef WARN_ON
+#define WARN_ON(a) do {} while (0)
+#endif
+
+#ifndef BUG_ON
+#define BUG_ON(cond)do {if (unlikely((cond) != 0)) BUG(); } while (0)
+#endif
+
+#ifndef likely
+#define likely(a) (a)
+#define unlikely(a) (a)
+#endif
+
+#ifndef container_of
+#define container_of list_entry
+#endif
+
+#endif
+
+/* MIPS specific -----------------------------------------------------------*/
+
+/*****************************************************************************
+ * Includes
+ *****************************************************************************/
+#include "au1200_otg.h"
+
+/*****************************************************************************
+ *  Types
+ *****************************************************************************/
+
+/* UDC CSR's */
+struct udc_csrs {
+
+	/* sca - setup command address */
+	u32 sca;
+
+	/* ep ne's */
+	u32 ne[UDC_USED_EP_NUM];
+} __attribute__ ((packed));
+
+/* AHB subsystem CSR registers */
+struct udc_regs {
+
+	/* device configuration */
+	u32 cfg;
+
+	/* device control */
+	u32 ctl;
+
+	/* device status */
+	u32 sts;
+
+	/* device interrupt */
+	u32 irqsts;
+
+	/* device interrupt mask */
+	u32 irqmsk;
+
+	/* endpoint interrupt  */
+	u32 ep_irqsts;
+
+	/* endpoint interrupt mask */
+	u32 ep_irqmsk;
+} __attribute__ ((packed));
+
+/* endpoint specific registers */
+struct udc_ep_regs {
+
+	/* endpoint control */
+	u32 ctl;
+
+	/* endpoint status */
+	u32 sts;
+
+	/* endpoint buffer size in/ receive packet frame number out  */
+	u32 bufin_framenum;
+
+	/* endpoint buffer size out/max packet size */
+	u32 bufout_maxpkt;
+
+	/* endpoint setup buffer pointer */
+	u32 subptr;
+
+	/* endpoint data descriptor pointer */
+	u32 desptr;
+
+	/* reserverd */
+	u32 reserved;
+
+	/* write/read confirmation */
+	u32 confirm;
+
+}  __attribute__ ((packed));
+
+#ifdef __KERNEL__
+/* control data DMA desc */
+struct udc_stp_dma {
+	/* status quadlet */
+	u32     status;
+	/* reserved */
+	u32     _reserved;
+	/* first setup word */
+	u32     data12;
+	/* second setup word */
+	u32     data34;
+} __attribute__((aligned(16)));
+
+/* normal data DMA desc */
+struct udc_data_dma {
+	/* status quadlet */
+	u32     status;
+	/* reserved */
+	u32     _reserved;
+	/* buffer pointer */
+	u32     bufptr;
+	/* next descriptor pointer */
+	u32     next;
+} __attribute__((aligned(16)));
+
+/* request packet */
+struct udc_request {
+	/* embedded gadget ep */
+	struct usb_request                  req;
+
+	/* flags */
+	unsigned                            dma_going:1,
+					    dma_done : 1;
+	/* phys. address */
+	dma_addr_t                          td_phys;
+	/* first dma desc. of chain */
+	struct udc_data_dma                 *td_data;
+
+	struct list_head                    queue;
+
+	/* chain length */
+	unsigned                            chain_len;
+	int				    serial_number;
+	bool				    ready_for_p_bit;
+
+};
+
+/* UDC specific endpoint parameters */
+struct udc_ep {
+	struct usb_ep                       ep;
+	struct udc_ep_regs                  *regs;
+	u32                                 *txfifo;
+	u32                                 *dma;
+	dma_addr_t                          td_phys;
+	dma_addr_t                          td_stp_dma;
+	struct udc_stp_dma                  *td_stp;
+	struct udc_data_dma                 *td;
+	/* temp request */
+	struct udc_request                  *req;
+	unsigned                            req_used;
+	unsigned                            req_completed;
+
+	/* NAK state */
+	unsigned                            naking;
+	struct tasklet_struct			execute_tasklet;
+	struct semaphore				in_use;
+	struct semaphore				in_et;
+
+	struct udc                          *dev;
+
+	/* queue for requests */
+	struct list_head                        queue;
+	const struct usb_endpoint_descriptor    *desc;
+	unsigned                                halted;
+	unsigned                                num:5,
+						fifo_depth : 14,
+						in : 1;
+};
+
+/* device struct */
+struct udc {
+	struct usb_gadget               gadget;
+	spinlock_t                      lock;
+	/* all endpoints */
+	struct udc_ep                   ep[UDC_EP_NUM];
+	struct usb_gadget_driver        *driver;
+	struct otg_transceiver          *otg_transceiver;
+	struct usb_otg_gadget_extension *otg_driver;
+	/* operational flags */
+	unsigned                        active:1,
+					waiting_zlp_ack_ep0in : 1,
+					set_cfg_not_acked : 1,
+					irq_registered : 1,
+					otg_supported : 1,
+					data_ep_enabled : 1,
+					data_ep_queued : 1,
+					mem_region : 1,
+					selfpowered : 1,
+					sys_suspended : 1,
+					connected;
+
+	u16                             chiprev;
+
+	/* registers */
+	struct device                   *pdev;
+	struct udc_csrs                 *csr;
+	struct udc_regs                 *regs;
+	struct udc_ep_regs              *ep_regs;
+	u32                             *rxfifo;
+	u32                             *txfifo;
+
+	/* DMA desc pools */
+	struct dma_pool                 *data_requests;
+	struct dma_pool                 *stp_requests;
+
+	/* device data */
+	unsigned long                   phys_addr;
+	void                            *virt_addr;
+	unsigned                        irq;
+
+	/* states */
+	u16                             cur_config;
+	u16                             cur_intf;
+	u16                             cur_alt;
+};
+
+/* setup request data */
+union udc_setup_data {
+	u32                        data[2];
+	struct usb_ctrlrequest     request;
+};
+#endif /*__KERNEL__*/
+
+/*****************************************************************************
+ *  Macros
+ *****************************************************************************/
+
+/***************************************
+ * SET and GET bitfields in u32 values
+ * via constants for mask/offset:
+ * <bit_field_stub_name> is the text between
+ * UDC_ and _MASK|_OFS of appropiate
+ * constant
+ ****************************************/
+/* set bitfield value in u32 u32Val */
+#define UDC_ADDBITS(u32Val, bitfield_val, bitfield_stub_name)\
+	(((u32Val) & (((u32) ~((u32) bitfield_stub_name##_MASK))))\
+	 |(((bitfield_val) << ((u32) bitfield_stub_name##_OFS))\
+		 & ((u32) bitfield_stub_name##_MASK)))
+
+/* set bitfield value in zero-initialized u32 u32Val */
+/* => bitfield bits in u32Val are all zero */
+#define UDC_INIT_SETBITS(u32Val, bitfield_val, bitfield_stub_name)\
+	((u32Val)\
+	 |(((bitfield_val) << ((u32) bitfield_stub_name##_OFS))\
+		 &((u32) bitfield_stub_name##_MASK)))
+
+/* get bitfield value from u32 u32Val */
+#define UDC_GETBITS(u32Val, bitfield_stub_name)\
+	((u32Val & ((u32) bitfield_stub_name##_MASK))\
+	 >> ((u32) bitfield_stub_name##_OFS))
+
+/* SET and GET bits in u32 values ------------------------------------------*/
+#define UDC_BIT(bit_stub_name) (1 << bit_stub_name)
+#define UDC_UNMASK_BIT(bit_stub_name) (~UDC_BIT(bit_stub_name))
+#define UDC_CLEAR_BIT(bit_stub_name) (~UDC_BIT(bit_stub_name))
+
+#define UDC_SET_BIT(bit_number, register_address)			\
+	do {								\
+		iowrite32(ioread32((register_address)) | (1 << bit_number),\
+				(register_address));			\
+		au_sync();						\
+	} while (0)
+
+/* Note that this takes a set of bits and does not shift them */
+#define	UDC_SET_BITS(bits_to_set, register_address)			\
+	do {								\
+		iowrite32(ioread32((register_address)) | (bits_to_set),	\
+				(register_address));			\
+		au_sync();						\
+	} while (0)
+
+#define UDC_UNSET_BIT(bit_number, register_address)			\
+	do {								\
+		iowrite32(ioread32((register_address)) & ~(1 << bit_number),\
+				(register_address)); 			\
+		au_sync();						\
+	} while (0)
+
+/* misc --------------------------------------------------------------------*/
+#define        DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
+
+/* print macros ------------------------------------------------------------*/
+
+#ifdef UDC_VERBOSE
+#ifndef UDC_DEBUG
+#define UDC_DEBUG
+#endif
+#endif
+
+/**
+ * \brief
+ * Macro for printing information in drivers
+ *
+ * This macro is used for printing kernel messages in driver source code.
+ * It should be used for printing useful information about states and called
+ * functions for normal operation (not for errors and warnings).
+ *
+ * \param fmt is format string for printk
+ * \param args... are arguments given to printk (number depends on <fmt>)
+ * \return code from printk
+ */
+#define INFO(args...) \
+	printk(KERN_INFO DRIVER_NAME_FOR_PRINT ": " args)
+
+/**
+ * \brief
+ * Macro for printing warnings in drivers
+ *
+ * This macro is used for printing kernel messages in driver source code.
+ * It should be used for printing warnings.
+ *
+ * \param fmt is format string for printk
+ * \param args... are arguments given to printk (number depends on <fmt>)
+ * \return code from printk
+ */
+#ifdef WARN
+#undef WARN
+#endif
+#define WARN(args...) \
+	printk(KERN_WARNING DRIVER_NAME_FOR_PRINT " warning: " args)
+
+/**
+ * \brief
+ * Macro for printing errors in drivers
+ *
+ * This macro is used for printing kernel messages in driver source code.
+ * It should be used for printing errors.
+ *
+ * \param fmt is format string for printk
+ * \param args... are arguments given to printk (number depends on <fmt>)
+ * \return code from printk
+ */
+#define ERR(args...) \
+	printk(KERN_ERR DRIVER_NAME_FOR_PRINT " error: " args)
+
+/**
+ * \brief
+ * Macro for printing debug messages in drivers
+ *
+ * This macro is used for printing kernel messages in driver source code
+ * when UDC_DEBUG is defined
+ * It should be used for printing debug messages.
+ *
+ * \param fmt is format string for printk
+ * \param args... are arguments given to printk (number depends on <fmt>)
+ * \return code from printk
+ */
+#ifdef UDC_DEBUG
+#define DBG(args...) \
+	printk(KERN_DEBUG DRIVER_NAME_FOR_PRINT " debug: " args)
+#else
+
+#define DBG(args...) \
+	do {} while (0)
+#endif
+
+/**
+ * \brief
+ * Macro for printing verbose debug messages in drivers
+ *
+ * This macro is used for printing kernel messages in driver source code
+ * when UDC_DEBUG and UDC_VERBOSE is defined
+ * It should be used for printing debug messages.
+ *
+ * \param fmt is format string for printk
+ * \param args... are arguments given to printk (number depends on <fmt>)
+ * \return code from printk
+ */
+#ifdef UDC_VERBOSE
+#define VDBG DBG
+#else
+#define VDBG(args...) \
+	do {} while (0)
+#endif
+
+/*****************************************************************************
+ *  Data
+ *****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+/*****************************************************************************
+ *  Functions
+ *****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+/*****************************************************************************
+ *  Inline Functions
+ *****************************************************************************/
+
+#endif /* #ifdef  AU1200UDC_H */
diff --git a/drivers/usb/gadget/au1200_uoc.h b/drivers/usb/gadget/au1200_uoc.h
new file mode 100644
index 0000000..569668a
--- /dev/null
+++ b/drivers/usb/gadget/au1200_uoc.h
@@ -0,0 +1,1021 @@
+/*
+ * Declarations and macros for the Au1200 On The Go port driver.
+ */
+
+/*
+ * Copyright (C) 2008 RMI Corporation (http://www.rmicorp.com)
+ * Author: Kevin Hickey (khickey@xxxxxxxxxxx)
+ *
+ * Adapted from earlier work by Karsten Boge
+ *
+ * THIS SOFTWARE IS PROVIDED BY RMI Corporation '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 RMI 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 program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef AU1200_UOC_H
+#define AU1200_UOC_H
+
+
+/*****************************************************************************
+*  Config options
+*****************************************************************************/
+#ifdef VERBOSE
+#ifndef DEBUG
+#define DEBUG
+#endif
+#endif
+
+
+/*****************************************************************************
+*  Constants
+*****************************************************************************/
+
+#define OTG_DRIVER_NAME        "au1200_otg"
+#define OTG_FLAGS_ACTIV        (1<<19)   /* full OTG functionality is activ  */
+
+/**********************************
+*  Register definitions
+**********************************/
+/* capabilities */
+#define OTG_CAP_APU            (1<<15)   /* automatic pull-up enable         */
+
+/* multiplexer */
+#define OTG_MUX_DISABLE_ALL    0         /* not assigned                     */
+#define OTG_MUX_ENABLE_UHC     (2<<0)    /* assigned to host                 */
+#define OTG_MUX_ENABLE_UDC     (3<<0)    /* assigned to device               */
+#define OTG_MUX_PUEN           (1<<2)    /* pull-up enable                   */
+#define OTG_MUX_VBUSVLD        (1<<8)    /* VBus valid                       */
+
+/* status */
+#define OTG_STS_ID             (1<<0)    /* ID pin status                    */
+#define OTG_STS_VBUSVLD        (1<<1)    /* VBus valid                       */
+#define OTG_STS_SESSVLD        (1<<2)    /* Session valid                    */
+#define OTG_STS_SESSEND        (1<<3)    /* Session end                      */
+#define OTG_STS_LST            (3<<4)    /* Line state                       */
+#define OTG_STS_LST_J          (1<<4)    /* Line state                       */
+#define OTG_STS_LST_K          (2<<4)    /* Line state                       */
+#define OTG_STS_PSPD           (3<<6)    /* Port speed                       */
+#define OTG_STS_PSPD_LS        (1<<7)    /* Port speed                       */
+#define OTG_STS_PSPD_FS        (2<<7)    /* Port speed                       */
+#define OTG_STS_FSOE           (1<<8)    /* FS output enable (OHC)           */
+#define OTG_STS_PCON           (1<<9)    /* Port connected                   */
+#define OTG_STS_PSUS           (1<<10)   /* Port suspended                   */
+#define OTG_STS_TMH            (1<<11)   /* Timer halted                     */
+#define OTG_STS_HNP_EN         (1<<12)   /* HNP enabled for B-dev            */
+#define OTG_STS_HNP_SUPP       (1<<13)   /* A-host supports HNP              */
+#define OTG_STS_HNP_ALTSUPP    (1<<14)   /* A-host supports alt. HNP         */
+#define OTG_STS_HNPSTS         (OTG_STS_HNP_EN | OTG_STS_HNP_SUPP | \
+		OTG_STS_HNP_ALTSUPP)
+#define OTG_STS_OC             (1<<15)   /* over-current                     */
+#define OTG_STS_DPR            (1<<16)   /* Downstream port reset            */
+
+/* control */
+#define OTG_CTL_DISABLE_ALL    0         /* not assigned                     */
+#define OTG_CTL_ENABLE_UHC     (2<<0)    /* assigned to host                 */
+#define OTG_CTL_ENABLE_UDC     (3<<0)    /* assigned to device               */
+#define OTG_CTL_MUX_MASK       (3<<0)    /* port mux mask                    */
+#define OTG_CTL_PPWR           (1<<2)    /* port power switch                */
+#define OTG_CTL_PPO            (1<<3)    /* port power override              */
+#define OTG_CTL_CHRG           (1<<4)    /* charge VBus                      */
+#define OTG_CTL_DISCHRG        (1<<5)    /* discharge VBus                   */
+#define OTG_CTL_IDSNSEN        (1<<6)    /* ID sense enable, ID-PU           */
+#define OTG_CTL_PADEN          (1<<7)
+#define OTG_CTL_PUEN           (1<<8)    /* pull-up enable                   */
+#define OTG_CTL_DMPDEN         (1<<9)    /* pull-down enable                 */
+#define OTG_CTL_HNPSFEN        (1<<10)   /* HNP SET_FEATURE enable           */
+#define OTG_CTL_WPCS_DEAS      (2<<16)   /* deassert port connect            */
+#define OTG_CTL_WPCS_ASRT      (3<<16)   /* assert port connect              */
+#define OTG_CTL_WPSS_DEAS      (2<<18)   /* deassert port suspend            */
+#define OTG_CTL_WPSS_ASRT      (3<<18)   /* assert port suspend              */
+/* timer conditions */
+#define OTG_CTL_TMR_RLP        (1<<28)   /* timer reload policy              */
+#define OTG_CTL_TMR_ALL        (0xf<<24) /* stop timer                       */
+#define OTG_CTL_TMR_STOP       0         /* timer disabled                   */
+#define OTG_CTL_TMR_UNCOND     (1<<24)   /* count unconditionally            */
+#define OTG_CTL_TMR_SE0        (2<<24)   /* count if LSt = FS-SE0            */
+#define OTG_CTL_TMR_FSJ        (3<<24)   /* count if LSt = FS-J              */
+#define OTG_CTL_TMR_FSK        (4<<24)   /* count if LSt = FS-K              */
+#define OTG_CTL_TMR_NOSE0      (5<<24)   /* count if LSt <> FS-SE0           */
+#define OTG_CTL_TMR_NORX       (6<<24)   /* count if Rx inactiv              */
+#define OTG_CTL_TMR_ID         (7<<24)   /* count if ID = 0                  */
+
+/* interrupts */
+#define OTG_INT_GLOBAL         (1<<31)   /* global interrupt enable          */
+#define OTG_INT_ENALL          0x7fff    /* enable all                       */
+#define OTG_INT_DISALL         0         /* disable all                      */
+#define OTG_INT_IDC            (1<<0)    /* ID pin change                    */
+#define OTG_INT_VBVC           (1<<1)    /* VBUS valid change                */
+#define OTG_INT_SVC            (1<<2)    /* Session valid change             */
+#define OTG_INT_SEC            (1<<3)    /* Session end change               */
+#define OTG_INT_LSTC           (1<<4)    /* Line state change                */
+#define OTG_INT_PSPDC          (1<<5)    /* Port speed change                */
+#define OTG_INT_FSOEC          (1<<6)    /* FS/LS OE change                  */
+#define OTG_INT_HSDD           (1<<7)    /* HS disconnect detected           */
+#define OTG_INT_RXACT          (1<<8)    /* Rx activity detected             */
+#define OTG_INT_PCC            (1<<9)    /* Port connect change              */
+#define OTG_INT_PSC            (1<<10)   /* Port suspend change              */
+#define OTG_INT_TMX            (1<<11)   /* Timer expired                    */
+#define OTG_INT_HNPFC          (1<<12)   /* HNP feature change               */
+#define OTG_INT_OCD            (1<<13)   /* over current detected            */
+#define OTG_INT_DPRC           (1<<14)   /* Downstream port reset change     */
+
+#define OTG_INT_ADDS   OTG_INT_SVC
+
+/**********************************
+ *  OTG state dependend data
+ **********************************/
+
+/*
+ * generic
+ */
+#define OTG_CTL_DEFAULT                      (OTG_CTL_PADEN | \
+		OTG_CTL_IDSNSEN)
+#define OTG_CTL_HOST_DEFAULT                 (OTG_CTL_DEFAULT | \
+		OTG_CTL_ENABLE_UHC)
+#ifdef CONFIG_USB_OTG
+#define OTG_CTL_PERIPHERAL_DEFAULT           (OTG_CTL_DEFAULT | \
+		OTG_CTL_HNPSFEN | \
+		OTG_CTL_ENABLE_UDC | \
+		OTG_CTL_PPO | OTG_CTL_PUEN)
+#else
+#define OTG_CTL_PERIPHERAL_DEFAULT           (OTG_CTL_DEFAULT | \
+		OTG_CTL_ENABLE_UDC | \
+		OTG_CTL_PPO | OTG_CTL_PUEN)
+#endif
+
+#define OTG_INT_DEFAULT                      OTG_INT_IDC
+
+/*
+ * OTG_STATE_UNDEFINED
+ */
+#define OTG_STATE_UNDEFINED_CONTROL          (OTG_CTL_DEFAULT | OTG_CTL_PPO | \
+		OTG_CTL_TMR_UNCOND)
+#define OTG_STATE_UNDEFINED_STATUS           0
+#define OTG_STATE_UNDEFINED_STATUS_MASK      0
+#define OTG_STATE_UNDEFINED_INTERRUPTS       OTG_INT_TMX
+
+/*
+ * OTG_STATE_NO_B_DEVICE_A
+ */
+#define OTG_STATE_NO_B_DEVICE_A_CONTROL      OTG_CTL_HOST_DEFAULT
+#define OTG_STATE_NO_B_DEVICE_A_STATUS       0
+#define OTG_STATE_NO_B_DEVICE_A_STATUS_MASK  0
+#define OTG_STATE_NO_B_DEVICE_A_INTERRUPTS   OTG_INT_DEFAULT
+
+/*
+ * OTG_STATE_NO_B_DEVICE_B
+ */
+#define OTG_STATE_NO_B_DEVICE_B_CONTROL      (OTG_CTL_DEFAULT | OTG_CTL_PPO)
+#define OTG_STATE_NO_B_DEVICE_B_STATUS       0
+#define OTG_STATE_NO_B_DEVICE_B_STATUS_MASK  0
+#define OTG_STATE_NO_B_DEVICE_B_INTERRUPTS   OTG_INT_DEFAULT
+
+/*
+ * OTG_STATE_A_IDLE
+ */
+#define OTG_STATE_A_IDLE_CONTROL             (OTG_CTL_DEFAULT | OTG_CTL_PPO)
+#define OTG_STATE_A_IDLE_STATUS              0
+#define OTG_STATE_A_IDLE_STATUS_MASK         0
+#define OTG_STATE_A_IDLE_INTERRUPTS          (OTG_INT_DEFAULT | OTG_INT_SVC | \
+		OTG_INT_LSTC)
+
+/*
+ * OTG_STATE_A_IDLE_WAIT_DP
+ */
+#define OTG_STATE_A_IDLE_WAIT_DP_CONTROL     (OTG_STATE_A_IDLE_CONTROL | \
+		OTG_CTL_TMR_UNCOND)
+#define OTG_STATE_A_IDLE_WAIT_DP_STATUS      0
+#define OTG_STATE_A_IDLE_WAIT_DP_STATUS_MASK 0
+#define OTG_STATE_A_IDLE_WAIT_DP_INTERRUPTS  (OTG_STATE_A_IDLE_INTERRUPTS | \
+		OTG_INT_TMX)
+
+/*
+ * OTG_STATE_A_IDLE_WAIT_VP
+ */
+#define OTG_STATE_A_IDLE_WAIT_VP_CONTROL     (OTG_STATE_A_IDLE_CONTROL | \
+		OTG_CTL_TMR_UNCOND)
+#define OTG_STATE_A_IDLE_WAIT_VP_STATUS      0
+#define OTG_STATE_A_IDLE_WAIT_VP_STATUS_MASK 0
+#define OTG_STATE_A_IDLE_WAIT_VP_INTERRUPTS  (OTG_STATE_A_IDLE_INTERRUPTS | \
+		OTG_INT_TMX)
+
+/*
+ * OTG_STATE_A_IDLE_WAIT_MP
+ */
+#define OTG_STATE_A_IDLE_WAIT_MP_CONTROL     (OTG_STATE_A_IDLE_CONTROL | \
+		OTG_CTL_TMR_UNCOND)
+#define OTG_STATE_A_IDLE_WAIT_MP_STATUS      0
+#define OTG_STATE_A_IDLE_WAIT_MP_STATUS_MASK 0
+#define OTG_STATE_A_IDLE_WAIT_MP_INTERRUPTS  (OTG_STATE_A_IDLE_INTERRUPTS | \
+		OTG_INT_TMX)
+
+/*
+ * OTG_STATE_A_IDLE_WAIT_DV
+ */
+#define OTG_STATE_A_IDLE_WAIT_DV_CONTROL     (OTG_STATE_A_IDLE_CONTROL | \
+		OTG_CTL_TMR_UNCOND)
+#define OTG_STATE_A_IDLE_WAIT_DV_STATUS      0
+#define OTG_STATE_A_IDLE_WAIT_DV_STATUS_MASK 0
+#define OTG_STATE_A_IDLE_WAIT_DV_INTERRUPTS  (OTG_STATE_A_IDLE_INTERRUPTS | \
+		OTG_INT_TMX)
+
+/*
+ * OTG_STATE_A_WAIT_VRISE
+ */
+#define OTG_STATE_A_WAIT_VRISE_CONTROL       (OTG_CTL_HOST_DEFAULT | \
+		OTG_CTL_TMR_UNCOND)
+#define OTG_STATE_A_WAIT_VRISE_STATUS        0
+#define OTG_STATE_A_WAIT_VRISE_STATUS_MASK   0
+#define OTG_STATE_A_WAIT_VRISE_INTERRUPTS    (OTG_INT_DEFAULT | OTG_INT_TMX | \
+		OTG_INT_VBVC)
+
+/*
+ * OTG_STATE_A_WAIT_BCON
+ */
+#define OTG_STATE_A_WAIT_BCON_CONTROL        OTG_CTL_HOST_DEFAULT
+#define OTG_STATE_A_WAIT_BCON_STATUS         0
+#define OTG_STATE_A_WAIT_BCON_STATUS_MASK    0
+#define OTG_STATE_A_WAIT_BCON_INTERRUPTS     (OTG_INT_DEFAULT | OTG_INT_TMX | \
+		OTG_INT_VBVC | OTG_INT_PCC)
+
+/*
+ * OTG_STATE_A_WAIT_BCON_VB
+ */
+#define OTG_STATE_A_WAIT_BCON_VB_CONTROL     (OTG_STATE_A_WAIT_BCON_CONTROL | \
+		OTG_CTL_TMR_UNCOND)
+#define OTG_STATE_A_WAIT_BCON_VB_STATUS      0
+#define OTG_STATE_A_WAIT_BCON_VB_STATUS_MASK 0
+#define OTG_STATE_A_WAIT_BCON_VB_INTERRUPTS  OTG_STATE_A_WAIT_BCON_INTERRUPTS
+
+/*
+ * OTG_STATE_A_HOST
+ */
+#define OTG_STATE_A_HOST_CONTROL             OTG_CTL_HOST_DEFAULT
+#define OTG_STATE_A_HOST_STATUS              0
+#define OTG_STATE_A_HOST_STATUS_MASK         0
+#ifdef CONFIG_USB_OTG
+#ifndef VERBOSE
+#define OTG_STATE_A_HOST_INTERRUPTS          (OTG_INT_DEFAULT | \
+		OTG_INT_VBVC | OTG_INT_DPRC | \
+		OTG_INT_PCC | OTG_INT_PSC)
+#else
+#define OTG_STATE_A_HOST_INTERRUPTS          (OTG_INT_DEFAULT | \
+		OTG_INT_VBVC | OTG_INT_DPRC | \
+		OTG_INT_PCC | OTG_INT_PSC | \
+		OTG_INT_PSPDC)
+/* OTG_INT_LSTC */
+#endif
+#else
+/* IDPIN mode only                                                   */
+#define OTG_STATE_A_HOST_INTERRUPTS          OTG_INT_IDC
+#endif
+
+/*
+ * OTG_STATE_A_SUSPEND
+ */
+#define OTG_STATE_A_SUSPEND_CONTROL          (OTG_CTL_HOST_DEFAULT | \
+		OTG_CTL_TMR_UNCOND)
+#define OTG_STATE_A_SUSPEND_STATUS           0
+#define OTG_STATE_A_SUSPEND_STATUS_MASK      0
+#define OTG_STATE_A_SUSPEND_INTERRUPTS       (OTG_INT_DEFAULT | OTG_INT_TMX | \
+		OTG_INT_VBVC |  OTG_INT_DPRC | \
+		OTG_INT_PCC | OTG_INT_PSC)
+
+/*
+ * OTG_STATE_A_PERIPHERAL
+ */
+#define OTG_STATE_A_PERIPHERAL_CONTROL       (OTG_CTL_PERIPHERAL_DEFAULT | \
+		OTG_CTL_PPWR | OTG_CTL_DMPDEN)
+#define OTG_STATE_A_PERIPHERAL_STATUS        0
+#define OTG_STATE_A_PERIPHERAL_STATUS_MASK   0
+#ifndef VERBOSE
+#define OTG_STATE_A_PERIPHERAL_INTERRUPTS    (OTG_INT_DEFAULT | \
+		OTG_INT_VBVC | OTG_INT_OCD | \
+		OTG_INT_PCC | OTG_INT_PSC)
+#else
+#define OTG_STATE_A_PERIPHERAL_INTERRUPTS    (OTG_INT_DEFAULT | \
+		OTG_INT_VBVC | OTG_INT_OCD | \
+		OTG_INT_PCC | OTG_INT_PSC | \
+		OTG_INT_PSPDC)
+/* OTG_INT_LSTC */
+#endif
+
+/*
+ * OTG_STATE_A_VBUS_ERR
+ */
+#define OTG_STATE_A_VBUS_ERR_CONTROL         (OTG_CTL_HOST_DEFAULT | \
+		OTG_CTL_PPO | OTG_CTL_DISCHRG)
+#define OTG_STATE_A_VBUS_ERR_STATUS          0
+#define OTG_STATE_A_VBUS_ERR_STATUS_MASK     0
+#define OTG_STATE_A_VBUS_ERR_INTERRUPTS      OTG_INT_DEFAULT
+
+/*
+ * OTG_STATE_A_WAIT_VFALL
+ */
+#define OTG_STATE_A_WAIT_VFALL_CONTROL       (OTG_CTL_HOST_DEFAULT | \
+		OTG_CTL_PPO)
+#define OTG_STATE_A_WAIT_VFALL_STATUS        0
+#define OTG_STATE_A_WAIT_VFALL_STATUS_MASK   0
+#define OTG_STATE_A_WAIT_VFALL_INTERRUPTS    (OTG_INT_DEFAULT | OTG_INT_SEC)
+
+/*
+ * OTG_STATE_A_WAIT_VFALL_DN
+ */
+#define OTG_STATE_A_WAIT_VFALL_DN_CONTROL    (OTG_STATE_A_WAIT_VFALL_CONTROL | \
+		OTG_CTL_DISCHRG)
+#define OTG_STATE_A_WAIT_VFALL_DN_STATUS      0
+#define OTG_STATE_A_WAIT_VFALL_DN_STATUS_MASK 0
+#define OTG_STATE_A_WAIT_VFALL_DN_INTERRUPTS  OTG_STATE_A_WAIT_VFALL_INTERRUPTS
+
+/*
+ * OTG_STATE_A_WAIT_BDISCON
+ */
+#define OTG_STATE_A_WAIT_BDISCON_CONTROL     (OTG_CTL_DEFAULT | \
+		OTG_CTL_PPO | OTG_CTL_PPWR | \
+		OTG_CTL_TMR_UNCOND)
+#define OTG_STATE_A_WAIT_BDISCON_STATUS      0
+#define OTG_STATE_A_WAIT_BDISCON_STATUS_MASK 0
+#define OTG_STATE_A_WAIT_BDISCON_INTERRUPTS  (OTG_INT_DEFAULT | OTG_INT_TMX | \
+		OTG_INT_VBVC | OTG_INT_OCD | \
+		OTG_INT_PSPDC | OTG_INT_LSTC)
+
+/*
+ * OTG_STATE_B_IDLE
+ */
+/*** HS-A0 WA: BUG-3885: VB_SESS_VLD value too high                        ***/
+/*** HS-A0 WA: BUG-3943: gadget suspend issue                              ***/
+#define OTG_STATE_B_IDLE_CONTROL             (OTG_CTL_PERIPHERAL_DEFAULT & \
+		~((u32) (OTG_CTL_PUEN | \
+				OTG_CTL_ENABLE_UDC)))
+#define OTG_STATE_B_IDLE_STATUS              0
+#define OTG_STATE_B_IDLE_STATUS_MASK         0
+#ifdef CONFIG_USB_OTG
+#define OTG_STATE_B_IDLE_INTERRUPTS          (OTG_INT_DEFAULT | OTG_INT_SVC)
+#else
+#ifdef CONFIG_USB_OTGMUX_IDPIN
+/* IDPIN mode                                                        */
+#define OTG_STATE_B_IDLE_INTERRUPTS          (OTG_INT_IDC | OTG_INT_SVC)
+#else
+/* gadget mode                                                       */
+#define OTG_STATE_B_IDLE_INTERRUPTS          OTG_INT_SVC
+#endif
+#endif
+
+/*
+ * OTG_STATE_B_PERIPHERAL
+ */
+#define OTG_STATE_B_PERIPHERAL_CONTROL       (OTG_CTL_PERIPHERAL_DEFAULT | \
+		OTG_CTL_DMPDEN)
+#define OTG_STATE_B_PERIPHERAL_STATUS        0
+#define OTG_STATE_B_PERIPHERAL_STATUS_MASK   0
+#ifdef CONFIG_USB_OTG
+#ifndef VERBOSE
+#define OTG_STATE_B_PERIPHERAL_INTERRUPTS    (OTG_INT_DEFAULT | OTG_INT_SVC | \
+		OTG_INT_PCC | OTG_INT_PSC | \
+		OTG_INT_HNPFC)
+#else
+#define OTG_STATE_B_PERIPHERAL_INTERRUPTS    (OTG_INT_DEFAULT | OTG_INT_SVC | \
+		OTG_INT_PCC | OTG_INT_PSC | \
+		OTG_INT_HNPFC | OTG_INT_PSPDC)
+/* OTG_INT_LSTC */
+#endif
+#else
+#ifdef CONFIG_USB_OTGMUX_IDPIN
+/* IDPIN mode                                                        */
+#define OTG_STATE_B_PERIPHERAL_INTERRUPTS    (OTG_INT_IDC | OTG_INT_SVC)
+#else
+/* gadget mode                                                       */
+#define OTG_STATE_B_PERIPHERAL_INTERRUPTS    OTG_INT_SVC
+#endif
+#endif
+
+/*
+ * OTG_STATE_B_PERIPHERAL_WT
+ */
+#define OTG_STATE_B_PERIPHERAL_WT_CONTROL    (OTG_STATE_B_PERIPHERAL_CONTROL | \
+		OTG_CTL_PPO | OTG_CTL_TMR_UNCOND)
+#define OTG_STATE_B_PERIPHERAL_WT_STATUS      0
+#define OTG_STATE_B_PERIPHERAL_WT_STATUS_MASK 0
+#define OTG_STATE_B_PERIPHERAL_WT_INTERRUPTS (OTG_STATE_B_PERIPHERAL_INTERRUPTS\
+		| OTG_INT_TMX)
+
+/*
+ * OTG_STATE_B_PERIPHERAL_DC
+ */
+#define OTG_STATE_B_PERIPHERAL_DC_CONTROL    (OTG_CTL_HOST_DEFAULT | \
+		OTG_CTL_PPO | OTG_CTL_DMPDEN | \
+		OTG_CTL_TMR_UNCOND)
+#define OTG_STATE_B_PERIPHERAL_DC_STATUS      0
+#define OTG_STATE_B_PERIPHERAL_DC_STATUS_MASK 0
+#define OTG_STATE_B_PERIPHERAL_DC_INTERRUPTS (OTG_STATE_B_PERIPHERAL_INTERRUPTS\
+		| OTG_INT_TMX | OTG_INT_LSTC)
+
+/*
+ * OTG_STATE_B_WAIT_ACON
+ */
+#define OTG_STATE_B_WAIT_ACON_CONTROL        (OTG_CTL_HOST_DEFAULT | \
+		OTG_CTL_PPO | OTG_CTL_TMR_UNCOND)
+#define OTG_STATE_B_WAIT_ACON_STATUS         0
+#define OTG_STATE_B_WAIT_ACON_STATUS_MASK    0
+#define OTG_STATE_B_WAIT_ACON_INTERRUPTS     (OTG_INT_DEFAULT | OTG_INT_SVC | \
+		OTG_INT_PCC | OTG_INT_PSC | \
+		OTG_INT_HNPFC | OTG_INT_TMX)
+
+/*
+ * OTG_STATE_B_HOST
+ */
+#define OTG_STATE_B_HOST_CONTROL             (OTG_CTL_HOST_DEFAULT | \
+		OTG_CTL_PPO)
+#define OTG_STATE_B_HOST_STATUS              0
+#define OTG_STATE_B_HOST_STATUS_MASK         0
+#define OTG_STATE_B_HOST_INTERRUPTS          (OTG_INT_DEFAULT | OTG_INT_SVC | \
+		OTG_INT_PCC | OTG_INT_SVC | \
+		OTG_INT_PSPDC)
+
+/*
+ * OTG_STATE_B_HOST_WT
+ */
+#define OTG_STATE_B_HOST_WT_CONTROL          (OTG_STATE_B_HOST_CONTROL | \
+		OTG_CTL_TMR_UNCOND)
+#define OTG_STATE_B_HOST_WT_STATUS           0
+#define OTG_STATE_B_HOST_WT_STATUS_MASK      0
+#define OTG_STATE_B_HOST_WT_INTERRUPTS       (OTG_INT_DEFAULT | OTG_INT_SVC | \
+		OTG_INT_PCC | OTG_INT_TMX)
+
+/*
+ * OTG_STATE_B_SRP_INIT
+ */
+#define OTG_STATE_B_SRP_INIT_CONTROL         OTG_STATE_B_IDLE_CONTROL
+#define OTG_STATE_B_SRP_INIT_STATUS          0
+#define OTG_STATE_B_SRP_INIT_STATUS_MASK     0
+#define OTG_STATE_B_SRP_INIT_INTERRUPTS      OTG_INT_DEFAULT
+
+/*
+ * OTG_STATE_B_SRP_WTSE0
+ */
+#define OTG_STATE_B_SRP_WAIT_SE0_CONTROL     (OTG_STATE_B_SRP_INIT_CONTROL | \
+		OTG_CTL_TMR_UNCOND)
+#define OTG_STATE_B_SRP_WAIT_SE0_STATUS      0
+#define OTG_STATE_B_SRP_WAIT_SE0_STATUS_MASK 0
+#define OTG_STATE_B_SRP_WAIT_SE0_INTERRUPTS  (OTG_STATE_B_SRP_INIT_INTERRUPTS \
+		| OTG_INT_TMX | OTG_INT_LSTC)
+
+/*
+ * OTG_STATE_B_SRP_D_PLS
+ *
+ * note: changing to this state requires an additional call:
+ *       set_srp_conditions (dev);
+ *       reset_srp_conditions (dev) is required for the next state
+ */
+#define OTG_STATE_B_SRP_D_PULSE_CONTROL      (OTG_CTL_PERIPHERAL_DEFAULT | \
+		OTG_CTL_PUEN | \
+		OTG_CTL_TMR_UNCOND)
+#define OTG_STATE_B_SRP_D_PULSE_STATUS       0
+#define OTG_STATE_B_SRP_D_PULSE_STATUS_MASK  0
+#define OTG_STATE_B_SRP_D_PULSE_INTERRUPTS   (OTG_STATE_B_SRP_INIT_INTERRUPTS \
+		| OTG_INT_SEC | OTG_INT_TMX)
+
+/*
+ * OTG_STATE_B_SRP_V_PLS
+ */
+#define OTG_STATE_B_SRP_V_PULSE_CONTROL      (OTG_STATE_B_SRP_INIT_CONTROL | \
+		OTG_CTL_CHRG | \
+		OTG_CTL_TMR_UNCOND)
+#define OTG_STATE_B_SRP_V_PULSE_STATUS       0
+#define OTG_STATE_B_SRP_V_PULSE_STATUS_MASK  0
+#define OTG_STATE_B_SRP_V_PULSE_INTERRUPTS   (OTG_STATE_B_SRP_INIT_INTERRUPTS \
+		| OTG_INT_TMX)
+
+/*
+ * OTG_STATE_B_SRP_V_DCG
+ */
+#define OTG_STATE_B_SRP_V_DCHRG_CONTROL      (OTG_STATE_B_SRP_INIT_CONTROL | \
+		OTG_CTL_DISCHRG | \
+		OTG_CTL_TMR_UNCOND)
+#define OTG_STATE_B_SRP_V_DCHRG_STATUS       0
+#define OTG_STATE_B_SRP_V_DCHRG_STATUS_MASK  0
+#define OTG_STATE_B_SRP_V_DCHRG_INTERRUPTS   (OTG_STATE_B_SRP_INIT_INTERRUPTS \
+		| OTG_INT_TMX)
+
+/*
+ * OTG_STATE_B_SRP_WTVB
+ */
+#define OTG_STATE_B_SRP_WAIT_VBUS_CONTROL    (OTG_STATE_B_SRP_INIT_CONTROL | \
+		OTG_CTL_TMR_UNCOND)
+#define OTG_STATE_B_SRP_WAIT_VBUS_STATUS      0
+#define OTG_STATE_B_SRP_WAIT_VBUS_STATUS_MASK 0
+#define OTG_STATE_B_SRP_WAIT_VBUS_INTERRUPTS (OTG_STATE_B_SRP_INIT_INTERRUPTS \
+		| OTG_INT_SVC | OTG_INT_TMX)
+
+/*********************************/
+
+/* other */
+
+#define OTG_APP_REQ_ACK        0
+
+
+/*****************************************************************************
+*  Types
+*****************************************************************************/
+
+
+/*****************************************************************************
+*  Macros
+*****************************************************************************/
+
+/* printing messages */
+
+#define INFO(args...) \
+	printk(KERN_INFO DRIVER_NAME_FOR_PRINT ": " args)
+
+#ifdef WARN
+#undef WARN
+#endif
+
+#define WARN(args...) \
+	printk(KERN_WARNING DRIVER_NAME_FOR_PRINT " warning: " args)
+
+#define ERR(args...) \
+	printk(KERN_ERR DRIVER_NAME_FOR_PRINT " error: " args)
+
+#ifdef DEBUG
+#define DBG(args...) \
+	printk(KERN_DEBUG DRIVER_NAME_FOR_PRINT " debug: " args)
+#else
+#define DBG(args...) \
+	do {} while (0)
+#endif
+
+#ifdef VERBOSE
+#define VDBG DBG
+#else
+#define VDBG(args...) \
+	do { } while (0)
+#endif
+
+/****************************************************************************/
+
+/* this should always return "1" and print something in verbose mode */
+#ifdef VERBOSE
+#define VDBG_SPC(fmt, args...) \
+	(VDBG(fmt, args) ? 1 : 1)
+#else
+#define VDBG_SPC(fmt, args...) 1
+#endif
+
+/* query bit(s) (long: 32-bit access) */
+#define IS_BIT_RES(data, code) \
+	(!((data) & (code)) ? \
+	 (VDBG_SPC("  OTG HW status: %s is reset\n", #data)) : 0)
+
+#define IS_BIT_SET(data, code) \
+	(((data) & (code)) ? \
+	 (VDBG_SPC("  OTG HW status: %s is set\n", #data)) : 0)
+
+/* query SW flag(s) */
+#define IS_FLAG_RES(dev, data) \
+	(!((data) & (dev)->transceiver.params) ? \
+	 (VDBG_SPC("  OTG SW status: %s is reset\n", #data)) : 0)
+
+#define IS_FLAG_SET(dev, data) \
+	(((data) & (dev)->transceiver.params) ? \
+	 (VDBG_SPC("  OTG SW status: %s is set\n", #data)) : 0)
+
+/* query event bit(s) */
+#define GOT_EVENT(data, code) \
+	(((data) & (code)) ? \
+	 (VDBG_SPC("  OTG event: %s\n", #data)) : 0)
+
+/* set SW flag */
+#ifdef VERBOSE
+#define SET_FLAG(dev, data) \
+do { \
+	if (!((data) & (dev)->transceiver.params)) \
+		DBG("  OTG SW status change: set flag %s\n", #data); \
+	(dev)->transceiver.params |= (data) \
+} while (0);
+#else
+#define SET_FLAG(dev, data) \
+	((dev)->transceiver.params |= (data))
+#endif
+
+/* reset SW flag */
+#ifdef VERBOSE
+#define RES_FLAG(dev, data) \
+do { \
+	if ((data) & (dev)->transceiver.params) \
+		DBG("  OTG SW status change: reset flag %s\n", #data); \
+	(dev)->transceiver.params &= ~((u32) (data)) \
+} while (0);
+#else
+#define RES_FLAG(dev, data) \
+	((dev)->transceiver.params &= ~((u32) (data)))
+#endif
+
+/* reset event bit */
+#define RES_EVENT(data, code) \
+	((code) &= ~((u32) (data)))
+/* NOTE: this is not really needed so far, might be replaced with */
+/* #define RES_EVENT(data, code) \                                */
+/* 	do {} while (0)                                           */
+
+/* change OTG state */
+#ifdef CONFIG_USB_OTG
+#define PREPARE_STATE_CHANGE(dev, new_state) \
+	switch ((new_state) & OTG_STATE_MASK) { \
+	case OTG_STATE_UNDEFINED: \
+		set_undef_state_defaults((dev)); \
+		break; \
+	case OTG_STATE_A_IDLE: \
+		set_a_state_defaults((dev)); \
+		break; \
+	case OTG_STATE_B_IDLE: \
+		set_b_state_defaults((dev)); \
+		break; \
+	default: \
+		break; \
+	} \
+	do {} while (0)
+#else
+#define PREPARE_STATE_CHANGE(dev, new_state) \
+	do {} while (0)
+#endif
+
+#define CHANGE_STATE(dev, new_state, pMask) \
+do { \
+	PREPARE_STATE_CHANGE(dev, new_state); \
+	iowrite32((new_state##_CONTROL), &(dev)->regs->ctl); \
+	*(pMask) = (new_state##_INTERRUPTS); \
+	(dev)->transceiver.state = (new_state); \
+	DBG("OTG new state: %s\n", #new_state); \
+} while (0);
+
+/* verify OTG state */
+#ifndef CONFIG_OTG_TEST_MODE
+
+#define CHECK_STATE(dev, act_state, pMask) \
+do { \
+	*(pMask) = (act_state##_INTERRUPTS); \
+	(dev)->transceiver.prv_state = (act_state); \
+	VDBG("OTG state: %s\n", #act_state); \
+} while (0);
+#else
+#define CHECK_STATE(dev, act_state, pMask) \
+do {\
+	*(pMask) = (act_state##_INTERRUPTS); \
+	(dev)->transceiver.prv_state = (act_state); \
+	if (((ioread32(&(dev)->regs->sts) ^ (act_state##_STATUS))) & \
+	    act_state##_STATUS_MASK) \
+		WARN("OTG warning: incorrect status\n"); \
+	VDBG("OTG state: %s\n", #act_state); \
+} while (0);
+#endif
+
+/* set timer */
+#define SET_OTG_TIMER(dev, val) \
+	set_timer((dev), ((OTG_TMR_##val) * 100))
+
+/* set timer (<1ms) */
+#define SET_OTG_TIMER_SHORT(dev, val) \
+	set_timer((dev), ((OTG_TMR_##val) / 10))
+
+/* set timer (>10ms) */
+#define SET_OTG_TIMER_LONG(dev, val) \
+	set_timer_long ((dev), ((OTG_TMR_##val) / 10))
+
+#ifdef VERBOSE
+#define HS_DISCON_WARNING() \
+	if (!(OTG_CTL_ENABLE_UHC ^ \
+	      (OTG_CTL_MUX_MASK & ioread32(&dev->regs->ctl))) && \
+	    !(OTG_STS_PSPD & ioread32(&dev->regs->sts))) \
+		DBG("  OTG warning: disable UHC from HS-mode\n")
+#else
+#define HS_DISCON_WARNING() \
+	do { } while (0)
+#endif
+
+
+/*****************************************************************************
+*  Data
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+struct otg_regs {
+	u32  cap;               /* capabilities */
+	u32  mux;               /* mux */
+	u32  sts;               /* status */
+	u32  ctl;               /* control */
+	u32  tmr;               /* timer */
+	u32  intr;              /* interrupt request */
+	u32  inten;             /* interrupt enable */
+} __attribute__ ((packed));
+
+
+struct otg {
+	spinlock_t              lock;
+	unsigned                enabled:1,
+				got_irq : 1,
+				region : 1;
+	u16                     chiprev;
+
+	struct platform_device  *pdev;
+	struct otg_regs         *regs;
+	struct otg_transceiver  transceiver;
+};
+#define otg_transceiver_to_otg(pTransceiver) \
+	container_of(otg, struct otg, pTransceiver)
+#define otg_to_transceiver(pOtg) \
+	(&pOtg->transceiver)
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+/*****************************************************************************
+*  Functions
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+extern int usb_gadget_register_otg(struct otg_transceiver * (
+			*get_transceiver)(void));
+extern int usb_gadget_unregister_otg(void);
+
+void otg_init_state(struct otg *);
+int otg_exit_state(struct otg *);
+
+#ifdef DEBUG
+static void print_regs(struct otg *);
+#endif  /* DEBUG */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+
+/*****************************************************************************
+*  Inline Functions
+*****************************************************************************/
+
+extern u32 otg_tmr_high_count;
+extern struct otg_ctl *otg_ctl;
+
+#ifdef CONFIG_USB_OTG
+/**
+ * \brief
+ * set neutral state information
+ *
+ * \param  dev   OTG controller info
+ *
+ * \return void
+ */
+static inline void set_undef_state_defaults(struct otg *dev)
+{
+	dev->transceiver.default_a = 0;
+	if (dev->transceiver.host)
+		dev->transceiver.host->is_b_host = 0;
+	if (dev->transceiver.gadget)
+		dev->transceiver.gadget->is_a_peripheral = 0;
+}
+
+/**
+ * \brief
+ * set A state information
+ *
+ * \param  dev   OTG controller info
+ *
+ * \return void
+ */
+static inline void set_a_state_defaults(struct otg *dev)
+{
+	dev->transceiver.default_a = 1;
+	if (dev->transceiver.host)
+		dev->transceiver.host->is_b_host = 0;
+	if (dev->transceiver.gadget)
+		dev->transceiver.gadget->is_a_peripheral = 1;
+}
+
+/**
+ * \brief
+ * set B state information
+ *
+ * \param  dev   OTG controller info
+ *
+ * \return void
+ */
+static inline void set_b_state_defaults(struct otg *dev)
+{
+	dev->transceiver.default_a = 0;
+	if (dev->transceiver.host)
+		dev->transceiver.host->is_b_host = 1;
+	if (dev->transceiver.gadget)
+		dev->transceiver.gadget->is_a_peripheral = 0;
+}
+
+/**
+ * \brief
+ * set B state information
+ *
+ * \param  dev   OTG controller info
+ *
+ * \return void
+ */
+static inline void reset_b_hnp_enable(struct otg *dev)
+{
+	if (dev->transceiver.host)
+		dev->transceiver.host->b_hnp_enable = 0;
+	VDBG("  OTG action: HNP disabled in B-device\n");
+}
+
+/**
+ * \brief
+ * set B state information
+ *
+ * \param  dev   OTG controller info
+ *
+ * \return void
+ */
+static inline int is_b_hnp_enabled(struct otg *dev)
+{
+	int retVal = 0;
+
+	if (dev->transceiver.host &&
+		dev->transceiver.host->b_hnp_enable) {
+		VDBG("  OTG status: HNP is enabled in HS-B-device\n");
+		retVal = 1;
+	}
+#ifdef VERBOSE
+	else
+		DBG("  OTG status: HNP is disabled in B-device\n");
+#endif
+	return retVal;
+}
+#endif
+
+/**
+ * \brief
+ * Read the status register
+ *
+ * \param  dev   OTG controller info
+ *
+ * \return status
+ */
+static inline u32 get_status(struct otg *dev)
+{
+	return ioread32(&dev->regs->sts);
+}
+
+/**
+ * \brief
+ * Load and start the timer for an unconditional run
+ *
+ * \param  dev   OTG controller info
+ * \param  val   Value to load
+ *
+ * \return void
+ */
+static inline void set_timer(struct otg *dev, u32 val)
+{
+	otg_tmr_high_count = 0;
+
+	iowrite32((val), &dev->regs->tmr);
+	VDBG("  OTG action: start timer: %d0 us\n", val);
+}
+
+/**
+ * \brief
+ * Load and start the timer for an unconditional run
+ *
+ * \param  dev   OTG controller info
+ * \param  val   Value to load
+ *
+ * \return void
+ */
+static inline void set_timer_long(struct otg *dev, u32 val)
+{
+	otg_tmr_high_count = val - 1;
+
+	iowrite32(TIMER_PERIOD, &dev->regs->tmr);
+	VDBG("  OTG action: start timer: %d0 ms\n", val);
+}
+
+/**
+ * \brief
+ * Re-start the timer (value already loaded)
+ *
+ * \param  dev   OTG controller info
+ *
+ * \return void
+ */
+static inline void restart_timer(struct otg *dev)
+{
+	iowrite32((ioread32(&dev->regs->ctl) | OTG_CTL_TMR_UNCOND),
+			&dev->regs->ctl);
+}
+
+/**
+ * \brief
+ * Reset the timer while running (value already loaded)
+ *
+ * \param  dev   OTG controller info
+ *
+ * \return void
+ */
+static inline void reset_timer(struct otg *dev)
+{
+	u32 temp;
+
+	temp = ioread32(&dev->regs->ctl);
+	iowrite32((temp & ~((u32) OTG_CTL_TMR_ALL)), &dev->regs->ctl);
+	iowrite32(temp, &dev->regs->ctl);
+	VDBG("  OTG action: re-start timer\n");
+}
+
+/**
+ * \brief
+ * Prepare the D-pulse
+ *
+ * \param  dev   OTG controller info
+ *
+ * \return void
+ */
+static inline void set_srp_conditions(struct otg *dev)
+{
+	VDBG("  OTG action: SRP init: no action needed due to A0 WAs\n");
+}
+
+/**
+ * \brief
+ * Reset conditions after SRP
+ *
+ * activates the auto-pull-up feature so after SRP the host
+ * will detect a device connect after calling this function
+ *
+ * \param  dev   OTG controller info
+ *
+ * \return void
+ */
+static inline void reset_srp_conditions(struct otg *dev)
+{
+	VDBG("  OTG action: SRP done: no action needed due to A0 WAs\n");
+}
+
+/**
+ * \brief
+ * enable HNP for both devices
+ *
+ * \param  dev   OTG controller info
+ *
+ * \return success
+ */
+static inline int otg_enable_hnp(struct otg *dev)
+{
+	int  retVal = 0;
+	return retVal;
+}
+
+#ifdef DEBUG
+/**
+ * \brief
+ * Print OTG controller registers (debug mode only)
+ *
+ * \param dev    OTG controller info
+ *
+ * \return void
+ */
+static inline void print_regs(struct otg *dev)
+{
+	DBG("-- UOC registers ---\n");
+	DBG("otg cap   = %08x\n", ioread32(&dev->regs->cap));
+	DBG("otg mux   = %08x\n", ioread32(&dev->regs->mux));
+	DBG("otg sts   = %08x\n", ioread32(&dev->regs->sts));
+	DBG("otg ctl   = %08x\n", ioread32(&dev->regs->ctl));
+	DBG("otg tmr   = %08x\n", ioread32(&dev->regs->tmr));
+	DBG("otg intr  = %08x\n", ioread32(&dev->regs->intr));
+	DBG("otg inten = %08x\n", ioread32(&dev->regs->inten));
+	DBG("--------------------\n");
+}
+#endif /* DEBUG */
+
+#endif /* AU1200_UOC_H */
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index 17d9905..8151d74 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -78,6 +78,12 @@
 #define	gadget_is_omap(g)	0
 #endif
 
+#ifdef CONFIG_USB_GADGET_AU1200
+#define gadget_is_au1200(g)	!strcmp("au1200_udc", (g)->name)
+#else
+#define gadget_is_au1200(g)	0
+#endif
+
 /* not yet ported 2.4 --> 2.6 */
 #ifdef CONFIG_USB_GADGET_N9604
 #define	gadget_is_n9604(g)	!strcmp("n9604_udc", (g)->name)
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 1db25d1..5b88c43 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -45,7 +45,12 @@ struct otg_transceiver {
 
 	u8			default_a;
 	enum usb_otg_state	state;
-
+#ifdef CONFIG_USB_PORT_AU1200OTG
+	u8			prv_state;
+	u32			params;
+	void			*otg_priv;
+	u8			hostcount;
+#endif
 	struct usb_bus		*host;
 	struct usb_gadget	*gadget;
 
-- 
1.5.4.3



[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux