[PATCH] udc:  Add UDC support for the CS5536

From: William Morrow <william.morrow@amd.com>

Add UDC support the Geode CS5536 companion chip.

Signed-off-by: William Morrow <william.morrow@amd.com>
Acked-by: Jordan Crouse <jordan.crouse@amd.com>
---

 Documentation/usb/amd5536udc.txt |  184 +
 Documentation/usb/amd5536uoc.txt |   89 +
 drivers/usb/gadget/Kconfig       |   46 
 drivers/usb/gadget/Makefile      |    6 
 drivers/usb/gadget/amd5536udc.c  | 4789 ++++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/amd5536udc.h  |  972 ++++++++
 drivers/usb/gadget/amd5536uoc.c  |  456 ++++
 drivers/usb/gadget/amd5536uoc.h  |  288 ++
 8 files changed, 6830 insertions(+), 0 deletions(-)

diff --git a/Documentation/usb/amd5536udc.txt b/Documentation/usb/amd5536udc.txt
new file mode 100644
index 0000000..abd1903
--- /dev/null
+++ b/Documentation/usb/amd5536udc.txt
@@ -0,0 +1,184 @@
+-------------------------------------------------------------------------------
+Howto for Linux device driver for the AMD5536 USB Device Controller (UDC)
+for gadget driver stack
+-------------------------------------------------------------------------------
+
+Author: Thomas Dahlmann
+
+INTRODUCTION:
+
+The AMD5536 UDC is part of x86 southbridge AMD5536 and MIPS CPU Au1200.
+It is a DMA capable usb device controller. The usb port is shared
+between host and UDC. The on-chip UOC controller is used to switch the
+usb port between host, UDC and neutral. So amd5536uoc driver is needed
+to get the UDC operating.
+
+-------------------------------------------------------------------------------
+WHAT YOU NEED:
+-------------------------------------------------------------------------------
+
+copy/replace following files to /usr/src/linux/drivers/usb/gadget
+        amd5536udc.c
+        amd5536udc.h
+        amd5536uoc.c
+        amd5536uoc.h
+        ether.c
+        file_storage.c
+        zero.c
+	inode.c
+        gadget_chips.h
+        Makefile
+        Kconfig
+
+-------------------------------------------------------------------------------
+HOW TO INSTALL IT:
+-------------------------------------------------------------------------------
+
+change to directory /usr/src/linux
+
+configure gadget as module:
+        "make menuconfig"
+        under "Code maturity level options" choose "Prompt for development ..."
+        goto "Device Drivers"
+        goto "USB support" -> "USB Gadget support"
+        choose "Support for USB Gadgets" as module
+        under choice "USB Peripheral Controller" choose "AMD5536-UDC"
+        under "USB Gadget Drivers"
+        choose "Gadget Zero" as module or
+        choose "Ethernet Gagdet" as module or
+        choose "File-backed Storage Gadget" as module
+        exit and save config
+
+compile and install modules:
+        "make modules modules_install"
+
+-------------------------------------------------------------------------------
+HOW TO USE IT:
+-------------------------------------------------------------------------------
+
+*** How to load FILE-BACKED STORAGE gadget driver - mass storage ***
+enable USB mass storage support for linux host:
+        change to directory /usr/src/linux
+        "make menuconfig"
+        under "File systems" choose "DOS/FAT/NT filesystems"
+        choose "MSDOS fs support"
+        under "Device Drivers" under "SCSI device support"
+                choose "SCSI device support"
+                choose "SCSI generic support"
+        under "Device Drivers" under "USB support" in section
+                "USB Device Class drivers" choose
+                "USB Mass Storage support"
+        compile new kernel
+create disk file:
+        "dd bs=1M count=128 if=/dev/zero of=/tmp/disk"
+        => creates a 128Mbyte image file /tmp/disk
+load modules:
+        "modprobe amd5536udc"
+        "modprobe g_file_storage file=/tmp/disk"
+        Note: multiple file arguments are possible, each will be a separate
+              drive for the host side, furthermore devices such as /dev/hda
+              (whole disk will be used) or /dev/hda1 (partition) can be used
+              as argument too
+        "modprobe amd5536uoc"
+create a primary FAT16 disk partition via linux host site:
+        "fdisk /dev/sda", make FAT16 prim. partition
+        => "n", "p", "1", "<RETURN>", "<RETURN>", "t", "6", "w",
+        "mkdosfs /dev/sda1"
+        "sync"
+create primary disk partition via Windows XP host site:
+        right click on "My Computer"
+        choose "Manage" => "Disk Management"
+        choose usb disk and follow instructions of partition menu
+mount usb mass storage device on linux host:
+        make directory "/mnt/gadget/"
+        "mount -t msdos /dev/sda1 /mnt/gadget"
+
+***  How to access files of disk image on UDC side ***
+When files were copied from host to UDC mass storage device then files
+are inside the monolitic disk image (see above) on UDC side. This
+disk image can be mounted via the loopback device driver to a
+directory on UDC side to access these files.
+Steps on UDC side:
+        enable kernel support for loopback device
+        change to directory /usr/src/linux
+        "make menuconfig"
+        under "Block devices" choose "Loopback device support"
+                and recompile the kernel
+        determine offset inside disk image:
+        "fdisk -l -u disk_image", output is like:
+>> You must set cylinders.
+>> You can do this from the extra functions menu.
+>>
+>> Disk /tmp/disk128: 5 heads, 52 sectors, 0 cylinders
+>> Units = sectors of 1 * 512 bytes
+>>
+>>         Device Boot    Start       End    Blocks   Id  System
+>> /tmp/disk128p1            52    262079    131014    6  FAT16
+
+        get offset my multiplying start value by sector size:
+        52 * 512 = 26624
+        mount disk image:
+        "mount -o loop,offset=26624 -t msdos disk_image /mnt"
+
+
+*** How to load ZERO gadget driver - simple BULK loop back ***
+load modules:
+UDC driver:
+        (a) Slave/Fifo mode:       "modprobe amd5536udc use_dma=0"
+        (b) DMA Buffer Fill mode:  "modprobe amd5536udc use_dma=1"
+        default:
+        (c) DMA PPBNDU mode:       "modprobe amd5536udc"
+        (d) DMA PPBDU mode:        "modprobe amd5536udc use_dma=1 use_dma_ppb=1 use_dma_ppb_du=1"
+        (e) fullspeed mode:        "modprobe amd5536udc use_fullspeed=1", can be combined
+                                    with all dma modes
+        (f) special higspeed
+            tx buffer size:        "modprobe amd5536udc hs_tx_buf=<buf_size in dwords>"
+                                   example: "modprobe amd5536udc use_dma=1 hs_tx_buf=128"
+                                            => buffer size = 512 bytes (=bulk max packet)
+Gadget Zero driver:
+        (a) Bulk loop:             "modprobe g_zero"
+        (b) Int loop:              "modprobe g_zero use_interrupt_traffic=1"
+        (c) Source/Sink            "modprobe g_zero loopdefault=0"
+                                   OUT data must all be zero's
+        (d) Source/Sink count      "modprobe g_zero loopdefault=0 pattern=1"
+                                   each OUT packet must count modulo63 (0,1,..,62,0,1,..)
+UOC driver:                        "modprobe amd5536uoc"
+example:
+        "modprobe amd5536udc"
+        "modprobe g_zero"
+        "modprobe amd5536uoc"
+        => loads driver for DMA PPBNDU mode and Bulk loop
+
+
+*** How to use ETHERNET gadget driver (CDC protocol) ***
+                   with Linux Host
+UDC side bringup:
+        load gadget modules
+        "modprobe amd5536udc"
+        "modprobe g_ether"
+        "modprobe amd5536uoc"
+        "ifconfig usb0 192.168.0.2"
+Host side bringup:
+        install support for CDC Ethernet:
+        change to directory /usr/src/linux
+        "make menuconfig"
+        under "Device Drivers" under "USB support" under
+        "USB Network adapters" choose
+        "Multi-purpose USB Networking Framework"
+        choose "CDC Ethernet support"
+        compile mew kernel
+        "modprobe CDCEther"
+        "ifconfig eth1 192.168.0.1"
+        note: assuming there is one network card assigned to eth0,
+                otherwise kernel messages of CDC Ethernet module show
+                which interface (ethX) is used
+Use network connection:
+        after bringup of host and UDC side it behaves like a normal
+                ethernet connection between host and UDC
+        test the connection:
+        host side: "ping -I eth1 192.168.0.2"
+        UDC side : "ping -I usb0 192.168.0.1"
+        note: the "-I" option assures that the USB cable is used, the
+                option can be omitted when the routing table is setup to avoid
+                using other network interfaces as eth0
+
diff --git a/Documentation/usb/amd5536uoc.txt b/Documentation/usb/amd5536uoc.txt
new file mode 100644
index 0000000..7d9dd6e
--- /dev/null
+++ b/Documentation/usb/amd5536uoc.txt
@@ -0,0 +1,89 @@
+--------------------------------------------------------------------------
+Howto for Linux device driver for the AMD5536 USB Options Controller (UOC)
+--------------------------------------------------------------------------
+
+Author: Karsten Boge
+
+(1)Introduction
+===============
+
+The AMD5536 UOC is part of x86 southbridge AMD5536.
+The USB port is shared between the USB Host Controller
+and the USB Device Controller as defined in BIOS setup.
+The on-chip UOC controller is used to switch the
+usb port between host, UDC and neutral.
+The amd5536uoc driver is needed to get the
+USB Device Controller operating.
+
+(2) Patches
+===========
+
+udc.patch:
+    This containes the UDC driver as together
+    with the UOC driver
+
+(3) Driver source code installation
+===================================
+
+- New files for UOC:
+    drivers/usb/gadget/amd5536uoc.h
+    drivers/usb/gadget/amd5536uoc.c
+
+(4) BIOS setup
+==================
+
+    PCI Configuration
+        UDC:    Enabled
+        OTG:    Enabled
+        Port 4 assignment:  Device
+
+(4) Config options
+==================
+
+    <M/*> Support for USB Gadgets
+         USB Periheral Controller (?choice?)
+             (X) AMD5536UDC
+
+    The role of the UOC port can be defined
+    within the BIOS setup exclusively.
+
+    Selecting the amd5536udc driver results in
+    building the amd5536uoc driver too.
+    If "Support for USB Gadgets" is configured to be statically
+    linked both modules will be linked into the kernel image
+    otherwise an additional module called amd5536uoc will be built
+
+
+(5) Compile and install
+=======================
+
+    If global USB support is configured to be used as
+    kernel module (usbcore.o) (recomended):
+
+      make modules SUBDIRS=drivers/usb/gadget
+      make modules_install
+
+    If it's linked into the kernel image an new kernel
+    image must be compiled and created before.
+
+(6) Usage
+=========
+
+    modprobe amd5536uoc
+
+    This will load the module and other modules which provide
+    interfaces used by the UOC driver (usbcore, amd5536udc).
+
+    The amd5536uoc driver is needed to power up the uoc logic
+    which controls the pullup resistors connected to either
+    the D+ or D- USB pins.
+    The function of this pullup resistors is to signal the host
+    that a device is connected, and at which speed the device
+    operates.
+
+    Make sure the USB port is assigned to device within the
+    BIOS setup otherwise the modules will not be loaded.
+
+
+
+
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index bbbc82a..2145264 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -90,6 +90,38 @@ config USB_NET2280
 	default USB_GADGET
 	select USB_GADGET_SELECTED
 
+config USB_GADGET_AMD5536UDC
+	boolean "AMD5536UDC"
+	depends on PCI || SOC_AU1200
+	select USB_GADGET_DUALSPEED
+	help
+	   AMD5536 UDC is a PCI based USB peripheral controller which
+	   supports both full and high speed USB 2.0 data transfers.
+
+	   It has six configurable endpoints, as well as endpoint zero
+	   (for control transfers) and several endpoints with dedicated
+	   functions.
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "amd5536udc" and force all
+	   gadget drivers to also be dynamically linked.
+
+	   If the AMD5536UDC driver is configured to be statically
+	   linked this module will be linked into the kernel image
+	   as well otherwise two additional modules called "amd5536udc"
+	   and "amd5536uoc" will be built.
+
+	   The AMD5536 USB device port can be used as
+	   either a host port or a device port depending on
+	   the assignment within the BIOS setup.
+	   For more information, see Documentation/usb/amd5536uoc.txt
+
+config USB_AMD5536UDC
+	tristate
+	depends on USB_GADGET_AMD5536UDC
+	select USB_GADGET_SELECTED
+	default USB_GADGET
+
 config USB_GADGET_PXA2XX
 	boolean "PXA 25x or IXP 4xx"
 	depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
@@ -426,4 +458,18 @@ # - none yet
 
 endchoice
 
+#
+# AMD5536 USB UOC options
+#
+
+config USB_GADGET_AMD5536UOC
+	boolean
+	depends on USB_GADGET_AMD5536UDC
+	default USB_GADGET_AMD5536UDC
+
+config USB_AMD5536UOC
+	tristate
+	depends on USB_GADGET_AMD5536UOC
+	default USB_GADGET
+
 endmenu
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index e71e086..5dbc3b9 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -3,6 +3,7 @@ # USB peripheral controller drivers
 #
 obj-$(CONFIG_USB_DUMMY_HCD)	+= dummy_hcd.o
 obj-$(CONFIG_USB_NET2280)	+= net2280.o
+obj-$(CONFIG_USB_AMD5536UDC)	+= amd5536udc.o
 obj-$(CONFIG_USB_PXA2XX)	+= pxa2xx_udc.o
 obj-$(CONFIG_USB_GOKU)		+= goku_udc.o
 obj-$(CONFIG_USB_OMAP)		+= omap_udc.o
@@ -31,3 +32,8 @@ obj-$(CONFIG_USB_FILE_STORAGE)	+= g_file
 obj-$(CONFIG_USB_G_SERIAL)	+= g_serial.o
 obj-$(CONFIG_USB_MIDI_GADGET)	+= g_midi.o
 
+#
+# AMD5536 USB UOC options
+#
+obj-$(CONFIG_USB_AMD5536UOC)	+= amd5536uoc.o
+
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
new file mode 100644
index 0000000..689d88f
--- /dev/null
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -0,0 +1,4789 @@
+/*
+ * AMD 5536 UDC high/full speed USB device controller.
+ */
+
+/*
+ * Copyright (C) 2005 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * 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
+ */
+
+/*****************************************************************************
+ * Defines
+ *****************************************************************************/
+
+/* debug control */
+#undef UDC_DEBUG
+//DISABLEDamd #define UDC_DEBUG     1
+#undef UDC_VERBOSE
+//DISABLEDamd #define   UDC_VERBOSE
+//DISABLEDamd #define UDC_REGISTER_DUMP
+
+/* device driver registration of kernel 2.6.x usage */
+//#define UDC_USE_DRIVER_REGISTER
+
+/* Driver strings */
+#define UDC_MOD_DESCRIPTION         "AMD 5536 UDC - USB Device Controller"
+#define UDC_DRIVER_VERSION_STRING   "01.00.0204 - $Revision: #13 $"
+
+/* kernel version of new gadget stack generation (for 2.6.x) */
+#define UDC_NEW_GADGET_KERNEL KERNEL_VERSION(2,5,59)
+
+/*****************************************************************************
+ *  Includes
+ *****************************************************************************/
+
+/* system */
+#include <linux/autoconf.h>
+#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 <linux/ioctl.h>
+#include <linux/fs.h>
+#if     LINUX_VERSION_CODE < UDC_NEW_GADGET_KERNEL
+#include <linux/wrapper.h>
+#else
+#include <linux/dmapool.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#endif
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+/* MIPS config */
+#ifdef CONFIG_SOC_AU1200
+#if     LINUX_VERSION_CODE < UDC_NEW_GADGET_KERNEL
+#include <asm/au1000.h>
+#else
+#include <asm/mach-au1x00/au1000.h>
+#endif
+#ifndef CONFIG_USB_NON_PCI_OTGDEVICE
+#define CONFIG_USB_NON_PCI_OTGDEVICE
+#endif
+#endif
+
+/* gadget stack */
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+#include <linux/usb/otg.h>
+
+/* udc specific */
+#include "amd5536udc.h"
+
+/* use RDE timer for new kernel only */
+#if   LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+#define UDC_USE_TIMER
+#endif
+/*****************************************************************************
+ *  Static Function Declarations
+ *****************************************************************************/
+
+void udc_tasklet_disconnect(unsigned long);
+#ifdef UDC_USE_TIMER
+void udc_timer_function(unsigned long v);
+void udc_pollstall_timer_function(unsigned long v);
+#endif
+static int udc_rxfifo_read_dwords(struct udc *dev, u32 * buf, int dwords);
+static void empty_req_queue(struct udc_ep *);
+static int udc_probe(struct pci_dev *pdev, const struct pci_device_id *id);
+static void udc_remove(struct pci_dev *pdev);
+static void udc_basic_init(struct udc *dev);
+static void udc_setup_endpoints(struct udc *dev);
+static void udc_soft_reset(struct udc *dev);
+#ifdef UDC_DEBUG
+static void dump_buffer(u8 * buf, u32 bytes);
+static int udc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		     unsigned long arg);
+static int udc_open(struct inode *inode, struct file *file);
+static int udc_release(struct inode *inode, struct file *file);
+#endif
+static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req);
+static u32 udc_get_ppbdu_rxbytes(struct udc_request *req);
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req);
+static int udc_create_dma_chain(struct udc_ep *ep, struct udc_request *req,
+				unsigned long buf_len, gfp_t gfp_flags);
+static inline int startup_registers(struct udc *dev);
+#ifdef CONFIG_SOC_AU1200
+void au1200_sync(void);
+#endif
+static int udc_remote_wakeup(struct udc *dev);
+#ifdef UDC_USE_DRIVER_REGISTER
+static int udc_suspend(struct udc *dev);
+static int udc_resume(struct udc *dev);
+#endif
+
+/*****************************************************************************
+ *  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;
+
+/* TODO this is used for dma chaining, global gfp not good */
+static gfp_t udc_gfp_flags = 0;
+
+/* slave mode: pending bytes in rx fifo after nyet,
+used if EPIN irq came but no req was available */
+static unsigned int udc_rxfifo_pending = 0;
+
+/* count soft resets after suspend to avoid loop */
+static int soft_reset_occured = 0;
+#ifdef UDC_IPBUG_3958_WORKAROUND_SOFT_RESET_ON_USBRESET
+static int soft_reset_after_usbreset_occured = 0;
+#endif
+
+#ifdef UDC_USE_TIMER
+/* timer */
+static struct timer_list udc_timer;
+static int stop_timer = 0;
+int set_rde = -1;
+DECLARE_COMPLETION(on_exit);
+static struct timer_list udc_pollstall_timer;
+static int stop_pollstall_timer = 0;
+DECLARE_COMPLETION(on_pollstall_exit);
+#endif
+
+/* tasklet for usb disconnect */
+DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
+		(unsigned long)&udc);
+
+#ifdef CONFIG_USB_NON_PCI_OTGDEVICE
+static struct pci_dev pdev_dummy;
+static struct pci_dev *pdev = &pdev_dummy;
+#endif
+
+#ifdef UDC_IPBUG_3958_WORKAROUND
+/* CNAK pending field: bit0 = ep0in, bit16 = ep0out */
+static u32 cnak_pending = 0;
+#define UDC_QUEUE_CNAK(ep, num) \
+        if (readl(&((ep)->regs->ctl)) & AMD_BIT(UDC_EPCTL_NAK)) { \
+                DBG("NAK could not be cleared for ep%d\n", num); \
+                cnak_pending |= 1 << (num); \
+                (ep)->naking = 1; \
+        } \
+        else \
+                cnak_pending = cnak_pending & (~(1<<(num)));
+#else
+#define UDC_QUEUE_CNAK(ep, num) {}
+#endif
+#ifdef UDC_IPBUG_3958_WORKAROUND_RXFIFO_FLUSH
+/* rxfifo cleari/trash buffer */
+static u8 udc_rxfifo_trash[UDC_RXFIFO_SIZE];
+#endif
+
+#ifdef UDC_IPBUG_3943_WORKAROUND
+/* otg registering count */
+static u32 otg_reg_count = 0;
+#endif
+/* gadget registering count */
+static u32 gadget_bind_count = 0;
+
+/* 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
+/* driver callback functions */
+static struct file_operations udc_fops = {
+      owner:THIS_MODULE,
+
+      read:NULL,
+      write:NULL,
+      ioctl:udc_ioctl,
+      open:udc_open,
+      release:udc_release,
+};
+#endif
+
+/* PCI device parameters */
+static struct pci_device_id pci_id[] = { {
+					  .vendor = UDC_PCI_VENID,
+					  .device = UDC_PCI_DEVID,
+					  .class = UDC_PCI_CLASS,
+					  .class_mask = UDC_PCI_CLASS_MASK,
+					  .subvendor = PCI_ANY_ID,
+					  .subdevice = PCI_ANY_ID,
+					  },
+{}
+};
+
+#ifndef CONFIG_USB_NON_PCI_OTGDEVICE
+/* PCI functions */
+static struct pci_driver udc_pci_driver = {
+	.name = (char *)name,
+	.id_table = pci_id,
+	.probe = udc_probe,
+	.remove = udc_remove,
+};
+#endif
+
+#ifdef UDC_DEBUG
+/* data for debuging only */
+static unsigned long no_pref_req = 0;
+static unsigned long no_req = 0;
+static u32 same_cfg = 0;
+static u32 num_enums = 0;
+#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 = 0;
+/* buffer fill mode */
+static int use_dma_bufferfill_mode = 0;
+/* full speed only mode */
+static int use_fullspeed = 0;
+/* 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, ulong, 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("Thomas Dahlmann");
+MODULE_LICENSE("GPL");
+
+#ifndef CONFIG_USB_NON_PCI_OTGDEVICE
+MODULE_DEVICE_TABLE(pci, pci_id);
+#endif
+
+/*****************************************************************************
+ *  Function Definitions
+ *****************************************************************************/
+
+/* AU specific */
+#ifdef CONFIG_SOC_AU1200
+void au1200_sync(void)
+{
+	au1200_sync_delay();
+}
+#endif
+
+#ifdef UDC_DEBUG
+/**
+ * Dumps byte read access
+ *
+ * \param a address pointer
+ * \return read byte
+ */
+static void print_td(struct udc_data_dma *p)
+{
+	INFO("td = %08lx: status=%08lx bufptr=%08lx next=%08lx\n",
+	     (unsigned long)p,
+	     (unsigned long)p->status,
+	     (unsigned long)p->bufptr, (unsigned long)p->next);
+}
+#endif
+
+/* printing registers --------------------------------------------------------*/
+/**
+ * Prints UDC device registers and endpoint irq registers
+ *
+ * \param dev pointer to device struct
+ */
+static void print_regs(struct udc *dev)
+{
+#ifndef UDC_IPBUG_3943_WORKAROUND
+	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");
+#endif
+	DBG("USE DMA        = %d\n", use_dma);
+	if (use_dma && use_dma_ppb && !use_dma_ppb_du) {
+		DBG("DMA mode       = PPBNDU (packet per buffer WITHOUT desc. update)\n");
+#ifndef UDC_DEBUG
+		INFO("DMA mode (PPBNDU)\n");
+#endif
+	} else if (use_dma && use_dma_ppb_du && use_dma_ppb_du) {
+		DBG("DMA mode       = PPBDU (packet per buffer WITH desc. update)\n");
+#ifndef UDC_DEBUG
+		INFO("DMA mode (PPBDU)\n");
+#endif
+	}
+	if (use_dma && use_dma_bufferfill_mode) {
+		DBG("DMA mode       = BF (buffer fill mode)\n");
+#ifndef UDC_DEBUG
+		INFO("DMA mode (BF)\n");
+#endif
+	}
+#ifndef UDC_DEBUG
+	if (!use_dma) {
+		INFO("FIFO mode\n");
+	}
+#endif
+#ifdef UDC_USE_TIMER
+	INFO("RDE timer is used\n");
+#endif
+	DBG("-------------------------------------------------------\n");
+}
+
+/**
+ * Prints snapshot of ep registers
+ *
+ * \param dev   pointer to device struct
+ */
+#ifdef UDC_DEBUG
+static void print_ep_regs(struct udc *dev, struct udc_ep_regs *ep_regs)
+{
+	INFO("ep control  = %08lx\n", (unsigned long)ep_regs->ctl);
+	INFO("ep status   = %08lx\n", (unsigned long)ep_regs->sts);
+	INFO("--------------------------------\n");
+}
+
+/* TODO tdahlman: remove */
+/**
+ * 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
+
+/* driver functions ----------------------------------------------------------*/
+/**
+ * Called by OS for insmod
+ *
+ * \param inode         file node
+ * \param               file struct
+ * \return read byte
+ */
+#ifdef UDC_DEBUG
+static int udc_open(struct inode *inode, struct file *file)
+{
+	int retval = 0;
+
+#if     LINUX_VERSION_CODE < UDC_NEW_GADGET_KERNEL
+	/* module use counter increment */
+	MOD_INC_USE_COUNT;
+#endif
+
+	return retval;
+}
+
+/**
+ * Called by OS for rmmod
+ *
+ * \param inode         file node
+ * \param file          file struct
+ * \return read byte
+ */
+static int udc_release(struct inode *inode, struct file *file)
+{
+	int retval = 0;
+
+#if     LINUX_VERSION_CODE < UDC_NEW_GADGET_KERNEL
+	/* module use counter decrement */
+	MOD_DEC_USE_COUNT;
+#endif
+	return retval;
+}
+
+/**
+ * Called by OS for ioctl() from user space
+ *
+ * \param inode         file node
+ * \param file          file struct
+ * \param command       ioctl command code
+ * \param argument      ioctl argument
+ * \return 0 if success
+ */
+static int udc_ioctl(struct inode *inode,
+		     struct file *file,
+		     unsigned int command, unsigned long argument)
+{
+	struct udc *dev = udc;
+
+	if (!dev)
+		return -EINVAL;
+
+	/* for testing PM */
+	switch (command) {
+	case 1:
+		udc_remote_wakeup(udc);
+		break;
+	case 5:
+		udc_suspend(udc);
+		break;
+	case 6:
+		udc_resume(udc);
+		break;
+	}
+
+	INFO("ioctl called\n");
+
+	//print_misc(dev);
+	return 0;
+}
+
+/**
+ *  Prints a buffers contents
+ *  \param buf          pointer to buffer
+ *  \param bytes        number bytes to print
+ */
+static void dump_buffer(u8 * buf, u32 bytes)
+{
+	int i;
+
+	printk("\nbuffer %lx = %d bytes:\n", (unsigned long)buf, bytes);
+	for (i = 0; i < bytes; i++) {
+		printk("%02x", *(buf + i));
+		if ((i + 1) % 16 == 0)
+			printk("\n");
+	}
+	printk("\n");
+}
+#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 = AMD_BIT(UDC_DEVINT_SVC) |
+	    AMD_BIT(UDC_DEVINT_ENUM) |
+	    AMD_BIT(UDC_DEVINT_US) |
+	    AMD_BIT(UDC_DEVINT_UR) |
+	    AMD_BIT(UDC_DEVINT_ES) |
+	    AMD_BIT(UDC_DEVINT_SI) |
+	    AMD_BIT(UDC_DEVINT_SOF) | AMD_BIT(UDC_DEVINT_SC);
+	writel(tmp, &dev->regs->irqmsk);
+
+	/* mask all ep interrupts */
+	writel(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;
+
+	DBG("udc_enable_ep0_interrupts()\n");
+
+	/* read irq mask */
+	tmp = readl(&dev->regs->ep_irqmsk);
+	/* enable ep0 irq's */
+	tmp &= AMD_UNMASK_BIT(UDC_EPINT_IN_EP0)
+	    & AMD_UNMASK_BIT(UDC_EPINT_OUT_EP0);
+	writel(tmp, &dev->regs->ep_irqmsk);
+
+	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;
+
+	DBG("enable device interrupts for setup data\n");
+
+	/* read irq mask */
+	tmp = readl(&dev->regs->irqmsk);
+
+	/* enable SET_INTERFACE, SET_CONFIG and other needed irq's */
+	tmp &= AMD_UNMASK_BIT(UDC_DEVINT_SI)
+	    & AMD_UNMASK_BIT(UDC_DEVINT_SC)
+	    & AMD_UNMASK_BIT(UDC_DEVINT_UR)
+#ifndef UDC_IPBUG_3943_WORKAROUND
+	    & AMD_UNMASK_BIT(UDC_DEVINT_US)
+#endif
+#ifndef UDC_IPBUG_3950_WORKAROUND
+	    & AMD_UNMASK_BIT(UDC_DEVINT_SVC)
+#endif
+	    & AMD_UNMASK_BIT(UDC_DEVINT_ENUM);
+	writel(tmp, &dev->regs->irqmsk);
+
+	return 0;
+}
+
+/**
+ * Calculates fifo start of endpoint based on preceeding endpoints
+ *
+ * \param ep           pointer to ep struct
+ * \return 0 if success
+ */
+static int udc_set_txfifo_addr(struct udc_ep *ep)
+{
+	struct udc *dev;
+	u32 tmp;
+	int i;
+
+	if (!ep || !(ep->in))
+		return -EINVAL;
+
+	dev = ep->dev;
+	ep->txfifo = dev->txfifo;
+
+	/* traverse ep's */
+	for (i = 0; i < ep->num; i++) {
+		if (dev->ep[i].regs) {
+			/* read fifo size */
+			tmp = readl(&dev->ep[i].regs->bufin_framenum);
+			tmp = AMD_GETBITS(tmp, UDC_EPIN_BUFF_SIZE);
+			ep->txfifo += tmp;
+		}
+	}
+	return 0;
+}
+
+/**
+ * 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_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;
+	}
+
+	DBG("udc_enable() ep %d\n", ep->num);
+
+	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 = readl(&dev->ep[ep->num].regs->ctl);
+	tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_EPCTL_ET);
+	writel(tmp, &dev->ep[ep->num].regs->ctl);
+
+	/* set max packet size */
+	tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
+	tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_EP_MAX_PKT_SIZE);
+	ep->ep.maxpacket = desc->wMaxPacketSize;
+	writel(tmp, &dev->ep[ep->num].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 = readl(&dev->ep[ep->num].regs->bufin_framenum);
+		/* double buffering: fifo size = 2 x max packet size */
+		tmp = AMD_ADDBITS(tmp,
+				  desc->wMaxPacketSize *
+				  UDC_EPIN_BUFF_SIZE_MULT / UDC_DWORD_BYTES,
+				  UDC_EPIN_BUFF_SIZE);
+		writel(tmp, &dev->ep[ep->num].regs->bufin_framenum);
+
+		/* calc. tx fifo base addr */
+		udc_set_txfifo_addr(ep);
+
+		/* flush fifo */
+		tmp = readl(&ep->regs->ctl);
+		tmp |= AMD_BIT(UDC_EPCTL_F);
+		writel(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;
+
+		/* set max packet size UDC CSR  */
+		tmp = readl(&dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+		tmp =
+		    AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_CSR_NE_MAX_PKT);
+		writel(tmp, &dev->csr->ne[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 = readl(&dev->csr->ne[udc_csr_epix]);
+	/* max packet */
+	tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_CSR_NE_MAX_PKT);
+	/* ep number */
+	tmp = AMD_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM);
+	/* ep direction */
+	tmp = AMD_ADDBITS(tmp, ep->in, UDC_CSR_NE_DIR);
+	/* ep type */
+	tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_CSR_NE_TYPE);
+	/* ep config */
+	tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, UDC_CSR_NE_CFG);
+	/* ep interface */
+	tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, UDC_CSR_NE_INTF);
+	/* ep alt */
+	tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, UDC_CSR_NE_ALT);
+	/* write reg */
+	writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+	/* enable ep irq */
+	tmp = readl(&dev->regs->ep_irqmsk);
+	tmp &= AMD_UNMASK_BIT(ep->num);
+	writel(tmp, &dev->regs->ep_irqmsk);
+
+	/* clear NAK by writing CNAK */
+	/* avoid BNA for DMA,  dont clear NAK until DMA desc. written */
+	if (!use_dma) {
+		tmp = readl(&ep->regs->ctl);
+		tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+		writel(tmp, &ep->regs->ctl);
+		ep->naking = 0;
+		UDC_QUEUE_CNAK(ep, ep->num);
+	}
+	tmp = desc->bEndpointAddress;
+	DBG("%s enabled\n", usbep->name);
+
+	spin_unlock_irqrestore(&dev->lock, iflags);
+	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 = readl(&ep->regs->ctl);
+		tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+		writel(tmp, &ep->regs->ctl);
+		ep->naking = 1;
+
+		/* disable interrupt */
+		tmp = readl(&regs->ep_irqmsk);
+		tmp |= AMD_BIT(ep->num);
+		writel(tmp, &regs->ep_irqmsk);
+
+		if (ep->in) {
+			/* unset P and IN bit of potential former DMA */
+			tmp = readl(&ep->regs->ctl);
+			tmp &= AMD_UNMASK_BIT(UDC_EPCTL_P);
+			writel(tmp, &ep->regs->ctl);
+
+			tmp = readl(&ep->regs->sts);
+			tmp |= AMD_BIT(UDC_EPSTS_IN);
+			writel(tmp, &ep->regs->sts);
+
+			/* flush the fifo */
+			tmp = readl(&ep->regs->ctl);
+			tmp |= AMD_BIT(UDC_EPCTL_F);
+			writel(tmp, &ep->regs->ctl);
+
+		}
+		/* reset desc pointer */
+		writel(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 = NULL;
+	unsigned long iflags;
+
+	if (!usbep)
+		return -EINVAL;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (usbep->name == ep0_string || !ep->desc)
+		return -EINVAL;
+
+	DBG("Disable ep-%d\n", ep->num);
+
+	spin_lock_irqsave(&ep->dev->lock, iflags);
+	empty_req_queue(ep);
+	ep_init(ep->dev->regs, ep);
+	spin_unlock_irqrestore(&ep->dev->lock, iflags);
+
+	return 0;
+}
+
+/**
+ * Allocates request packet, called by gadget driver
+ *
+ * \param _ep           pointer to usb ep struct
+ * \param gfp_flags     flags for kmalloc
+ * \return allocated request packet, 0 if error
+ */
+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;
+
+	VDBG("udc_alloc_req()\n");
+	if (!usbep)
+		return 0;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	/* TODO gfp flags used for dma chaining later - find better way */
+	udc_gfp_flags = gfp;
+
+	VDBG("udc_alloc_req(): ep%d\n", ep->num);
+	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);
+
+	if (ep->dma) {
+
+#if defined(CONFIG_MIPS)
+		gfp = GFP_ATOMIC | GFP_DMA;
+#endif
+		/* FIXME ep0 in requests are allocated from data pool here */
+		dma_desc = pci_pool_alloc(ep->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 = AMD_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);
+		req->td_data = dma_desc;
+		req->td_data_last = NULL;
+		req->chain_len = 1;
+	}
+
+	return &req->req;
+}
+
+/**
+ * Frees request packet, called by gadget driver
+ *
+ * \param usbep   pointer to usb ep struct
+ * \param usbreq  pointer to request packet to be freed
+ */
+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);
+	VDBG("free_req req=%lx\n", (unsigned long)req);
+	WARN_ON(!list_empty(&req->queue));
+	if (req->td_data) {
+		VDBG("req->td_data=%lx\n", (unsigned long)req->td_data);
+
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+		/* re-link broken chain  */
+		if (req->td_data_last) {
+			req->td_data_last->next = req->td_data_last_next;
+		}
+#endif
+		/* free dma chain if created */
+		if (req->chain_len > 1) {
+			udc_free_dma_chain(ep->dev, req);
+		}
+
+		pci_pool_free(ep->dev->data_requests, req->td_data,
+			      req->td_phys);
+	}
+	kfree(req);
+}
+
+/* choose dma buffer allocation method */
+#undef USE_KMALLOC
+#if     defined(CONFIG_X86)
+#define USE_KMALLOC
+/* FIXME TMP26: cached dma buffers seem no to work for 2.6.x to be
+ *  examined */
+#elif   defined(CONFIG_MIPS)
+/* MIPS kernel 2.4 */
+#if     LINUX_VERSION_CODE < UDC_NEW_GADGET_KERNEL
+#if !defined(CONFIG_NONCOHERENT_IO)
+#define USE_KMALLOC
+#endif				/* !defined(CONFIG_NONCOHERENT_IO) */
+#endif				/* LINUX_VERSION_CODE < UDC_NEW_GADGET_KERNEL */
+#if   LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+#ifdef CONFIG_DMA_COHERENT
+#define USE_KMALLOC
+#endif				/* CONFIG_DMA_COHERENT */
+#endif				/* LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL */
+#endif
+
+/**
+ * Allocates data buffer for request packet, called by gadget driver
+ *
+ * \param usbep         pointer to usb ep struct
+ * \param bytes         number bytes to allocate
+ * \param dma           pointer to dma struct
+ * \param gfp_flags     flags for allocate
+ * \return pointer to allocated buffer, 0 if error
+ */
+static void *udc_alloc_buffer(struct usb_ep *usbep,
+			      unsigned len, dma_addr_t * dma, gfp_t gfp)
+{
+	void *ptr;
+	struct udc_ep *ep;
+	VDBG("alloc_buffer(): %s\n", usbep->name);
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	*dma = DMA_DONT_USE;
+
+	if (!usbep)
+		return 0;
+
+	if (ep->dma) {
+#if     defined(USE_KMALLOC)
+
+#if defined(CONFIG_MIPS)
+		gfp = GFP_ATOMIC | GFP_DMA;
+#endif
+		ptr = kmalloc(len, gfp);
+
+		if (ptr)
+			*dma = virt_to_phys(ptr);
+
+#elif   LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+		ptr = dma_alloc_coherent(&ep->dev->pdev->dev, len, dma, gfp);
+#elif defined (CONFIG_MIPS)
+		ptr = pci_alloc_consistent(ep->dev->pdev, len, dma);
+#else
+#error no memory allocator
+#endif
+	} else
+		ptr = kmalloc(len, gfp);
+
+	VDBG("alloc_buffer() ptr = %lx dma=%lx\n", (unsigned long)ptr,
+	     (unsigned long)*dma);
+	return ptr;
+}
+
+/**
+ * Free data buffer for request packet, called by gadget driver
+ *
+ * \param usbep         pointer to usb ep struct
+ * \param buf           pointer to buffer to be freed
+ * \param dma           pointer to dma struct
+ * \param len           number bytes to be freed
+ * \return pointer to allocated buffer, 0 if error
+ */
+static void
+udc_free_buffer(struct usb_ep *usbep, void *buf, dma_addr_t dma, unsigned len)
+{
+	struct udc_ep *ep;
+
+	VDBG("ep %s - free buffer %lx\n", usbep->name, (unsigned long)buf);
+
+	/* null pointer ? */
+	if (!buf) {
+		return;
+	}
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (!ep)
+		return;
+
+#ifndef USE_KMALLOC
+	if (dma != DMA_DONT_USE) {
+#if   LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+		dma_free_coherent(&ep->dev->pdev->dev, len, buf, dma);
+#else
+		pci_free_consistent(ep->dev->pdev, len, buf, dma);
+#endif
+	} else
+#endif
+	{
+		if (!(ep->dma))
+			kfree(buf);
+	}
+
+}
+
+/**
+ * Write data to TX fifo for IN packets
+ *
+ * \param ep            pointer to ep struct
+ * \param req           pointer to request packet
+ * \return allocated request packet, 0 if error
+ */
+static void udc_txfifo_write(struct udc_ep *ep, struct usb_request *req)
+{
+	u8 *req_buf;
+	u32 *buf;
+	int i, j;
+	unsigned bytes = 0;
+	unsigned remaining = 0;
+
+	VDBG("udc_txfifo_write()\n");
+
+	if (!req || !ep)
+		return;
+
+	req_buf = req->buf + req->actual;
+	prefetch(req_buf);
+	remaining = req->length - req->actual;
+
+	buf = (u32 *) req_buf;
+
+	bytes = ep->ep.maxpacket;
+	if (bytes > remaining)
+		bytes = remaining;
+
+	/* dwords first */
+	for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+		writel(*(buf + i), ep->txfifo);
+	}
+
+	/* remaining bytes must be written by byte access */
+	for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+		writeb((u8) (*(buf + i) >> (j << UDC_BITS_PER_BYTE_SHIFT)),
+		       ep->txfifo);
+	}
+
+#ifdef UDC_IPBUG_2253_WORKAROUND
+	{
+		u32 tmp;
+
+		/* NAK if small packet until write confirm completed */
+		if (bytes < UDC_SMALL_PACKET) {
+			/* set NAK */
+			tmp = readl(&ep->regs->ctl);
+			tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+			writel(tmp, &ep->regs->ctl);
+			ep->naking = 1;
+			wb_flush();
+		}
+
+		/* dummy write confirm */
+		writel(0, &ep->regs->confirm);
+
+		/* stop NAKing after small packet DMA */
+		if (ep->naking) {
+			/* clear NAK by writing CNAK */
+			tmp = readl(&ep->regs->ctl);
+			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(tmp, &ep->regs->ctl);
+			ep->naking = 0;
+			UDC_QUEUE_CNAK(ep, ep->num);
+		}
+	}
+#else
+	/* dummy write confirm */
+	writel(0, &ep->regs->confirm);
+#endif
+}
+
+/**
+ * Read dwords from RX fifo for OUT transfers
+ *
+ * \param dev           pointer to device struct
+ * \param buf           pointer to buffer to be filled
+ * \param dwords        number of dwords to be read
+ * \return allocated request packet, 0 if error
+ */
+static int udc_rxfifo_read_dwords(struct udc *dev, u32 * buf, int dwords)
+{
+	int i;
+
+	VDBG("udc_read_dwords(): %d dwords\n", dwords);
+
+	for (i = 0; i < dwords; i++) {
+		*(buf + i) = readl(dev->rxfifo);
+	}
+	return 0;
+}
+
+/**
+ * Read bytes from RX fifo for OUT transfers
+ *
+ * \param dev           pointer to device struct
+ * \param buf           pointer to buffer to be filled
+ * \param bytes         number of bytes to be read
+ * \return allocated request packet, 0 if error
+ */
+static int udc_rxfifo_read_bytes(struct udc *dev, u8 * buf, int bytes)
+{
+	int i, j;
+	u32 tmp;
+
+	VDBG("udc_read_bytes(): %d bytes\n", bytes);
+
+	/* dwords first */
+	for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+		*((u32 *) (buf + (i << 2))) = readl(dev->rxfifo);
+	}
+
+	/* remaining bytes must be read by byte access */
+	if (bytes % UDC_DWORD_BYTES) {
+		tmp = readl(dev->rxfifo);
+		for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+			*(buf + (i << 2) + j) = (u8) (tmp & UDC_BYTE_MASK);
+			tmp = tmp >> UDC_BITS_PER_BYTE;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Read data from RX fifo for OUT transfers
+ *
+ * \param ep            pointer to ep struct
+ * \param req           pointer to request packet
+ * \return true if request completes for short or max packet, false otherwise
+ */
+static int udc_rxfifo_read(struct udc_ep *ep, struct udc_request *req)
+{
+	u8 *buf;
+	unsigned buf_space;
+	unsigned bytes = 0;
+	unsigned finished = 0;
+
+	/* received number bytes */
+	bytes = readl(&ep->regs->sts);
+	bytes = AMD_GETBITS(bytes, UDC_EPSTS_RX_PKT_SIZE);
+
+	buf_space = req->req.length - req->req.actual;
+	buf = req->req.buf + req->req.actual;
+	if (bytes > buf_space) {
+		if ((buf_space % ep->ep.maxpacket) != 0) {
+			ERR("%s: received %d bytes, rx-buffer space =  %d bytes => buffer overrun\n", ep->ep.name, bytes, buf_space);
+			req->req.status = -EOVERFLOW;
+		}
+		bytes = buf_space;
+	}
+	req->req.actual += bytes;
+
+	/* last packet ? */
+	if (((bytes % ep->ep.maxpacket) != 0)
+	    || (!bytes)
+	    || ((req->req.actual == req->req.length) && !req->req.zero))
+		finished = 1;
+
+	/* read rx fifo bytes */
+	VDBG("ep %s: rxfifo read %d bytes\n", ep->ep.name, bytes);
+	udc_rxfifo_read_bytes(ep->dev, buf, bytes);
+
+	return finished;
+}
+
+/**
+ * create/re-init a DMA descriptor or a DMA descriptor chain
+ *
+ * \param ep            pointer to endpoint struct
+ * \param req           pointer to request packet
+ */
+static int prep_dma(struct udc_ep *ep, struct udc_request *req)
+{
+	int retval = 0;
+	u32 tmp;
+	VDBG("prep_dma\n");
+	VDBG("prep_dma ep%d req->td_data=%lx\n",
+	     ep->num, (unsigned long)req->td_data);
+
+	/* set buffer pointer */
+	req->td_data->bufptr = req->req.dma;
+
+	/* set last bit */
+	req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+
+	/* build/re-init dma chain if maxpkt scatter mode, not for EP0 */
+	if (use_dma_ppb && ep->num != UDC_EP0OUT_IX && ep->num != UDC_EP0IN_IX) {
+
+		retval =
+		    udc_create_dma_chain(ep, req, ep->ep.maxpacket,
+					 udc_gfp_flags);
+		if (retval != 0) {
+			if (retval == -ENOMEM)
+				INFO("Out of DMA memory (allocation failed)\n");
+			return retval;
+		}
+		/*TODO better place ? */
+		if (ep->in) {
+			if (req->req.length == ep->ep.maxpacket) {
+				/* write tx bytes */
+				req->td_data->status =
+				    AMD_ADDBITS(req->td_data->status,
+						ep->ep.maxpacket,
+						UDC_DMA_IN_STS_TXBYTES);
+
+			}
+		}
+
+	}
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+	else {			/* EP0 */
+		/* point to itself */
+		req->td_data->next = req->td_phys;
+	}
+#endif
+
+	if (ep->in) {
+		VDBG("IN: use_dma_ppb=%d req->req.length=%d ep->ep.maxpacket=%d ep%d\n", use_dma_ppb, req->req.length, ep->ep.maxpacket, ep->num);
+		/* if bytes < max packet then tx bytes must */
+		/* be written in packet per buffer mode */
+		if (!use_dma_ppb || req->req.length < ep->ep.maxpacket
+		    || ep->num == UDC_EP0OUT_IX || ep->num == UDC_EP0IN_IX) {
+			/* write tx bytes */
+			req->td_data->status = AMD_ADDBITS(req->td_data->status,
+							   req->req.length,
+							   UDC_DMA_IN_STS_TXBYTES);
+			/* reset frame num */
+			req->td_data->status = AMD_ADDBITS(req->td_data->status,
+							   0,
+							   UDC_DMA_IN_STS_FRAMENUM);
+		}
+		/* set HOST BUSY */
+		req->td_data->status
+		    = AMD_ADDBITS(req->td_data->status,
+				  UDC_DMA_STP_STS_BS_HOST_BUSY,
+				  UDC_DMA_STP_STS_BS);
+	} else {
+		VDBG("OUT set host ready\n");
+		/* set HOST READY */
+		req->td_data->status
+		    = AMD_ADDBITS(req->td_data->status,
+				  UDC_DMA_STP_STS_BS_HOST_READY,
+				  UDC_DMA_STP_STS_BS);
+
+		/* clear NAK by writing CNAK */
+		if (ep->naking) {
+			tmp = readl(&ep->regs->ctl);
+			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(tmp, &ep->regs->ctl);
+			ep->naking = 0;
+			UDC_QUEUE_CNAK(ep, ep->num);
+		}
+
+	}
+
+	return retval;
+}
+
+/**
+ * Completes request packet
+ *
+ * \param ep            pointer to ep struct
+ * \param req           pointer to request packet
+ * \param sts           status of request
+ */
+static void complete_req(struct udc_ep *ep, struct udc_request *req, int sts)
+{
+	struct udc *dev;
+	unsigned halted;
+
+	VDBG("complete_req(): ep%d\n", ep->num);
+
+	dev = ep->dev;
+	/* unmap DMA */
+	if (req->dma_mapping) {
+		if (ep->in)
+			pci_unmap_single(dev->pdev,
+					 req->req.dma,
+					 req->req.length, PCI_DMA_TODEVICE);
+		else
+			pci_unmap_single(dev->pdev,
+					 req->req.dma,
+					 req->req.length, PCI_DMA_FROMDEVICE);
+		req->dma_mapping = 0;
+		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;
+
+	/* remove from ep queue */
+	list_del_init(&req->queue);
+
+	VDBG("req %p => complete %d bytes at %s with sts %d\n",
+	     &req->req, req->req.length, ep->ep.name, sts);
+	if (spin_is_locked(&dev->lock)) {
+		spin_unlock(&dev->lock);
+		req->req.complete(&ep->ep, &req->req);
+		spin_lock(&dev->lock);
+	} else {
+		req->req.complete(&ep->ep, &req->req);
+	}
+	ep->halted = halted;
+}
+
+/**
+ * frees pci pool descriptors of a DMA chain
+ *
+ * \param dev           pointer to device struct
+ * \param req           pointer to request packet
+ * \return 0 if success
+ */
+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;
+
+	DBG("free chain req = %lx\n", (unsigned long)req);
+
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+	/* re-link broken chain  */
+	if (req->td_data_last) {
+		req->td_data_last->next = req->td_data_last_next;
+	}
+#endif
+	/* do not free first desc., will be done by free for request */
+	td_last = req->td_data;
+#if defined (CONFIG_MIPS) && !defined(CONFIG_DMA_COHERENT)
+	td = UNCAC_ADDR(phys_to_virt(td_last->next));
+#else
+	td = phys_to_virt(td_last->next);
+#endif
+
+	for (i = 1; i < req->chain_len; i++) {
+
+		pci_pool_free(dev->data_requests, td,
+			      (dma_addr_t) td_last->next);
+		td_last = td;
+#if defined (CONFIG_MIPS) && !defined(CONFIG_DMA_COHERENT)
+		td = UNCAC_ADDR(phys_to_virt(td_last->next));
+#else
+		td = phys_to_virt(td_last->next);
+#endif
+	}
+
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+	req->td_data_last = NULL;
+#endif
+	return ret_val;
+}
+
+/**
+ * Iterates to the end of a DMA chain and returns last descriptor
+ *
+ * \param req           pointer to request packet
+ * \return pointer to last descriptori of chain
+ */
+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 & AMD_BIT(UDC_DMA_IN_STS_L))) {
+#if defined (CONFIG_MIPS) && !defined(CONFIG_DMA_COHERENT)
+		td = UNCAC_ADDR(phys_to_virt(td->next));
+#else
+		td = phys_to_virt(td->next);
+#endif
+	}
+
+	return td;
+
+}
+
+/**
+ * Iterates to the end of a DMA chain and counts bytes received
+ *
+ * \param req           pointer to request packet
+ * \return number of received bytes
+ */
+static u32 udc_get_ppbdu_rxbytes(struct udc_request *req)
+{
+	struct udc_data_dma *td;
+	u32 count;
+
+	td = req->td_data;
+	/* received number bytes */
+	count = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_RXBYTES);
+
+	while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+#if defined (CONFIG_MIPS) && !defined(CONFIG_DMA_COHERENT)
+		td = UNCAC_ADDR(phys_to_virt(td->next));
+#else
+		td = phys_to_virt(td->next);
+#endif
+		/* received number bytes */
+		if (td) {
+			count +=
+			    AMD_GETBITS(td->status, UDC_DMA_OUT_STS_RXBYTES);
+		}
+	}
+
+	return count;
+
+}
+
+/**
+ * Creates or re-inits a DMA chain
+ *
+ * \param ep            pointer to endpoint struct
+ * \param req           pointer to request packet
+ * \param buf_len       number of buffer bytes per descriptor (except last short)
+ */
+static int udc_create_dma_chain(struct udc_ep *ep, struct udc_request *req,
+				unsigned long buf_len, gfp_t gfp_flags)
+{
+	unsigned long bytes = req->req.length;
+	unsigned int i;
+	dma_addr_t dma_addr;
+	struct udc_data_dma *td = NULL;
+	struct udc_data_dma *last = NULL;
+	unsigned long txbytes;
+	unsigned create_new_chain = 0;
+	unsigned len;
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+	dma_addr_t last_next = DMA_DONT_USE;
+#endif
+
+	VDBG("udc_create_dma_chain: bytes=%ld buf_len=%ld\n", bytes, buf_len);
+	dma_addr = DMA_DONT_USE;
+
+	/* unset L bit in first desc for OUT */
+	if (!ep->in) {
+		req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
+	}
+
+	/* alloc only new desc's if not already available */
+	len = req->req.length / ep->ep.maxpacket;
+	if (req->req.length % ep->ep.maxpacket) {
+		len++;
+	}
+
+	if (len > req->chain_len) {
+		/* shorter chain already allocated before */
+		if (req->chain_len > 1) {
+			udc_free_dma_chain(ep->dev, req);
+		}
+		req->chain_len = len;
+		create_new_chain = 1;
+	}
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+	/* re-link broken chain  */
+	if (req->td_data_last) {
+		req->td_data_last->next = req->td_data_last_next;
+	}
+	/* if only one td then last_next is root td */
+	last_next = req->td_phys;
+#endif
+
+	td = req->td_data;
+	/* gen. required number of descriptors and buffers */
+	for (i = buf_len; i < bytes; i += buf_len) {
+		/* create or determine next desc. */
+		if (create_new_chain) {
+
+#if defined(CONFIG_MIPS)
+			gfp_flags = GFP_ATOMIC | GFP_DMA;
+#endif
+			td = pci_pool_alloc(ep->dev->data_requests, gfp_flags,
+					    &dma_addr);
+			if (!td)
+				return -ENOMEM;
+
+			td->status = 0;
+		} else if (i == buf_len) {
+			/* first td */
+#if defined (CONFIG_MIPS) && !defined(CONFIG_DMA_COHERENT)
+			td = (struct udc_data_dma *)
+			    UNCAC_ADDR(phys_to_virt(req->td_data->next));
+#else
+			td = (struct udc_data_dma *)phys_to_virt(req->td_data->
+								 next);
+#endif
+			td->status = 0;
+		} else {
+#if defined (CONFIG_MIPS) && !defined(CONFIG_DMA_COHERENT)
+			td = (struct udc_data_dma *)
+			    UNCAC_ADDR(phys_to_virt(last->next));
+#else
+			td = (struct udc_data_dma *)phys_to_virt(last->next);
+#endif
+			td->status = 0;
+		}
+
+		if (td) {
+			/* assign buffer */
+			td->bufptr = req->req.dma + i;
+		} else {
+			break;
+		}
+
+		/* short packet ? */
+		if ((bytes - i) >= buf_len) {
+			txbytes = buf_len;
+		} else {
+			/* short packet */
+			txbytes = bytes - i;
+		}
+
+		/* link td and assign tx bytes */
+		if (i == buf_len) {
+			if (create_new_chain) {
+				req->td_data->next = dma_addr;
+			} else {
+				//req->td_data->next = virt_to_phys(td);
+			}
+			/* write tx bytes */
+			if (ep->in) {
+				/* first desc */
+				req->td_data->status =
+				    AMD_ADDBITS(req->td_data->status,
+						ep->ep.maxpacket,
+						UDC_DMA_IN_STS_TXBYTES);
+				/* second desc */
+				td->status = AMD_ADDBITS(td->status,
+							 txbytes,
+							 UDC_DMA_IN_STS_TXBYTES);
+			}
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+			last_next = req->td_data->next;
+#endif
+		} else {
+			if (create_new_chain) {
+				last->next = dma_addr;
+			} else {
+				//last->next = virt_to_phys(td);
+			}
+			if (ep->in) {
+				/* write tx bytes */
+				td->status = AMD_ADDBITS(td->status,
+							 txbytes,
+							 UDC_DMA_IN_STS_TXBYTES);
+			}
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+			last_next = last->next;
+#endif
+		}
+		last = td;
+	}
+	/* set last bit */
+	if (td) {
+		td->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+		/* last desc. points to itself */
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+		/* remember broken chain next pointer */
+		req->td_data_last_next = td->next;
+		/* point to itself */
+		td->next = last_next;
+#endif
+		req->td_data_last = td;
+	}
+
+	return 0;
+}
+
+/**
+ * Enabling RX DMA
+ *
+ * \param dev           pointer to UDC device object
+ */
+static inline void udc_set_rde(struct udc *dev)
+{
+	u32 tmp;
+
+	VDBG("udc_set_rde()\n");
+#ifdef UDC_USE_TIMER
+	/* stop RDE timer */
+	if (timer_pending(&udc_timer)) {
+		set_rde = 0;
+		mod_timer(&udc_timer, jiffies - 1);
+	}
+#endif
+	/* set RDE */
+	tmp = readl(&dev->regs->ctl);
+	tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+	writel(tmp, &dev->regs->ctl);
+}
+
+/**
+ * Queues a request packet, called by gadget driver
+ *
+ * \param usbep         pointer to usb ep struct
+ * \param usbreq        pointer to request packet to be freed
+ * \param gfp           flags for alloc
+ * \return 0 if success
+ */
+static int udc_queue(struct usb_ep *usbep, struct usb_request *usbreq,
+		gfp_t gfp)
+{
+	int retval = 0;
+	unsigned long iflags;
+	struct udc_ep *ep;
+	struct udc_request *req;
+	struct udc *dev;
+	u32 tmp;
+
+	VDBG("udc_queue()\n");
+
+	/* check the inputs */
+	req = container_of(usbreq, struct udc_request, req);
+	VDBG("!usbep=%d !req=%d !buf=%d !compl=%d !empty_list=%d \n",
+	     !usbep, !usbreq, !usbreq->buf, !usbreq->complete,
+	     !list_empty(&req->queue));
+
+	if (!usbep || !usbreq || !usbreq->complete || !usbreq->buf
+	    || !list_empty(&req->queue))
+		return -EINVAL;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+		return -EINVAL;
+
+	VDBG("udc_queue(): ep%d-in=%d\n", ep->num, ep->in);
+	dev = ep->dev;
+
+	/* exit on suspend */
+	if (dev->sys_suspended)
+		return -ESHUTDOWN;
+
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	/* map dma (usally done before) */
+	if (ep->dma && usbreq->length != 0 && usbreq->dma == DMA_DONT_USE) {
+		VDBG("DMA map req %lx\n", (unsigned long)req);
+		if (ep->in)
+			usbreq->dma = pci_map_single(dev->pdev,
+						     usbreq->buf,
+						     usbreq->length,
+						     PCI_DMA_TODEVICE);
+		else
+			usbreq->dma = pci_map_single(dev->pdev,
+						     usbreq->buf,
+						     usbreq->length,
+						     PCI_DMA_FROMDEVICE);
+		req->dma_mapping = 1;
+	}
+
+	VDBG("%s queue req %p, len %d req->td_data=%lx buf %p\n",
+	     usbep->name, usbreq, usbreq->length, (unsigned long)req->td_data,
+	     usbreq->buf);
+
+	spin_lock_irqsave(&dev->lock, iflags);
+	usbreq->actual = 0;
+	usbreq->status = -EINPROGRESS;
+	req->dma_done = 0;
+
+	/* on empty queue just do first transfer */
+	if (list_empty(&ep->queue)) {
+		/* zlp */
+		if (ep->in && usbreq->length == 0) {
+			/* IN zlp's are handled by hardware */
+			complete_req(ep, req, 0);
+			VDBG("%s: zlp\n", ep->ep.name);
+			/* if set_config or set_intf is waiting for ack by zlp
+			   then set CSR_DONE */
+			if (dev->set_cfg_not_acked) {
+				tmp = readl(&dev->regs->ctl);
+				tmp |= AMD_BIT(UDC_DEVCTL_CSR_DONE);
+				writel(tmp, &dev->regs->ctl);
+				dev->set_cfg_not_acked = 0;
+			}
+			/* setup command is ACK'ed now by zlp */
+			if (dev->waiting_zlp_ack_ep0in) {
+				/* clear NAK by writing CNAK in EP0_IN */
+				tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+				tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+				writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+				dev->ep[UDC_EP0IN_IX].naking = 0;
+				UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX],
+					       UDC_EP0IN_IX);
+				dev->waiting_zlp_ack_ep0in = 0;
+			}
+			goto finished;
+		}
+		if (ep->dma) {
+			retval = prep_dma(ep, req);
+			if (retval != 0)
+				goto finished;
+			/* write desc pointer to enable DMA */
+			if (ep->in) {
+				/* set HOST READY */
+				req->td_data->status
+				    = AMD_ADDBITS(req->td_data->status,
+						  UDC_DMA_IN_STS_BS_HOST_READY,
+						  UDC_DMA_IN_STS_BS);
+			}
+
+			/* write desc pointer */
+			writel(req->td_phys, &ep->regs->desptr);
+			/* clear NAK by writing CNAK */
+			if (ep->naking) {
+				tmp = readl(&ep->regs->ctl);
+				tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+				writel(tmp, &ep->regs->ctl);
+				ep->naking = 0;
+				UDC_QUEUE_CNAK(ep, ep->num);
+			}
+
+			if (!ep->in) {
+				/* enable DMA */
+				udc_set_rde(dev);
+				if (ep->num != UDC_EP0OUT_IX)
+					dev->data_ep_queued = 1;
+			}
+#ifdef UDC_DISABLE_IRQ_IF_EMPTY_IN_QUEUE
+			else {
+				/* enable ep irq */
+				tmp = readl(&dev->regs->ep_irqmsk);
+				tmp &= AMD_UNMASK_BIT(ep->num);
+				writel(tmp, &dev->regs->ep_irqmsk);
+			}
+#endif
+		}
+
+	} else if (ep->dma) {
+
+		/* TODO use prep_dma also for OUT ep's, this is not possible
+		   for PPB modes currently, because of chain creation reasons */
+		if (ep->in) {
+			retval = prep_dma(ep, req);
+			if (retval != 0)
+				goto finished;
+		}
+
+	}
+	VDBG("list_add\n");
+	/* add request to ep queue */
+	if (req) {
+
+		list_add_tail(&req->queue, &ep->queue);
+
+		/* stop OUT naking */
+		if (!ep->in) {
+			if (!use_dma && udc_rxfifo_pending) {
+				DBG("udc_queue(): pending bytes in rxfifo after nyet\n");
+				/* read pending bytes afer nyet: referring to isr */
+				if (udc_rxfifo_read(ep, req)) {
+					/* finish */
+					complete_req(ep, req, 0);
+				}
+				udc_rxfifo_pending = 0;
+
+			}
+		}
+
+	}
+
+      finished:
+	spin_unlock_irqrestore(&dev->lock, iflags);
+	return retval;
+}
+
+/**
+ * Empty request queue of an endpoint
+ *
+ * \param ep            pointer to ep struct
+ */
+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
+ *
+ * \param usbep           pointer to usb ep struct
+ * \param usbreq          pointer to request packet to be freed
+ * \return 0 if success
+ */
+static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+	struct udc_ep *ep;
+	struct udc_request *req;
+	unsigned req_may_used = 0;
+	unsigned halted;
+	unsigned long iflags;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (!usbep
+	    || !usbreq
+	    || (!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);
+	halted = ep->halted;
+	ep->halted = 1;
+	/* request in processing or next one */
+	if (ep->queue.next == &req->queue) {
+		req_may_used = 1;
+	}
+	complete_req(ep, req, -ECONNRESET);
+	ep->halted = halted;
+
+	spin_unlock_irqrestore(&ep->dev->lock, iflags);
+	if (req_may_used)
+		return -EOPNOTSUPP;
+	else
+		return 0;
+}
+
+/**
+ * Halt or clear halt of endpoint
+ *
+ * \param usbe          pointer to ep struct
+ * \param halt          1 - halt, 0 - clear halt
+ * \return 0 if success
+ */
+static int udc_set_halt(struct usb_ep *usbep, int halt)
+{
+	struct udc_ep *ep;
+	u32 tmp;
+	unsigned long iflags;
+	int retval = 0;
+
+	if (!usbep)
+		return -EINVAL;
+
+	DBG("set_halt %s: halt=%d\n", usbep->name, halt);
+
+	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;
+
+	/* exit on suspend */
+	if (ep->dev->sys_suspended)
+		return -ESHUTDOWN;
+
+	spin_lock_irqsave(&udc_stall_spinlock, iflags);
+	/* halt or clear halt */
+	if (halt) {
+		if (ep->num == 0)
+			ep->dev->stall_ep0in = 1;
+		else {
+			/* FIXME rxfifo empty should be taken into acount */
+			/* set STALL */
+			tmp = readl(&ep->regs->ctl);
+			tmp |= AMD_BIT(UDC_EPCTL_S);
+			writel(tmp, &ep->regs->ctl);
+			ep->halted = 1;
+
+#ifdef UDC_USE_TIMER
+			/* setup poll timer */
+			if (!timer_pending(&udc_pollstall_timer)) {
+				udc_pollstall_timer.expires = jiffies + HZ
+				    * UDC_POLLSTALL_TIMER_USECONDS
+				    / (1000 * 1000);
+				if (!stop_pollstall_timer) {
+					DBG("start polltimer\n");
+					add_timer(&udc_pollstall_timer);
+				}
+			}
+#endif
+		}
+	} else {
+		/* ep is halted by set_halt() before */
+		if (ep->halted) {
+			tmp = readl(&ep->regs->ctl);
+			/* clear stall bit */
+			tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+			/* clear NAK by writing CNAK */
+			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(tmp, &ep->regs->ctl);
+			ep->halted = 0;
+			UDC_QUEUE_CNAK(ep, ep->num);
+		}
+	}
+	spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
+	return retval;
+}
+
+/**
+ * Return fifo fill state (not used, not implemented)
+ *
+ * \param usbep            pointer to usb ep struct
+ * \return available bytes in fifo
+ */
+static int udc_fifo_status(struct usb_ep *usbep)
+{
+	return 0;
+}
+
+/**
+ * Flush the endpoint fifo (not implemented)
+ *
+ * \param usbep            pointer to usb ep struct
+ */
+static void udc_fifo_flush(struct usb_ep *usbep)
+{
+	return;
+}
+
+/* gadget interface */
+static struct usb_ep_ops udc_ep_ops = {
+	.enable = udc_enable,
+	.disable = udc_disable,
+
+	.queue = udc_queue,
+	.dequeue = udc_dequeue,
+
+	.alloc_request = udc_alloc_request,
+	.free_request = udc_free_request,
+
+	.alloc_buffer = udc_alloc_buffer,
+	.free_buffer = udc_free_buffer,
+
+	.set_halt = udc_set_halt,
+	.fifo_status = udc_fifo_status,
+	.fifo_flush = udc_fifo_flush,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * Get frame count fifo (not implemented)
+ *
+ * \param gadget            pointer to gadget struct
+ * \return frame count
+ */
+static int udc_get_frame(struct usb_gadget *gadget)
+{
+	return 0;
+}
+
+/**
+ * Remote wakeup gadget interface
+ *
+ * \param gadget            pointer to gadget struct
+ * \return 0 if success
+ */
+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
+ *
+ * \param gadget            pointer to gadget struct
+ * \param cmd               command
+ * \param par               parmater
+ * \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 = readl(&dev->regs->cfg);
+
+	if (tmp & AMD_BIT(UDC_DEVCFG_HNPSFEN))
+		retval = 1;
+	else
+		retval = 0;
+	spin_unlock_irqrestore(&dev->lock, iflags);
+	return retval;
+}
+
+/* gadget operations */
+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
+ *
+ * \param dev           pointer to dev struct
+ */
+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;
+}
+
+/**
+ * Sets fifo mode, called by gadget driver
+ *
+ * \param gadget        pointer to gadget struct
+ * \param md            not used
+ * \return 0 if success
+ */
+int amd5536udc_set_fifo_mode(struct usb_gadget *gadget, int md)
+{
+	struct udc *dev;
+	unsigned long iflags;
+
+	if (!gadget)
+		return -ENODEV;
+
+	dev = container_of(gadget, struct udc, gadget);
+
+	spin_lock_irqsave(&dev->lock, iflags);
+	make_ep_lists(dev);
+	spin_unlock_irqrestore(&dev->lock, iflags);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(amd5536udc_set_fifo_mode);
+
+/**
+ * \brief
+ * init registers at driver load time
+ *
+ * \param dev        pointer to device struc
+ * \return 0 if success
+ */
+static int startup_registers(struct udc *dev)
+{
+	u32 tmp;
+
+	/* 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 = readl(&dev->regs->cfg);
+	if (use_fullspeed) {
+		tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+	} else {
+		tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
+	}
+	writel(tmp, &dev->regs->cfg);
+
+	return 0;
+}
+
+/**
+ * Inits UDC context
+ *
+ * \param dev           pointer to device struct
+ */
+static void udc_basic_init(struct udc *dev)
+{
+	u32 tmp;
+
+	DBG("udc_basic_init()\n");
+
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+#ifdef UDC_USE_TIMER
+	/* stop RDE timer */
+	if (timer_pending(&udc_timer)) {
+		set_rde = 0;
+		mod_timer(&udc_timer, jiffies - 1);
+	}
+	/* stop poll stall timer */
+	if (timer_pending(&udc_pollstall_timer)) {
+		mod_timer(&udc_pollstall_timer, jiffies - 1);
+	}
+#endif
+	/* disable DMA */
+	tmp = readl(&dev->regs->ctl);
+	tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+	tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_TDE);
+	writel(tmp, &dev->regs->ctl);
+
+	/* enable dynamic CSR programming */
+	tmp = readl(&dev->regs->cfg);
+	tmp |= AMD_BIT(UDC_DEVCFG_CSR_PRG);
+	/* set self powered */
+	tmp |= AMD_BIT(UDC_DEVCFG_SP);
+	/* set remote wakeupable */
+	tmp |= AMD_BIT(UDC_DEVCFG_RWKP);
+	writel(tmp, &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;
+	u32 reg;
+
+	DBG("udc_setup_endpoints()\n");
+
+	/* read enum speed */
+	tmp = readl(&dev->regs->sts);
+	tmp = AMD_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];
+		/* TODO 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
+		   => to be improved for general ep_init() */
+		if (!ep->desc) {
+			ep_init(dev->regs, ep);
+		}
+
+		if (use_dma) {
+			/* TODO ep->dma is not really used, just to indicate that */
+			/* DMA is active: remove this */
+			/* dma regs = dev control regs */
+			ep->dma = (u32 *) & dev->regs->ctl;
+
+			/* nak OUT endpoints until enable - not for ep0 */
+			if (tmp != UDC_EP0IN_IX
+			    && tmp != UDC_EP0OUT_IX && tmp > UDC_EPIN_NUM) {
+				/* set NAK  */
+				reg = readl(&dev->ep[tmp].regs->ctl);
+				reg |= AMD_BIT(UDC_EPCTL_SNAK);
+				writel(reg, &dev->ep[tmp].regs->ctl);
+				dev->ep[tmp].naking = 1;
+
+			}
+		}
+	}
+	/* 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;
+	}
+
+	/* 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;
+}
+
+/**
+ * Bringup after Connect event,
+ * initial bringup to be ready for ep0 events
+ *
+ * \param dev           pointer to device struct
+ */
+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
+ *
+ * \param dev           pointer to device struct
+ */
+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
+ *
+ * \param par   pointer to device struct pointer
+ */
+void udc_tasklet_disconnect(unsigned long par)
+{
+	struct udc *dev = (struct udc *)(*((struct udc **)par));
+	u32 tmp;
+
+	DBG("Tasklet disconnect\n");
+
+	/* 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 */
+#ifdef UDC_IPCASE_8000018724_WORKAROUND
+		udc_soft_reset(dev);
+#endif
+		soft_reset_occured++;
+	}
+#ifndef UDC_IPBUG_3950_WORKAROUND
+	/* re-enable dev interrupts */
+	udc_enable_dev_setup_interrupts(dev);
+#endif
+	/* back to full speed ? */
+	if (use_fullspeed) {
+		tmp = readl(&dev->regs->cfg);
+		tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+		writel(tmp, &dev->regs->cfg);
+	}
+
+	/* TODO for AU1200: disable UDC memory */
+}
+
+/**
+ * Reset the UDC core
+ *
+ * \param dev           pointer to device struct
+ */
+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 */
+	writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqsts);
+	/* device int. status reset */
+	writel(UDC_DEV_MSK_DISABLE, &dev->regs->irqsts);
+
+	/* FIXME: reset is the only way to restart DMA now,
+	   later if the hw bug is fixed, use a softer way */
+	spin_lock_irq(&udc_irq_spinlock);
+	writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+	readl(&dev->regs->cfg);
+	spin_unlock_irq(&udc_irq_spinlock);
+
+}
+
+#ifdef UDC_USE_TIMER
+/**
+ * RDE timer callback to set RDE bit
+ *
+ * \param v           timer callback argument
+ */
+void udc_timer_function(unsigned long v)
+{
+	u32 tmp;
+	unsigned int i;
+	unsigned int bulk_data_arrived;
+	spin_lock_irq(&udc_irq_spinlock);
+	if (set_rde) {
+		/* open the fifo if fifo was filled on last timer call */
+		if (set_rde > 1) {
+			bulk_data_arrived = 0;
+			/* check wether OUT bulk data is arrived */
+			for (i = UDC_EPIN_NUM + 1; i < UDC_EP_NUM; i++) {
+				tmp = readl(&udc->ep[i].regs->sts);
+				if (AMD_GETBITS(tmp, UDC_EPSTS_OUT)
+				    == UDC_EPSTS_OUT_DATA) {
+					//&& AMD_GETBITS(tmp, UDC_EPSTS_RX_PKT_SIZE)){
+					bulk_data_arrived = 1;
+					break;
+				}
+			}
+			/* if OUT bulk data in fifo wait for queueing which
+			   sets RDE, if not open fifo for setup packet */
+			if (!bulk_data_arrived) {
+				/* set RDE */
+				tmp = readl(&udc->regs->ctl);
+				tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+				writel(tmp, &udc->regs->ctl);
+			} else
+				INFO("ep%d - queueing delay longer than %d second(s)\n", i, UDC_RDE_TIMER_SECONDS);
+			set_rde = -1;
+		} else if (readl(&udc->regs->sts) &
+			   AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+			/* if fifo empty setup polling, do not just
+			   open the fifo */
+			udc_timer.expires = jiffies + HZ / UDC_RDE_TIMER_DIV;
+			if (!stop_timer) {
+				add_timer(&udc_timer);
+			}
+		} else {
+			/* fifo contains data now, setup timer for opening
+			   the fifo when timer expires to be able to receive
+			   setup packets, when data packets gets queued by
+			   gadget layer then timer will forced to expire with
+			   set_rde=0 (RDE is set in udc_queue()) */
+			set_rde++;
+			/* debug: lhadmot_timer_start = 221070 */
+			udc_timer.expires =
+			    jiffies + HZ * UDC_RDE_TIMER_SECONDS;
+			if (!stop_timer) {
+				add_timer(&udc_timer);
+			}
+		}
+
+	} else
+		set_rde = -1;	/* RDE was set by udc_queue() */
+	spin_unlock_irq(&udc_irq_spinlock);
+	if (stop_timer)
+		complete(&on_exit);
+
+}
+
+/**
+ *  Handle halt state, used in stall poll timer
+ *
+ * \param ep    pointer to endpoint struct
+ */
+static inline void udc_handle_halt_state(struct udc_ep *ep)
+{
+	u32 tmp;
+	/* set stall as long not halted */
+	if (ep->halted == 1) {
+		tmp = readl(&ep->regs->ctl);
+		/* STALL cleared ? */
+		if (!(tmp & AMD_BIT(UDC_EPCTL_S))) {
+			DBG("ep %d: set STALL again\n", ep->num);
+			/* set STALL again */
+			tmp |= AMD_BIT(UDC_EPCTL_S);
+			writel(tmp, &ep->regs->ctl);
+		}
+	}
+}
+
+/**
+ *  Stall timer callback to poll S bit and set it again after
+ *  CLEAR_FEATURE
+ *
+ * \param v           timer callback argument
+ */
+void udc_pollstall_timer_function(unsigned long v)
+{
+	struct udc_ep *ep;
+	int halted = 0;
+	unsigned long iflags;
+
+	spin_lock_irqsave(&udc_stall_spinlock, iflags);
+	/* TODO only one IN and OUT endpoints are handled */
+	/* IN poll stall */
+	ep = &udc->ep[UDC_EPIN_IX];
+	udc_handle_halt_state(ep);
+	if (ep->halted)
+		halted = 1;
+	/* OUT poll stall  */
+	ep = &udc->ep[UDC_EPOUT_IX];
+	udc_handle_halt_state(ep);
+	if (ep->halted)
+		halted = 1;
+
+	/* setup timer again when still halted */
+	if (!stop_pollstall_timer && halted) {
+		udc_pollstall_timer.expires = jiffies + HZ
+		    * UDC_POLLSTALL_TIMER_USECONDS / (1000 * 1000);
+		add_timer(&udc_pollstall_timer);
+	}
+	spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
+
+	if (stop_pollstall_timer)
+		complete(&on_pollstall_exit);
+}
+#endif
+
+#if defined(UDC_IPBUG_3950_WORKAROUND) \
+    || defined(UDC_IPCASE_8000018724_WORKAROUND) \
+    && !defined(UDC_HSB1)
+/**
+ * Called by OTG driver to notify us regarding an OTG event
+ *
+ * \param code           notify code
+ */
+void otg_notify(unsigned int code)
+{
+	VDBG("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;
+	}
+}
+#endif
+
+/**
+ * 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;
+
+	DBG("activate_control_endpoints\n");
+
+	/* flush fifo */
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+	tmp |= AMD_BIT(UDC_EPCTL_F);
+	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+	/* set ep0 directions */
+	dev->ep[UDC_EP0IN_IX].in = 1;
+	dev->ep[UDC_EP0OUT_IX].in = 0;
+
+	/* set buffer size (tx fifo entries) of EP0_IN */
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp =
+		    AMD_ADDBITS(tmp, UDC_FS_EPIN0_BUFF_SIZE,
+				UDC_EPIN_BUFF_SIZE);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp = AMD_ADDBITS(tmp, UDC_EPIN0_BUFF_SIZE, UDC_EPIN_BUFF_SIZE);
+	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+
+	/* set max packet size of EP0_IN */
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp =
+		    AMD_ADDBITS(tmp, UDC_FS_EP0IN_MAX_PKT_SIZE,
+				UDC_EP_MAX_PKT_SIZE);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp =
+		    AMD_ADDBITS(tmp, UDC_EP0IN_MAX_PKT_SIZE,
+				UDC_EP_MAX_PKT_SIZE);
+	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+
+	/* set max packet size of EP0_OUT */
+	tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp =
+		    AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+				UDC_EP_MAX_PKT_SIZE);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp =
+		    AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+				UDC_EP_MAX_PKT_SIZE);
+	writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+
+	/* set max packet size of EP0 in UDC CSR  */
+	tmp = readl(&dev->csr->ne[0]);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp =
+		    AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+				UDC_CSR_NE_MAX_PKT);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp =
+		    AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+				UDC_CSR_NE_MAX_PKT);
+	writel(tmp, &dev->csr->ne[0]);
+
+	if (use_dma) {
+		dev->ep[UDC_EP0OUT_IX].td->status |= AMD_BIT(UDC_DMA_OUT_STS_L);
+		/* write dma desc address */
+		writel(dev->ep[UDC_EP0OUT_IX].td_stp_dma,
+		       &dev->ep[UDC_EP0OUT_IX].regs->subptr);
+		writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+		       &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+#ifdef UDC_USE_TIMER
+		/* stop RDE timer */
+		if (timer_pending(&udc_timer)) {
+			set_rde = 0;
+			mod_timer(&udc_timer, jiffies - 1);
+		}
+		/* stop pollstall timer */
+		if (timer_pending(&udc_pollstall_timer)) {
+			mod_timer(&udc_pollstall_timer, jiffies - 1);
+		}
+#endif
+		/* enable DMA */
+		tmp = readl(&dev->regs->ctl);
+		tmp |= AMD_BIT(UDC_DEVCTL_MODE)
+		    | AMD_BIT(UDC_DEVCTL_RDE)
+		    | AMD_BIT(UDC_DEVCTL_TDE);
+		if (use_dma_bufferfill_mode) {
+			tmp |= AMD_BIT(UDC_DEVCTL_BF);
+		} else if (use_dma_ppb_du) {
+			tmp |= AMD_BIT(UDC_DEVCTL_DU);
+		}
+		writel(tmp, &dev->regs->ctl);
+	}
+
+	/* clear NAK by writing CNAK for EP0IN */
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+	tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+	dev->ep[UDC_EP0IN_IX].naking = 0;
+	UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+	/* clear NAK by writing CNAK for EP0OUT */
+	tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+	tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+	writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+	dev->ep[UDC_EP0OUT_IX].naking = 0;
+	UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+}
+
+/**
+ * \brief
+ * Make endpoint 0 ready for control traffic
+ *
+ * \param dev        pointer to device struc
+ * \return 0 if success
+ */
+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;
+}
+
+/**
+ * \brief
+ * Called by gadget driver to register itself
+ *
+ * \param driver        pointer to gadget driver struct
+ * \return 0 if success
+ */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct udc *dev = udc;
+	int retval;
+	u32 tmp;
+
+	if (!driver || !driver->bind
+	    || !driver->unbind
+	    || !driver->setup || driver->speed != USB_SPEED_HIGH)
+		return -EINVAL;
+	if (!dev)
+		return -ENODEV;
+	if (dev->driver)
+		return -EBUSY;
+
+#if     LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+	driver->driver.bus = 0;
+#endif
+	dev->driver = driver;
+#if     LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+	dev->gadget.dev.driver = &driver->driver;
+#endif
+
+#if     LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+#ifndef CONFIG_MIPS
+	/* FIXME TMP26: temporary disabled device file system usage until
+	 * working for Au1200 */
+	device_create_file(&dev->pdev->dev, &dev_attr_function);
+	device_create_file(&dev->pdev->dev, &dev_attr_queues);
+#endif
+#endif
+
+#ifdef CONFIG_USB_OTG
+	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;
+#if     LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+		dev->gadget.dev.driver = 0;
+#endif
+		return retval;
+	}
+
+	/* 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 = readl(&dev->regs->ctl);
+		tmp = tmp & AMD_CLEAR_BIT(UDC_DEVCTL_SD);
+		writel(tmp, &dev->regs->ctl);
+	}
+#ifndef UDC_IPBUG_3950_WORKAROUND
+	usb_connect(dev);
+#endif
+
+	return 0;
+}
+
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+/**
+ * Called by OTG driver to register itself
+ *
+ *
+ * \param get_transceiver  function pointer to get OTG info
+ * \return 0 if success
+ */
+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 !defined(UDC_HSB1)
+	if (!dev->otg_transceiver->otg_priv)
+		return -EINVAL;
+	dev->otg_driver = (struct usb_otg_gadget_extension *)
+	    dev->otg_transceiver->otg_priv;
+#endif
+
+#ifdef UDC_IPBUG_3943_WORKAROUND
+	/* init registers here first with suspend bug */
+	if (!otg_reg_count) {
+		startup_registers(dev);
+		otg_reg_count++;
+	}
+#endif
+
+#ifdef UDC_IPBUG_3950_WORKAROUND
+	/* set notify function */
+	dev->otg_driver->notify = otg_notify;
+#endif
+	/* if gadget driver already registered */
+	/* call gadget bind() to switch to mux udc to phy */
+	/* TODO use SD bit to disconnect/connect later, in */
+	/* AMD5536 RevA0 this does not work ! */
+	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");
+#if !defined(UDC_HSB1)
+			dev->otg_driver = NULL;
+#endif
+			dev->otg_transceiver = NULL;
+			return retval;
+		}
+		/* get ready for ep0 traffic */
+		setup_ep0(dev);
+
+		/* clear SD */
+		tmp = readl(&dev->regs->ctl);
+		tmp = tmp & AMD_CLEAR_BIT(UDC_DEVCTL_SD);
+		writel(tmp, &dev->regs->ctl);
+	}
+
+	INFO("registered uoc driver\n");
+
+	return 0;
+}
+
+EXPORT_SYMBOL(usb_gadget_register_otg);
+
+/**
+ * Called by OTG driver to unregister itself
+ *
+ *
+ * \return 0 if success
+ */
+int usb_gadget_unregister_otg(void)
+{
+	struct udc *dev = udc;
+	unsigned long flags;
+	u32 tmp;
+
+	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 !defined(UDC_HSB1)
+	if (dev->otg_driver) {
+#ifdef UDC_IPBUG_3950_WORKAROUND
+		dev->otg_driver->notify = NULL;
+#endif
+		dev->otg_driver = NULL;
+	}
+#endif
+
+	/* set SD */
+	tmp = readl(&dev->regs->ctl);
+	tmp |= AMD_BIT(UDC_DEVCTL_SD);
+	writel(tmp, &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) {
+		spin_unlock(&dev->lock);
+		driver->disconnect(&dev->gadget);
+		spin_lock(&dev->lock);
+	}
+	/* init */
+	udc_setup_endpoints(dev);
+}
+
+/**
+ * Called by gadget driver to unregister itself
+ *
+ * \param driver        pointer to gadget driver struct
+ * \return 0 if success
+ */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct udc *dev = udc;
+	unsigned long iflags;
+	u32 tmp;
+
+	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);
+	}
+
+	/* set SD */
+	tmp = readl(&dev->regs->ctl);
+	tmp |= AMD_BIT(UDC_DEVCTL_SD);
+	writel(tmp, &dev->regs->ctl);
+
+	gadget_bind_count = 0;
+	dev->driver = 0;
+
+	DBG("%s: unregistered\n", driver->driver.name);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+#ifdef UDC_IPBUG_3958_WORKAROUND
+/**
+ * Clear pending NAK bits
+ *
+ * \param dev           pointer to UDC device object
+ * \return 0 if success
+ */
+static void udc_process_cnak_queue(struct udc *dev)
+{
+	u32 tmp;
+	u32 reg;
+	/* check epin's */
+	DBG("CNAK pending queue processing\n");
+	for (tmp = 0; tmp < UDC_EPIN_NUM_USED; tmp++) {
+		if (cnak_pending & (1 << tmp)) {
+			DBG("CNAK pending for ep%d\n", tmp);
+			/* clear NAK by writing CNAK */
+			reg = readl(&dev->ep[tmp].regs->ctl);
+			reg |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(reg, &dev->ep[tmp].regs->ctl);
+			dev->ep[tmp].naking = 0;
+			UDC_QUEUE_CNAK(&dev->ep[tmp], dev->ep[tmp].num);
+		}
+	}
+	/* ...  and ep0out */
+	if (cnak_pending & (1 << UDC_EP0OUT_IX)) {
+		DBG("CNAK pending for ep%d\n", UDC_EP0OUT_IX);
+		/* clear NAK by writing CNAK */
+		reg = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+		reg |= AMD_BIT(UDC_EPCTL_CNAK);
+		writel(reg, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+		dev->ep[UDC_EP0OUT_IX].naking = 0;
+		UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX],
+			       dev->ep[UDC_EP0OUT_IX].num);
+	}
+}
+#endif
+
+/**
+ * Enabling RX DMA after setup packet
+ *
+ * \param dev           pointer to UDC device object
+ */
+static inline void udc_ep0_set_rde(struct udc *dev)
+{
+	if (use_dma) {
+#ifndef UDC_USE_TIMER
+		udc_set_rde(dev);
+#else
+		/* only enable RXDMA when no data endpoint enabled
+		   or data is queued */
+		if (!dev->data_ep_enabled || dev->data_ep_queued) {
+			udc_set_rde(dev);
+		} else {
+			/* setup timer for enabling RDE (to not enable
+			   RXFIFO DMA for data endpoints to early) */
+			if (set_rde != 0 && !timer_pending(&udc_timer)) {
+				udc_timer.expires =
+				    jiffies + HZ / UDC_RDE_TIMER_DIV;
+				set_rde = 1;
+				if (!stop_timer) {
+					add_timer(&udc_timer);
+				}
+			}
+		}
+#endif
+	}
+}
+
+/**
+ * Interrupt handler for data OUT traffic
+ *
+ * \param dev           pointer to UDC device object
+ * \param ep_ix         endpoint index
+ * \return 0 if success
+ */
+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 int count;
+	struct udc_data_dma *td = NULL;
+	unsigned dma_done;
+
+	VDBG("ep%d irq\n", ep_ix);
+	ep = &dev->ep[ep_ix];
+
+	tmp = readl(&ep->regs->sts);
+	if (use_dma) {
+		/* BNA event ? */
+		if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+			ERR("BNA ep%dout occured - DESPTR = %lx \n", ep->num,
+			    (unsigned long)readl(&ep->regs->desptr));
+
+			/* clear BNA */
+			writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts);
+			/* TODO no early return */
+			return 1;
+		}
+	}
+	/* HE event ? */
+	if (tmp & AMD_BIT(UDC_EPSTS_HE)) {
+		ERR("HE ep%dout occured\n", ep->num);
+
+		/* clear HE */
+		writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+		/* TODO no early return */
+		return 1;
+	}
+
+	if (!list_empty(&ep->queue)) {
+
+		/* next request */
+		req = list_entry(ep->queue.next, struct udc_request, queue);
+	} else {
+		req = 0;
+#ifdef UDC_DEBUG
+		no_req++;
+#endif
+		udc_rxfifo_pending = 1;
+	}
+	VDBG("req = %lx\n", (unsigned long)req);
+	/* fifo mode *************** */
+	if (!use_dma) {
+
+		/* read fifo */
+		if (req && udc_rxfifo_read(ep, req)) {
+			/* finish */
+			complete_req(ep, req, 0);
+			/* next request */
+			if (!list_empty(&ep->queue) && !ep->halted) {
+				req = list_entry(ep->queue.next,
+						 struct udc_request, queue);
+			} else
+				req = 0;
+		}
+
+	} /* DMA ******************* */
+	else if (req) {
+
+		/* check for DMA done */
+		if (!use_dma_ppb) {
+			dma_done =
+			    AMD_GETBITS(req->td_data->status,
+					UDC_DMA_OUT_STS_BS);
+		} /* packet per buffer mode - rx bytes */
+		else {
+			td = udc_get_last_dma_desc(req);
+			dma_done = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_BS);
+		}
+		if (dma_done == UDC_DMA_OUT_STS_BS_DMA_DONE) {
+			/* buffer fill mode - rx bytes */
+			if (!use_dma_ppb) {
+				/* received number bytes */
+				count =
+				    AMD_GETBITS(req->td_data->status,
+						UDC_DMA_OUT_STS_RXBYTES);
+				VDBG("rx bytes=%lx\n", (unsigned long)count);
+			} /* packet per buffer mode - rx bytes */
+			else {
+				VDBG("req->td_data=%lx\n",
+				     (unsigned long)req->td_data);
+				VDBG("last desc = %lx\n", (unsigned long)td);
+				/* received number bytes */
+				if (use_dma_ppb_du) {
+					/* every desc. counts bytes */
+					count = udc_get_ppbdu_rxbytes(req);
+				} else {
+					/* last desc. counts bytes */
+					count =
+					    AMD_GETBITS(td->status,
+							UDC_DMA_OUT_STS_RXBYTES);
+					if (!count) {
+						/* on 64k packets the RXBYTES field is zero */
+						if (req->req.length ==
+						    UDC_DMA_MAXPACKET)
+							count =
+							    UDC_DMA_MAXPACKET;
+					}
+				}
+				VDBG("last desc rx bytes=%lx\n",
+				     (unsigned long)count);
+			}
+
+			tmp = req->req.length - req->req.actual;
+			if (count > tmp) {
+				if ((tmp % ep->ep.maxpacket) != 0) {
+					ERR("%s: received %d bytes, rx-buffer space =  %d bytes => buffer overrun\n", ep->ep.name, count, tmp);
+					req->req.status = -EOVERFLOW;
+				}
+				count = tmp;
+			}
+			req->req.actual += count;
+
+			/* complete request */
+			complete_req(ep, req, 0);
+
+			/* next request */
+			if (!list_empty(&ep->queue) && !ep->halted) {
+				req = list_entry(ep->queue.next,
+						 struct udc_request, queue);
+
+				/* next dma */
+				ret_val = prep_dma(ep, req);
+				if (ret_val != 0)
+					goto finished;
+				/* write desc pointer */
+				writel(req->td_phys, &ep->regs->desptr);
+
+				/* enable DMA */
+				udc_set_rde(dev);
+			} else {
+#ifdef UDC_DEBUG
+				no_pref_req++;
+				VDBG("OUT queue empty\n");
+#endif
+				/* schedule timer for setting RDE if queue remains empty
+				 * to allow ep0 packets pass through */
+#ifdef UDC_USE_TIMER
+				if (set_rde != 0 && !timer_pending(&udc_timer)) {
+					udc_timer.expires =
+					    jiffies +
+					    HZ * UDC_RDE_TIMER_SECONDS;
+					set_rde = 1;
+					if (!stop_timer) {
+						add_timer(&udc_timer);
+					}
+				}
+#endif
+				if (ep->num != UDC_EP0OUT_IX)
+					dev->data_ep_queued = 0;
+			}
+
+		} else {
+			/* RX DMA must be reenabled for each desc in PPBDU mode */
+			if (use_dma_ppb_du) {
+				udc_set_rde(dev);
+			}
+		}
+
+	}
+#ifdef UDC_IPBUG_3958_WORKAROUND
+	/* check pending CNAKS */
+	if (cnak_pending) {
+		/* CNAk processing when rxfifo empty only */
+		if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+			udc_process_cnak_queue(dev);
+		}
+	}
+#endif
+
+	/* clear OUT bits in ep status */
+	writel(UDC_EPSTS_OUT_DATA_CLEAR, &ep->regs->sts);
+      finished:
+	return ret_val;
+}
+
+/**
+ * Interrupt handler for data IN traffic
+ *
+ * \param dev           pointer to UDC device object
+ * \param ep_ix         endpoint index
+ * \return 0 if success
+ */
+static inline int udc_data_in_isr(struct udc *dev, int ep_ix)
+{
+	int ret_val = 0;
+	u32 tmp;
+	struct udc_ep *ep;
+	struct udc_request *req;
+	struct udc_data_dma *td;
+	unsigned dma_done;
+	unsigned len;
+
+	ep = &dev->ep[ep_ix];
+
+	tmp = readl(&ep->regs->sts);
+	if (use_dma) {
+		/* BNA ? */
+		if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+			ERR("BNA ep%din occured - DESPTR = %08lx \n",
+			    ep->num, (unsigned long)readl(&ep->regs->desptr));
+
+			/* clear BNA */
+			writel(tmp, &ep->regs->sts);
+			/* TODO no early return */
+
+			return 1;
+		}
+	}
+	/* HE event ? */
+	if (tmp & AMD_BIT(UDC_EPSTS_HE)) {
+		ERR("HE ep%dn occured -  DESPTR = %08lx \n",
+		    ep->num, (unsigned long)readl(&ep->regs->desptr));
+
+		/* clear HE */
+		writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+		/* TODO no early return */
+		return 1;
+	}
+
+	tmp = readl(&ep->regs->sts);
+
+	/* DMA completion */
+	if (tmp & AMD_BIT(UDC_EPSTS_TDC)) {
+		VDBG("TDC set- completion\n");
+		if (!list_empty(&ep->queue)) {
+			req = list_entry(ep->queue.next,
+					 struct udc_request, queue);
+			if (req) {
+				/* lengh bytes transfered */
+				/* check dma done of last desc. in PPBDU mode */
+				if (use_dma_ppb_du) {
+					td = udc_get_last_dma_desc(req);
+					if (td) {
+						/* RTL bug (Bugzilla #3672): the TDC */
+						/* irq is quicker */
+						/* than the desc. update in memory */
+						/* TDC is set, but DMA is busy */
+						dma_done =
+						    AMD_GETBITS(td->status,
+								UDC_DMA_IN_STS_BS);
+						/* don't care DMA done as long the above mentioned RTL bug is */
+						/* present, TODO check dma_done if this is fixed */
+						//if (dma_done == UDC_DMA_IN_STS_BS_DMA_DONE) {
+						req->req.actual =
+						    req->req.length;
+						//}
+					}
+				} else {
+					/* assume all bytes transferred */
+					/* TODO check error status */
+					req->req.actual = req->req.length;
+				}
+
+				if (req->req.actual == req->req.length) {
+#ifdef UDC_IPBUG_2253_WORKAROUND
+					/* stop NAKing after small packet DMA */
+					if (ep->naking) {
+						/* clear NAK by writing CNAK */
+						tmp = readl(&ep->regs->ctl);
+						tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+						writel(tmp, &ep->regs->ctl);
+						ep->naking = 0;
+						UDC_QUEUE_CNAK(ep, ep->num);
+					}
+#endif
+					/* complete req */
+					complete_req(ep, req, 0);
+					req->dma_going = 0;
+#ifdef UDC_DISABLE_IRQ_IF_EMPTY_IN_QUEUE
+					/* further request available ? */
+					if (list_empty(&ep->queue)) {
+						/* disable interrupt */
+						tmp =
+						    readl(&dev->regs->
+							  ep_irqmsk);
+						tmp |= AMD_BIT(ep->num);
+						writel(tmp,
+						       &dev->regs->ep_irqmsk);
+					}
+#endif
+
+				}
+			}
+		}
+
+		/* clear TDC bit */
+		writel(AMD_BIT(UDC_EPSTS_TDC), &ep->regs->sts);
+
+	} /* status reg has IN bit set ? */
+	else if (tmp & AMD_BIT(UDC_EPSTS_IN)) {
+		if (!list_empty(&ep->queue)) {
+			/* next request */
+			req = list_entry(ep->queue.next,
+					 struct udc_request, queue);
+			/* FIFO mode ******* */
+			if (!use_dma) {
+				/* write fifo */
+				udc_txfifo_write(ep, &(req->req));
+				len = req->req.length - req->req.actual;
+				if (len > ep->ep.maxpacket)
+					len = ep->ep.maxpacket;
+				req->req.actual += len;
+				if (req->req.actual == req->req.length
+				    || (len != ep->ep.maxpacket)) {
+					//&& (!req->req.zero || len != ep->ep.maxpacket)) {
+					/* complete req */
+					complete_req(ep, req, 0);
+				}
+			} /* DMA **************** */
+			else if (req && !req->dma_going) {
+				VDBG("IN DMA : req=%lx req->td_data=%lx\n",
+				     (unsigned long)req,
+				     (unsigned long)req->td_data);
+				if (req->td_data) {
+
+					req->dma_going = 1;
+
+					/* unset L bit of first desc. for chain */
+					if (use_dma_ppb
+					    && req->req.length >
+					    ep->ep.maxpacket) {
+						req->td_data->status &=
+						    AMD_CLEAR_BIT
+						    (UDC_DMA_IN_STS_L);
+					}
+
+					/* write desc pointer */
+					writel(req->td_phys, &ep->regs->desptr);
+
+					wb_flush();
+					/* set HOST READY */
+					req->td_data->status
+					    = AMD_ADDBITS(req->td_data->status,
+							  UDC_DMA_IN_STS_BS_HOST_READY,
+							  UDC_DMA_IN_STS_BS);
+
+					wb_flush();
+
+#ifdef UDC_IPBUG_2253_WORKAROUND
+					/* NAK if small packet until TDC interrupt */
+					if (req->req.length < UDC_SMALL_PACKET) {
+						/* set NAK */
+						tmp = readl(&ep->regs->ctl);
+						tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+						writel(tmp, &ep->regs->ctl);
+						ep->naking = 1;
+						wb_flush();
+					}
+#endif
+					/* set poll demand bit */
+					tmp = readl(&ep->regs->ctl);
+					tmp |= AMD_BIT(UDC_EPCTL_P);
+					writel(tmp, &ep->regs->ctl);
+				}
+			}
+
+		}
+
+		/* clear IN bit */
+		writel(AMD_BIT(UDC_EPSTS_IN), &ep->regs->sts);
+	}
+
+	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;
+	u32 count;
+	int set = 0;
+	struct udc_ep *ep;
+	struct udc_ep *ep_tmp;
+
+	ep = &dev->ep[UDC_EP0OUT_IX];
+
+	/* clear irq */
+	writel(AMD_BIT(UDC_EPINT_OUT_EP0), &dev->regs->ep_irqsts);
+
+	tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+	/* check BNA and clear if set */
+	if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+		VDBG("BNA set\n");
+		writel(AMD_BIT(UDC_EPSTS_BNA),
+		       &dev->ep[UDC_EP0OUT_IX].regs->sts);
+	}
+
+	/* type of data: SETUP or DATA 0 bytes */
+	tmp = AMD_GETBITS(tmp, UDC_EPSTS_OUT);
+	VDBG("data_typ = %lx\n", (unsigned long)tmp);
+	/* setup data */
+	if (tmp == UDC_EPSTS_OUT_SETUP) {
+
+		ep->dev->stall_ep0in = 0;
+		dev->waiting_zlp_ack_ep0in = 0;
+
+		/* set NAK for EP0_IN */
+		tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+		tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+		writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+		dev->ep[UDC_EP0IN_IX].naking = 1;
+		/* get setup data */
+		if (use_dma) {
+
+			/* clear OUT bits in ep status */
+			writel(UDC_EPSTS_OUT_SETUP_CLEAR,
+			       &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+			setup_data.data[0] =
+			    dev->ep[UDC_EP0OUT_IX].td_stp->data12;
+			setup_data.data[1] =
+			    dev->ep[UDC_EP0OUT_IX].td_stp->data34;
+			/* set HOST READY */
+			writel(UDC_DMA_STP_STS_BS_HOST_READY,
+			       &dev->ep[UDC_EP0OUT_IX].td_stp->status);
+		} else {
+			/* read fifo */
+			udc_rxfifo_read_dwords(dev, setup_data.data, 2);
+		}
+
+		/* determine direction of control data */
+		if ((setup_data.request.bRequestType & USB_DIR_IN) != 0) {
+			dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+			/* enable RDE */
+			udc_ep0_set_rde(dev);
+			set = 0;
+		} else {
+			dev->gadget.ep0 = &dev->ep[UDC_EP0OUT_IX].ep;
+#ifdef UDC_USE_TIMER
+			set = 1;
+			dev->ep[UDC_EP0OUT_IX].naking = 1;
+			/* setup timer for enabling RDE (to not enable
+			   RXFIFO DMA for data to early) */
+			set_rde = 1;
+			if (!timer_pending(&udc_timer)) {
+				udc_timer.expires =
+				    jiffies + HZ / UDC_RDE_TIMER_DIV;
+				if (!stop_timer) {
+					add_timer(&udc_timer);
+				}
+			}
+#endif
+		}
+		/* mass storage reset must be processed here because
+		   next packet may be a CLEAR_FEATURE HALT which would not
+		   clear the stall bit when no STALL handshale was received before
+		   (autostall can cause this) */
+		if (setup_data.data[0] == UDC_MSCRES_DWORD0 &&
+		    setup_data.data[1] == UDC_MSCRES_DWORD1) {
+			DBG("MSC Reset\n");
+			/* clear stall bits */
+			/* TODO only one IN and OUT endpoints are handled */
+			ep_tmp = &udc->ep[UDC_EPIN_IX];
+			udc_set_halt(&ep_tmp->ep, 0);
+			ep_tmp = &udc->ep[UDC_EPOUT_IX];
+			udc_set_halt(&ep_tmp->ep, 0);
+		}
+
+		/* call gadget with setup data received */
+		spin_unlock(&dev->lock);
+		setup_supported = dev->driver->setup(&dev->gadget,
+						     &setup_data.request);
+		spin_lock(&dev->lock);
+
+		tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+		/* ep0 in returns data (not zlp) on IN phase */
+		if (setup_supported >= 0
+		    && setup_supported < UDC_EP0IN_MAXPACKET) {
+			/* clear NAK by writing CNAK in EP0_IN */
+			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+			dev->ep[UDC_EP0IN_IX].naking = 0;
+			UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+		} else if (setup_supported < 0) {
+			/* if unsupported request then stall */
+			tmp |= AMD_BIT(UDC_EPCTL_S);
+			writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+		} else
+			dev->waiting_zlp_ack_ep0in = 1;
+
+		/* clear NAK by writing CNAK in EP0_OUT */
+		if (!set) {
+			tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+			dev->ep[UDC_EP0OUT_IX].naking = 0;
+			UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+		}
+
+		if (!use_dma) {
+			/* clear OUT bits in ep status */
+			writel(UDC_EPSTS_OUT_SETUP_CLEAR,
+			       &dev->ep[UDC_EP0OUT_IX].regs->sts);
+		}
+
+	} /* data packet 0 bytes */
+	else if (tmp == UDC_EPSTS_OUT_DATA) {
+		/* clear OUT bits in ep status */
+		writel(UDC_EPSTS_OUT_DATA_CLEAR,
+		       &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+		/* get setup data: only 0 packet */
+		if (use_dma) {
+			/* no req if 0 packet, just reactivate */
+			if (list_empty(&dev->ep[UDC_EP0OUT_IX].queue)) {
+				VDBG("ZLP\n");
+
+				/* set HOST READY */
+				dev->ep[UDC_EP0OUT_IX].td->status =
+				    AMD_ADDBITS(dev->ep[UDC_EP0OUT_IX].td->
+						status,
+						UDC_DMA_OUT_STS_BS_HOST_READY,
+						UDC_DMA_OUT_STS_BS);
+				/* enable RDE */
+				udc_ep0_set_rde(dev);
+			} else {
+				/* control write */
+				udc_data_out_isr(dev, UDC_EP0OUT_IX);
+				/* re-program desc. pointer for possible ZLPs */
+				writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+				       &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+				/* enable RDE */
+				udc_ep0_set_rde(dev);
+			}
+		} else {
+
+			/* received number bytes */
+			count = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+			count = AMD_GETBITS(count, UDC_EPSTS_RX_PKT_SIZE);
+			/* FIXME disabled out data for fifo mode */
+			count = 0;
+
+			/* 0 packet or real data ? */
+			if (count != 0) {
+				udc_data_out_isr(dev, UDC_EP0OUT_IX);
+			} else {
+				/* dummy read confirm */
+				readl(&dev->ep[UDC_EP0OUT_IX].regs->confirm);
+			}
+		}
+	}
+#ifdef UDC_IPBUG_3958_WORKAROUND
+	/* check pending CNAKS */
+	if (cnak_pending) {
+		/* CNAk processing when rxfifo empty only */
+		if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+			udc_process_cnak_queue(dev);
+		}
+	}
+#endif
+
+	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;
+	unsigned len;
+
+	ep = &dev->ep[UDC_EP0IN_IX];
+
+	/* clear irq */
+	writel(AMD_BIT(UDC_EPINT_IN_EP0), &dev->regs->ep_irqsts);
+
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->sts);
+	/* DMA completion */
+	if (tmp & AMD_BIT(UDC_EPSTS_TDC)) {
+		VDBG("isr: TDC clear \n");
+#ifdef UDC_IPBUG_2253_WORKAROUND
+		/* stop NAKing after small packet DMA */
+		if (ep->naking) {
+			/* clear NAK by writing CNAK */
+			tmp = readl(&ep->regs->ctl);
+			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(tmp, &ep->regs->ctl);
+			ep->naking = 0;
+			UDC_QUEUE_CNAK(ep, ep->num);
+		}
+#endif
+		/* clear TDC bit */
+		writel(AMD_BIT(UDC_EPSTS_TDC),
+		       &dev->ep[UDC_EP0IN_IX].regs->sts);
+	} /* status reg has IN bit set ? */
+	else if (tmp & AMD_BIT(UDC_EPSTS_IN)) {
+		if (ep->dma) {
+			/* clear IN bit */
+			writel(AMD_BIT(UDC_EPSTS_IN),
+			       &dev->ep[UDC_EP0IN_IX].regs->sts);
+		}
+		if (dev->stall_ep0in) {
+			DBG("stall ep0in\n");
+			/* halt ep0in */
+			tmp = readl(&ep->regs->ctl);
+			tmp |= AMD_BIT(UDC_EPCTL_S);
+			writel(tmp, &ep->regs->ctl);
+		} else {
+			if (!list_empty(&ep->queue)) {
+				/* next request */
+				req = list_entry(ep->queue.next,
+						 struct udc_request, queue);
+
+				if (ep->dma) {
+					/* write desc pointer */
+					writel(req->td_phys, &ep->regs->desptr);
+					/* set HOST READY */
+					req->td_data->status
+					    = AMD_ADDBITS(req->td_data->status,
+							  UDC_DMA_STP_STS_BS_HOST_READY,
+							  UDC_DMA_STP_STS_BS);
+					wb_flush();
+
+#ifdef UDC_IPBUG_2253_WORKAROUND
+					/* NAK if small packet until TDC interrupt */
+					if (req->req.length < UDC_SMALL_PACKET) {
+						/* set NAK */
+						tmp = readl(&ep->regs->ctl);
+						tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+						writel(tmp, &ep->regs->ctl);
+						ep->naking = 1;
+						wb_flush();
+					}
+#endif
+					/* set poll demand bit */
+					tmp =
+					    readl(&dev->ep[UDC_EP0IN_IX].regs->
+						  ctl);
+					tmp |= AMD_BIT(UDC_EPCTL_P);
+					writel(tmp,
+					       &dev->ep[UDC_EP0IN_IX].regs->
+					       ctl);
+
+					/* all bytes will be transferred */
+					req->req.actual = req->req.length;
+
+					/* complete req */
+					complete_req(ep, req, 0);
+
+				} else {
+					/* write fifo */
+					udc_txfifo_write(ep, &(req->req));
+
+					/* lengh bytes transfered */
+					len = req->req.length - req->req.actual;
+					if (len > ep->ep.maxpacket)
+						len = ep->ep.maxpacket;
+
+					req->req.actual += len;
+					if (req->req.actual == req->req.length
+					    || (len != ep->ep.maxpacket)) {
+						//&& (!req->req.zero || len != ep->ep.maxpacket)) {
+						/* complete req */
+						complete_req(ep, req, 0);
+					}
+				}
+
+			}
+		}
+		ep->halted = 0;
+		dev->stall_ep0in = 0;
+		if (!ep->dma) {
+			/* clear IN bit */
+			writel(AMD_BIT(UDC_EPSTS_IN),
+			       &dev->ep[UDC_EP0IN_IX].regs->sts);
+		}
+	}
+
+	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;
+
+	/* SET_CONFIG irq ? */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_SC)) {
+
+		/* read config value */
+		tmp = readl(&dev->regs->sts);
+		cfg = AMD_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 */
+		/* TODO - put this to extra function or use udc_setup_endpoints() or udc_enable() */
+		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 = readl(&dev->csr->ne[udc_csr_epix]);
+			/* ep cfg */
+			tmp =
+			    AMD_ADDBITS(tmp, ep->dev->cur_config,
+					UDC_CSR_NE_CFG);
+			/* write reg */
+			writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+			/* clear stall bits */
+			ep->halted = 0;
+			tmp = readl(&ep->regs->ctl);
+			tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+			writel(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 & AMD_BIT(UDC_DEVINT_SI)) {
+		dev->set_cfg_not_acked = 1;
+		/* read interface and alt setting values */
+		tmp = readl(&dev->regs->sts);
+		dev->cur_alt = AMD_GETBITS(tmp, UDC_DEVSTS_ALT);
+		dev->cur_intf = AMD_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);
+
+		/* programm the NE registers */
+		/* TODO - put this to extra function or use udc_setup_endpoints() or udc_enable() */
+		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 = readl(&dev->csr->ne[udc_csr_epix]);
+			/* ep interface */
+			tmp =
+			    AMD_ADDBITS(tmp, ep->dev->cur_intf,
+					UDC_CSR_NE_INTF);
+			//tmp = AMD_ADDBITS(tmp, 2, UDC_CSR_NE_INTF);
+			/* ep alt */
+			tmp =
+			    AMD_ADDBITS(tmp, ep->dev->cur_alt, UDC_CSR_NE_ALT);
+			//tmp = AMD_ADDBITS(tmp, 1, UDC_CSR_NE_ALT);
+			/* write reg */
+			writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+			/* clear stall bits */
+			ep->halted = 0;
+			tmp = readl(&ep->regs->ctl);
+			tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+			writel(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 & AMD_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]);
+
+#ifdef UDC_IPBUG_3958_WORKAROUND_SOFT_RESET_ON_USBRESET
+		/* soft reset when rxfifo not empty */
+		tmp = readl(&dev->regs->sts);
+		if (!(tmp & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) &&
+		    !soft_reset_after_usbreset_occured) {
+			udc_soft_reset(dev);
+			soft_reset_after_usbreset_occured++;
+		}
+#endif
+
+		/* DMA reset to kill potential old DMA hw hang, */
+		/* POLL bit is already reset by ep_init() through */
+		/* disconnect() */
+		UDC_DMARST(tmp, dev);
+
+		/* put into initial config */
+		udc_basic_init(dev);
+
+#ifdef UDC_IPBUG_3958_WORKAROUND_RXFIFO_FLUSH_ON_USBRESET
+		/* TODO this workaround hang sometimes */
+		{
+			u32 reg;
+			u32 val;
+			/* TODO outsource this */
+			/* take care of PCSBUG#1503, empty rxfifo to allow CNAK */
+			/* disable DMA */
+			tmp = readl(&dev->regs->ctl);
+			writel(tmp & AMD_UNMASK_BIT(UDC_DEVCTL_MODE),
+			       &dev->regs->ctl);
+			/* empty rxfifo */
+			reg = readl(&dev->regs->sts);
+			while (!(reg & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))) {
+				DBG("RXFIFO not empty\n");
+				/* clear all OUT and BNA bits */
+				for (i = UDC_EPIN_NUM; i < UDC_EP_NUM; i++) {
+					ep = &dev->ep[i];
+					reg = readl(&ep->regs->sts);
+					/* BNA clear */
+					if (reg & AMD_BIT(UDC_EPSTS_BNA)) {
+						ERR("BNA ep%d occured - ep sts = %08lx \n", ep->num, (unsigned long)reg);
+						/* clear BNA */
+						writel(reg |
+						       AMD_BIT(UDC_EPSTS_BNA),
+						       &ep->regs->sts);
+					}
+					if (reg & AMD_BIT(UDC_EPSTS_OUT_DATA) ||
+					    reg & AMD_BIT(UDC_EPSTS_OUT_SETUP))
+					{
+						/* received number bytes */
+						val = readl(&ep->regs->sts);
+						val =
+						    AMD_GETBITS(val,
+								UDC_EPSTS_RX_PKT_SIZE);
+						/* read rx fifo bytes */
+						DBG("Clear ep%d rxfifo bytes count=%d\n", ep->num, val);
+						udc_rxfifo_read_bytes(dev,
+								      udc_rxfifo_trash,
+								      val);
+						/* clear OUT/SETUP bits in ep status */
+						writel(reg |
+						       UDC_EPSTS_OUT_SETUP_CLEAR
+						       |
+						       UDC_EPSTS_OUT_DATA_CLEAR,
+						       &ep->regs->sts);
+					}
+				}
+				reg = readl(&dev->regs->sts);
+			}
+			/* re-enable DMA if was active */
+			writel(tmp, &dev->regs->ctl);
+		}
+#endif
+
+		/* enable device setup interrupts */
+		udc_enable_dev_setup_interrupts(dev);
+
+	}			/* USB suspend */
+#ifndef UDC_IPBUG_3943_WORKAROUND
+	if (dev_irq & AMD_BIT(UDC_DEVINT_US)) {
+		DBG("USB Suspend interrupt\n");
+
+	}			/* new speed ? */
+#endif
+	if (dev_irq & AMD_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);
+	}
+#ifndef UDC_IPBUG_3950_WORKAROUND
+	/* session valid change interrupt */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_SVC)) {
+		DBG("USB SVC interrupt\n");
+
+		/* check that session is not valid to detect disconnect */
+		tmp = readl(&dev->regs->sts);
+		if (!(tmp & AMD_BIT(UDC_DEVSTS_SESSVLD))) {
+			DBG("USB Disconnect (session valid low)\n");
+			/* cleanup on disconnect */
+			usb_disconnect(udc);
+		}
+
+	}
+#endif
+
+	return ret_val;
+}
+
+/**
+ * Interrupt Service Routine, see Linux Kernel Doc for parameters
+ *
+ * \param irq           irq number
+ * \param pdev          pointer to device object
+ * \param ptregs        not specified
+ */
+static irqreturn_t udc_irq(int irq, void *pdev)
+{
+	struct udc *dev = pdev;
+	u32 reg;
+	u16 i;
+	u32 ep_irq;
+
+#ifdef UDC_IPBUG_3943_WORKAROUND
+	/* 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;
+#endif
+
+	if (dev->sys_suspended)
+		return IRQ_HANDLED;
+
+	spin_lock(&dev->lock);
+
+	/* check for ep irq */
+	reg = readl(&dev->regs->ep_irqsts);
+	if (reg) {
+		/* EP0 OUT */
+		if (reg & AMD_BIT(UDC_EPINT_OUT_EP0)) {
+			udc_control_out_isr(dev);
+		}		/* EP0 IN */
+		if (reg & AMD_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 */
+				writel(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 */
+				writel(ep_irq, &dev->regs->ep_irqsts);
+				udc_data_in_isr(dev, i);
+			}
+
+		}
+
+	}
+
+	/* check for dev irq */
+	reg = readl(&dev->regs->irqsts);
+	if (reg) {
+		/* clear irq */
+		writel(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
+ */
+#if     LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+static void gadget_release(struct device *pdev)
+{
+	struct amd5536udc *dev = dev_get_drvdata(pdev);
+	kfree(dev);
+}
+#endif
+
+/**
+ * Reset all pci context
+ *
+ * \param pdev        pointer to pci device struct
+ */
+static void udc_remove(struct pci_dev *pdev)
+{
+	struct udc *dev;
+
+#ifdef UDC_DEBUG
+	/* debug */
+	print_misc(udc);
+#endif
+	dev = pci_get_drvdata(pdev);
+	/* gadget driver registered ? */
+	if (dev->driver) {
+		WARN("unregistering %s on pci 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) {
+		pci_pool_destroy(dev->data_requests);
+	}
+	if (dev->stp_requests) {
+		/* cleanup DMA desc's for ep0in */
+		pci_pool_free(dev->stp_requests,
+			      dev->ep[UDC_EP0OUT_IX].td_stp,
+			      dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+		pci_pool_free(dev->stp_requests,
+			      dev->ep[UDC_EP0OUT_IX].td,
+			      dev->ep[UDC_EP0OUT_IX].td_phys);
+
+		pci_pool_destroy(dev->stp_requests);
+	}
+
+	/* init controller by soft reset */
+	writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+	if (dev->irq_registered)
+		free_irq(pdev->irq, dev);
+	if (dev->regs)
+		iounmap(dev->regs);
+	if (dev->mem_region)
+		release_mem_region(pci_resource_start(pdev, 0),
+				   pci_resource_len(pdev, 0));
+#ifndef CONFIG_USB_NON_PCI_OTGDEVICE
+	if (dev->active)
+		pci_disable_device(pdev);
+#endif
+
+#if     LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+#ifndef CONFIG_MIPS
+	/* FIXME TMP26: temporary disabled device file system usage until
+	 * working for Au1200 */
+	device_unregister (&dev->gadget.dev);
+	//device_remove_file (&pdev->dev, &dev_attr_registers);
+#endif
+#endif
+	pci_set_drvdata(pdev, 0);
+
+#ifdef CONFIG_USB_NON_PCI_OTGDEVICE
+	{
+		u32 tmp;
+		/* disable UDC memory, DMA and clock */
+		tmp = readl((u32 *) (USB_MSR_BASE + USB_MSR_MCFG));
+		tmp &= AMD_CLEAR_BIT(USBMSRMCFG_DMEMEN)
+		    & AMD_CLEAR_BIT(USBMSRMCFG_DBMEN)
+		    & AMD_CLEAR_BIT(USBMSRMCFG_UDCCLKEN);
+		writel(tmp, USB_MSR_BASE + USB_MSR_MCFG);
+	}
+#endif
+
+#if     LINUX_VERSION_CODE < UDC_NEW_GADGET_KERNEL || defined(CONFIG_MIPS)
+	/* done by gadget.dev.release() in kernel 2.6.x
+	 * TMP26: device registration currently disabled for Au1200 */
+	kfree(dev);
+#endif
+#ifdef UDC_USE_TIMER
+	/* remove timer */
+	stop_timer++;
+	if (timer_pending(&udc_timer))
+		wait_for_completion(&on_exit);
+	if (udc_timer.data)
+		del_timer_sync(&udc_timer);
+	/* remove pollstall timer */
+	stop_pollstall_timer++;
+	if (timer_pending(&udc_pollstall_timer))
+		wait_for_completion(&on_pollstall_exit);
+	if (udc_pollstall_timer.data)
+		del_timer_sync(&udc_pollstall_timer);
+#endif
+	udc = 0;
+}
+
+/**
+ * Called by pci bus driver to init pci context
+ *
+ * \param pdev        pointer to pci device struct
+ * \param id          pointer to pci device id
+ * \return 0 if success
+ */
+static int udc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct udc *dev;
+	char tmp[8];
+	char *tmpstr;
+	unsigned long resource;
+	unsigned long len;
+	void *start_addr = 0;
+	struct udc_stp_dma *td_stp;
+	struct udc_data_dma *td_data;
+	u32 reg;
+	int retval;
+
+	VDBG("udc_probe()\n");
+
+#ifdef CONFIG_USB_NON_PCI_OTGDEVICE
+	{
+		u32 tmp;
+		/*
+		 * Fill in the dummy pci_dev
+		 */
+		memset(pdev, 0, sizeof(struct pci_dev));
+#if     LINUX_VERSION_CODE < UDC_NEW_GADGET_KERNEL
+		strcpy(pdev->name, "non-PCI UDC");
+#endif
+		pdev->resource[0].name = "UDC Registers";
+		pdev->resource[0].start = USB_UDC_BASE;
+		pdev->resource[0].end = USB_UDC_BASE + USB_UDC_LEN - 1;
+		pdev->resource[0].flags = 0;
+		pdev->irq = AU1200_USB_INT;
+
+		tmp = readl((u32 *) (USB_MSR_BASE + USB_MSR_MCFG));
+		if (tmp == 0) {
+			/* default value */
+			tmp = USBMSRMCFG_DEFAULT;
+			writel(tmp, USB_MSR_BASE + USB_MSR_MCFG);
+			readl((u32 *) USB_MSR_BASE + USB_MSR_MCFG);
+			udelay(1000);
+		}
+		/* enable UDC memory, DMA, clock, cacheable memory,
+		 * read combining and prefetch enable */
+		tmp |= AMD_BIT(USBMSRMCFG_DMEMEN) | AMD_BIT(USBMSRMCFG_DBMEN)
+		    | AMD_BIT(USBMSRMCFG_UDCCLKEN)
+		    | AMD_BIT(USBMSRMCFG_PHYPLLEN)
+#ifdef CONFIG_DMA_COHERENT
+		    | AMD_BIT(USBMSRMCFG_UCAM)
+#endif
+		    | AMD_BIT(USBMSRMCFG_RDCOMB)
+		    | AMD_BIT(USBMSRMCFG_PFEN);
+		writel(tmp, USB_MSR_BASE + USB_MSR_MCFG);
+	}
+#endif
+	/* one udc only */
+	if (udc) {
+		WARN("already probed: %04x/%04x\n", UDC_PCI_VENID,
+		     UDC_PCI_DEVID);
+		return -EBUSY;
+	}
+
+	/* init */
+	dev = kmalloc(sizeof(struct udc), GFP_KERNEL);
+	if (!dev) {
+		retval = -ENOMEM;
+		goto finished;
+	}
+
+	/* mark timer as not initialized */
+	udc_timer.data = 0;
+	udc_pollstall_timer.data = 0;
+
+	/* device struct setup */
+	memset(dev, 0, sizeof(struct udc));
+	spin_lock_init(&dev->lock);
+	spin_lock_init(&udc_irq_spinlock);
+	spin_lock_init(&udc_stall_spinlock);
+	dev->pdev = pdev;
+	dev->gadget.ops = &udc_ops;
+
+#if     LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+	strcpy(dev->gadget.dev.bus_id, "gadget");
+	dev->gadget.dev.parent = &pdev->dev;
+	dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+	dev->gadget.dev.release = gadget_release;
+	dev->gadget.name = name;
+#else
+	dev->gadget.dev.bus_id = "gadget";
+#endif
+	dev->gadget.name = name;
+	dev->gadget.is_dualspeed = 1;
+
+	/* pci setup */
+#ifndef CONFIG_USB_NON_PCI_OTGDEVICE
+	if (pci_enable_device(pdev) < 0) {
+		retval = -ENODEV;
+		goto finished;
+	}
+#endif
+	dev->active = 1;
+
+	resource = pci_resource_start(pdev, 0);
+	len = pci_resource_len(pdev, 0);
+
+	if (!request_mem_region(resource, len, name)) {
+		DBG("pci device used already\n");
+		retval = -EBUSY;
+		goto finished;
+	}
+	dev->mem_region = 1;
+
+	start_addr = ioremap_nocache(resource, len);
+	if (start_addr == NULL) {
+		DBG("start address cannot be mapped\n");
+		retval = -EFAULT;
+		goto finished;
+	}
+
+	/* udc csr registers base */
+	dev->csr = (struct udc_csrs *)(start_addr + UDC_CSR_ADDR);
+	/* dev registers base */
+	dev->regs = (struct udc_regs *)(start_addr + UDC_DEVCFG_ADDR);
+	/* ep registers base */
+	dev->ep_regs = (struct udc_ep_regs *)(start_addr + UDC_EPREGS_ADDR);
+	/* fifo's base */
+	dev->rxfifo = (u32 *) (start_addr + UDC_RXFIFO_ADDR);
+	dev->txfifo = (u32 *) (start_addr + UDC_TXFIFO_ADDR);
+
+	/* init registers, interrupts, ... */
+#ifndef UDC_IPBUG_3943_WORKAROUND
+	startup_registers(dev);
+#else
+	{
+		u32 tmp;
+
+		/* TODO put this to extra function,
+		 * this all is extracted from usb_init() and
+		 * udc_basic_init() but without register access */
+		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;
+			}
+			if (use_dma) {
+				/* TODO ep->dma is not really used, just to indicate that */
+				/* DMA is active: remove this */
+				/* dma regs = dev control regs */
+				ep->dma = (u32 *) & dev->regs->ctl;
+			}
+		}
+		dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
+		dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
+	}
+#endif
+
+	if (!pdev->irq) {
+		ERR("pdev->irq not set\n");
+		retval = -ENODEV;
+		goto finished;
+	}
+
+	snprintf(tmp, sizeof tmp, "%d", pdev->irq);
+	tmpstr = tmp;
+
+	if (request_irq(pdev->irq, udc_irq, SA_SHIRQ, name, dev) != 0) {
+		ERR("error on request_irq() with %s\n", tmpstr);
+		retval = -EBUSY;
+		goto finished;
+	}
+	dev->irq_registered = 1;
+
+	if (use_dma) {
+		/* 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 */
+#if     LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+		dev->data_requests = pci_pool_create("data_requests", pdev,
+						     sizeof(struct
+							    udc_data_dma),
+						     UDC_PCIPOOL_ALIGN,
+						     UDC_PCIPOOL_CROSS);
+#else
+		dev->data_requests = pci_pool_create("data_requests", pdev,
+						     sizeof(struct
+							    udc_data_dma),
+						     UDC_PCIPOOL_ALIGN,
+						     UDC_PCIPOOL_CROSS,
+						     GFP_KERNEL /* 2.4 only */
+						     );
+#endif
+		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 */
+#if     LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+		dev->stp_requests = pci_pool_create("setup requests", pdev,
+						    sizeof(struct udc_stp_dma),
+						    UDC_PCIPOOL_ALIGN,
+						    UDC_PCIPOOL_CROSS);
+#else
+		dev->stp_requests = pci_pool_create("setup requests", pdev,
+						    sizeof(struct udc_stp_dma),
+						    UDC_PCIPOOL_ALIGN,
+						    UDC_PCIPOOL_CROSS,
+						    GFP_KERNEL /* 2.4 only */
+						    );
+#endif
+		if (!dev->stp_requests) {
+			DBG("can't get stp request pool\n");
+			retval = -ENOMEM;
+			goto finished;
+		}
+		/* setup */
+		td_stp = pci_pool_alloc(dev->stp_requests, UDC_PCIPOOL_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 = pci_pool_alloc(dev->stp_requests, UDC_PCIPOOL_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;
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+		/* point to itself */
+		dev->ep[UDC_EP0OUT_IX].td->next =
+		    dev->ep[UDC_EP0OUT_IX].td_phys;
+#endif
+	}
+
+	dev->chiprev = 0;
+
+#ifndef CONFIG_USB_NON_PCI_OTGDEVICE
+	pci_set_master(pdev);
+#ifdef  HAVE_PCI_SET_MWI
+	pci_set_mwi(pdev);
+#endif
+	/* chip rev for Hs AMD5536 */
+	pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) & dev->chiprev);
+#else
+	/* chip rev for Au1200 */
+	dev->chiprev = (u16) read_c0_prid() & 0xff;
+#endif
+
+	pci_set_drvdata(pdev, dev);
+
+	INFO("%s\n", mod_desc);
+
+	/* TODO make defines for rev. strings */
+#ifdef CONFIG_SOC_AU1200
+	INFO("irq %s, mem %08lx, chip rev %02x (Au1200 %s)\n",
+	     tmpstr, resource, dev->chiprev, (dev->chiprev == 0) ? "AB" : "AC");
+	tmpstr = UDC_DRIVER_VERSION_STRING;
+#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 UDC_AUA1
+	if (dev->chiprev < UDC_AUA1) {
+		ERR("Your chip revision is %s, it must be at least %s\n",
+		    "AB", "AC");
+		retval = -ENODEV;
+		goto finished;
+	}
+	INFO("driver version: %s (for Au1200 AC)\n", tmpstr);
+#else
+	INFO("driver version: %s (for Au1200 AB)\n", tmpstr);
+#endif
+#ifdef CONFIG_DMA_COHERENT
+	INFO("Compiled for coherent memory.\n");
+#endif
+#ifdef CONFIG_DMA_NONCOHERENT
+	INFO("Compiled for non-coherent memory.\n");
+#endif
+#else
+	INFO("irq %s, pci mem %08lx, chip rev %02x (Geode5536 %s)\n",
+	     tmpstr, resource, dev->chiprev,
+	     (dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1");
+	tmpstr = UDC_DRIVER_VERSION_STRING;
+#ifdef UDC_HSB1
+	if (dev->chiprev == UDC_HSA0_REV) {
+		ERR("Your chip revision is %s, it must be at least %s\n",
+		    "A0", "B1");
+		retval = -ENODEV;
+		goto finished;
+	}
+	INFO("driver version: %s (for Geode5536 B1)\n", tmpstr);
+#else
+	INFO("driver version: %s (for Geode5536 A0)\n", tmpstr);
+#endif
+#endif
+	udc = dev;
+
+#if     LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+#ifndef CONFIG_MIPS
+	/* FIXME TMP26: temporary disabled device file system usage until
+	 * working for Au1200 */
+	device_register (&dev->gadget.dev);
+	//device_create_file (&pdev->dev, &dev_attr_registers);
+#endif
+#endif
+
+#ifdef UDC_USE_TIMER
+	/* timer init */
+	init_timer(&udc_timer);
+	udc_timer.function = udc_timer_function;
+	udc_timer.data = 1;
+	/* timer pollstall init */
+	init_timer(&udc_pollstall_timer);
+	udc_pollstall_timer.function = udc_pollstall_timer_function;
+	udc_pollstall_timer.data = 1;
+#endif
+
+	/* set SD */
+	reg = readl(&dev->regs->ctl);
+	reg |= AMD_BIT(UDC_DEVCTL_SD);
+	writel(reg, &dev->regs->ctl);
+
+	/* print dev register info */
+	print_regs(dev);
+
+	return 0;
+
+      finished:
+	if (dev)
+		udc_remove(pdev);
+	return retval;
+}
+
+/**
+ *  Initiates a remote wakeup
+ *
+ * \return 0 if success
+ */
+/* initiate remote wakeup */
+static int udc_remote_wakeup(struct udc *dev)
+{
+	u32 tmp;
+
+	INFO("UDC initiates remote wakeup\n");
+
+	tmp = readl(&dev->regs->ctl);
+	tmp |= AMD_BIT(UDC_DEVCTL_RES);
+	writel(tmp, &dev->regs->ctl);
+	/* wait 1ms before clear resume bit */
+	// udelay(1000);
+	tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES);
+	writel(tmp, &dev->regs->ctl);
+
+	return 0;
+}
+
+/* PM currently under debug */
+#ifdef UDC_DEBUG
+/**
+ *  Suspends UDC
+ *
+ * \return 0 if success
+ */
+static int udc_suspend(struct udc *dev)
+{
+	int retval = 0;
+
+	INFO("UDC suspend\n");
+#ifdef CONFIG_MIPS
+	u32 tmp;
+	/* 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 = readl((u32 *) (USB_MSR_BASE + USB_MSR_MCFG));
+	tmp &= AMD_CLEAR_BIT(USBMSRMCFG_UDCCLKEN);
+	writel(tmp, USB_MSR_BASE + USB_MSR_MCFG);
+
+#endif
+
+	return retval;
+}
+
+/**
+ *  Resumes UDC
+ *
+ * \return 0 if success
+ */
+static int udc_resume(struct udc *dev)
+{
+	int retval = 0;
+
+	INFO("UDC resume\n");
+#ifdef CONFIG_MIPS
+	u32 tmp;
+	/* switch on UDC clock */
+	tmp = readl((u32 *) (USB_MSR_BASE + USB_MSR_MCFG));
+	tmp |= AMD_BIT(USBMSRMCFG_UDCCLKEN);
+	writel(tmp, 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);
+	}
+#endif
+
+	return retval;
+}
+#endif
+
+#ifdef UDC_USE_DRIVER_REGISTER
+/* TODO we provide device_driver functions to attach
+ * to device system which allows power management and
+ * more. Currently we just call the PCI probe function.
+ * So later pci_dev dummy is to be removed */
+
+static int udc_au1xxx_drv_probe(struct device *dev)
+{
+	int retval;
+
+	DBG("udc_au1xxx_drv_probe()\n");
+	retval = udc_probe(pdev, pci_id);
+	if (retval == 0)
+		dev_set_drvdata(dev, (struct udc *)pci_get_drvdata(pdev));
+	return retval;
+}
+
+static int udc_au1xxx_drv_remove(struct device *dev)
+{
+	DBG("udc_au1xxx_drv_remove()\n");
+	udc_remove(pdev);
+	dev_set_drvdata(dev, NULL);
+	return 0;
+}
+
+static int udc_au1xxx_drv_suspend(struct device *dev, u32 state, u32 level)
+{
+	struct udc *udc_dev = dev_get_drvdata(dev);
+	return udc_suspend(udc_dev);
+}
+
+static int udc_au1xxx_drv_resume(struct device *dev, u32 level)
+{
+	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,
+};
+#endif
+
+/**
+ * Inits driver
+ *
+ * \return 0 if success
+ */
+static int __init init(void)
+{
+	int rc;
+
+#ifdef UDC_DEBUG
+	/* register char device */
+	rc = register_chrdev(UDC_MAJOR_NUM, UDC_DEVICE_NAME, &udc_fops);
+	if (rc < 0) {
+		printk("Error registering udc char device");
+	}
+#endif
+
+#ifdef CONFIG_USB_NON_PCI_OTGDEVICE
+#if   LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL && defined(UDC_USE_DRIVER_REGISTER)
+
+	/* probe by device system */
+	rc = driver_register(&udc_au1xxx_driver);
+#else
+	/* manual probe */
+	rc = udc_probe(pdev, pci_id);
+#endif
+#else
+	/* probe by PCI bus driver */
+	rc = pci_module_init(&udc_pci_driver);
+#endif
+	if( rc == 0 && udc == NULL )
+	{
+		pci_unregister_driver(&udc_pci_driver);
+		rc = -ENODEV;
+	}
+
+	return rc;
+}
+
+module_init(init);
+
+/**
+ * Cleans driver
+ */
+static void __exit cleanup(void)
+{
+#ifdef UDC_DEBUG
+	/* unregister char device */
+	unregister_chrdev(UDC_MAJOR_NUM, UDC_DEVICE_NAME);
+#endif
+
+#ifdef CONFIG_USB_NON_PCI_OTGDEVICE
+#if   LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL && defined(UDC_USE_DRIVER_REGISTER)
+	/* unregister at device system */
+	driver_unregister(&udc_au1xxx_driver);
+#else
+	/* manual remove */
+	udc_remove(pdev);
+#endif
+#else
+	/* unregister at PCI bus driver */
+	pci_unregister_driver(&udc_pci_driver);
+#endif
+
+}
+
+module_exit(cleanup);
diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h
new file mode 100644
index 0000000..1b9d319
--- /dev/null
+++ b/drivers/usb/gadget/amd5536udc.h
@@ -0,0 +1,972 @@
+/*
+ * Header for driver for AMD 5536 UDC high/full speed USB device controller
+ */
+
+/*
+ * Copyright (C) 2005 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * 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 AMD5536UDC_H
+#define AMD5536UDC_H
+
+/*****************************************************************************
+*  Constants
+*****************************************************************************/
+
+/* Driver  constants -------------------------------------------------------*/
+#define DRIVER_NAME_FOR_PRINT "amd5536udc"
+
+/* PCI constants -----------------------------------------------------------*/
+#define UDC_PCI_VENID 0x1022
+#define UDC_PCI_DEVID 0x2096
+#define UDC_PCI_CLASS ((PCI_CLASS_SERIAL_USB << 8) | 0xfe)
+#define UDC_PCI_CLASS_MASK 0xffffffff
+
+/* Platform specific -------------------------------------------------------*/
+#if defined(CONFIG_MIPS)
+#define UDC_PCIPOOL_ALIGN       32
+#define UDC_PCIPOOL_CROSS       4096
+#define UDC_PCIPOOL_GFP_STP     (GFP_ATOMIC | GFP_DMA)
+#else
+#define UDC_PCIPOOL_ALIGN       0
+#define UDC_PCIPOOL_CROSS       0
+#define UDC_PCIPOOL_GFP_STP     (GFP_KERNEL)
+#endif
+
+/* temp define for AU1200, will live in au1000.h normally */
+#ifndef USB_UDC_BASE
+#define USB_UDC_BASE              0x14022000
+#define USB_UDC_LEN               0x2000
+#define USB_MSR_BASE              0xB4020000
+#define USB_MSR_MCFG              4
+#define USBMSRMCFG_DMEMEN         4
+#define USBMSRMCFG_DBMEN          5
+#define USBMSRMCFG_UDCCLKEN       18
+#define USBMSRMCFG_PHYPLLEN       19
+#define AU1200_USB_INT            29
+#endif
+#ifndef USBMSRMCFG_UCAM
+#define USBMSRMCFG_UCAM           7
+#endif
+#define USBMSRMCFG_DEFAULT        0x00d02000
+
+/* other constants */
+#define UDC_RDE_TIMER_SECONDS                   1
+#define UDC_RDE_TIMER_DIV                       10
+#define UDC_POLLSTALL_TIMER_USECONDS            500
+
+/* Special optimization for certain gadgets ------------------------------- */
+/* use hardware NAK if IN queue empty, this can be used to
+* avoid interrupt flood as for the ethernet gadget where host side
+* sends IN tokens permamently */
+#define UDC_DISABLE_IRQ_IF_EMPTY_IN_QUEUE
+/*#undef UDC_DISABLE_IRQ_IF_EMPTY_IN_QUEUE*/
+
+/* IP core defect/bug/case workarounds ---------------------------------------- */
+/* Hs AMD5536 A0 workarounds */
+/* Description: "Last descriptor loop */
+#define UDC_IPDEFECT_9000004946_WORKAROUND
+/* Description: "DMA machine not restartable" */
+#define UDC_IPCASE_8000018724_WORKAROUND
+/* Description: "UDC not accessible when phy is suspended */
+#define UDC_IPBUG_3943_WORKAROUND
+/* Description: "USB device needs session-valid status information */
+#define UDC_IPBUG_3950_WORKAROUND
+/* Description: "Clearing endpoint NAK bits not possible if RxFIFO
+   not empty (PCS#1503) */
+#define UDC_IPBUG_3958_WORKAROUND
+#ifdef UDC_IPBUG_3958_WORKAROUND
+/* option 1: flush rxfifo on USB reset */
+#undef UDC_IPBUG_3958_WORKAROUND_RXFIFO_FLUSH_ON_USBRESET
+/* option 2: soft reset on USB reset */
+#ifndef UDC_IPBUG_3958_WORKAROUND_RXFIFO_FLUSH_ON_USBRESET
+#define UDC_IPBUG_3958_WORKAROUND_SOFT_RESET_ON_USBRESET
+#endif
+#endif
+/* UDC data errors during loop test (DMA)
+   - found only with Au1200 but used for Hs too, bug entry
+     is in Au1200 bugzilla
+   - the workaround applies only for small packets */
+#define UDC_IPBUG_2253_WORKAROUND
+#define UDC_SMALL_PACKET        32
+
+/* Disable workarounds which don't apply to Hs AMD5536 B1/ Au1200 A1 */
+/* And enable new features */
+
+/* Hs AMD5536 A0 flag */
+/* #define UDC_HSA0 */
+/* Hs AMD5536 B1 flag */
+#define UDC_HSB1
+
+/* Hs AMD5536 chip rev. */
+#define UDC_HSA0_REV 1
+#define UDC_HSB1_REV 2
+
+/* consistency */
+#ifdef UDC_HSB1
+#undef UDC_HSA0
+#endif
+
+/* Au1200 rev. */
+#if defined(CONFIG_MIPS)
+#undef UDC_HSB1
+#undef UDC_HSA0
+/* revision value */
+#define UDC_AUAB_REV 0
+#define UDC_AUAC_REV 1
+#define UDC_AUA0 0
+/* Au1200 AC flag */
+//#define UDC_AUA1 1
+#endif
+
+/* disable workarounds for newer chip revisions */
+#ifdef UDC_HSB1
+#undef UDC_IPBUG_3943_WORKAROUND
+#undef UDC_IPBUG_3950_WORKAROUND
+#define UDC_DMARST_AVAIL
+#endif
+#ifdef UDC_AUA1
+#undef UDC_IPBUG_3943_WORKAROUND
+#endif
+
+/* SETUP usb commands
+*  needed, because some SETUP's are handled in hw, but must be passed to
+*  gadget driver above -----------------------------------------------------*/
+/* SET_CONFIG */
+#define UDC_SETCONFIG_DWORD0                    0x00000900
+#define UDC_SETCONFIG_DWORD0_VALUE_MASK         0xffff0000
+#define UDC_SETCONFIG_DWORD0_VALUE_OFS          16
+
+#define UDC_SETCONFIG_DWORD1                    0x00000000
+
+/* SET_INTERFACE */
+#define UDC_SETINTF_DWORD0                      0x00000b00
+#define UDC_SETINTF_DWORD0_ALT_MASK             0xffff0000
+#define UDC_SETINTF_DWORD0_ALT_OFS              16
+
+#define UDC_SETINTF_DWORD1                      0x00000000
+#define UDC_SETINTF_DWORD1_INTF_MASK            0x0000ffff
+#define UDC_SETINTF_DWORD1_INTF_OFS             0
+
+/* Mass storage reset */
+#define UDC_MSCRES_DWORD0                       0x0000ff21
+#define UDC_MSCRES_DWORD1                       0x00000000
+
+/* 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_SVC                          7
+#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                          0x7f
+
+/* 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               0xffffffff
+/* 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
+
+/* 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 => TODO replace follwing constant */
+#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
+//DISABLEDamd #define UDC_EP0_MAXPKT                          64
+/* max packet fullspeed */
+//DISABLEDamd #define UDC_FS_EP0_MAXPKT                       8
+
+/* 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
+
+#ifndef        IRQ_NONE
+typedef void irqreturn_t;
+#define IRQ_HANDLED
+#define IRQ_NONE
+#define IRQ_RETVAL(a)
+#endif
+#endif
+
+/* MIPS specific -----------------------------------------------------------*/
+#if defined(CONFIG_MIPS)
+/* sync does it without refilling the pipe,
+   so read after write can bypass write */
+#define au1200_sync_delay() {\
+  asm(".set noreorder"); \
+  asm("b l1");\
+  asm("l1:");\
+  asm("sync");\
+  asm("nop");\
+  asm("nop");\
+  asm("nop");\
+  asm("nop");\
+  asm("b l2");\
+  asm("l2:");\
+  asm("nop");\
+  asm("nop");\
+  asm(".set reorder");\
+}
+
+//DISABLEDamd #define wb_flush() au1200_sync()
+#define wb_flush() __asm__ volatile ("sync")
+
+/* special write functions for MIPS (with write buffer flush) */
+#undef writel
+#undef writeb
+#if     LINUX_VERSION_CODE < UDC_NEW_GADGET_KERNEL
+#define writel(d,a) {((*(volatile unsigned int *)(a))=(__ioswab32(d)));wb_flush();}
+#else
+#define writel(d,a) {((*(volatile unsigned int *)(a))=(d));wb_flush();}
+#endif
+#define writeb(d,a) {((*(volatile unsigned char *)(a))=(d));wb_flush();}
+
+/* dma pool alloc wrapper */
+#if   LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+#undef	pci_pool
+#undef  pci_pool_create
+#undef	pci_pool_destroy
+#undef	pci_pool_alloc
+#undef	pci_pool_free
+#define	pci_pool dma_pool
+/* FIXME TMP26: use "struct device*" if device file system works */
+/* #define pci_pool_create(name, pdev, size, align, allocation) \
+	dma_pool_create(name, &pdev->dev, size, align, allocation) */
+#define pci_pool_create(name, pdev, size, align, allocation) \
+		dma_pool_create(name, NULL, size, align, allocation)
+#define	pci_pool_destroy(pool) dma_pool_destroy(pool)
+#define	pci_pool_alloc(pool, flags, handle) dma_pool_alloc(pool, flags, handle)
+#define	pci_pool_free(pool, vaddr, addr) dma_pool_free(pool, vaddr, addr)
+#endif
+#else
+#define wb_flush() {}
+#endif
+
+/*****************************************************************************
+* Includes
+*****************************************************************************/
+
+#if !defined(UDC_HSB1)
+#include "amd5536otg.h"
+#endif
+
+/*****************************************************************************
+*  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_mapping:1, dma_done:1;
+	/* phys. address */
+	dma_addr_t td_phys;
+	/* first dma desc. of chain */
+	struct udc_data_dma *td_data;
+	/* last dma desc. of chain */
+	struct udc_data_dma *td_data_last;
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+	/* next pointer of broken chain */
+	dma_addr_t td_data_last_next;
+#endif
+
+	struct list_head queue;
+
+	/* chain length */
+	unsigned chain_len;
+
+};
+
+/* 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 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;
+#if !defined(UDC_HSB1)
+	struct usb_otg_gadget_extension *otg_driver;
+#endif
+	/* operational flags */
+	unsigned active:1,
+	    stall_ep0in: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 pci_dev *pdev;
+	struct udc_csrs *csr;
+	struct udc_regs *regs;
+	struct udc_ep_regs *ep_regs;
+	u32 *rxfifo;
+	u32 *txfifo;
+
+	/* DMA desc pools */
+	struct pci_pool *data_requests;
+	struct pci_pool *stp_requests;
+
+	/* 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 AMD_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 AMD_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 AMD_GETBITS(u32Val, bitfield_stub_name)\
+        ((u32Val & ((u32) bitfield_stub_name##_MASK))\
+        >> ((u32) bitfield_stub_name##_OFS))
+
+/* SET and GET bits in u32 values ------------------------------------------*/
+#define AMD_BIT(bit_stub_name) (1 << bit_stub_name)
+#define AMD_UNMASK_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+#define AMD_CLEAR_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+
+/* misc --------------------------------------------------------------------*/
+#define        DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
+
+/* UDC specific macros -----------------------------------------------------*/
+#ifdef UDC_DMARST_AVAIL
+#define UDC_DMARST(tmp, dev) \
+        DBG("DMA machine reset\n"); \
+        tmp = readl(&dev->regs->cfg); \
+        writel(tmp | AMD_BIT(UDC_DEVCFG_DMARST), &dev->regs->cfg); \
+        writel(tmp, &dev->regs->cfg);
+#else
+#define UDC_DMARST(tmp, dev) {}
+#endif
+
+/* print macros ------------------------------------------------------------*/
+
+#ifdef UDC_VERBOSE
+#ifndef UDC_DEBUG
+#define UDC_DEBUG
+#endif
+#endif
+
+/* Driver name for printing messages, this should be defined by driver */
+#ifndef DRIVER_NAME_FOR_PRINT
+//#define DRIVER_NAME_FOR_PRINT "amd5536"
+#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
+ */
+#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  AMD5536UDC_H */
diff --git a/drivers/usb/gadget/amd5536uoc.c b/drivers/usb/gadget/amd5536uoc.c
new file mode 100644
index 0000000..52042d8
--- /dev/null
+++ b/drivers/usb/gadget/amd5536uoc.c
@@ -0,0 +1,456 @@
+/*
+ * AMD 5536 USB UOC controller driver
+ */
+
+/*
+ * Copyright (C) 2005 AMD (http://www.amd.com)
+ * Author: Karsten Boge
+ *
+ * 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
+ */
+
+/*****************************************************************************
+ * Defines
+ *****************************************************************************/
+
+/* #define DEBUG */
+/* #define VERBOSE */
+
+#define	DRIVER_DESC		"AMD 5536 USB UOC Controller"
+#define	DRIVER_VERSION		"01.00.0204 - $Revision: #8 $"
+#define DRIVER_NAME_FOR_PRINT   UOC_DRIVER_NAME
+
+/*****************************************************************************
+ *  Includes
+ *****************************************************************************/
+
+#include <linux/autoconf.h>
+#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 <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+#include <linux/usb.h>
+#include <linux/usb_gadget.h>
+#include <linux/usb/otg.h>
+
+#include "amd5536uoc.h"
+
+/*****************************************************************************
+ *  Function Declarations
+ *****************************************************************************/
+
+static int uoc5536_set_peripheral(struct otg_transceiver *,
+				  struct usb_gadget *);
+
+/*****************************************************************************
+ *  Data
+ *****************************************************************************/
+
+static const char driver_name[] = UOC_DRIVER_NAME;
+static const char driver_desc[] = DRIVER_DESC;
+
+static struct uoc *the_controller;
+static const char *transceiver_label = "cs5536_uoc";
+
+/*****************************************************************************
+ *  Function Definitions
+ *****************************************************************************/
+
+/**
+ * \brief
+ * fill UOC transceiver struct
+ *
+ * \param  transceiver  UOC transceiver
+ *
+ * \return              void
+ */
+static inline void uoc_init_transceiver(struct otg_transceiver *transceiver)
+{
+	transceiver->dev = NULL;
+	transceiver->label = transceiver_label;
+	transceiver->default_a = 0;
+	transceiver->state = 0;
+	transceiver->host = NULL;
+	transceiver->gadget = NULL;
+	transceiver->port_status = 0;
+	transceiver->port_change = 0;
+	transceiver->set_host = NULL;
+	transceiver->set_peripheral = uoc5536_set_peripheral;
+	transceiver->set_power = NULL;
+	transceiver->start_srp = NULL;
+	transceiver->start_hnp = NULL;
+}
+
+/**
+ * \brief
+ * OTG get transceiver: provide info to others
+ *
+ * \param  void
+ *
+ * \return pointer to transceiver struct
+ */
+struct otg_transceiver *otg_get_transceiver(void)
+{
+	return uoc_to_transceiver(the_controller);
+}
+
+/**
+ * \brief
+ * Bind/unbind the UOC controller to/from usb gadget
+ *
+ * \param  transceiver  this transceiver
+ * \param  gadget       usb gadget info
+ *
+ * \return error code
+ */
+static int uoc5536_set_peripheral(struct otg_transceiver *transceiver,
+				  struct usb_gadget *gadget)
+{
+	struct uoc *uoc = the_controller;
+
+	if (unlikely(transceiver != uoc_to_transceiver(uoc))) {
+		ERR("USB UOC: unknown transceiver\n");
+		return -EINVAL;
+	}
+	if (gadget) {
+		if (transceiver->gadget) {
+			ERR("USB gadget: UOC driver already registered\n");
+			return -EBUSY;
+		}
+		DBG("bind UOC driver to USB gadget\n");
+		transceiver->gadget = gadget;
+
+		/* Enable UOC hardware (incl. auto pull-up enable)                   */
+		writel((readl(&uoc->regs->cap) | UOC_CAP_APU), &uoc->regs->cap);
+
+		return 0;
+	} else {
+		DBG("unbind UOC driver from USB gadget\n");
+
+		/* Reset auto pull-up (does not reset pull-up)                                                         */
+		writel((readl(&uoc->regs->cap) & ~((u32) UOC_CAP_APU)),
+		       &uoc->regs->cap);
+
+		/* Reset pull-up                                                         */
+		writel((readl(&uoc->regs->mux) & ~((u32) UOC_MUX_PUEN)),
+		       &uoc->regs->mux);
+
+		transceiver->gadget = NULL;
+		return 0;
+	}
+}
+
+/**
+ * \brief
+ * UOC probe: init hardware, register the driver
+ *
+ * \param  uoc   uoc controller info
+ *
+ * \return  success
+ */
+static inline int __init uoc_probe(struct uoc *uoc)
+{
+	int retval;
+	u32 port_mux;
+
+	/* initialize the UOC controller */
+
+	VDBG("UOC init ...\n");
+
+#ifdef VERBOSE
+	/* print regs */
+	print_regs(uoc);
+#endif
+
+	/* Make sure the port mux setting corresponds to .config to avoid bug 5190 */
+	port_mux = readl(&uoc->regs->ctl) & UOC_CTL_MUX_MASK;
+	if (port_mux != UOC_CTL_ENABLE_UDC) {
+		ERR("Your USB port is assigned to %s, it must be assigned to %s within the BIOS setup\n", (port_mux == UOC_CTL_ENABLE_UHC ? "Host" : "Not used"), "Device");
+		retval = -ENODEV;
+		goto err1;
+	}
+
+	/* turn on the UOC controller                                        */
+	writel((readl(&uoc->regs->ctl) | UOC_CTL_PADEN), &uoc->regs->ctl);
+
+	INFO("Port is assigned to device\n");
+
+	VDBG("UOC 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;
+	}
+
+	return 0;
+
+      err1:
+
+	return retval;
+}
+
+/**
+ * \brief
+ * UOC remove: deregister the driver, clean-up hardware
+ *
+ * \param  uoc   uoc controller info
+ *
+ * \return void
+ */
+static inline void __exit uoc_remove(struct uoc *uoc)
+{
+
+	/* unregistering from the usb gadget */
+	usb_gadget_unregister_otg();
+
+	/* Disable UOC hardware (incl. auto pull-up disable)                   */
+	writel((readl(&uoc->regs->ctl) & ~((u32) UOC_CTL_PADEN)),
+	       &uoc->regs->ctl);
+
+	VDBG("UOC exit: UOC-HW disabled\n");
+
+}
+
+#ifdef CONFIG_PCI
+
+/**
+ * \brief
+ * UOC PCI probe: enable, init controller hardware
+ *
+ * \param  pdev   pci device info
+ * \param  id     pci ids
+ *
+ * \return  success
+ */
+static int __init uoc_pci_probe(struct pci_dev *pdev,
+				const struct pci_device_id *id)
+{
+	struct uoc *uoc;
+	u32 resource, len;
+	void *base;
+	int retval;
+	char buf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }, *bufp;
+
+	/* alloc, and start init */
+	uoc = (struct uoc *)kmalloc(sizeof(struct uoc), GFP_KERNEL);
+	if (!uoc) {
+		ERR("couldn't allocate memory for UOC driver\n");
+		retval = -ENOMEM;
+		goto err1;
+	}
+	DBG("kmalloc: UOC driver: %p\n", uoc);
+
+	/* hold global device pointer */
+	the_controller = uoc;
+
+	memset(uoc, 0, sizeof(struct uoc));
+	spin_lock_init(&uoc->lock);
+
+	uoc->pdev = pdev;
+
+	/* now all the pci goodies ...                                       */
+	if (pci_enable_device(pdev) < 0) {
+		ERR("couldn't enable PCI device\n");
+		retval = -ENODEV;
+		goto err2;
+	}
+	uoc->enabled = 1;
+
+	resource = pci_resource_start(pdev, 0);
+	len = pci_resource_len(pdev, 0);
+
+	if (!request_mem_region(resource, len, driver_name)) {
+		ERR("controller already in use\n");
+		retval = -EBUSY;
+		goto err3;
+	}
+	uoc->region = 1;
+
+	base = ioremap_nocache(resource, len);
+	if (!base) {
+		ERR("couldn't map memory\n");
+		retval = -EFAULT;
+		goto err4;
+	}
+	uoc->regs = (struct uoc_regs *)base;
+	bufp = buf;
+
+	pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) & uoc->chiprev);
+
+	/* chip rev >= "B1" supported */
+	if (uoc->chiprev == A0_REV) {
+		ERR("Your chip revision is %s, it must be at least %s\n",
+		    "A0", "B1");
+		retval = -ENODEV;
+		goto err5;
+	}
+
+	/* UOC transceiver info */
+
+#if    LINUX_VERSION_CODE < KERNEL_VERSION(2,5,59)
+	uoc->transceiver.dev = NULL;
+#else
+	uoc->transceiver.dev = &pdev->dev;
+#endif
+	uoc_init_transceiver(uoc_to_transceiver(uoc));
+
+	/* done */
+	INFO("%s\n", driver_desc);
+	INFO("pci mem %08x, chip rev %02x (Geode5536 %s)\n",
+	     resource, uoc->chiprev, (uoc->chiprev == A0_REV ? "A0" : "B1"));
+
+	bufp = DRIVER_VERSION;
+	INFO("driver version: %s\n", bufp);
+
+	if ((retval = uoc_probe(uoc)) == 0) {
+		pci_set_drvdata(pdev, uoc);
+		return 0;
+	}
+
+	/* something went wrong */
+
+      err5:
+	uoc->regs = NULL;
+	iounmap(base);
+      err4:
+	uoc->region = 0;
+	release_mem_region(resource, len);
+      err3:
+	uoc->enabled = 0;
+	pci_disable_device(pdev);
+      err2:
+	uoc->pdev = NULL;
+	the_controller = NULL;
+	DBG("kfree: UOC driver: %p\n", uoc);
+	kfree(uoc);
+      err1:
+	uoc = NULL;
+	return retval;
+}
+
+/**
+ * \brief
+ * UOC PCI remove: clean-up, disable controller hardware
+ *
+ * \param  pdev   pci device info
+ *
+ * \return void
+ */
+static void __exit uoc_pci_remove(struct pci_dev *pdev)
+{
+	struct uoc *uoc = pci_get_drvdata(pdev);
+
+	uoc_remove(uoc);
+
+	iounmap(uoc->regs);
+	uoc->regs = NULL;
+	uoc->region = 0;
+	release_mem_region(pci_resource_start(pdev, 0),
+			   pci_resource_len(pdev, 0));
+	uoc->enabled = 0;
+	pci_disable_device(pdev);
+	uoc->pdev = NULL;
+	the_controller = NULL;
+	DBG("kfree: UOC driver: %p\n", uoc);
+	kfree(uoc);
+	uoc = NULL;
+	pci_set_drvdata(pdev, NULL);
+}
+#endif
+
+/*****************************************************************************
+ *  More data
+ *****************************************************************************/
+
+#ifdef CONFIG_PCI
+/**
+ * \brief
+ * PCI ID table
+ *
+ */
+static struct pci_device_id pci_ids[] = { {
+					   .vendor = PCI_VENDOR_ID_AMD,
+					   .device =
+					   PCI_DEVICE_ID_AMD_CS5536_UOC,
+					   .subvendor = PCI_ANY_ID,
+					   .subdevice = PCI_ANY_ID,
+					   .class = 0,
+					   .class_mask = 0,
+
+					   }, { /* end: all zeroes */ }
+};
+
+/**
+ * \brief
+ * PCI driver struct to be used for driver registration
+ * ( this is a "new style" PCI driver module )
+ *
+ */
+static struct pci_driver uoc_pci_driver = {
+	.name = (char *)driver_name,
+	.id_table = pci_ids,
+	.probe = uoc_pci_probe,
+	.remove = uoc_pci_remove,
+};
+
+MODULE_DEVICE_TABLE(pci, pci_ids);
+#endif
+/* 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("Karsten Boge");
+MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_PCI
+
+static int __init init(void)
+{
+	int rc = pci_module_init(&uoc_pci_driver);
+	if( rc == 0 && the_controller == NULL )
+	{
+		pci_unregister_driver(&uoc_pci_driver);
+		rc = -ENODEV;
+	}
+	return rc;
+}
+static void __exit cleanup(void)
+{
+	pci_unregister_driver(&uoc_pci_driver);
+}
+#endif
+module_init(init);
+module_exit(cleanup);
diff --git a/drivers/usb/gadget/amd5536uoc.h b/drivers/usb/gadget/amd5536uoc.h
new file mode 100644
index 0000000..ba8248b
--- /dev/null
+++ b/drivers/usb/gadget/amd5536uoc.h
@@ -0,0 +1,288 @@
+/*
+ * AMD 5536 USB UOC controller driver
+ */
+
+/*
+ * Copyright (C) 2005 AMD (http://www.amd.com)
+ * Author: Karsten Boge
+ *
+ * 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 AMD5536UOC_H
+#define AMD5536UOC_H
+
+/*****************************************************************************
+*  Config options
+*****************************************************************************/
+
+#ifdef VERBOSE
+#ifndef DEBUG
+#define DEBUG
+#endif
+#endif
+
+/*****************************************************************************
+*  Constants
+*****************************************************************************/
+
+#define UOC_DRIVER_NAME        "amd5536uoc"
+
+#ifdef CONFIG_PCI
+#ifndef PCI_VENDOR_ID_AMD
+#define PCI_VENDOR_ID_AMD             0x1022
+#endif
+#ifndef PCI_DEVICE_ID_AMD_CS5536_UOC
+#define PCI_DEVICE_ID_AMD_CS5536_UOC  0x2097
+#endif
+#else
+#error "!!! UNKNOWN SYSTEM BUS TYPE !!!"
+#endif
+
+/* AMD5536 chip rev. */
+#define A0_REV 1
+#define B1_REV 2
+
+/**********************************
+*  CS5536UOC Register definitions
+**********************************/
+
+/* capabilities */
+#define UOC_CAP_APU            (1<<15)	/* automatic pull-up enable         */
+
+/* multiplexer */
+#define UOC_MUX_DISABLE_ALL    0	/* not assigned                     */
+#define UOC_MUX_ENABLE_UHC     (2<<0)	/* assigned to host                 */
+#define UOC_MUX_ENABLE_UDC     (3<<0)	/* assigned to device               */
+#define UOC_MUX_PUEN           (1<<2)	/* pull-up enable                   */
+#define UOC_MUX_VBUSVLD        (1<<8)	/* VBus valid                       */
+
+/* status */
+#define UOC_STS_ID             (1<<0)	/* ID pin status                    */
+#define UOC_STS_VBUSVLD        (1<<1)	/* VBus valid                       */
+#define UOC_STS_SESSVLD        (1<<2)	/* Session valid                    */
+#define UOC_STS_SESSEND        (1<<3)	/* Session end                      */
+#define UOC_STS_LST            (3<<4)	/* Line state                       */
+#define UOC_STS_LST_J          (1<<4)	/* Line state                       */
+#define UOC_STS_LST_K          (2<<4)	/* Line state                       */
+#define UOC_STS_PSPD           (3<<6)	/* Port speed                       */
+#define UOC_STS_PSPD_LS        (2<<6)	/* Port speed                       */
+#define UOC_STS_PSPD_FS        (1<<6)	/* Port speed                       */
+#define UOC_STS_FSOE           (1<<8)	/* FS output enable (OHC)           */
+#define UOC_STS_PCON           (1<<9)	/* Port connected                   */
+#define UOC_STS_PSUS           (1<<10)	/* Port suspended                   */
+#define UOC_STS_TMH            (1<<11)	/* Timer halted                     */
+#define UOC_STS_HNP_EN         (1<<12)	/* HNP enabled for B-dev            */
+#define UOC_STS_HNP_SUPP       (1<<13)	/* A-host supports HNP              */
+#define UOC_STS_HNP_ALTSUPP    (1<<14)	/* A-host supports alt. HNP         */
+#define UOC_STS_HNPSTS         (UOC_STS_HNP_EN | UOC_STS_HNP_SUPP | \
+                                UOC_STS_HNP_ALTSUPP)
+#define UOC_STS_OC             (1<<15)	/* over-current                     */
+#define UOC_STS_DPR            (1<<16)	/* Downstream port reset            */
+
+/* control */
+#define UOC_CTL_DISABLE_ALL    0	/* not assigned                     */
+#define UOC_CTL_ENABLE_UHC     (2<<0)	/* assigned to host                 */
+#define UOC_CTL_ENABLE_UDC     (3<<0)	/* assigned to device               */
+#define UOC_CTL_MUX_MASK       (3<<0)	/* port mux mask                    */
+#define UOC_CTL_PPWR           (1<<2)	/* port power switch                */
+#define UOC_CTL_PPO            (1<<3)	/* port power override              */
+#define UOC_CTL_CHRG           (1<<4)	/* charge VBus                      */
+#define UOC_CTL_DISCHRG        (1<<5)	/* discharge VBus                   */
+#define UOC_CTL_IDSNSEN        (1<<6)	/* ID sense enable, ID-PU           */
+#define UOC_CTL_PADEN          (1<<7)
+#define UOC_CTL_PUEN           (1<<8)	/* pull-up enable                   */
+#define UOC_CTL_DMPDEN         (1<<9)	/* pull-down enable                 */
+#define UOC_CTL_HNPSFEN        (1<<10)	/* HNP SET_FEATURE enable           */
+#define UOC_CTL_WPCS_DEAS      (2<<16)	/* deassert port connect            */
+#define UOC_CTL_WPCS_ASRT      (3<<16)	/* assert port connect              */
+#define UOC_CTL_WPSS_DEAS      (2<<18)	/* deassert port suspend            */
+#define UOC_CTL_WPSS_ASRT      (3<<18)	/* assert port suspend              */
+/* timer conditions */
+#define UOC_CTL_TMR_RLP        (1<<28)	/* timer reload policy              */
+#define UOC_CTL_TMR_ALL        (0xf<<24)	/* stop timer                       */
+#define UOC_CTL_TMR_STOP       0	/* timer disabled                   */
+#define UOC_CTL_TMR_UNCOND     (1<<24)	/* count unconditionally            */
+#define UOC_CTL_TMR_SE0        (2<<24)	/* count if LSt = FS-SE0            */
+#define UOC_CTL_TMR_FSJ        (3<<24)	/* count if LSt = FS-J              */
+#define UOC_CTL_TMR_FSK        (4<<24)	/* count if LSt = FS-K              */
+#define UOC_CTL_TMR_NOSE0      (5<<24)	/* count if LSt <> FS-SE0           */
+#define UOC_CTL_TMR_NORX       (6<<24)	/* count if Rx inactiv              */
+#define UOC_CTL_TMR_ID         (7<<24)	/* count if ID = 0                  */
+
+/* interrupts */
+#define UOC_INT_GLOBAL         (1<<31)	/* global interrupt enable          */
+#define UOC_INT_ENALL          0x7fff	/* enable all                       */
+#define UOC_INT_DISALL         0	/* disable all                      */
+#define UOC_INT_IDC            (1<<0)	/* ID pin change                    */
+#define UOC_INT_VBVC           (1<<1)	/* VBUS valid change                */
+#define UOC_INT_SVC            (1<<2)	/* Session valid change             */
+#define UOC_INT_SEC            (1<<3)	/* Session end change               */
+#define UOC_INT_LSTC           (1<<4)	/* Line state change                */
+#define UOC_INT_PSPDC          (1<<5)	/* Port speed change                */
+#define UOC_INT_FSOEC          (1<<6)	/* FS/LS OE change                  */
+#define UOC_INT_HSDD           (1<<7)	/* HS disconnect detected           */
+#define UOC_INT_RXACT          (1<<8)	/* Rx activity detected             */
+#define UOC_INT_PCC            (1<<9)	/* Port connect change              */
+#define UOC_INT_PSC            (1<<10)	/* Port suspend change              */
+#define UOC_INT_TMX            (1<<11)	/* Timer expired                    */
+#define UOC_INT_HNPFC          (1<<12)	/* HNP feature change               */
+#define UOC_INT_OCD            (1<<13)	/* over current detected            */
+#define UOC_INT_DPRC           (1<<14)	/* Downstream port reset change     */
+
+/*****************************************************************************
+*  Types
+*****************************************************************************/
+
+/*****************************************************************************
+*  Macros
+*****************************************************************************/
+
+/* printing messages */
+
+#define INFO(args...) \
+        printk(KERN_INFO DRIVER_NAME_FOR_PRINT ": " args)
+
+#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
+
+/*****************************************************************************
+*  Data
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+	struct uoc_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 uoc {
+		spinlock_t lock;
+		unsigned enabled:1, got_irq:1, region:1;
+		u16 chiprev;
+
+		struct pci_dev *pdev;
+		struct uoc_regs *regs;
+		struct otg_transceiver transceiver;
+	};
+#define uoc_transceiver_to_uoc(pTransceiver) \
+	container_of (uoc, struct uoc, pTransceiver)
+#define uoc_to_transceiver(pUoc) \
+	&pUoc->transceiver
+
+#ifdef	__KERNEL__
+
+/* 2.5 and 2.4.older portability changes ... */
+
+#ifndef container_of
+#define	container_of	list_entry
+#endif
+
+#ifndef likely
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
+
+#ifndef BUG_ON
+#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
+#endif
+
+#ifndef WARN_ON
+#define	WARN_ON(x)	do { } while (0)
+#endif
+
+#endif				/* __KERNEL__ */
+
+#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);
+
+#ifdef DEBUG
+	static void print_regs(struct uoc *);
+#endif				/* DEBUG */
+
+#ifdef __cplusplus
+}				/* extern "C" */
+#endif
+/*****************************************************************************
+*  Inline Functions
+*****************************************************************************/
+#ifdef DEBUG
+/**
+ * \brief
+ * Print UOC controller registers (debug mode only)
+ *
+ * \param dev    UOC controller info
+ *
+ * \return void
+ */ static inline void print_regs(struct uoc *dev)
+{
+	DBG("-- UOC registers ---\n");
+	DBG("uoc cap   = %08x\n", readl(&dev->regs->cap));
+	DBG("uoc mux   = %08x\n", readl(&dev->regs->mux));
+	DBG("uoc sts   = %08x\n", readl(&dev->regs->sts));
+	DBG("uoc ctl   = %08x\n", readl(&dev->regs->ctl));
+	DBG("uoc tmr   = %08x\n", readl(&dev->regs->tmr));
+	DBG("uoc intr  = %08x\n", readl(&dev->regs->intr));
+	DBG("uoc inten = %08x\n", readl(&dev->regs->inten));
+	DBG("--------------------\n");
+}
+#endif				/* DEBUG */
+
+#endif				/* AMD5536UOC_H */
