Browse Source

Port arcotg_udc driver from linux.

Signed-off-by: Trace Russell <b45800@freescale.com>
Trace Russell 12 years ago
parent
commit
5e9346e7e5

+ 74 - 0
board/freescale/vf610twr/vf610twr.c

@@ -18,6 +18,7 @@
  */
 
 #include <common.h>
+#include <malloc.h>
 #include <asm/io.h>
 #include <asm/arch/imx-regs.h>
 #include <asm/arch/iomux-vf610.h>
@@ -28,6 +29,8 @@
 #include <fsl_esdhc.h>
 #include <miiphy.h>
 #include <netdev.h>
+#include <usb_mass_storage.h>
+#include <usb/arcotg_udc.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -425,3 +428,74 @@ void udc_pins_setting(void)
 }
 #endif
 
+#ifdef CONFIG_USB_GADGET
+void board_usb_init(void)
+{
+	struct fsl_usb2_platform_data *pdata;
+	pdata = calloc(sizeof(*pdata), 1);
+	fsl_udc_probe(pdata);
+}
+#endif
+
+#ifdef CONFIG_USB_GADGET_MASS_STORAGE
+static int ums_read_sector(struct ums_device *ums_dev,
+                           ulong start, lbaint_t blkcnt, void *buf)
+{
+        if (ums_dev->mmc->block_dev.block_read(ums_dev->dev_num,
+                        start + ums_dev->offset, blkcnt, buf) != blkcnt)
+                return -1;
+
+        return 0;
+}
+
+static int ums_write_sector(struct ums_device *ums_dev,
+                            ulong start, lbaint_t blkcnt, const void *buf)
+{
+        if (ums_dev->mmc->block_dev.block_write(ums_dev->dev_num,
+                        start + ums_dev->offset, blkcnt, buf) != blkcnt)
+                return -1;
+
+        return 0;
+}
+
+static void ums_get_capacity(struct ums_device *ums_dev,
+                             long long int *capacity)
+{
+        long long int tmp_capacity;
+
+        tmp_capacity = (long long int) ((ums_dev->offset + ums_dev->part_size)
+                                        * SECTOR_SIZE);
+        *capacity = ums_dev->mmc->capacity - tmp_capacity;
+}
+
+static struct ums_board_info ums_board = {
+        .read_sector = ums_read_sector,
+        .write_sector = ums_write_sector,
+        .get_capacity = ums_get_capacity,
+        .name = "Vybrid UMS disk",
+        .ums_dev = {
+                .mmc = NULL,
+                .dev_num = 0,
+                .offset = 0,
+                .part_size = 0.
+        },
+};
+
+struct ums_board_info *board_ums_init(unsigned int dev_num, unsigned int offset,
+                                      unsigned int part_size)
+{
+        struct mmc *mmc;
+
+        mmc = find_mmc_device(dev_num);
+        if (!mmc)
+                return NULL;
+
+        ums_board.ums_dev.mmc = mmc;
+        ums_board.ums_dev.dev_num = dev_num;
+        ums_board.ums_dev.offset = offset;
+        ums_board.ums_dev.part_size = part_size;
+
+        return &ums_board;
+}
+#endif
+

+ 1 - 0
drivers/usb/gadget/Makefile

@@ -35,6 +35,7 @@ endif
 # new USB gadget layer dependencies
 ifdef CONFIG_USB_GADGET
 COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
+COBJS-$(CONFIG_USB_GADGET_ARCOTG_UDC) += arcotg_udc.o
 COBJS-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o
 COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
 COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o

+ 342 - 0
drivers/usb/gadget/arc_otg.h

@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __ASM_ARCH_MXC_ARC_OTG_H__
+#define __ASM_ARCH_MXC_ARC_OTG_H__
+
+#ifdef CONFIG_ARCH_MX3
+extern volatile u32 *mx3_usb_otg_addr;
+#define OTG_BASE_ADDR		mx3_usb_otg_addr
+#else
+extern void __iomem *imx_otg_base;
+#define OTG_BASE_ADDR           imx_otg_base
+#endif
+
+#define USB_OTGREGS_BASE	(OTG_BASE_ADDR + 0x000)
+#define USB_H1REGS_BASE		(OTG_BASE_ADDR + 0x200)
+#define USB_H2REGS_BASE		(OTG_BASE_ADDR + 0x400)
+#if (defined CONFIG_ARCH_MX5 | defined CONFIG_ARCH_MX6)
+#define USB_H3REGS_BASE		(OTG_BASE_ADDR + 0x600)
+#define USB_OTHERREGS_BASE	(OTG_BASE_ADDR + 0x800)
+#else
+#define USB_OTHERREGS_BASE	(OTG_BASE_ADDR + 0x600)
+#endif
+
+#define USBOTG_REG32(offset)	(*((volatile u32 __force *)(USB_OTGREGS_BASE + (offset))))
+#define USBOTG_REG16(offset)	(*((volatile u16 __force *)(USB_OTGREGS_BASE + (offset))))
+
+#define USBH1_REG32(offset)	(*((volatile u32 __force *)(USB_H1REGS_BASE + (offset))))
+#define USBH1_REG16(offset)	(*((volatile u16 __force *)(USB_H1REGS_BASE + (offset))))
+
+#define USBH2_REG32(offset)	(*((volatile u32 __force *)(USB_H2REGS_BASE + (offset))))
+#define USBH2_REG16(offset)	(*((volatile u16 __force *)(USB_H2REGS_BASE + (offset))))
+
+#define USBH3_REG32(offset)	(*((volatile u32 __force *)(USB_H3REGS_BASE + (offset))))
+#define USBH3_REG16(offset)	(*((volatile u16 __force *)(USB_H3REGS_BASE + (offset))))
+
+#define USBOTHER_REG(offset)	(*((volatile u32 __force *)(USB_OTHERREGS_BASE + (offset))))
+
+/*
+ * OTG registers
+ */
+#define UOG_ID			USBOTG_REG32(0x00)	/* Host ID */
+#define UOG_HWGENERAL		USBOTG_REG32(0x04)	/* Host General */
+#define UOG_HWHOST		USBOTG_REG32(0x08)	/* Host h/w params */
+#define UOG_HWTXBUF		USBOTG_REG32(0x10)	/* TX buffer h/w params */
+#define UOG_HWRXBUF		USBOTG_REG32(0x14)	/* RX buffer h/w params */
+#define UOG_CAPLENGTH		USBOTG_REG16(0x100)	/* Capability register length */
+#define UOG_HCIVERSION		USBOTG_REG16(0x102)	/* Host Interface version */
+#define UOG_HCSPARAMS		USBOTG_REG32(0x104)	/* Host control structural params */
+#define UOG_HCCPARAMS		USBOTG_REG32(0x108)	/* control capability params */
+#define UOG_DCIVERSION		USBOTG_REG32(0x120)	/* device interface version */
+/* start EHCI registers: */
+#define UOG_USBCMD		USBOTG_REG32(0x140)	/* USB command register */
+#define UOG_USBSTS		USBOTG_REG32(0x144)	/* USB status register */
+#define UOG_USBINTR		USBOTG_REG32(0x148)	/* interrupt enable register */
+#define UOG_FRINDEX		USBOTG_REG32(0x14c)	/* USB frame index */
+/*      segment                             (0x150)	   addr bits 63:32 if needed */
+#define UOG_PERIODICLISTBASE	USBOTG_REG32(0x154)	/* host crtlr frame list base addr */
+#define UOG_DEVICEADDR		USBOTG_REG32(0x154)	/* device crtlr device address */
+#define UOG_ASYNCLISTADDR	USBOTG_REG32(0x158)	/* host ctrlr next async addr */
+#define UOG_EPLISTADDR		USBOTG_REG32(0x158)	/* device ctrlr endpoint list addr */
+#define UOG_BURSTSIZE		USBOTG_REG32(0x160)	/* host ctrlr embedded TT async buf status */
+#define UOG_TXFILLTUNING	USBOTG_REG32(0x164)	/* TX FIFO fill tuning */
+#define UOG_ULPIVIEW		USBOTG_REG32(0x170)	/* ULPI viewport */
+#define UOG_CFGFLAG		USBOTG_REG32(0x180)	/* configflag (supports HS) */
+#define UOG_PORTSC1		USBOTG_REG32(0x184)	/* port status and control */
+/* end EHCI registers: */
+#define UOG_OTGSC		USBOTG_REG32(0x1a4)	/* OTG status and control */
+#define UOG_USBMODE		USBOTG_REG32(0x1a8)	/* USB device mode */
+#define UOG_ENDPTSETUPSTAT	USBOTG_REG32(0x1ac)	/* endpoint setup status */
+#define UOG_ENDPTPRIME		USBOTG_REG32(0x1b0)	/* endpoint initialization */
+#define UOG_ENDPTFLUSH		USBOTG_REG32(0x1b4)	/* endpoint de-initialize */
+#define UOG_ENDPTSTAT		USBOTG_REG32(0x1b8)	/* endpoint status */
+#define UOG_ENDPTCOMPLETE	USBOTG_REG32(0x1bc)	/* endpoint complete */
+#define UOG_EPCTRL0		USBOTG_REG32(0x1c0)	/* endpoint control0 */
+#define UOG_EPCTRL1		USBOTG_REG32(0x1c4)	/* endpoint control1 */
+#define UOG_EPCTRL2		USBOTG_REG32(0x1c8)	/* endpoint control2 */
+#define UOG_EPCTRL3		USBOTG_REG32(0x1cc)	/* endpoint control3 */
+#define UOG_EPCTRL4		USBOTG_REG32(0x1d0)	/* endpoint control4 */
+#define UOG_EPCTRL5		USBOTG_REG32(0x1d4)	/* endpoint control5 */
+#define UOG_EPCTRL6		USBOTG_REG32(0x1d8)	/* endpoint control6 */
+#define UOG_EPCTRL7		USBOTG_REG32(0x1dc)	/* endpoint control7 */
+
+/*
+ * Host 1 registers
+ */
+#define UH1_ID			USBH1_REG32(0x00)	/* Host ID */
+#define UH1_HWGENERAL		USBH1_REG32(0x04)	/* Host General */
+#define UH1_HWHOST		USBH1_REG32(0x08)	/* Host h/w params */
+#define UH1_HWTXBUF		USBH1_REG32(0x10)	/* TX buffer h/w params */
+#define UH1_HWRXBUF		USBH1_REG32(0x14)	/* RX buffer h/w params */
+#define UH1_CAPLENGTH		USBH1_REG16(0x100)	/* Capability register length */
+#define UH1_HCIVERSION		USBH1_REG16(0x102)	/* Host Interface version */
+#define UH1_HCSPARAMS		USBH1_REG32(0x104)	/* Host control structural params */
+#define UH1_HCCPARAMS		USBH1_REG32(0x108)	/* control capability params */
+/* start EHCI registers: */
+#define UH1_USBCMD		USBH1_REG32(0x140)	/* USB command register */
+#define UH1_USBSTS		USBH1_REG32(0x144)	/* USB status register */
+#define UH1_USBINTR		USBH1_REG32(0x148)	/* interrupt enable register */
+#define UH1_FRINDEX		USBH1_REG32(0x14c)	/* USB frame index */
+/*      segment                            (0x150)	   addr bits 63:32 if needed */
+#define UH1_PERIODICLISTBASE	USBH1_REG32(0x154)	/* host crtlr frame list base addr */
+#define UH1_ASYNCLISTADDR	USBH1_REG32(0x158)	/* host ctrlr nest async addr */
+#define UH1_BURSTSIZE		USBH1_REG32(0x160)	/* host ctrlr embedded TT async buf status */
+#define UH1_TXFILLTUNING	USBH1_REG32(0x164)	/* TX FIFO fill tuning */
+/*      configured_flag                    (0x180)	   configflag (supports HS) */
+#define UH1_PORTSC1		USBH1_REG32(0x184)	/* port status and control */
+/* end EHCI registers: */
+#define UH1_USBMODE		USBH1_REG32(0x1a8)	/* USB device mode */
+
+/*
+ * Host 2 registers
+ */
+#define UH2_ID			USBH2_REG32(0x00)	/* Host ID */
+#define UH2_HWGENERAL		USBH2_REG32(0x04)	/* Host General */
+#define UH2_HWHOST		USBH2_REG32(0x08)	/* Host h/w params */
+#define UH2_HWTXBUF		USBH2_REG32(0x10)	/* TX buffer h/w params */
+#define UH2_HWRXBUF		USBH2_REG32(0x14)	/* RX buffer h/w params */
+#define UH2_CAPLENGTH		USBH2_REG16(0x100)	/* Capability register length */
+#define UH2_HCIVERSION		USBH2_REG16(0x102)	/* Host Interface version */
+#define UH2_HCSPARAMS		USBH2_REG32(0x104)	/* Host control structural params */
+#define UH2_HCCPARAMS		USBH2_REG32(0x108)	/* control capability params */
+/* start EHCI registers: */
+#define UH2_USBCMD		USBH2_REG32(0x140)	/* USB command register */
+#define UH2_USBSTS		USBH2_REG32(0x144)	/* USB status register */
+#define UH2_USBINTR		USBH2_REG32(0x148)	/* interrupt enable register */
+#define UH2_FRINDEX		USBH2_REG32(0x14c)	/* USB frame index */
+/*      segment                            (0x150)	   addr bits 63:32 if needed */
+#define UH2_PERIODICLISTBASE	USBH2_REG32(0x154)	/* host crtlr frame list base addr */
+#define UH2_ASYNCLISTADDR	USBH2_REG32(0x158)	/* host ctrlr nest async addr */
+#define UH2_BURSTSIZE		USBH2_REG32(0x160)	/* host ctrlr embedded TT async buf status */
+#define UH2_TXFILLTUNING	USBH2_REG32(0x164)	/* TX FIFO fill tuning */
+#define UH2_ULPIVIEW		USBH2_REG32(0x170)	/* ULPI viewport */
+/*      configured_flag                    (0x180)	   configflag (supports HS) */
+#define UH2_PORTSC1		USBH2_REG32(0x184)	/* port status and control */
+/* end EHCI registers */
+#define UH2_USBMODE		USBH2_REG32(0x1a8)	/* USB device mode */
+/*
+ * Host 2 registers
+ */
+#define UH2_ID			USBH2_REG32(0x00)	/* Host ID */
+#define UH2_HWGENERAL		USBH2_REG32(0x04)	/* Host General */
+#define UH2_HWHOST		USBH2_REG32(0x08)	/* Host h/w params */
+#define UH2_HWTXBUF		USBH2_REG32(0x10)	/* TX buffer h/w params */
+#define UH2_HWRXBUF		USBH2_REG32(0x14)	/* RX buffer h/w params */
+#define UH2_CAPLENGTH		USBH2_REG16(0x100)	/* Capability register length */
+#define UH2_HCIVERSION		USBH2_REG16(0x102)	/* Host Interface version */
+#define UH2_HCSPARAMS		USBH2_REG32(0x104)	/* Host control structural params */
+#define UH2_HCCPARAMS		USBH2_REG32(0x108)	/* control capability params */
+/* start EHCI registers: */
+#define UH2_USBCMD		USBH2_REG32(0x140)	/* USB command register */
+#define UH2_USBSTS		USBH2_REG32(0x144)	/* USB status register */
+#define UH2_USBINTR		USBH2_REG32(0x148)	/* interrupt enable register */
+#define UH2_FRINDEX		USBH2_REG32(0x14c)	/* USB frame index */
+/*      segment                            (0x150)	   addr bits 63:32 if needed */
+#define UH2_PERIODICLISTBASE	USBH2_REG32(0x154)	/* host crtlr frame list base addr */
+#define UH2_ASYNCLISTADDR	USBH2_REG32(0x158)	/* host ctrlr nest async addr */
+#define UH2_BURSTSIZE		USBH2_REG32(0x160)	/* host ctrlr embedded TT async buf status */
+#define UH2_TXFILLTUNING	USBH2_REG32(0x164)	/* TX FIFO fill tuning */
+#define UH2_ULPIVIEW		USBH2_REG32(0x170)	/* ULPI viewport */
+/*      configured_flag                    (0x180)	   configflag (supports HS) */
+#define UH2_PORTSC1		USBH2_REG32(0x184)	/* port status and control */
+/* end EHCI registers */
+#define UH2_USBMODE		USBH2_REG32(0x1a8)	/* USB device mode */
+/*
+ * Host 2 registers
+ */
+#define UH3_ID			USBH3_REG32(0x00)	/* Host ID */
+#define UH3_HWGENERAL		USBH3_REG32(0x04)	/* Host General */
+#define UH3_HWHOST		USBH3_REG32(0x08)	/* Host h/w params */
+#define UH3_HWTXBUF		USBH3_REG32(0x10)	/* TX buffer h/w params */
+#define UH3_HWRXBUF		USBH3_REG32(0x14)	/* RX buffer h/w params */
+#define UH3_CAPLENGTH		USBH3_REG16(0x100)	/* Capability register length */
+#define UH3_HCIVERSION		USBH3_REG16(0x102)	/* Host Interface version */
+#define UH3_HCSPARAMS		USBH3_REG32(0x104)	/* Host control structural params */
+#define UH3_HCCPARAMS		USBH3_REG32(0x108)	/* control capability params */
+/* start EHCI registers: */
+#define UH3_USBCMD		USBH3_REG32(0x140)	/* USB command register */
+#define UH3_USBSTS		USBH3_REG32(0x144)	/* USB status register */
+#define UH3_USBINTR		USBH3_REG32(0x148)	/* interrupt enable register */
+#define UH3_FRINDEX		USBH3_REG32(0x14c)	/* USB frame index */
+/*      segment                            (0x150)	   addr bits 63:32 if needed */
+#define UH3_PERIODICLISTBASE	USBH3_REG32(0x154)	/* host crtlr frame list base addr */
+#define UH3_ASYNCLISTADDR	USBH3_REG32(0x158)	/* host ctrlr nest async addr */
+#define UH3_BURSTSIZE		USBH3_REG32(0x160)	/* host ctrlr embedded TT async buf status */
+#define UH3_TXFILLTUNING	USBH3_REG32(0x164)	/* TX FIFO fill tuning */
+#define UH3_ULPIVIEW		USBH3_REG32(0x170)	/* ULPI viewport */
+/*      configured_flag                    (0x180)	   configflag (supports HS) */
+#define UH3_PORTSC1		USBH3_REG32(0x184)	/* port status and control */
+/* end EHCI registers */
+#define UH3_USBMODE		USBH3_REG32(0x1a8)	/* USB device mode */
+
+/*
+ * other regs (not part of ARC core)
+ */
+#define USBCTRL			USBOTHER_REG(0x00)	/* USB Control register */
+#define USB_OTG_MIRROR		USBOTHER_REG(0x04)	/* USB OTG mirror register */
+#define USB_PHY_CTR_FUNC	USBOTHER_REG(0x08)      /* OTG UTMI PHY Function Control register */
+#define USB_PHY_CTR_FUNC2	USBOTHER_REG(0x0c)      /* OTG UTMI PHY Function Control register */
+#define USB_CTRL_1		USBOTHER_REG(0x10)	/* USB Cotrol Register 1*/
+#define USBCTRL_HOST2		USBOTHER_REG(0x14)	/* USB Cotrol Register 1*/
+#define USBCTRL_HOST3		USBOTHER_REG(0x18)	/* USB Cotrol Register 1*/
+#define USBH1_PHY_CTRL0		USBOTHER_REG(0x1c)	/* USB Cotrol Register 1*/
+#define USBH1_PHY_CTRL1		USBOTHER_REG(0x20)	/* USB Cotrol Register 1*/
+#define USB_CLKONOFF_CTRL       USBOTHER_REG(0x24)      /* USB Clock on/off Control Register */
+
+/* mx6x other regs */
+#define USB_OTG_CTRL			USBOTHER_REG(0x00)	/* USB OTG Control register */
+#define USB_H1_CTRL			USBOTHER_REG(0x04)	/* USB H1 Control register */
+#define USB_H2_CTRL			USBOTHER_REG(0x08)	/* USB H2 Control register */
+#define USB_H3_CTRL			USBOTHER_REG(0x0c)	/* USB H3 Control register */
+#define USB_UH2_HSIC_CTRL		USBOTHER_REG(0x10)	/* USB Host2 HSIC Control Register */
+#define USB_UH3_HSIC_CTRL		USBOTHER_REG(0x14)	/* USB Host3 HSIC Control Register */
+#define USB_OTG_PHY_CTRL_0		USBOTHER_REG(0x18)	/* OTG UTMI PHY Control 0 Register */
+#define USB_H1_PHY_CTRL_0		USBOTHER_REG(0x1c)	/* OTG UTMI PHY Control 1 Register */
+#define USB_UH2_HSIC_DLL_CFG1		USBOTHER_REG(0x20)      /* USB Host2 HSIC DLL Configuration Register 1 */
+#define USB_UH2_HSIC_DLL_CFG2		USBOTHER_REG(0x24)      /* USB Host2 HSIC DLL Configuration Register 2 */
+#define USB_UH2_HSIC_DLL_CFG3		USBOTHER_REG(0x28)      /* USB Host2 HSIC DLL Configuration Register 3 */
+#define USB_UH3_HSIC_DLL_CFG1		USBOTHER_REG(0x30)      /* USB Host3 HSIC DLL Configuration Register 1 */
+#define USB_UH3_HSIC_DLL_CFG2		USBOTHER_REG(0x34)      /* USB Host3 HSIC DLL Configuration Register 2 */
+#define USB_UH3_HSIC_DLL_CFG3		USBOTHER_REG(0x38)      /* USB Host3 HSIC DLL Configuration Register 3 */
+/*
+ * register bits
+ */
+
+/* x_PORTSCx */
+#define PORTSC_PTS_MASK			(3 << 30)	/* parallel xcvr select mask */
+#define PORTSC_PTS_UTMI			(0 << 30)	/* UTMI/UTMI+ */
+#define PORTSC_PTS_PHILIPS		(1 << 30)	/* Philips classic */
+#define PORTSC_PTS_ULPI			(2 << 30)	/* ULPI */
+#define PORTSC_PTS_SERIAL		(3 << 30)	/* serial */
+#define PORTSC_STS			(1 << 29)	/* serial xcvr select */
+#define PORTSC_PTW                      (1 << 28)       /* UTMI width */
+#define PORTSC_PORT_SPEED_FULL		(0x0<<26)
+#define PORTSC_PORT_SPEED_LOW		       (0x1<<26)
+#define PORTSC_PORT_SPEED_HIGH		(0x2<<26)
+#define PORTSC_PORT_SPEED_UNDEF		(0x3<<26)
+#define PORTSC_PORT_SPEED_MASK		(0x3<<26)
+#define PORTSC_HSIC_MODE                (1 << 25)       /* Only for HSIC */
+#define PORTSC_PHCD                     (1 << 23)       /* Low Power Suspend */
+#define PORTSC_WKDC			(1 << 21)	/* wakeup on discnt*/
+#define PORTSC_WKCN			(1 << 20)	/* wakeup on connect*/
+#define PORTSC_PORT_POWER		(1 << 12)	/* port power */
+#define PORTSC_LS_MASK			(3 << 10)	/* Line State mask */
+#define PORTSC_LS_SE0			(0 << 10)	/* SE0     */
+#define PORTSC_LS_K_STATE		(1 << 10)	/* K-state */
+#define PORTSC_LS_J_STATE		(2 << 10)	/* J-state */
+#define PORTSC_PORT_RESET		(1 <<  8)	/* Port reset */
+#define PORTSC_PORT_SUSPEND		(1 <<  7)	/* Suspend */
+#define PORTSC_PORT_FORCE_RESUME	(1 <<  6)	/* Force port resume */
+#define PORTSC_OVER_CURRENT_CHG		(1 <<  5)	/* over current change */
+#define PORTSC_OVER_CURRENT_ACT		(1 <<  4)	/* over currrent active */
+#define PORTSC_PORT_EN_DIS_CHANGE	(1 <<  3)	/* port {en,dis}able change */
+#define PORTSC_PORT_ENABLE		(1 <<  2)	/* port enabled */
+#define PORTSC_CONNECT_STATUS_CHANGE	(1 <<  1)	/* connect status change */
+#define PORTSC_CURRENT_CONNECT_STATUS	(1 <<  0)	/* current connect status */
+
+#define PORTSC_W1C_BITS                     \
+	(PORTSC_CONNECT_STATUS_CHANGE | \
+	PORTSC_PORT_EN_DIS_CHANGE | \
+	PORTSC_OVER_CURRENT_CHG)
+
+/* UOG_OTGSC Register Bits */
+/* control bits: */
+#define  OTGSC_CTRL_VBUS_DISCHARGE	(1 <<  0)
+#define  OTGSC_CTRL_VBUS_CHARGE		(1 <<  1)
+#define  OTGSC_CTRL_OTG_TERM		(1 <<  3)	/* controls DM pulldown */
+#define  OTGSC_CTRL_DATA_PULSING	(1 <<  4)
+#define  OTGSC_CTRL_USB_ID_PU		(1 <<  5)	/* enable ID pullup */
+/* current status: (R/O) */
+#define  OTGSC_STS_USB_ID		(1 <<  8)	/* 0=A-device  1=B-device */
+#define  OTGSC_STS_A_VBUS_VALID		(1 <<  9)
+#define  OTGSC_STS_A_SESSION_VALID	(1 << 10)
+#define  OTGSC_STS_B_SESSION_VALID	(1 << 11)
+#define  OTGSC_STS_B_SESSION_END	(1 << 12)
+#define  OTGSC_STS_1ms_TIMER		(1 << 13)
+#define  OTGSC_STS_DATA_PULSE		(1 << 14)
+/* interrupt status: (write to clear) */
+#define  OTGSC_IS_MASK			(0x7f << 16)
+#define  OTGSC_IS_USB_ID		(1 << 16)
+#define  OTGSC_IS_A_VBUS_VALID		(1 << 17)
+#define  OTGSC_IS_A_SESSION_VALID	(1 << 18)
+#define  OTGSC_IS_B_SESSION_VALID	(1 << 19)
+#define  OTGSC_IS_B_SESSION_END		(1 << 20)
+#define  OTGSC_IS_1ms_TIMER		(1 << 21)
+#define  OTGSC_IS_DATA_PULSE		(1 << 22)
+/* interrupt enables: */
+#define  OTGSC_IE_MASK			(0x7f << 24)
+#define  OTGSC_IE_USB_ID		(1 << 24)
+#define  OTGSC_IE_A_VBUS_VALID		(1 << 25)
+#define  OTGSC_IE_A_SESSION_VALID	(1 << 26)
+#define  OTGSC_IE_B_SESSION_VALID	(1 << 27)
+#define  OTGSC_IE_B_SESSION_END		(1 << 28)
+#define  OTGSC_IE_1ms_TIMER		(1 << 29)
+#define  OTGSC_IE_DATA_PULSE		(1 << 30)
+
+/* UOG_USBSTS bits */
+#define USBSTS_PCI                     (1 << 2) /* Port Change Detect */
+#define USBSTS_URI                     (1 << 6) /* USB Reset Received */
+
+/* USBCMD */
+#define UCMD_RUN_STOP           (1 << 0)        /* controller run/stop */
+#define UCMD_RESET		(1 << 1)	/* controller reset */
+#define UCMD_ITC_NO_THRESHOLD	 (~(0xff << 16))	/* Interrupt Threshold Control */
+
+#if 1				/* FIXME these here for compatibility between my names and Leo's */
+/* OTG interrupt enable bit masks */
+#define  OTGSC_INTERRUPT_ENABLE_BITS_MASK	OTGSC_IE_MASK
+#define  OTGSC_INTSTS_MASK			OTGSC_IS_MASK
+
+/* OTG interrupt status bit masks */
+#define  OTGSC_INTERRUPT_STATUS_BITS_MASK	OTGSC_IS_MASK
+#endif
+
+/* x_USBMODE */
+#define USBMODE_SLOM		(1 << 3)	/* setup lockout mode */
+#define USBMODE_ES		(1 << 2)	/* (big) endian select */
+#define USBMODE_CM_MASK		(3 << 0)	/* controller mode mask */
+#define USBMODE_CM_HOST		(3 << 0)	/* host */
+#define USBMODE_CM_DEVICE	(2 << 0)	/* device */
+#define USBMODE_CM_reserved	(1 << 0)	/* reserved */
+
+#define HCSPARAMS_PPC           (0x1<<4)        /* Port Power Control */
+extern enum fsl_usb2_modes get_usb_mode(struct fsl_usb2_platform_data *pdata);
+
+#endif /* __ASM_ARCH_MXC_ARC_OTG_H__ */
+

+ 3112 - 0
drivers/usb/gadget/arcotg_udc.c

@@ -0,0 +1,3112 @@
+/*
+ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#undef VERBOSE
+
+#include <common.h>
+#include <asm/errno.h>
+#include <linux/list.h>
+#include <malloc.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+#include <asm/io.h>
+
+#include <asm/mach-types.h>
+
+#include <usb/lin_gadget_compat.h>
+#include <usb/arcotg_udc.h>
+#include <usb/fsl_devices.h>
+
+typedef int irqreturn_t;
+typedef int pm_message_t;
+#define IRQ_NONE 0
+#define GFP_ATOMIC 0
+#define __init
+#define __exit
+#define __devinit
+#define pr_warning printf
+#define pr_debug(args...)
+
+#define	DRIVER_DESC	"ARC USBOTG Device Controller driver"
+#define	DRIVER_AUTHOR	"Freescale Semiconductor"
+#define	DRIVER_VERSION	"1 August 2005"
+
+#ifdef CONFIG_PPC_MPC512x
+#define BIG_ENDIAN_DESC
+#endif
+
+#ifdef BIG_ENDIAN_DESC
+#define cpu_to_hc32(x)	(x)
+#define hc32_to_cpu(x)	(x)
+#else
+#define cpu_to_hc32(x)	cpu_to_le32((x))
+#define hc32_to_cpu(x)	le32_to_cpu((x))
+#endif
+#define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
+DEFINE_MUTEX(udc_resume_mutex);
+extern void usb_debounce_id_vbus(void);
+static const char driver_name[] = "fsl-usb2-udc";
+static const char driver_desc[] = DRIVER_DESC;
+
+volatile static struct usb_dr_device *dr_regs;
+volatile static struct usb_sys_interface *usb_sys_regs;
+
+/* it is initialized in probe()  */
+static struct fsl_udc *udc_controller;
+
+#ifdef POSTPONE_FREE_LAST_DTD
+static struct ep_td_struct *last_free_td;
+#endif
+static const struct usb_endpoint_descriptor
+fsl_ep0_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	0,
+	.bmAttributes =		USB_ENDPOINT_XFER_CONTROL,
+	.wMaxPacketSize =	USB_MAX_CTRL_PAYLOAD,
+};
+static const size_t g_iram_size = IRAM_TD_PPH_SIZE;
+static unsigned long g_iram_base;
+static __iomem void *g_iram_addr;
+
+typedef int (*dev_sus)(struct device *dev, pm_message_t state);
+typedef int (*dev_res) (struct device *dev);
+static int udc_suspend(struct fsl_udc *udc);
+static int fsl_udc_suspend(struct fsl_usb2_platform_data *pdata, pm_message_t state);
+static int fsl_udc_resume(void);
+static void fsl_ep_fifo_flush(struct usb_ep *_ep);
+static void gadget_wait_line_to_se0(void);
+
+extern void fsl_platform_set_test_mode(struct fsl_usb2_platform_data *pdata, enum usb_test_mode mode);
+
+#ifdef CONFIG_WORKAROUND_ARCUSB_REG_RW
+static void safe_writel(u32 val32, volatile u32 *addr)
+{
+	__asm__ ("swp %0, %0, [%1]" : : "r"(val32), "r"(addr));
+}
+#endif
+
+#ifdef CONFIG_PPC32
+#define fsl_readl(addr)		in_le32((addr))
+#define fsl_writel(addr, val32) out_le32((val32), (addr))
+#elif defined (CONFIG_WORKAROUND_ARCUSB_REG_RW)
+#define fsl_readl(addr)		readl((addr))
+#define fsl_writel(val32, addr) safe_writel(val32, addr)
+#else
+#define fsl_readl(addr)		readl((addr))
+#define fsl_writel(addr, val32) writel((addr), (val32))
+#endif
+
+/********************************************************************
+ *	Internal Used Function
+********************************************************************/
+
+#ifdef DUMP_QUEUES
+static void dump_ep_queue(struct fsl_ep *ep)
+{
+	int ep_index;
+	struct fsl_req *req;
+	struct ep_td_struct *dtd;
+
+	if (list_empty(&ep->queue)) {
+		pr_debug("udc: empty\n");
+		return;
+	}
+
+	ep_index = ep_index(ep) * 2 + ep_is_in(ep);
+	pr_debug("udc: ep=0x%p  index=%d\n", ep, ep_index);
+
+	list_for_each_entry(req, &ep->queue, queue) {
+		pr_debug("udc: req=0x%p  dTD count=%d\n", req, req->dtd_count);
+		pr_debug("udc: dTD head=0x%p  tail=0x%p\n", req->head,
+			 req->tail);
+
+		dtd = req->head;
+
+		while (dtd) {
+			if (le32_to_cpu(dtd->next_td_ptr) & DTD_NEXT_TERMINATE)
+				break;	/* end of dTD list */
+
+			dtd = dtd->next_td_virt;
+		}
+	}
+}
+#else
+static inline void dump_ep_queue(struct fsl_ep *ep)
+{
+}
+#endif
+
+#if (defined CONFIG_ARCH_MX35 || defined CONFIG_ARCH_MX25)
+/*
+ * The Phy at MX35 and MX25 have bugs, it must disable, and re-eable phy
+ * if the phy clock is disabled before
+ */
+void reset_phy(void)
+{       
+        u32 phyctrl;
+        phyctrl = fsl_readl(&dr_regs->phyctrl1);
+        phyctrl &= ~PHY_CTRL0_USBEN;
+        fsl_writel(phyctrl, &dr_regs->phyctrl1);
+        
+        phyctrl = fsl_readl(&dr_regs->phyctrl1);
+        phyctrl |= PHY_CTRL0_USBEN;
+        fsl_writel(phyctrl, &dr_regs->phyctrl1);
+}
+#else
+void reset_phy(void){; }
+#endif
+
+/* Needed for i2c/serial transceivers */
+static inline void       
+fsl_platform_set_device_mode(struct fsl_usb2_platform_data *pdata)
+{
+        if (pdata->xcvr_ops && pdata->xcvr_ops->set_device)
+                pdata->xcvr_ops->set_device();
+}
+
+static inline void
+fsl_platform_pullup_enable(struct fsl_usb2_platform_data *pdata)
+{
+        if (pdata->xcvr_ops && pdata->xcvr_ops->pullup)
+                pdata->xcvr_ops->pullup(1);
+}
+
+static inline void
+fsl_platform_pullup_disable(struct fsl_usb2_platform_data *pdata)
+{       
+        if (pdata->xcvr_ops && pdata->xcvr_ops->pullup)
+                pdata->xcvr_ops->pullup(0);
+} 
+
+/*-----------------------------------------------------------------
+ * done() - retire a request; caller blocked irqs
+ * @status : request status to be set, only works when
+ *	request is still in progress.
+ *--------------------------------------------------------------*/
+static void done(struct fsl_ep *ep, struct fsl_req *req, int status)
+{
+	struct fsl_udc *udc = NULL;
+	unsigned char stopped = ep->stopped;
+	struct ep_td_struct *curr_td, *next_td;
+	int j;
+
+	udc = (struct fsl_udc *)ep->udc;
+	/* Removed the req from fsl_ep->queue */
+	list_del_init(&req->queue);
+
+	/* req.status should be set as -EINPROGRESS in ep_queue() */
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = status;
+	else
+		status = req->req.status;
+
+	/* Free dtd for the request */
+	next_td = req->head;
+	for (j = 0; j < req->dtd_count; j++) {
+		curr_td = next_td;
+		if (j != req->dtd_count - 1) {
+			next_td = curr_td->next_td_virt;
+#ifdef POSTPONE_FREE_LAST_DTD
+			free(curr_td);
+		} else {
+			if (last_free_td != NULL)
+				free(last_free_td);
+			last_free_td = curr_td;
+		}
+#else
+		}
+
+		free(curr_td);
+#endif
+	}
+
+	if (USE_MSC_WR(req->req.length)) {
+		memmove(req->req.buf, req->req.buf + 1, MSC_BULK_CB_WRAP_LEN);
+	}
+
+	if (status && (status != -ESHUTDOWN))
+		VDBG("complete %s req %p stat %d len %u/%u",
+			ep->ep.name, &req->req, status,
+			req->req.actual, req->req.length);
+
+	ep->stopped = 1;
+
+	spin_unlock(&ep->udc->lock);
+	/* complete() is from gadget layer,
+	 * eg fsg->bulk_in_complete() */
+	if (req->req.complete)
+		req->req.complete(&ep->ep, &req->req);
+
+	spin_lock(&ep->udc->lock);
+	ep->stopped = stopped;
+}
+
+/*-----------------------------------------------------------------
+ * nuke(): delete all requests related to this ep
+ * called with spinlock held
+ *--------------------------------------------------------------*/
+static void nuke(struct fsl_ep *ep, int status)
+{
+	ep->stopped = 1;
+	/*
+	 * At udc stop mode, the clock is already off
+	 * So flush fifo, should be done at clock on mode.
+	 */
+	if (!ep->udc->stopped)
+		fsl_ep_fifo_flush(&ep->ep);
+
+	/* Whether this eq has request linked */
+	while (!list_empty(&ep->queue)) {
+		struct fsl_req *req = NULL;
+
+		req = list_entry(ep->queue.next, struct fsl_req, queue);
+		done(ep, req, status);
+	}
+	dump_ep_queue(ep);
+}
+
+/*------------------------------------------------------------------
+	Internal Hardware related function
+ ------------------------------------------------------------------*/
+static void dr_discharge_line(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+	/* enable/disable pulldown dp and dm */
+	if (pdata->dr_discharge_line) {
+		pdata->dr_discharge_line(enable);
+	/*
+	 * Some platforms, like mx6x,  are very slow change line state
+	 * to SE0 for dp and dm.
+	 * So, we need to discharge dp and dm, otherwise there is a wakeup interrupt
+	 * after we enable the wakeup function.
+	 */
+	if (enable)
+		gadget_wait_line_to_se0();
+	}
+
+}
+
+static inline void
+dr_wake_up_enable(struct fsl_udc *udc, bool enable)
+{
+	struct fsl_usb2_platform_data *pdata;
+	pdata = udc->pdata;
+
+	if (pdata && pdata->wake_up_enable)
+		pdata->wake_up_enable(pdata, enable);
+}
+
+static inline void dr_clk_gate(bool on)
+{
+	struct fsl_usb2_platform_data *pdata = udc_controller->pdata;
+
+	if (!pdata || !pdata->usb_clock_for_pm)
+		return;
+	pdata->usb_clock_for_pm(on);
+	if (on)
+		reset_phy();
+}
+
+static void dr_phy_low_power_mode(struct fsl_udc *udc, bool enable)
+{
+	struct fsl_usb2_platform_data *pdata = udc->pdata;
+	u32 portsc;
+	unsigned long flags;
+	spin_lock_irqsave(&pdata->lock, flags);
+
+	if (pdata && pdata->phy_lowpower_suspend) {
+		pdata->phy_lowpower_suspend(pdata, enable);
+	} else {
+		if (enable) {
+			portsc = fsl_readl(&dr_regs->portsc1);
+			portsc |= PORTSCX_PHY_LOW_POWER_SPD;
+			fsl_writel(portsc, &dr_regs->portsc1);
+		} else {
+			portsc = fsl_readl(&dr_regs->portsc1);
+			portsc &= ~PORTSCX_PHY_LOW_POWER_SPD;
+			fsl_writel(portsc, &dr_regs->portsc1);
+		}
+	}
+	pdata->lowpower = enable;
+	spin_unlock_irqrestore(&pdata->lock, flags);
+}
+
+static int dr_controller_setup(struct fsl_udc *udc)
+{
+	unsigned int tmp = 0, portctrl = 0;
+	unsigned int ctrl = 0;
+	unsigned long timeout;
+	struct fsl_usb2_platform_data *pdata;
+
+#define FSL_UDC_RESET_TIMEOUT 1000 /* msec */
+
+	/* before here, make sure dr_regs has been initialized */
+	if (!udc)
+		return -EINVAL;
+	pdata = udc->pdata;
+
+	/* Stop and reset the usb controller */
+	tmp = fsl_readl(&dr_regs->usbcmd);
+	tmp &= ~USB_CMD_RUN_STOP;
+	fsl_writel(tmp, &dr_regs->usbcmd);
+
+	tmp = fsl_readl(&dr_regs->usbcmd);
+	tmp |= USB_CMD_CTRL_RESET;
+	fsl_writel(tmp, &dr_regs->usbcmd);
+
+	/* Wait for reset to complete */
+	timeout = get_timer(0) + FSL_UDC_RESET_TIMEOUT;
+	while (fsl_readl(&dr_regs->usbcmd) & USB_CMD_CTRL_RESET) {
+		if (get_timer(0) > timeout) {
+			ERR("udc reset timeout! \n");
+			return -ETIMEDOUT;
+		}
+	}
+
+	/* Set the controller as device mode */
+	tmp = fsl_readl(&dr_regs->usbmode);
+	tmp &= ~USB_MODE_CTRL_MODE_MASK;	/* clear mode bits */
+	tmp |= USB_MODE_CTRL_MODE_DEVICE;
+	/* Disable Setup Lockout */
+	tmp |= USB_MODE_SETUP_LOCK_OFF;
+	if (pdata->es)
+		tmp |= USB_MODE_ES;
+	fsl_writel(tmp, &dr_regs->usbmode);
+	/* wait dp to 0v */
+	dr_discharge_line(pdata, true);
+
+	fsl_platform_set_device_mode(pdata);
+
+	/* Clear the setup status */
+	fsl_writel(0xffffffff, &dr_regs->usbsts);
+
+	tmp = udc->ep_qh_dma;
+	tmp &= USB_EP_LIST_ADDRESS_MASK;
+	fsl_writel(tmp, &dr_regs->endpointlistaddr);
+
+	VDBG("vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x",
+		(int)udc->ep_qh, (int)tmp,
+		fsl_readl(&dr_regs->endpointlistaddr));
+
+	/* Config PHY interface */
+	portctrl = fsl_readl(&dr_regs->portsc1);
+	portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
+	switch (udc->phy_mode) {
+	case FSL_USB2_PHY_ULPI:
+		portctrl |= PORTSCX_PTS_ULPI;
+		break;
+	case FSL_USB2_PHY_UTMI_WIDE:
+		portctrl |= PORTSCX_PTW_16BIT;
+		/* fall through */
+	case FSL_USB2_PHY_UTMI:
+		portctrl |= PORTSCX_PTS_UTMI;
+		break;
+	case FSL_USB2_PHY_SERIAL:
+		portctrl |= PORTSCX_PTS_FSLS;
+		break;
+	default:
+		return -EINVAL;
+	}
+	fsl_writel(portctrl, &dr_regs->portsc1);
+
+	if (pdata->change_ahb_burst) {
+		/* if usb should not work in default INCRx mode */
+		tmp = fsl_readl(&dr_regs->sbuscfg);
+		tmp = (tmp & ~0x07) | pdata->ahb_burst_mode;
+		fsl_writel(tmp, &dr_regs->sbuscfg);
+	}
+
+	if (pdata->have_sysif_regs) {
+		/* Config control enable i/o output, cpu endian register */
+		ctrl = __raw_readl(&usb_sys_regs->control);
+		ctrl |= USB_CTRL_IOENB;
+		__raw_writel(ctrl, &usb_sys_regs->control);
+	}
+
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+	/* Turn on cache snooping hardware, since some PowerPC platforms
+	 * wholly rely on hardware to deal with cache coherent. */
+
+	if (pdata->have_sysif_regs) {
+		/* Setup Snooping for all the 4GB space */
+		tmp = SNOOP_SIZE_2GB;	/* starts from 0x0, size 2G */
+		__raw_writel(tmp, &usb_sys_regs->snoop1);
+		tmp |= 0x80000000;	/* starts from 0x8000000, size 2G */
+		__raw_writel(tmp, &usb_sys_regs->snoop2);
+	}
+#endif
+
+	return 0;
+}
+
+/* Enable DR irq and set controller to run state */
+static void dr_controller_run(struct fsl_udc *udc)
+{
+	u32 temp;
+
+	udc_controller->usb_state = USB_STATE_ATTACHED;
+	udc_controller->ep0_dir = 0;
+
+	fsl_platform_pullup_enable(udc->pdata);
+
+	/* Enable DR irq reg */
+	temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN
+		| USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN
+		| USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN;
+
+	fsl_writel(temp, &dr_regs->usbintr);
+
+	/* enable BSV irq */
+	temp = fsl_readl(&dr_regs->otgsc);
+	temp |= OTGSC_B_SESSION_VALID_IRQ_EN;
+	fsl_writel(temp, &dr_regs->otgsc);
+
+	/* If vbus not on and used low power mode */
+	if (!(temp & OTGSC_B_SESSION_VALID)) {
+		/* Set stopped before low power mode */
+		udc->vbus_active = false;
+		udc->stopped = 1;
+		/* enable wake up */
+		dr_wake_up_enable(udc, true);
+		/* enter lower power mode */
+		dr_phy_low_power_mode(udc, true);
+		printk(KERN_DEBUG "%s: udc enter low power mode \n", __func__);
+	} else {
+#ifdef CONFIG_ARCH_MX37
+		/*
+		 add some delay for USB timing issue. USB may be
+		 recognize as FS device
+		 during USB gadget remote wake up function
+		*/
+		mdelay(100);
+#endif
+		/* Clear stopped bit */
+		udc->stopped = 0;
+
+		/* disable pulldown dp and dm */
+		dr_discharge_line(udc->pdata, false);
+		udc->vbus_active = true;
+	}
+
+	return;
+}
+
+static void dr_controller_stop(struct fsl_udc *udc)
+{
+	unsigned int tmp;
+
+	pr_debug("%s\n", __func__);
+
+	/* if we're in OTG mode, and the Host is currently using the port,
+	 * stop now and don't rip the controller out from under the
+	 * ehci driver
+	 */
+	if (udc->gadget.is_otg) {
+		if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) {
+			pr_debug("udc: Leaving early\n");
+			return;
+		}
+	}
+
+	/* disable all INTR */
+	fsl_writel(0, &dr_regs->usbintr);
+
+	/* disable wake up */
+	dr_wake_up_enable(udc, false);
+	/* disable BSV irq */
+	tmp = fsl_readl(&dr_regs->otgsc);
+	tmp &= ~OTGSC_B_SESSION_VALID_IRQ_EN;
+	fsl_writel(tmp, &dr_regs->otgsc);
+
+	/* Set stopped bit for isr */
+	udc->stopped = 1;
+
+	/* disable IO output */
+/*	usb_sys_regs->control = 0; */
+
+	fsl_platform_pullup_disable(udc->pdata);
+
+	/* set controller to Stop */
+	tmp = fsl_readl(&dr_regs->usbcmd);
+	tmp &= ~USB_CMD_RUN_STOP;
+	fsl_writel(tmp, &dr_regs->usbcmd);
+
+	/* disable pulldown dp and dm */
+	dr_discharge_line(udc->pdata, true);
+	return;
+}
+
+void dr_ep_setup(unsigned char ep_num, unsigned char dir, unsigned char ep_type)
+{
+	unsigned int tmp_epctrl = 0;
+
+	tmp_epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
+	if (dir) {
+		if (ep_num)
+			tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
+		tmp_epctrl |= EPCTRL_TX_ENABLE;
+		tmp_epctrl |= ((unsigned int)(ep_type)
+				<< EPCTRL_TX_EP_TYPE_SHIFT);
+	} else {
+		if (ep_num)
+			tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
+		tmp_epctrl |= EPCTRL_RX_ENABLE;
+		tmp_epctrl |= ((unsigned int)(ep_type)
+				<< EPCTRL_RX_EP_TYPE_SHIFT);
+	}
+
+	fsl_writel(tmp_epctrl, &dr_regs->endptctrl[ep_num]);
+}
+
+static void
+dr_ep_change_stall(unsigned char ep_num, unsigned char dir, int value)
+{
+	u32 tmp_epctrl = 0;
+
+	tmp_epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
+
+	if (value) {
+		/* set the stall bit */
+		if (dir)
+			tmp_epctrl |= EPCTRL_TX_EP_STALL;
+		else
+			tmp_epctrl |= EPCTRL_RX_EP_STALL;
+	} else {
+		/* clear the stall bit and reset data toggle */
+		if (dir) {
+			tmp_epctrl &= ~EPCTRL_TX_EP_STALL;
+			tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
+		} else {
+			tmp_epctrl &= ~EPCTRL_RX_EP_STALL;
+			tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
+		}
+	}
+	fsl_writel(tmp_epctrl, &dr_regs->endptctrl[ep_num]);
+}
+
+/* Get stall status of a specific ep
+   Return: 0: not stalled; 1:stalled */
+static int dr_ep_get_stall(unsigned char ep_num, unsigned char dir)
+{
+	u32 epctrl;
+
+	epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
+	if (dir)
+		return (epctrl & EPCTRL_TX_EP_STALL) ? 1 : 0;
+	else
+		return (epctrl & EPCTRL_RX_EP_STALL) ? 1 : 0;
+}
+
+/********************************************************************
+	Internal Structure Build up functions
+********************************************************************/
+
+/*------------------------------------------------------------------
+* struct_ep_qh_setup(): set the Endpoint Capabilites field of QH
+ * @zlt: Zero Length Termination Select (1: disable; 0: enable)
+ * @mult: Mult field
+ ------------------------------------------------------------------*/
+static void struct_ep_qh_setup(struct fsl_udc *udc, unsigned char ep_num,
+		unsigned char dir, unsigned char ep_type,
+		unsigned int max_pkt_len,
+		unsigned int zlt, unsigned char mult)
+{
+	struct ep_queue_head *p_QH = &udc->ep_qh[2 * ep_num + dir];
+	unsigned int tmp = 0;
+
+	/* set the Endpoint Capabilites in QH */
+	switch (ep_type) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		/* Interrupt On Setup (IOS). for control ep  */
+		tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
+			| EP_QUEUE_HEAD_IOS;
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
+			| (mult << EP_QUEUE_HEAD_MULT_POS);
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+	case USB_ENDPOINT_XFER_INT:
+		tmp = max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS;
+		break;
+	default:
+		VDBG("error ep type is %d", ep_type);
+		return;
+	}
+	if (zlt)
+		tmp |= EP_QUEUE_HEAD_ZLT_SEL;
+	p_QH->max_pkt_length = cpu_to_hc32(tmp);
+
+	return;
+}
+
+/* Setup qh structure and ep register for ep0. */
+static void ep0_setup(struct fsl_udc *udc)
+{
+	/* the intialization of an ep includes: fields in QH, Regs,
+	 * fsl_ep struct */
+	struct_ep_qh_setup(udc, 0, USB_RECV, USB_ENDPOINT_XFER_CONTROL,
+			USB_MAX_CTRL_PAYLOAD, 0, 0);
+	struct_ep_qh_setup(udc, 0, USB_SEND, USB_ENDPOINT_XFER_CONTROL,
+			USB_MAX_CTRL_PAYLOAD, 0, 0);
+	dr_ep_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL);
+	dr_ep_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL);
+
+	return;
+
+}
+
+/***********************************************************************
+		Endpoint Management Functions
+***********************************************************************/
+
+/*-------------------------------------------------------------------------
+ * when configurations are set, or when interface settings change
+ * for example the do_set_interface() in gadget layer,
+ * the driver will enable or disable the relevant endpoints
+ * ep0 doesn't use this routine. It is always enabled.
+-------------------------------------------------------------------------*/
+static int fsl_ep_enable(struct usb_ep *_ep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct fsl_udc *udc = NULL;
+	struct fsl_ep *ep = NULL;
+	unsigned short max = 0;
+	unsigned char mult = 0, zlt;
+	int retval = -EINVAL;
+	unsigned long flags = 0;
+
+	ep = container_of(_ep, struct fsl_ep, ep);
+
+	pr_debug("udc: %s ep.name=%s\n", __func__, ep->ep.name);
+	/* catch various bogus parameters */
+	if (!_ep || !desc || ep->desc
+			|| (desc->bDescriptorType != USB_DT_ENDPOINT))
+		return -EINVAL;
+
+	udc = ep->udc;
+
+	if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN))
+		return -ESHUTDOWN;
+
+	max = le16_to_cpu(desc->wMaxPacketSize);
+
+	/* Disable automatic zlp generation.  Driver is reponsible to indicate
+	 * explicitly through req->req.zero.  This is needed to enable multi-td
+	 * request. */
+	zlt = 1;
+
+	/* Assume the max packet size from gadget is always correct */
+	switch (desc->bmAttributes & 0x03) {
+	case USB_ENDPOINT_XFER_CONTROL:
+	case USB_ENDPOINT_XFER_BULK:
+	case USB_ENDPOINT_XFER_INT:
+		/* mult = 0.  Execute N Transactions as demonstrated by
+		 * the USB variable length packet protocol where N is
+		 * computed using the Maximum Packet Length (dQH) and
+		 * the Total Bytes field (dTD) */
+		mult = 0;
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		/* Calculate transactions needed for high bandwidth iso */
+		mult = (unsigned char)(1 + ((max >> 11) & 0x03));
+		max = max & 0x7ff;	/* bit 0~10 */
+		/* 3 transactions at most */
+		if (mult > 3)
+			goto en_done;
+		break;
+	default:
+		goto en_done;
+	}
+
+	spin_lock_irqsave(&udc->lock, flags);
+	ep->ep.maxpacket = max;
+	ep->desc = desc;
+	ep->stopped = 0;
+
+	/* Controller related setup */
+	/* Init EPx Queue Head (Ep Capabilites field in QH
+	 * according to max, zlt, mult) */
+	struct_ep_qh_setup(udc, (unsigned char) ep_index(ep),
+			(unsigned char) ((desc->bEndpointAddress & USB_DIR_IN)
+					?  USB_SEND : USB_RECV),
+			(unsigned char) (desc->bmAttributes
+					& USB_ENDPOINT_XFERTYPE_MASK),
+			max, zlt, mult);
+
+	/* Init endpoint ctrl register */
+	dr_ep_setup((unsigned char) ep_index(ep),
+			(unsigned char) ((desc->bEndpointAddress & USB_DIR_IN)
+					? USB_SEND : USB_RECV),
+			(unsigned char) (desc->bmAttributes
+					& USB_ENDPOINT_XFERTYPE_MASK));
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+	retval = 0;
+
+	VDBG("enabled %s (ep%d%s) maxpacket %d", ep->ep.name,
+			ep->desc->bEndpointAddress & 0x0f,
+			(desc->bEndpointAddress & USB_DIR_IN)
+				? "in" : "out", max);
+en_done:
+	return retval;
+}
+
+/*---------------------------------------------------------------------
+ * @ep : the ep being unconfigured. May not be ep0
+ * Any pending and uncomplete req will complete with status (-ESHUTDOWN)
+*---------------------------------------------------------------------*/
+static int fsl_ep_disable(struct usb_ep *_ep)
+{
+	struct fsl_udc *udc = NULL;
+	struct fsl_ep *ep = NULL;
+	unsigned long flags = 0;
+	u32 epctrl;
+	int ep_num;
+
+	ep = container_of(_ep, struct fsl_ep, ep);
+	if (!_ep || !ep->desc) {
+		VDBG("%s not enabled", _ep ? ep->ep.name : NULL);
+		return -EINVAL;
+	}
+
+	/* disable ep on controller */
+	ep_num = ep_index(ep);
+	epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
+	if (ep_is_in(ep))
+		epctrl &= ~EPCTRL_TX_ENABLE;
+	else
+		epctrl &= ~EPCTRL_RX_ENABLE;
+	fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]);
+
+	udc = (struct fsl_udc *)ep->udc;
+	spin_lock_irqsave(&udc->lock, flags);
+	/* nuke all pending requests (does flush) */
+	nuke(ep, -ESHUTDOWN);
+
+	ep->desc = 0;
+	ep->stopped = 1;
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	VDBG("disabled %s OK", _ep->name);
+	return 0;
+}
+
+/*---------------------------------------------------------------------
+ * allocate a request object used by this endpoint
+ * the main operation is to insert the req->queue to the eq->queue
+ * Returns the request, or null if one could not be allocated
+*---------------------------------------------------------------------*/
+static struct usb_request *
+fsl_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct fsl_req *req = NULL;
+
+	req = kzalloc(sizeof *req, gfp_flags);
+	if (!req)
+		return NULL;
+
+	req->req.dma = DMA_ADDR_INVALID;
+	pr_debug("udc: req=0x%p   set req.dma=0x%x\n", req, req->req.dma);
+	INIT_LIST_HEAD(&req->queue);
+
+	return &req->req;
+}
+
+static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fsl_req *req = NULL;
+
+	req = container_of(_req, struct fsl_req, req);
+
+	if (_req)
+		kfree(req);
+}
+
+static void update_qh(struct fsl_req *req)
+{
+	struct fsl_ep *ep = req->ep;
+	int i = ep_index(ep) * 2 + ep_is_in(ep);
+	u32 temp;
+	struct ep_queue_head *dQH = &ep->udc->ep_qh[i];
+
+	/* Write dQH next pointer and terminate bit to 0 */
+	temp = req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
+	if (NEED_IRAM(req->ep)) {
+		/* set next dtd stop bit,ensure only one dtd in this list */
+		req->cur->next_td_ptr |= cpu_to_hc32(DTD_NEXT_TERMINATE);
+		temp = req->cur->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
+	}
+	dQH->next_dtd_ptr = cpu_to_hc32(temp);
+	/* Clear active and halt bit */
+	temp = cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
+			     | EP_QUEUE_HEAD_STATUS_HALT));
+	dQH->size_ioc_int_sts &= temp;
+
+	/* Prime endpoint by writing 1 to ENDPTPRIME */
+	temp = ep_is_in(ep)
+	    ? (1 << (ep_index(ep) + 16))
+	    : (1 << (ep_index(ep)));
+	fsl_writel(temp, &dr_regs->endpointprime);
+}
+
+/*-------------------------------------------------------------------------*/
+static int fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
+{
+	u32 temp, bitmask, tmp_stat;
+
+	/* VDBG("QH addr Register 0x%8x", dr_regs->endpointlistaddr);
+	VDBG("ep_qh[%d] addr is 0x%8x", i, (u32)&(ep->udc->ep_qh[i])); */
+
+	bitmask = ep_is_in(ep)
+		? (1 << (ep_index(ep) + 16))
+		: (1 << (ep_index(ep)));
+
+	/*
+	 * check if
+	 * - the request is empty, and
+	 * - the request is not the status request for ep0
+	 */
+	if (!(list_empty(&ep->queue)) &&
+		!((ep_index(ep) == 0) && (req->req.length == 0))) {
+		/* Add td to the end */
+		struct fsl_req *lastreq;
+		lastreq = list_entry(ep->queue.prev, struct fsl_req, queue);
+		if (NEED_IRAM(ep)) {
+			/* only one dtd in dqh */
+			lastreq->tail->next_td_ptr =
+			    cpu_to_hc32(req->head->td_dma | DTD_NEXT_TERMINATE);
+			goto out;
+		} else {
+			lastreq->tail->next_td_ptr =
+			    cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK);
+		}
+		/* Read prime bit, if 1 goto done */
+		if (fsl_readl(&dr_regs->endpointprime) & bitmask)
+			goto out;
+		do {
+			/* Set ATDTW bit in USBCMD */
+			temp = fsl_readl(&dr_regs->usbcmd);
+			fsl_writel(temp | USB_CMD_ATDTW, &dr_regs->usbcmd);
+
+			/* Read correct status bit */
+			tmp_stat = fsl_readl(&dr_regs->endptstatus) & bitmask;
+
+		} while (!(fsl_readl(&dr_regs->usbcmd) & USB_CMD_ATDTW));
+
+		/* Write ATDTW bit to 0 */
+		temp = fsl_readl(&dr_regs->usbcmd);
+		fsl_writel(temp & ~USB_CMD_ATDTW, &dr_regs->usbcmd);
+
+		if (tmp_stat)
+			goto out;
+	}
+	update_qh(req);
+out:
+	return 0;
+}
+
+/* Fill in the dTD structure
+ * @req: request that the transfer belongs to
+ * @length: return actually data length of the dTD
+ * @dma: return dma address of the dTD
+ * @is_last: return flag if it is the last dTD of the request
+ * return: pointer to the built dTD */
+static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
+		dma_addr_t *dma, int *is_last)
+{
+	u32 swap_temp;
+	struct ep_td_struct *dtd;
+
+	/* how big will this transfer be? */
+	*length = min(req->req.length - req->req.actual,
+			(unsigned)EP_MAX_LENGTH_TRANSFER);
+	if (NEED_IRAM(req->ep))
+		*length = min(*length, g_iram_size);
+	dtd = malloc(sizeof(*dtd));
+	if (dtd == NULL)
+		return dtd;
+
+	dtd->td_dma = *dma;
+	/* Clear reserved field */
+	swap_temp = hc32_to_cpu(dtd->size_ioc_sts);
+	swap_temp &= ~DTD_RESERVED_FIELDS;
+	dtd->size_ioc_sts = cpu_to_hc32(swap_temp);
+
+	/* Init all of buffer page pointers */
+	swap_temp = (u32) (req->req.dma + req->req.actual);
+	if (NEED_IRAM(req->ep))
+		swap_temp = (u32) (req->req.dma);
+	dtd->buff_ptr0 = cpu_to_hc32(swap_temp);
+	dtd->buff_ptr1 = cpu_to_hc32(swap_temp + 0x1000);
+	dtd->buff_ptr2 = cpu_to_hc32(swap_temp + 0x2000);
+	dtd->buff_ptr3 = cpu_to_hc32(swap_temp + 0x3000);
+	dtd->buff_ptr4 = cpu_to_hc32(swap_temp + 0x4000);
+
+	req->req.actual += *length;
+
+	/* zlp is needed if req->req.zero is set */
+	if (req->req.zero) {
+		if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0)
+			*is_last = 1;
+		else
+			*is_last = 0;
+	} else if (req->req.length == req->req.actual)
+		*is_last = 1;
+	else
+		*is_last = 0;
+
+	if ((*is_last) == 0)
+		VDBG("multi-dtd request!\n");
+	/* Fill in the transfer size; set active bit */
+	swap_temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE);
+
+	/* Enable interrupt for the last dtd of a request */
+	if (*is_last && !req->req.no_interrupt)
+		swap_temp |= DTD_IOC;
+	if (NEED_IRAM(req->ep))
+		swap_temp |= DTD_IOC;
+
+	dtd->size_ioc_sts = cpu_to_hc32(swap_temp);
+
+	VDBG("length = %d address= 0x%x", *length, (int)dtd);
+
+	return dtd;
+}
+
+/* Generate dtd chain for a request */
+static int fsl_req_to_dtd(struct fsl_req *req)
+{
+	unsigned	count;
+	int		is_last;
+	int		is_first = 1;
+	struct ep_td_struct	*last_dtd = NULL, *dtd;
+	dma_addr_t dma;
+
+	if (NEED_IRAM(req->ep)) {
+		req->oridma = req->req.dma;
+		/* here, replace user buffer to iram buffer */
+		if (ep_is_in(req->ep)) {
+			req->req.dma = req->ep->udc->iram_buffer[1];
+			if ((list_empty(&req->ep->queue))) {
+				/* copy data only when no bulk in transfer is
+				   running */
+				memcpy((char *)req->ep->udc->iram_buffer_v[1],
+				       req->req.buf, min(req->req.length,
+							 g_iram_size));
+			}
+		} else {
+			req->req.dma = req->ep->udc->iram_buffer[0];
+		}
+	}
+
+	if (USE_MSC_WR(req->req.length))
+		req->req.dma += 1;
+
+	do {
+		dtd = fsl_build_dtd(req, &count, &dma, &is_last);
+		if (dtd == NULL)
+			return -ENOMEM;
+
+		if (is_first) {
+			is_first = 0;
+			req->head = dtd;
+		} else {
+			last_dtd->next_td_ptr = cpu_to_hc32(dma);
+			last_dtd->next_td_virt = dtd;
+		}
+		last_dtd = dtd;
+
+		req->dtd_count++;
+	} while (!is_last);
+
+	dtd->next_td_ptr = cpu_to_hc32(DTD_NEXT_TERMINATE);
+	req->cur = req->head;
+	req->tail = dtd;
+
+	return 0;
+}
+
+/* queues (submits) an I/O request to an endpoint */
+static int
+fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct fsl_ep *ep = container_of(_ep, struct fsl_ep, ep);
+	struct fsl_req *req = container_of(_req, struct fsl_req, req);
+	struct fsl_udc *udc;
+	unsigned long flags;
+	int is_iso = 0;
+
+
+	if (!_ep || !ep->desc) {
+		VDBG("%s, bad ep\n", __func__);
+		return -EINVAL;
+	}
+
+	udc = ep->udc;
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/* catch various bogus parameters */
+	if (!_req || !req->req.buf || (ep_index(ep)
+				      && !list_empty(&req->queue))) {
+		VDBG("%s, bad params\n", __func__);
+		spin_unlock_irqrestore(&udc->lock, flags);
+		return -EINVAL;
+	}
+	if (usb_endpoint_xfer_isoc(ep->desc)) {
+		if (req->req.length > ep->ep.maxpacket) {
+			spin_unlock_irqrestore(&udc->lock, flags);
+			return -EMSGSIZE;
+		}
+		is_iso = 1;
+	}
+
+	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
+		spin_unlock_irqrestore(&udc->lock, flags);
+		return -ESHUTDOWN;
+	}
+	req->ep = ep;
+
+	/* map virtual address to hardware */
+	if (req->req.dma == DMA_ADDR_INVALID) {
+		req->req.dma = req->req.buf;
+		req->mapped = 1;
+	} else {
+		req->mapped = 0;
+	}
+
+	req->req.status = -EINPROGRESS;
+	req->req.actual = 0;
+	req->dtd_count = 0;
+	if (NEED_IRAM(ep)) {
+		req->last_one = 0;
+		req->buffer_offset = 0;
+	}
+
+	/* build dtds and push them to device queue */
+	if (!fsl_req_to_dtd(req)) {
+		fsl_queue_td(ep, req);
+	} else {
+		spin_unlock_irqrestore(&udc->lock, flags);
+		return -ENOMEM;
+	}
+
+	/* irq handler advances the queue */
+	if (req != NULL)
+		list_add_tail(&req->queue, &ep->queue);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+/* dequeues (cancels, unlinks) an I/O request from an endpoint */
+static int fsl_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fsl_ep *ep = container_of(_ep, struct fsl_ep, ep);
+	struct fsl_req *req;
+	unsigned long flags;
+	int ep_num, stopped, ret = 0;
+	struct fsl_udc *udc = NULL;
+	u32 epctrl;
+
+	if (!_ep || !_req)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ep->udc->lock, flags);
+	stopped = ep->stopped;
+	udc = ep->udc;
+
+	/* Stop the ep before we deal with the queue */
+	ep->stopped = 1;
+	ep_num = ep_index(ep);
+	epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
+	if (ep_is_in(ep))
+		epctrl &= ~EPCTRL_TX_ENABLE;
+	else
+		epctrl &= ~EPCTRL_RX_ENABLE;
+	fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]);
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* The request is in progress, or completed but not dequeued */
+	if (ep->queue.next == &req->queue) {
+		_req->status = -ECONNRESET;
+		fsl_ep_fifo_flush(_ep);	/* flush current transfer */
+
+		/* The request isn't the last request in this ep queue */
+		if (req->queue.next != &ep->queue) {
+			struct ep_queue_head *qh;
+			struct fsl_req *next_req;
+
+			qh = ep->qh;
+			next_req = list_entry(req->queue.next, struct fsl_req,
+					queue);
+
+			/* prime with dTD of next request */
+			update_qh(next_req);
+		}
+
+		/* The request hasn't been processed, patch up the TD chain */
+	} else {
+		struct fsl_req *prev_req;
+
+		prev_req = list_entry(req->queue.prev, struct fsl_req, queue);
+		prev_req->tail->next_td_ptr = req->tail->next_td_ptr;
+	}
+
+	done(ep, req, -ECONNRESET);
+
+	/* Enable EP */
+out:	epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
+	if (ep_is_in(ep))
+		epctrl |= EPCTRL_TX_ENABLE;
+	else
+		epctrl |= EPCTRL_RX_ENABLE;
+	fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]);
+	ep->stopped = stopped;
+
+	spin_unlock_irqrestore(&ep->udc->lock, flags);
+	return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------
+ * modify the endpoint halt feature
+ * @ep: the non-isochronous endpoint being stalled
+ * @value: 1--set halt  0--clear halt
+ * Returns zero, or a negative error code.
+*----------------------------------------------------------------*/
+static int fsl_ep_set_halt(struct usb_ep *_ep, int value)
+{
+	struct fsl_ep *ep = NULL;
+	unsigned long flags = 0;
+	int status = -EOPNOTSUPP;	/* operation not supported */
+	unsigned char ep_dir = 0, ep_num = 0;
+	struct fsl_udc *udc = NULL;
+
+	ep = container_of(_ep, struct fsl_ep, ep);
+	udc = ep->udc;
+	if (!_ep || !ep->desc) {
+		status = -EINVAL;
+		goto out;
+	}
+	if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN)) {
+		status = -ESHUTDOWN;
+		goto out;
+	}
+
+	if (usb_endpoint_xfer_isoc(ep->desc)) {
+		status = -EOPNOTSUPP;
+		goto out;
+	}
+
+	/* Attempt to halt IN ep will fail if any transfer requests
+	 * are still queue */
+	if (value && ep_is_in(ep) && !list_empty(&ep->queue)) {
+		status = -EAGAIN;
+		goto out;
+	}
+
+	status = 0;
+	ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV;
+	ep_num = (unsigned char)(ep_index(ep));
+	spin_lock_irqsave(&ep->udc->lock, flags);
+	dr_ep_change_stall(ep_num, ep_dir, value);
+	spin_unlock_irqrestore(&ep->udc->lock, flags);
+
+	if (ep_index(ep) == 0) {
+		udc->ep0_dir = 0;
+	}
+out:
+	VDBG(" %s %s halt stat %d", ep->ep.name,
+			value ?  "set" : "clear", status);
+
+	return status;
+}
+
+static int arcotg_fifo_status(struct usb_ep *_ep)
+{
+	struct fsl_ep *ep;
+	struct fsl_udc *udc;
+	int size = 0;
+	u32 bitmask;
+	struct ep_queue_head *d_qh;
+
+	ep = container_of(_ep, struct fsl_ep, ep);
+	if (!_ep || (!ep->desc && ep_index(ep) != 0))
+		return -ENODEV;
+
+	udc = (struct fsl_udc *)ep->udc;
+
+	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	d_qh = &ep->udc->ep_qh[ep_index(ep) * 2 + ep_is_in(ep)];
+
+	bitmask = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) :
+	    (1 << (ep_index(ep)));
+
+	if (fsl_readl(&dr_regs->endptstatus) & bitmask)
+		size = (d_qh->size_ioc_int_sts & DTD_PACKET_SIZE)
+		    >> DTD_LENGTH_BIT_POS;
+
+	pr_debug("%s %u\n", __func__, size);
+	return size;
+}
+
+static void fsl_ep_fifo_flush(struct usb_ep *_ep)
+{
+	struct fsl_ep *ep;
+	int ep_num, ep_dir;
+	u32 bits;
+	unsigned long timeout;
+#define FSL_UDC_FLUSH_TIMEOUT 1000 /* msec */
+
+	if (!_ep) {
+		return;
+	} else {
+		ep = container_of(_ep, struct fsl_ep, ep);
+		if (!ep->desc)
+			return;
+	}
+	ep_num = ep_index(ep);
+	ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV;
+
+	if (ep_num == 0)
+		bits = (1 << 16) | 1;
+	else if (ep_dir == USB_SEND)
+		bits = 1 << (16 + ep_num);
+	else
+		bits = 1 << ep_num;
+
+	timeout = get_timer(0) + FSL_UDC_FLUSH_TIMEOUT;
+	do {
+		fsl_writel(bits, &dr_regs->endptflush);
+
+		/* Wait until flush complete */
+		while (fsl_readl(&dr_regs->endptflush)) {
+			if (get_timer(0) > timeout) {
+				ERR("ep flush timeout\n");
+				return;
+			}
+		}
+		/* See if we need to flush again */
+	} while (fsl_readl(&dr_regs->endptstatus) & bits);
+}
+
+static struct usb_ep_ops fsl_ep_ops = {
+	.enable = fsl_ep_enable,
+	.disable = fsl_ep_disable,
+
+	.alloc_request = fsl_alloc_request,
+	.free_request = fsl_free_request,
+
+	.queue = fsl_ep_queue,
+	.dequeue = fsl_ep_dequeue,
+
+	.set_halt = fsl_ep_set_halt,
+	.fifo_status = arcotg_fifo_status,
+	.fifo_flush = fsl_ep_fifo_flush,	/* flush fifo */
+};
+
+/*-------------------------------------------------------------------------
+		Gadget Driver Layer Operations
+-------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------
+ * Get the current frame number (from DR frame_index Reg )
+ *----------------------------------------------------------------------*/
+static int fsl_get_frame(struct usb_gadget *gadget)
+{
+	return (int)(fsl_readl(&dr_regs->frindex) & USB_FRINDEX_MASKS);
+}
+
+/*-----------------------------------------------------------------------
+ * Tries to wake up the host connected to this gadget
+ -----------------------------------------------------------------------*/
+static int fsl_wakeup(struct usb_gadget *gadget)
+{
+	struct fsl_udc *udc = container_of(gadget, struct fsl_udc, gadget);
+	u32 portsc;
+
+	/* Remote wakeup feature not enabled by host */
+	if (!udc->remote_wakeup)
+		return -ENOTSUPP;
+
+	portsc = fsl_readl(&dr_regs->portsc1);
+	/* not suspended? */
+	if (!(portsc & PORTSCX_PORT_SUSPEND))
+		return 0;
+	/* trigger force resume */
+	portsc |= PORTSCX_PORT_FORCE_RESUME;
+	fsl_writel(portsc, &dr_regs->portsc1);
+	return 0;
+}
+
+static int can_pullup(struct fsl_udc *udc)
+{
+	return udc->driver && udc->softconnect && udc->vbus_active;
+}
+
+/* Notify controller that VBUS is powered, Called by whatever
+   detects VBUS sessions */
+static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+	struct fsl_udc	*udc;
+	unsigned long	flags;
+
+	udc = container_of(gadget, struct fsl_udc, gadget);
+	spin_lock_irqsave(&udc->lock, flags);
+	VDBG("VBUS %s\n", is_active ? "on" : "off");
+	udc->vbus_active = (is_active != 0);
+	if (can_pullup(udc))
+		fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
+				&dr_regs->usbcmd);
+	else
+		fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP),
+				&dr_regs->usbcmd);
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return 0;
+}
+
+/* constrain controller's VBUS power usage
+ * This call is used by gadget drivers during SET_CONFIGURATION calls,
+ * reporting how much power the device may consume.  For example, this
+ * could affect how quickly batteries are recharged.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+	struct fsl_udc *udc;
+	struct fsl_usb2_platform_data *pdata;
+
+	udc = container_of(gadget, struct fsl_udc, gadget);
+	//if (udc->transceiver)
+		//return otg_set_power(udc->transceiver, mA);
+	pdata = udc->pdata;
+	if (pdata->xcvr_ops && pdata->xcvr_ops->set_vbus_draw) {
+		pdata->xcvr_ops->set_vbus_draw(pdata->xcvr_ops, pdata, mA);
+		return 0;
+	}
+	return -ENOTSUPP;
+}
+
+/* Change Data+ pullup status
+ * this func is used by usb_gadget_connect/disconnet
+ */
+static int fsl_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct fsl_udc *udc;
+
+	udc = container_of(gadget, struct fsl_udc, gadget);
+	udc->softconnect = (is_on != 0);
+	if (can_pullup(udc))
+		fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
+				&dr_regs->usbcmd);
+	else
+		fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP),
+				&dr_regs->usbcmd);
+
+	return 0;
+}
+
+/*
+ * The USB PHY/Charger driver can't visit usb_gadget directly, so
+ * supply a wrapped function for usb charger visiting.
+ */
+static void usb_charger_pullup_dp(bool enable)
+{
+	fsl_pullup(&udc_controller->gadget, (int)enable);
+}
+
+/* defined in gadget.h */
+static struct usb_gadget_ops fsl_gadget_ops = {
+	.get_frame = fsl_get_frame,
+	.wakeup = fsl_wakeup,
+/*	.set_selfpowered = fsl_set_selfpowered,	*/ /* Always selfpowered */
+	.vbus_session = fsl_vbus_session,
+	.vbus_draw = fsl_vbus_draw,
+	.pullup = fsl_pullup,
+};
+
+/* Set protocol stall on ep0, protocol stall will automatically be cleared
+   on new transaction */
+static void ep0stall(struct fsl_udc *udc)
+{
+	u32 tmp;
+
+	/* must set tx and rx to stall at the same time */
+	tmp = fsl_readl(&dr_regs->endptctrl[0]);
+	tmp |= EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL;
+	fsl_writel(tmp, &dr_regs->endptctrl[0]);
+	udc->ep0_dir = 0;
+}
+
+/* Prime a status phase for ep0 */
+static int ep0_prime_status(struct fsl_udc *udc, int direction)
+{
+	struct fsl_req *req = udc->status_req;
+	struct fsl_ep *ep;
+	int status = 0;
+
+	if (direction == EP_DIR_IN)
+		udc->ep0_dir = USB_DIR_IN;
+	else
+		udc->ep0_dir = USB_DIR_OUT;
+
+	ep = &udc->eps[0];
+
+	req->ep = ep;
+	req->req.length = 0;
+	req->req.status = -EINPROGRESS;
+
+	status = fsl_ep_queue(&ep->ep, &req->req, GFP_ATOMIC);
+	return status;
+}
+
+static inline int udc_reset_ep_queue(struct fsl_udc *udc, u8 pipe)
+{
+	struct fsl_ep *ep = get_ep_by_pipe(udc, pipe);
+
+	if (!ep->name)
+		return 0;
+
+	nuke(ep, -ESHUTDOWN);
+
+	return 0;
+}
+
+/*
+ * ch9 Set address
+ */
+static void ch9setaddress(struct fsl_udc *udc, u16 value, u16 index, u16 length)
+{
+	/* Save the new address to device struct */
+	udc->device_address = (u8) value;
+	/* Update usb state */
+	udc->usb_state = USB_STATE_ADDRESS;
+
+	/* for USB CV 3.0 test, the gap between the ACK of the set_address
+	 * and the subsequently setup packet may be very little, say 500us,
+	 * and if the latency we handle the ep completion is greater than
+	 * this gap, there is no response to the subsequent setup packet.
+	 * It will cause the CV test fail */
+	/* There is another way to set address, we can set the bit 24 to
+	 * 1 to make IC set this address instead of SW, it is more fast
+	 * and safe than SW way */
+	fsl_writel(udc->device_address << USB_DEVICE_ADDRESS_BIT_POS |
+			1 << USB_DEVICE_ADDRESS_ADV_BIT_POS,
+			&dr_regs->deviceaddr);
+
+	/* Status phase */
+	if (ep0_prime_status(udc, EP_DIR_IN))
+		ep0stall(udc);
+}
+
+/*
+ * ch9 Get status
+ */
+static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
+		u16 index, u16 length)
+{
+	u16 tmp = 0;		/* Status, cpu endian */
+
+	struct fsl_req *req;
+	struct fsl_ep *ep;
+	int status = 0;
+
+	ep = &udc->eps[0];
+
+	if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+		/* Get device status */
+		tmp = 1 << USB_DEVICE_SELF_POWERED;
+		tmp |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP;
+	} else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
+		/* Get interface status */
+		/* We don't have interface information in udc driver */
+		tmp = 0;
+	} else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) {
+		/* Get endpoint status */
+		struct fsl_ep *target_ep;
+
+		target_ep = get_ep_by_pipe(udc, get_pipe_by_windex(index));
+
+		/* stall if endpoint doesn't exist */
+		if (!target_ep->desc)
+			goto stall;
+		tmp = dr_ep_get_stall(ep_index(target_ep), ep_is_in(target_ep))
+				<< USB_ENDPOINT_HALT;
+	}
+
+	udc->ep0_dir = USB_DIR_IN;
+	/* Borrow the per device data_req */
+	/* status_req had been used to prime status */
+	req = udc->data_req;
+	/* Fill in the reqest structure */
+	*((u16 *) req->req.buf) = cpu_to_le16(tmp);
+	req->ep = ep;
+	req->req.length = 2;
+
+	status = fsl_ep_queue(&ep->ep, &req->req, GFP_ATOMIC);
+	if (status) {
+		udc_reset_ep_queue(udc, 0);
+		ERR("Can't respond to getstatus request \n");
+		goto stall;
+	}
+	/* Status phase */
+	if (ep0_prime_status(udc, EP_DIR_OUT))
+		ep0stall(udc);
+	return;
+stall:
+	ep0stall(udc);
+
+}
+
+static void setup_received_irq(struct fsl_udc *udc,
+		struct usb_ctrlrequest *setup)
+{
+	u16 wValue = le16_to_cpu(setup->wValue);
+	u16 wIndex = le16_to_cpu(setup->wIndex);
+	u16 wLength = le16_to_cpu(setup->wLength);
+	struct usb_gadget *gadget = &(udc->gadget);
+	unsigned mA = 500;
+	udc_reset_ep_queue(udc, 0);
+
+	/* We process some stardard setup requests here */
+	switch (setup->bRequest) {
+	case USB_REQ_GET_STATUS:
+		/* Data+Status phase from udc */
+		if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK))
+					!= (USB_DIR_IN | USB_TYPE_STANDARD))
+			break;
+		spin_unlock(&udc->lock);
+		ch9getstatus(udc, setup->bRequestType, wValue, wIndex, wLength);
+		spin_lock(&udc->lock);
+		return;
+
+	case USB_REQ_SET_ADDRESS:
+		/* Status phase from udc */
+		if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD
+						| USB_RECIP_DEVICE))
+			break;
+		spin_unlock(&udc->lock);
+		ch9setaddress(udc, wValue, wIndex, wLength);
+		spin_lock(&udc->lock);
+		return;
+	case USB_REQ_SET_CONFIGURATION:
+		spin_unlock(&udc->lock);
+		fsl_vbus_draw(gadget, mA);
+		spin_lock(&udc->lock);
+	     break;
+	case USB_REQ_CLEAR_FEATURE:
+	case USB_REQ_SET_FEATURE:
+		/* Status phase from udc */
+	{
+		int rc = -EOPNOTSUPP;
+		u16 ptc = 0;
+
+		if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK))
+				== (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) {
+			int pipe = get_pipe_by_windex(wIndex);
+			struct fsl_ep *ep;
+
+			if (wValue != 0 || wLength != 0 || pipe >= (udc->max_ep / 2))
+				break;
+			ep = get_ep_by_pipe(udc, pipe);
+
+			spin_unlock(&udc->lock);
+			rc = fsl_ep_set_halt(&ep->ep,
+					(setup->bRequest == USB_REQ_SET_FEATURE)
+						? 1 : 0);
+			spin_lock(&udc->lock);
+
+		} else if ((setup->bRequestType & (USB_RECIP_MASK
+				| USB_TYPE_MASK)) == (USB_RECIP_DEVICE
+				| USB_TYPE_STANDARD)) {
+			/* Note: The driver has not include OTG support yet.
+			 * This will be set when OTG support is added */
+			if (setup->wValue == USB_DEVICE_TEST_MODE)
+				ptc = setup->wIndex >> 8;
+			else if (setup->wValue == USB_DEVICE_REMOTE_WAKEUP) {
+				if (setup->bRequest == USB_REQ_SET_FEATURE)
+					udc->remote_wakeup = 1;
+				else
+					udc->remote_wakeup = 0;
+			}
+			else if (gadget_is_otg(&udc->gadget)) {
+				if (setup->bRequest ==
+				    USB_DEVICE_B_HNP_ENABLE)
+					udc->gadget.b_hnp_enable = 1;
+				else if (setup->bRequest ==
+					 USB_DEVICE_A_HNP_SUPPORT)
+					udc->gadget.a_hnp_support = 1;
+				else if (setup->bRequest ==
+					 USB_DEVICE_A_ALT_HNP_SUPPORT)
+					udc->gadget.a_alt_hnp_support = 1;
+				else
+					break;
+			} else {
+				break;
+			}
+			rc = 0;
+		} else
+			break;
+
+		if (rc == 0) {
+			spin_unlock(&udc->lock);
+			if (ep0_prime_status(udc, EP_DIR_IN))
+				ep0stall(udc);
+			spin_lock(&udc->lock);
+		}
+		if (ptc) {
+			u32 tmp;
+
+			mdelay(10);
+			//fsl_platform_set_test_mode(udc->pdata, ptc);
+			tmp = fsl_readl(&dr_regs->portsc1) | (ptc << 16);
+			fsl_writel(tmp, &dr_regs->portsc1);
+			printk(KERN_INFO "udc: switch to test mode 0x%x.\n", ptc);
+		}
+
+		return;
+	}
+
+	default:
+		break;
+	}
+
+	/* Requests handled by gadget */
+	if (wLength) {
+		/* Data phase from gadget, status phase from udc */
+		udc->ep0_dir = (setup->bRequestType & USB_DIR_IN)
+				?  USB_DIR_IN : USB_DIR_OUT;
+		spin_unlock(&udc->lock);
+		if (udc->driver->setup(&udc->gadget,
+				&udc->local_setup_buff) < 0) {
+			/* cancel all requests on ep0 */
+			udc_reset_ep_queue(udc, 0);
+			ep0stall(udc);
+		} else {
+			/* prime the status phase */
+			int dir = EP_DIR_IN;
+			if (setup->bRequestType & USB_DIR_IN)
+				dir = EP_DIR_OUT;
+			if (ep0_prime_status(udc, dir))
+				ep0stall(udc);
+		}
+	} else {
+		/* No data phase, IN status from gadget */
+		udc->ep0_dir = USB_DIR_IN;
+		spin_unlock(&udc->lock);
+		if (udc->driver->setup(&udc->gadget,
+				&udc->local_setup_buff) < 0)
+			ep0stall(udc);
+	}
+	spin_lock(&udc->lock);
+}
+
+/* Process request for Data or Status phase of ep0
+ * prime status phase if needed */
+static void ep0_req_complete(struct fsl_udc *udc, struct fsl_ep *ep0,
+		struct fsl_req *req)
+{
+	done(ep0, req, 0);
+}
+
+/* Tripwire mechanism to ensure a setup packet payload is extracted without
+ * being corrupted by another incoming setup packet */
+static void tripwire_handler(struct fsl_udc *udc, u8 ep_num, u8 *buffer_ptr)
+{
+	u32 temp;
+	struct ep_queue_head *qh;
+	struct fsl_usb2_platform_data *pdata = udc->pdata;
+
+	qh = &udc->ep_qh[ep_num * 2 + EP_DIR_OUT];
+
+	/* Clear bit in ENDPTSETUPSTAT */
+	temp = fsl_readl(&dr_regs->endptsetupstat);
+	fsl_writel(temp | (1 << ep_num), &dr_regs->endptsetupstat);
+
+	/* while a hazard exists when setup package arrives */
+	do {
+		/* Set Setup Tripwire */
+		temp = fsl_readl(&dr_regs->usbcmd);
+		fsl_writel(temp | USB_CMD_SUTW, &dr_regs->usbcmd);
+
+		/* Copy the setup packet to local buffer */
+		if (pdata->le_setup_buf) {
+			u32 *p = (u32 *)buffer_ptr;
+			u32 *s = (u32 *)qh->setup_buffer;
+
+			/* Convert little endian setup buffer to CPU endian */
+			*p++ = le32_to_cpu(*s++);
+			*p = le32_to_cpu(*s);
+		} else {
+			memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8);
+		}
+	} while (!(fsl_readl(&dr_regs->usbcmd) & USB_CMD_SUTW));
+
+	/* Clear Setup Tripwire */
+	temp = fsl_readl(&dr_regs->usbcmd);
+	fsl_writel(temp & ~USB_CMD_SUTW, &dr_regs->usbcmd);
+}
+
+static void iram_process_ep_complete(struct fsl_req *curr_req,
+				     int cur_transfer)
+{
+	char *buf;
+	u32 len;
+	int in = ep_is_in(curr_req->ep);
+
+	if (in)
+		buf = (char *)udc_controller->iram_buffer_v[1];
+	else
+		buf = (char *)udc_controller->iram_buffer_v[0];
+
+	if (curr_req->cur->next_td_ptr == cpu_to_hc32(DTD_NEXT_TERMINATE)
+	    || (cur_transfer < g_iram_size)
+	    || (curr_req->req.length == curr_req->req.actual))
+		curr_req->last_one = 1;
+
+	if (curr_req->last_one) {
+		/* the last transfer */
+		if (!in) {
+			memcpy(curr_req->req.buf + curr_req->buffer_offset, buf,
+			       cur_transfer);
+		}
+		if (curr_req->tail->next_td_ptr !=
+				    cpu_to_hc32(DTD_NEXT_TERMINATE)) {
+			/* have next request,queue it */
+			struct fsl_req *next_req;
+			next_req =
+			    list_entry(curr_req->queue.next,
+				       struct fsl_req, queue);
+			if (in)
+				memcpy(buf, next_req->req.buf,
+				       min(g_iram_size, next_req->req.length));
+			update_qh(next_req);
+		}
+		curr_req->req.dma = curr_req->oridma;
+	} else {
+		/* queue next dtd */
+		/* because had next dtd, so should finish */
+		/* tranferring g_iram_size data */
+		curr_req->buffer_offset += g_iram_size;
+		/* pervious set stop bit,now clear it */
+		curr_req->cur->next_td_ptr &= ~cpu_to_hc32(DTD_NEXT_TERMINATE);
+		curr_req->cur = curr_req->cur->next_td_virt;
+		if (in) {
+			len =
+			    min(curr_req->req.length - curr_req->buffer_offset,
+				g_iram_size);
+			memcpy(buf, curr_req->req.buf + curr_req->buffer_offset,
+			       len);
+		} else {
+			memcpy(curr_req->req.buf + curr_req->buffer_offset -
+			       g_iram_size, buf, g_iram_size);
+		}
+		update_qh(curr_req);
+	}
+}
+
+/* process-ep_req(): free the completed Tds for this req */
+static int process_ep_req(struct fsl_udc *udc, int pipe,
+		struct fsl_req *curr_req)
+{
+	struct ep_td_struct *curr_td;
+	int	td_complete, actual, remaining_length, j, tmp;
+	int	status = 0;
+	int	errors = 0;
+	struct  ep_queue_head *curr_qh = &udc->ep_qh[pipe];
+	int direction = pipe % 2;
+	int total = 0, real_len;
+
+	curr_td = curr_req->head;
+	td_complete = 0;
+	actual = curr_req->req.length;
+	real_len = curr_req->req.length;
+
+	for (j = 0; j < curr_req->dtd_count; j++) {
+		remaining_length = (hc32_to_cpu(curr_td->size_ioc_sts)
+					& DTD_PACKET_SIZE)
+				>> DTD_LENGTH_BIT_POS;
+		if (NEED_IRAM(curr_req->ep)) {
+			if (real_len >= g_iram_size) {
+				actual = g_iram_size;
+				real_len -= g_iram_size;
+			} else {	/* the last packet */
+				actual = real_len;
+				curr_req->last_one = 1;
+			}
+		}
+		actual -= remaining_length;
+		total += actual;
+
+		errors = hc32_to_cpu(curr_td->size_ioc_sts) & DTD_ERROR_MASK;
+		if (errors) {
+			if (errors & DTD_STATUS_HALTED) {
+				ERR("dTD error %08x QH=%d\n", errors, pipe);
+				/* Clear the errors and Halt condition */
+				tmp = hc32_to_cpu(curr_qh->size_ioc_int_sts);
+				tmp &= ~errors;
+				curr_qh->size_ioc_int_sts = cpu_to_hc32(tmp);
+				status = -EPIPE;
+				/* FIXME: continue with next queued TD? */
+
+				break;
+			}
+			if (errors & DTD_STATUS_DATA_BUFF_ERR) {
+				VDBG("Transfer overflow");
+				status = -EPROTO;
+				break;
+			} else if (errors & DTD_STATUS_TRANSACTION_ERR) {
+				VDBG("ISO error");
+				status = -EILSEQ;
+				break;
+			} else
+				ERR("Unknown error has occured (0x%x)!\r\n",
+					errors);
+
+		} else if (hc32_to_cpu(curr_td->size_ioc_sts)
+				& DTD_STATUS_ACTIVE) {
+			VDBG("Request not complete");
+			status = REQ_UNCOMPLETE;
+			return status;
+		} else if (remaining_length) {
+			if (direction) {
+				VDBG("Transmit dTD remaining length not zero");
+				status = -EPROTO;
+				break;
+			} else {
+				td_complete++;
+				break;
+			}
+		} else {
+			td_complete++;
+			VDBG("dTD transmitted successful ");
+		}
+		if (NEED_IRAM(curr_req->ep))
+			if (curr_td->
+			    next_td_ptr & cpu_to_hc32(DTD_NEXT_TERMINATE))
+				break;
+		if (j != curr_req->dtd_count - 1)
+			curr_td = (struct ep_td_struct *)curr_td->next_td_virt;
+	}
+
+	if (status)
+		return status;
+	curr_req->req.actual = total;
+	if (NEED_IRAM(curr_req->ep))
+		iram_process_ep_complete(curr_req, actual);
+	return 0;
+}
+
+/* Process a DTD completion interrupt */
+static void dtd_complete_irq(struct fsl_udc *udc)
+{
+	u32 bit_pos;
+	int i, ep_num, direction, bit_mask, status;
+	struct fsl_ep *curr_ep;
+	struct fsl_req *curr_req, *temp_req;
+
+	/* Clear the bits in the register */
+	bit_pos = fsl_readl(&dr_regs->endptcomplete);
+	fsl_writel(bit_pos, &dr_regs->endptcomplete);
+
+	if (!bit_pos)
+		return;
+
+	for (i = 0; i < udc->max_ep; i++) {
+		ep_num = i >> 1;
+		direction = i % 2;
+
+		bit_mask = 1 << (ep_num + 16 * direction);
+
+		if (!(bit_pos & bit_mask))
+			continue;
+
+		curr_ep = get_ep_by_pipe(udc, i);
+
+		/* If the ep is configured */
+		if (curr_ep->name == NULL) {
+			INFO("Invalid EP?");
+			continue;
+		}
+
+		/* process the req queue until an uncomplete request */
+		list_for_each_entry_safe(curr_req, temp_req, &curr_ep->queue,
+				queue) {
+			status = process_ep_req(udc, i, curr_req);
+
+			VDBG("status of process_ep_req= %d, ep = %d",
+					status, ep_num);
+			if (status == REQ_UNCOMPLETE)
+				break;
+			/* write back status to req */
+			curr_req->req.status = status;
+
+			if (ep_num == 0) {
+				ep0_req_complete(udc, curr_ep, curr_req);
+				break;
+			} else {
+				if (NEED_IRAM(curr_ep)) {
+					if (curr_req->last_one)
+						done(curr_ep, curr_req, status);
+					/* only check the 1th req */
+					break;
+				} else
+					done(curr_ep, curr_req, status);
+			}
+		}
+		dump_ep_queue(curr_ep);
+	}
+}
+
+static void fsl_udc_speed_update(struct fsl_udc *udc)
+{
+	u32 speed = 0;
+	u32 loop = 0;
+
+	/* Wait for port reset finished */
+	while ((fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)
+		&& (loop++ < 1000))
+		;
+
+	speed = (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_SPEED_MASK);
+	switch (speed) {
+	case PORTSCX_PORT_SPEED_HIGH:
+		udc->gadget.speed = USB_SPEED_HIGH;
+		break;
+	case PORTSCX_PORT_SPEED_FULL:
+		udc->gadget.speed = USB_SPEED_FULL;
+		break;
+	case PORTSCX_PORT_SPEED_LOW:
+		udc->gadget.speed = USB_SPEED_LOW;
+		break;
+	default:
+		udc->gadget.speed = USB_SPEED_UNKNOWN;
+		break;
+	}
+}
+
+/* Process a port change interrupt */
+static void port_change_irq(struct fsl_udc *udc)
+{
+	if (udc->bus_reset)
+		udc->bus_reset = 0;
+
+	/* Update port speed */
+	fsl_udc_speed_update(udc);
+
+	/* Update USB state */
+	if (!udc->resume_state)
+		udc->usb_state = USB_STATE_DEFAULT;
+}
+
+/* Process suspend interrupt */
+static void suspend_irq(struct fsl_udc *udc)
+{
+	pr_debug("%s begins\n", __func__);
+
+	udc->resume_state = udc->usb_state;
+	udc->usb_state = USB_STATE_SUSPENDED;
+
+	/* report suspend to the driver, serial.c does not support this */
+	if (udc->driver->suspend)
+		udc->driver->suspend(&udc->gadget);
+
+	pr_debug("%s ends\n", __func__);
+}
+
+static void bus_resume(struct fsl_udc *udc)
+{
+	udc->usb_state = udc->resume_state;
+	udc->resume_state = 0;
+
+	/* report resume to the driver, serial.c does not support this */
+	if (udc->driver->resume)
+		udc->driver->resume(&udc->gadget);
+}
+
+/* Clear up all ep queues */
+static int reset_queues(struct fsl_udc *udc)
+{
+	u8 pipe;
+
+	for (pipe = 0; pipe < udc->max_pipes; pipe++)
+		udc_reset_ep_queue(udc, pipe);
+
+	spin_unlock(&udc->lock);
+	/* report disconnect; the driver is already quiesced */
+	udc->driver->disconnect(&udc->gadget);
+	spin_lock(&udc->lock);
+
+	return 0;
+}
+
+/* Process reset interrupt */
+static void reset_irq(struct fsl_udc *udc)
+{
+	u32 temp;
+
+	/* Clear the device address */
+	temp = fsl_readl(&dr_regs->deviceaddr);
+	fsl_writel(temp & ~USB_DEVICE_ADDRESS_MASK, &dr_regs->deviceaddr);
+
+	udc->device_address = 0;
+
+	/* Clear usb state */
+	udc->resume_state = 0;
+	udc->ep0_dir = 0;
+	udc->remote_wakeup = 0;	/* default to 0 on reset */
+	udc->gadget.b_hnp_enable = 0;
+	udc->gadget.a_hnp_support = 0;
+	udc->gadget.a_alt_hnp_support = 0;
+
+	/* Clear all the setup token semaphores */
+	temp = fsl_readl(&dr_regs->endptsetupstat);
+	fsl_writel(temp, &dr_regs->endptsetupstat);
+
+	/* Clear all the endpoint complete status bits */
+	temp = fsl_readl(&dr_regs->endptcomplete);
+	fsl_writel(temp, &dr_regs->endptcomplete);
+
+	/* Write 1s to the flush register */
+	fsl_writel(0xffffffff, &dr_regs->endptflush);
+
+	/* Bus is reseting */
+	udc->bus_reset = 1;
+	/* Reset all the queues, include XD, dTD, EP queue
+	 * head and TR Queue */
+	reset_queues(udc);
+	udc->usb_state = USB_STATE_DEFAULT;
+}
+
+#define FSL_DP_CHANGE_TIMEOUT 1000 /* 1000 ms */
+static void gadget_wait_line_to_se0(void)
+{
+	unsigned long timeout;
+	timeout = get_timer(0) + FSL_DP_CHANGE_TIMEOUT;
+	/* Wait for DP to SE0 */
+	while (!((fsl_readl(&dr_regs->portsc1) &
+		(u32)((1 << 10) | (1 << 11))) == PORTSCX_LINE_STATUS_SE0)) {
+		if (get_timer(0) > timeout) {
+			pr_warning(KERN_ERR "wait dp to SE0 timeout, please check"
+					" your hardware design!\n");
+			break;
+		}
+		mdelay(1);
+	}
+}
+
+#define FSL_WAIT_CLASS_DRIVER_TIMEOUT 3000 /* 3s */
+static void gadget_wait_class_driver_finish(void)
+{
+	unsigned long timeout;
+	struct fsl_udc *udc = udc_controller;
+	struct fsl_ep *ep;
+	int i = 2;
+	timeout = get_timer(0) + FSL_WAIT_CLASS_DRIVER_TIMEOUT;
+	/* for non-control endpoints */
+	while (i < (int)(udc_controller->max_ep)) {
+		ep = &udc->eps[i++];
+		if (ep->stopped == 0) {
+			if (get_timer(0) > timeout) {
+				i = 2;
+				mdelay(10);
+				continue;
+			} else {
+				pr_warning(KERN_WARNING "We have waited 3s, but the class driver"
+						" has still not finishes!\n");
+				break;
+			}
+		}
+	}
+}
+
+static void fsl_gadget_disconnect_event(void)
+{
+	struct fsl_udc *udc = udc_controller;
+	unsigned long flags;
+	struct fsl_usb2_platform_data *pdata;
+	u32 tmp;
+
+	pdata = udc->pdata;
+
+	/* wait line to se0 */
+	dr_discharge_line(pdata, true);
+	/*
+	 * Wait class drivers finish, an well-behaviour class driver should
+	 * call ep_disable when it is notified to be disconnected.
+	 */
+	gadget_wait_class_driver_finish();
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/* here we need to enable the B_SESSION_IRQ
+	 * to enable the following device attach
+	 */
+	tmp = fsl_readl(&dr_regs->otgsc);
+	if (!(tmp & (OTGSC_B_SESSION_VALID_IRQ_EN)))
+		fsl_writel(tmp | (OTGSC_B_SESSION_VALID_IRQ_EN),
+				&dr_regs->otgsc);
+	udc->stopped = 1;
+	spin_unlock_irqrestore(&udc->lock, flags);
+	/* enable wake up */
+	dr_wake_up_enable(udc, true);
+	/* close USB PHY clock */
+	dr_phy_low_power_mode(udc, true);
+	/* close dr controller clock */
+	dr_clk_gate(false);
+	printk(KERN_DEBUG "%s: udc enter low power mode\n", __func__);
+}
+
+/* if wakup udc, return true; else return false*/
+bool try_wake_up_udc(struct fsl_udc *udc)
+{
+	struct fsl_usb2_platform_data *pdata;
+	u32 irq_src;
+
+	pdata = udc->pdata;
+
+	/* check if Vbus change irq */
+	irq_src = fsl_readl(&dr_regs->otgsc) & (~OTGSC_ID_CHANGE_IRQ_STS);
+	if (irq_src & OTGSC_B_SESSION_VALID_IRQ_STS) {
+		u32 tmp;
+		/* Only handle device interrupt event
+		 * For mx53 loco board, the debug ID value is 0 and
+		 * DO NOT support OTG function
+		 */
+		if (!machine_is_mx53_loco())
+			if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID))
+				return false;
+
+		fsl_writel(irq_src, &dr_regs->otgsc);
+
+		tmp = fsl_readl(&dr_regs->usbcmd);
+		/* check BSV bit to see if fall or rise */
+		if (irq_src & OTGSC_B_SESSION_VALID) {
+			if (udc->suspended) /*let the system pm resume the udc */
+				return true;
+			udc->vbus_active = true;
+			udc->stopped = 0;
+			/* disable pulldown dp and dm */
+			dr_discharge_line(pdata, false);
+		} else {
+			udc->vbus_active = false;
+			fsl_pullup(&udc_controller->gadget, false); /* usbcmd.rs=0 */
+			/* here we need disable B_SESSION_IRQ, after
+			 * schedule_work finished, it need to be enabled again.
+			 * Doing like this can avoid conflicting between rapid
+			 * plug in/out.
+			 */
+			tmp = fsl_readl(&dr_regs->otgsc);
+			if (tmp & (OTGSC_B_SESSION_VALID_IRQ_EN))
+				fsl_writel(tmp &
+					   (~OTGSC_B_SESSION_VALID_IRQ_EN),
+					   &dr_regs->otgsc);
+			/* update port status */
+			fsl_udc_speed_update(udc);
+			spin_unlock(&udc->lock);
+			if (udc->driver)
+				udc->driver->disconnect(&udc->gadget);
+			spin_lock(&udc->lock);
+			return false;
+		}
+	}
+
+	return true;
+}
+/*
+ * USB device controller interrupt handler
+ */
+static irqreturn_t fsl_udc_irq(int irq, void *_udc)
+{
+	struct fsl_udc *udc = _udc;
+	u32 irq_src;
+	irqreturn_t status = IRQ_NONE;
+	unsigned long flags;
+	struct fsl_usb2_platform_data *pdata = udc->pdata;
+
+	if (pdata->irq_delay)
+		return status;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+#ifdef CONFIG_USB_OTG
+	/* if no gadget register in this driver, we need do noting */
+	if (udc->transceiver->gadget == NULL) {
+		goto irq_end;
+	}
+	/* only handle device interrupt event */
+	if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) {
+		goto irq_end;
+	}
+#endif
+	if (try_wake_up_udc(udc) == false) {
+		goto irq_end;
+	}
+	irq_src = fsl_readl(&dr_regs->usbsts) & fsl_readl(&dr_regs->usbintr);
+	/* Clear notification bits */
+	fsl_writel(irq_src, &dr_regs->usbsts);
+
+	/* only handle enabled interrupt */
+	if (irq_src == 0x0)
+		goto irq_end;
+
+	VDBG("0x%x\n", irq_src);
+
+	/* Need to resume? */
+	if (udc->usb_state == USB_STATE_SUSPENDED)
+		if ((fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_SUSPEND) == 0)
+			bus_resume(udc);
+
+	/* USB Interrupt */
+	if (irq_src & USB_STS_INT) {
+		VDBG("Packet int");
+		/* Setup package, we only support ep0 as control ep */
+		if (fsl_readl(&dr_regs->endptsetupstat) & EP_SETUP_STATUS_EP0) {
+			tripwire_handler(udc, 0,
+					(u8 *) (&udc->local_setup_buff));
+			setup_received_irq(udc, &udc->local_setup_buff);
+			status = IRQ_HANDLED;
+		}
+
+		/* completion of dtd */
+		if (fsl_readl(&dr_regs->endptcomplete)) {
+			dtd_complete_irq(udc);
+			status = IRQ_HANDLED;
+		}
+	}
+
+	/* SOF (for ISO transfer) */
+	if (irq_src & USB_STS_SOF) {
+		status = IRQ_HANDLED;
+	}
+
+	/* Port Change */
+	if (irq_src & USB_STS_PORT_CHANGE) {
+		port_change_irq(udc);
+		status = IRQ_HANDLED;
+	}
+
+	/* Reset Received */
+	if (irq_src & USB_STS_RESET) {
+		VDBG("reset int");
+		reset_irq(udc);
+		status = IRQ_HANDLED;
+	}
+
+	/* Sleep Enable (Suspend) */
+	if (irq_src & USB_STS_SUSPEND) {
+		VDBG("suspend int");
+		if (!(udc->usb_state == USB_STATE_SUSPENDED))
+			suspend_irq(udc);
+		status = IRQ_HANDLED;
+	}
+
+	if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) {
+		VDBG("Error IRQ %x ", irq_src);
+	}
+
+irq_end:
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return status;
+}
+
+/*----------------------------------------------------------------*
+ * Hook to gadget drivers
+ * Called by initialization code of gadget drivers
+*----------------------------------------------------------------*/
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	int retval = -ENODEV;
+	unsigned long flags = 0;
+
+	if (!udc_controller)
+		return -ENODEV;
+
+	if (!driver || !driver->bind || (driver->speed != USB_SPEED_FULL
+			&& driver->speed != USB_SPEED_HIGH)
+			|| !driver->disconnect
+			|| !driver->setup)
+		return -EINVAL;
+
+	if (udc_controller->driver)
+		return -EBUSY;
+
+	/* lock is needed but whether should use this lock or another */
+	spin_lock_irqsave(&udc_controller->lock, flags);
+
+	//driver->driver.bus = 0;
+	udc_controller->pdata->port_enables = 1;
+	/* hook up the driver */
+	udc_controller->driver = driver;
+	//udc_controller->gadget.dev.driver = &driver->driver;
+	spin_unlock_irqrestore(&udc_controller->lock, flags);
+	dr_clk_gate(true);
+
+	/* bind udc driver to gadget driver */
+	retval = driver->bind(&udc_controller->gadget);
+	if (retval) {
+		VDBG("bind to %s --> %d", driver->driver.name, retval);
+		//udc_controller->gadget.dev.driver = 0;
+		udc_controller->driver = 0;
+		dr_clk_gate(false);
+		goto out;
+	}
+	if (0) {
+#if 0
+	if (udc_controller->transceiver) {
+		printk(KERN_INFO "Suspend udc for OTG auto detect\n");
+		udc_controller->suspended = 1;
+		dr_wake_up_enable(udc_controller, true);
+		dr_clk_gate(false);
+		/* export udc suspend/resume call to OTG */
+		udc_controller->gadget.dev.driver->suspend = (dev_sus)fsl_udc_suspend;
+		udc_controller->gadget.dev.driver->resume = (dev_res)fsl_udc_resume;
+
+		/* connect to bus through transceiver */
+		retval = otg_set_peripheral(udc_controller->transceiver,
+					    &udc_controller->gadget);
+		if (retval < 0) {
+			ERR("can't bind to transceiver\n");
+			driver->unbind(&udc_controller->gadget);
+			udc_controller->gadget.dev.driver = 0;
+			udc_controller->driver = 0;
+			return retval;
+		}
+#endif
+	} else {
+		/* Enable DR IRQ reg and Set usbcmd reg  Run bit */
+		dr_controller_run(udc_controller);
+		if (udc_controller->stopped)
+			dr_clk_gate(false);
+	}
+	printk(KERN_INFO "%s: bind to driver \n",
+			udc_controller->gadget.name);
+
+out:
+	if (retval) {
+		printk(KERN_DEBUG "retval %d \n", retval);
+		udc_controller->pdata->port_enables = 0;
+	}
+	return retval;
+}
+EXPORT_SYMBOL(usb_gadget_probe_driver);
+
+/* Disconnect from gadget driver */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct fsl_ep *loop_ep;
+	unsigned long flags;
+
+	if (!udc_controller)
+		return -ENODEV;
+
+	if (!driver || driver != udc_controller->driver || !driver->unbind)
+		return -EINVAL;
+
+	if (udc_controller->stopped)
+		dr_clk_gate(true);
+
+#if 0
+	if (udc_controller->transceiver)
+		(void)otg_set_peripheral(udc_controller->transceiver, 0);
+#endif
+
+	/* stop DR, disable intr */
+	dr_controller_stop(udc_controller);
+
+	udc_controller->pdata->port_enables = 0;
+	/* in fact, no needed */
+	udc_controller->usb_state = USB_STATE_ATTACHED;
+	udc_controller->ep0_dir = 0;
+
+	/* stand operation */
+	spin_lock_irqsave(&udc_controller->lock, flags);
+	udc_controller->gadget.speed = USB_SPEED_UNKNOWN;
+	nuke(&udc_controller->eps[0], -ESHUTDOWN);
+	list_for_each_entry(loop_ep, &udc_controller->gadget.ep_list,
+			ep.ep_list)
+		nuke(loop_ep, -ESHUTDOWN);
+	spin_unlock_irqrestore(&udc_controller->lock, flags);
+
+	/* disconnect gadget before unbinding */
+	driver->disconnect(&udc_controller->gadget);
+
+	/* unbind gadget and unhook driver. */
+	driver->unbind(&udc_controller->gadget);
+	//udc_controller->gadget.dev.driver = 0;
+	udc_controller->driver = 0;
+
+	if (udc_controller->gadget.is_otg) {
+		dr_wake_up_enable(udc_controller, true);
+	}
+
+	dr_phy_low_power_mode(udc_controller, true);
+
+	dr_clk_gate(false);
+	printk(KERN_INFO "unregistered gadget driver \r\n");
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/* Release udc structures */
+static void fsl_udc_release(struct device *dev)
+{
+	free(udc_controller->ep_qh);
+	kfree(udc_controller);
+	udc_controller = NULL;
+}
+
+/******************************************************************
+	Internal structure setup functions
+*******************************************************************/
+/*------------------------------------------------------------------
+ * init resource for globle controller
+ * Return the udc handle on success or NULL on failure
+ ------------------------------------------------------------------*/
+static int __init struct_udc_setup(struct fsl_udc *udc,
+		struct fsl_usb2_platform_data *pdata)
+{
+	size_t size;
+
+	udc->phy_mode = pdata->phy_mode;
+
+	udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL);
+	if (!udc->eps) {
+		ERR("malloc fsl_ep failed\n");
+		return -1;
+	}
+
+	/* initialized QHs, take care of alignment */
+	size = udc->max_ep * sizeof(struct ep_queue_head);
+	if (size < QH_ALIGNMENT)
+		size = QH_ALIGNMENT;
+	else if ((size % QH_ALIGNMENT) != 0) {
+		size += QH_ALIGNMENT + 1;
+		size &= ~(QH_ALIGNMENT - 1);
+	}
+	udc->ep_qh = malloc(size);
+	if (!udc->ep_qh) {
+		ERR("malloc QHs for udc failed\n");
+		kfree(udc->eps);
+		return -1;
+	}
+
+	udc->ep_qh_size = size;
+
+	/* Initialize ep0 status request structure */
+	/* FIXME: fsl_alloc_request() ignores ep argument */
+	udc->status_req = container_of(fsl_alloc_request(NULL, GFP_KERNEL),
+			struct fsl_req, req);
+	/* allocate a small amount of memory to get valid address */
+	udc->status_req->req.buf = kmalloc(8, GFP_KERNEL);
+	udc->status_req->req.dma = virt_to_phys(udc->status_req->req.buf);
+	/* Initialize ep0 data request structure */
+	udc->data_req = container_of(fsl_alloc_request(NULL, GFP_KERNEL),
+			struct fsl_req, req);
+	udc->data_req->req.buf = kmalloc(8, GFP_KERNEL);
+	udc->data_req->req.dma = virt_to_phys(udc->data_req->req.buf);
+
+	udc->resume_state = USB_STATE_NOTATTACHED;
+	udc->usb_state = USB_STATE_POWERED;
+	udc->ep0_dir = 0;
+	udc->remote_wakeup = 0;	/* default to 0 on reset */
+	spin_lock_init(&udc->lock);
+
+	return 0;
+}
+
+/*----------------------------------------------------------------
+ * Setup the fsl_ep struct for eps
+ * Link fsl_ep->ep to gadget->ep_list
+ * ep0out is not used so do nothing here
+ * ep0in should be taken care
+ *--------------------------------------------------------------*/
+static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index,
+		char *name, int link)
+{
+	struct fsl_ep *ep = &udc->eps[index];
+
+	ep->udc = udc;
+	strcpy(ep->name, name);
+	ep->ep.name = ep->name;
+
+	ep->ep.ops = &fsl_ep_ops;
+	/*
+	 * For ep0, the endpoint is enabled after controller initialization
+	 * For non-ep0, the endpoint is stopped default, and will be enabled
+	 * by class driver when needed.
+	 */
+	if (index)
+		ep->stopped = 1;
+	else
+		ep->stopped = 0;
+
+	/* for ep0: maxP defined in desc
+	 * for other eps, maxP is set by epautoconfig() called by gadget layer
+	 */
+	ep->ep.maxpacket = (unsigned short) ~0;
+
+	/* the queue lists any req for this ep */
+	INIT_LIST_HEAD(&ep->queue);
+
+	/* gagdet.ep_list used for ep_autoconfig so no ep0 */
+	if (link)
+		list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+	ep->gadget = &udc->gadget;
+	ep->qh = &udc->ep_qh[index];
+
+	return 0;
+}
+
+struct usb_dr_device *get_dr_regs(void)
+{
+	int i;
+	struct usb_dr_device *dr_regs;
+
+	dr_regs = calloc(sizeof(*dr_regs), 1);
+
+	dr_regs->caplength = USB_CAPLENGTH;
+	dr_regs->hciversion = USB_HCIVERSION;
+	dr_regs->hcsparams = USB_HCSPARAMS;
+	dr_regs->hccparams = USB_HCCPARAMS;
+	dr_regs->dciversion = USB_DCIVERSION;
+	dr_regs->dccparams = USB_DCCPARAMS;
+	dr_regs->usbcmd = USB_USBCMD;
+	dr_regs->usbsts = USB_USBSTS;
+	dr_regs->usbintr = USB_USBINTR;
+	dr_regs->frindex = USB_FRINDEX;
+	dr_regs->deviceaddr = USB_DEVICEADDR;
+	dr_regs->endpointlistaddr = USB_ENDPOINTLISTADDR;
+	dr_regs->burstsize = USB_BURSTSIZE;
+	dr_regs->txttfilltuning = USB_TXFILLTUNING;
+	dr_regs->configflag = 0; /* TODO */
+	dr_regs->portsc1 = USB_PORTSC1;
+	dr_regs->otgsc = USB_OTGSC;
+	dr_regs->usbmode = USB_USBMODE;
+	dr_regs->endptsetupstat = USB_ENDPTSETUPSTAT;
+	dr_regs->endpointprime = USB_ENDPTPRIME;
+	dr_regs->endptflush = USB_ENDPTFLUSH;
+	dr_regs->endptstatus = USB_ENDPTSTAT;
+	dr_regs->endptcomplete = USB_ENDPTCOMPLETE;
+	for(i = 0; i < 6; i++)
+		dr_regs->endptctrl[i] = USB_ENDPTCTRL(i);
+
+	return dr_regs;
+}
+
+/* Driver probe function
+ * all intialization operations implemented here except enabling usb_intr reg
+ * board setup should have been done in the platform code
+ */
+int __devinit fsl_udc_probe(struct fsl_usb2_platform_data *pdata)
+{
+	int ret = -ENODEV;
+	unsigned int i;
+	u32 dccparams;
+
+	udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL);
+	if (udc_controller == NULL) {
+		ERR("malloc udc failed\n");
+		return -ENOMEM;
+	}
+	udc_controller->pdata = pdata;
+
+#ifdef CONFIG_USB_OTG
+	/* Memory and interrupt resources will be passed from OTG */
+	udc_controller->transceiver = otg_get_transceiver();
+	if (!udc_controller->transceiver) {
+		printk(KERN_ERR "Can't find OTG driver!\n");
+		ret = -ENODEV;
+		goto err1a;
+	}
+	udc_controller->gadget.is_otg = 1;
+#endif
+	//dr_regs = get_dr_regs();
+	dr_regs = (void *) OTG_BASE_ADDR;
+	if (!dr_regs) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+	pdata->regs = (void *)dr_regs;
+	/*
+	 * do platform specific init: check the clock, grab/config pins, etc.
+	 */
+	//set_usboh3_clk();
+	set_usb_phy1_clk();
+	enable_usboh3_clk(1);
+	enable_usb_phy1_clk(1);
+#if 0
+	if (pdata->init && pdata->init(pdata)) {
+		pdata->lowpower = false;
+		ret = -ENODEV;
+		goto err2a;
+	}
+#endif
+	spin_lock_init(&pdata->lock);
+
+	/* Due to mx35/mx25's phy's bug */
+	reset_phy();
+
+	if (pdata->have_sysif_regs)
+		usb_sys_regs = (struct usb_sys_interface *)
+				((u32)dr_regs + USB_DR_SYS_OFFSET);
+
+	/* Read Device Controller Capability Parameters register */
+	dccparams = fsl_readl(&dr_regs->dccparams);
+	if (!(dccparams & DCCPARAMS_DC)) {
+		ERR("This SOC doesn't support device role\n");
+		ret = -ENODEV;
+		goto err2;
+	}
+	/* Get max device endpoints */
+	/* DEN is bidirectional ep number, max_ep doubles the number */
+	udc_controller->max_ep = (dccparams & DCCPARAMS_DEN_MASK) * 2;
+
+	/* Initialize the udc structure including QH member and other member */
+	if (struct_udc_setup(udc_controller, pdata)) {
+		ERR("Can't initialize udc data structure\n");
+		ret = -ENOMEM;
+		goto err3;
+	}
+
+	/* initialize usb hw reg except for regs for EP,
+	 * leave usbintr reg untouched */
+	dr_controller_setup(udc_controller);
+
+
+#if 0
+	temp = 0;
+	/* Enable DR irq reg */
+	temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN
+        | USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN
+        | USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN
+	| USB_INTR_SOF_EN;
+
+	fsl_writel(temp, &dr_regs->usbintr);
+
+	/* Set controller to Run */
+	//temp = readl(USB_USBCMD);
+	//temp |= USB_CMD_RUN_STOP;
+	//writel(temp, USB_USBCMD);
+#endif
+
+
+	/* Setup gadget structure */
+	udc_controller->gadget.ops = &fsl_gadget_ops;
+	udc_controller->gadget.is_dualspeed = 1;
+	udc_controller->gadget.ep0 = &udc_controller->eps[0].ep;
+	INIT_LIST_HEAD(&udc_controller->gadget.ep_list);
+	udc_controller->gadget.speed = USB_SPEED_UNKNOWN;
+	udc_controller->gadget.name = driver_name;
+
+	/* Setup gadget.dev and register with kernel */
+	//dev_set_name(&udc_controller->gadget.dev, "gadget");
+	//udc_controller->gadget.dev.release = fsl_udc_release;
+	//udc_controller->gadget.dev.parent = NULL;
+	//udc_controller->gadget.dev.groups = fsl_udc_attr_groups;
+
+	/* setup QH and epctrl for ep0 */
+	ep0_setup(udc_controller);
+
+	/* setup udc->eps[] for ep0 */
+	struct_ep_setup(udc_controller, 0, "ep0", 0);
+	/* for ep0: the desc defined here;
+	 * for other eps, gadget layer called ep_enable with defined desc
+	 */
+	udc_controller->eps[0].desc = &fsl_ep0_desc;
+	udc_controller->eps[0].ep.maxpacket = USB_MAX_CTRL_PAYLOAD;
+
+	/* setup the udc->eps[] for non-control endpoints and link
+	 * to gadget.ep_list */
+	for (i = 1; i < (int)(udc_controller->max_ep / 2); i++) {
+		char name[14];
+
+		sprintf(name, "ep%dout", i);
+		struct_ep_setup(udc_controller, i * 2, name, 1);
+		sprintf(name, "ep%din", i);
+		struct_ep_setup(udc_controller, i * 2 + 1, name, 1);
+	}
+
+	if (g_iram_size) {
+		g_iram_addr = iram_alloc(USB_IRAM_SIZE, &g_iram_base);
+		for (i = 0; i < IRAM_PPH_NTD; i++) {
+			udc_controller->iram_buffer[i] =
+				g_iram_base + i * g_iram_size;
+			udc_controller->iram_buffer_v[i] =
+				g_iram_addr + i * g_iram_size;
+		}
+	}
+
+#ifdef POSTPONE_FREE_LAST_DTD
+	last_free_td = NULL;
+#endif
+
+	/* disable all INTR */
+#ifndef CONFIG_USB_OTG
+	fsl_writel(0, &dr_regs->usbintr);
+	dr_wake_up_enable(udc_controller, false);
+#else
+	dr_wake_up_enable(udc_controller, true);
+#endif
+
+/*
+ * As mx25/mx35 does not implement clk_gate, should not let phy to low
+ * power mode due to IC bug
+ */
+#if !(defined CONFIG_ARCH_MX35 || defined CONFIG_ARCH_MX25)
+{
+	dr_phy_low_power_mode(udc_controller, true);
+}
+#endif
+	udc_controller->stopped = 1;
+
+	/* let the gadget register function open the clk */
+	dr_clk_gate(false);
+
+	/* create usb charger */
+#ifdef CONFIG_IMX_USB_CHARGER
+	udc_controller->charger.dev = &pdev->dev;
+	udc_controller->charger.dp_pullup = usb_charger_pullup_dp;
+	udc_controller->charger.enable = true;
+	if (pdata->charger_base_addr)
+		udc_controller->charger.charger_base_addr = pdata->charger_base_addr;
+	if (imx_usb_create_charger(&udc_controller->charger, "imx_usb_charger"))
+		dev_err(&pdev->dev, "Can't create usb charger\n");
+#else
+	//udc_controller->charger.dp_pullup = usb_charger_pullup_dp;
+	//udc_controller->charger.enable = false;
+#endif
+
+	return 0;
+
+err3:
+err2:
+	if (pdata->exit)
+		pdata->exit(pdata);
+err2a:
+err1:
+err1a:
+	kfree(udc_controller);
+	udc_controller = NULL;
+	return ret;
+}
+
+/* Driver removal function
+ * Free resources and finish pending transactions
+ */
+static int  fsl_udc_remove(struct fsl_usb2_platform_data *pdata)
+{
+	u32 temp;
+
+	if (!udc_controller)
+		return -ENODEV;
+	//udc_controller->done = &done;
+	/* open USB PHY clock */
+	dr_clk_gate(true);
+
+	/* disable wake up and otgsc interrupt for safely remove udc driver*/
+	temp = fsl_readl(&dr_regs->otgsc);
+	temp &= ~(0x7f << 24);
+	fsl_writel(temp, &dr_regs->otgsc);
+	dr_wake_up_enable(udc_controller, false);
+
+	dr_discharge_line(pdata, true);
+	/* DR has been stopped in usb_gadget_unregister_driver() */
+	/* Free allocated memory */
+	if (g_iram_size)
+		iram_free(g_iram_base, IRAM_PPH_NTD * g_iram_size);
+	kfree(udc_controller->status_req->req.buf);
+	kfree(udc_controller->status_req);
+	kfree(udc_controller->data_req->req.buf);
+	kfree(udc_controller->data_req);
+	kfree(udc_controller->eps);
+
+#ifdef CONFIG_IMX_USB_CHARGER
+	imx_usb_remove_charger(&udc_controller->charger);
+#endif
+	/*
+	 * do platform specific un-initialization:
+	 * release iomux pins, etc.
+	 */
+	if (pdata->exit)
+		pdata->exit(pdata);
+
+	return 0;
+}
+
+static bool udc_can_wakeup_system(void)
+{
+#if 0
+	struct fsl_usb2_platform_data *pdata = udc_controller->pdata;
+
+	if (pdata->operating_mode == FSL_USB2_DR_OTG)
+		if (device_may_wakeup(udc_controller->transceiver->dev))
+			return true;
+		else
+			return false;
+	else
+		if (device_may_wakeup(udc_controller->gadget.dev.parent))
+			return true;
+		else
+			return false;
+#endif
+	return false;
+}
+
+static int udc_suspend(struct fsl_udc *udc)
+{
+	struct fsl_usb2_platform_data *pdata = udc_controller->pdata;
+	u32 mode, usbcmd;
+
+	/*
+	 * When it is the PM suspend routine and the device has no
+	 * abilities to wakeup system, it should not set wakeup enable.
+	 * Otherwise, the system will wakeup even the user only wants to
+	 * charge using usb
+	 */
+	if (pdata->pmflags == 0) {
+		if (!udc_can_wakeup_system()) {
+			dr_wake_up_enable(udc, false);
+		} else {
+			if (pdata->platform_phy_power_on)
+				pdata->platform_phy_power_on();
+			dr_wake_up_enable(udc, true);
+		}
+	}
+
+	/*
+	 * If the controller is already stopped, then this must be a
+	 * PM suspend.  Remember this fact, so that we will leave the
+	 * controller stopped at PM resume time.
+	 */
+	if (udc->suspended) {
+		printk(KERN_DEBUG "gadget already suspended, leaving early\n");
+		goto out;
+	}
+
+	mode = fsl_readl(&dr_regs->usbmode) & USB_MODE_CTRL_MODE_MASK;
+	usbcmd = fsl_readl(&dr_regs->usbcmd);
+	if (mode != USB_MODE_CTRL_MODE_DEVICE) {
+		printk(KERN_DEBUG "gadget not in device mode, leaving early\n");
+		goto out;
+	}
+
+
+	if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_A_BUS_VALID)) {
+		/* stop the controller */
+		usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP;
+		fsl_writel(usbcmd, &dr_regs->usbcmd);
+		udc->stopped = 1;
+	}
+
+	dr_phy_low_power_mode(udc, true);
+out:
+	if (udc->suspended > 1) {
+		pr_warning(
+			"It's the case usb device is on otg port\
+				and the gadget driver"
+			"is loaded during boots up\n"
+			"So, do not increase suspended counter Or\
+				there is a error, "
+			"please debug it !!!\n"
+			 );
+		return 0;
+	}
+
+	udc->suspended++;
+
+	return 0;
+}
+
+/*-----------------------------------------------------------------
+ * Modify Power management attributes
+ * Used by OTG statemachine to disable gadget temporarily
+ -----------------------------------------------------------------*/
+static int fsl_udc_suspend(struct fsl_usb2_platform_data *pdata, pm_message_t state)
+{
+	int ret;
+	printk(KERN_DEBUG "udc suspend begins\n");
+	if (get_gadget_data(&udc_controller->gadget) == NULL) {
+		/* if no gadget is binded, quit */
+		return 0;
+	}
+
+	if (udc_controller->stopped)
+		dr_clk_gate(true);
+	if (((!(udc_controller->gadget.is_otg)) ||
+		(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) &&
+			(udc_controller->usb_state > USB_STATE_POWERED) &&
+			(udc_controller->usb_state < USB_STATE_SUSPENDED)) {
+		return -EBUSY;/* keep the clk on */
+	} else
+		ret = udc_suspend(udc_controller);
+	dr_clk_gate(false);
+
+	printk(KERN_DEBUG "USB Gadget suspend ends\n");
+	return ret;
+}
+
+/*-----------------------------------------------------------------
+ * Invoked on USB resume. May be called in_interrupt.
+ * Here we start the DR controller and enable the irq
+ *-----------------------------------------------------------------*/
+static int fsl_udc_resume(void)
+{
+	struct fsl_usb2_platform_data *pdata = udc_controller->pdata;
+	struct fsl_usb2_wakeup_platform_data *wake_up_pdata = pdata->wakeup_pdata;
+	printk(KERN_DEBUG "USB Gadget resume begins\n");
+
+	if (get_gadget_data(&udc_controller->gadget) == NULL) {
+		/* if no gadget is binded, quit */
+		return 0;
+	}
+	mutex_lock(&udc_resume_mutex);
+
+	pr_debug("%s(): stopped %d  suspended %d\n", __func__,
+		 udc_controller->stopped, udc_controller->suspended);
+	/* Do noop if the udc is already at resume state */
+	if (udc_controller->suspended == 0) {
+		u32 temp;
+		if (udc_controller->stopped)
+			dr_clk_gate(true);
+		mdelay(3);
+		if (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) {
+			temp = fsl_readl(&dr_regs->otgsc);
+			/* if b_session_irq_en is cleared by otg */
+			if (!(temp & OTGSC_B_SESSION_VALID_IRQ_EN)) {
+				temp |= OTGSC_B_SESSION_VALID_IRQ_EN;
+				fsl_writel(temp, &dr_regs->otgsc);
+			}
+		}
+		if (udc_controller->stopped)
+			dr_clk_gate(false);
+		mutex_unlock(&udc_resume_mutex);
+		return 0;
+	}
+
+	/*
+	 * If the controller was stopped at suspend time, then
+	 * don't resume it now.
+	 */
+
+	if (udc_controller->suspended > 1) {
+		printk(KERN_DEBUG "gadget was already stopped, leaving early\n");
+		if (udc_controller->stopped) {
+			dr_clk_gate(true);
+		}
+		goto end;
+	}
+
+	/*
+	 * To fix suspend issue connected to usb charger,if stopped is 0
+	 * suspended is 1,clock on and out of low power mode to avoid
+	 * next system suspend no clock to cause system hang.
+	 */
+	if (udc_controller->suspended && !udc_controller->stopped) {
+		dr_clk_gate(true);
+		dr_wake_up_enable(udc_controller, false);
+		dr_phy_low_power_mode(udc_controller, false);
+	}
+	/* Enable DR irq reg and set controller Run */
+	if (udc_controller->stopped) {
+		/* the clock is already on at usb wakeup routine */
+		if (pdata->lowpower)
+			dr_clk_gate(true);
+		dr_wake_up_enable(udc_controller, false);
+		dr_phy_low_power_mode(udc_controller, false);
+		mdelay(3);
+		/* if in host mode, we need to do nothing */
+		if ((fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) == 0) {
+			dr_phy_low_power_mode(udc_controller, true);
+			dr_wake_up_enable(udc_controller, true);
+			goto end;
+		}
+		dr_controller_setup(udc_controller);
+		dr_controller_run(udc_controller);
+	}
+end:
+	/* if udc is resume by otg id change and no device
+	 * connecting to the otg, otg will enter low power mode*/
+	if (udc_controller->stopped) {
+		/*
+		 * If it is PM resume routine, the udc is at low power mode,
+		 * and the udc has no abilities to wakeup system, it should
+		 * set the abilities to wakeup itself. Otherwise, the usb
+		 * subsystem will not leave from low power mode.
+		 */
+		if (!udc_can_wakeup_system() &&
+			(pdata->pmflags == 0)) {
+			dr_wake_up_enable(udc_controller, true);
+		}
+
+		dr_clk_gate(false);
+	}
+
+	--udc_controller->suspended;
+	mutex_unlock(&udc_resume_mutex);
+	printk(KERN_DEBUG "USB Gadget resume ends\n");
+	return 0;
+}
+
+/*-------------------------------------------------------------------------
+	Register entry point for the peripheral controller driver
+--------------------------------------------------------------------------*/
+
+#if 0
+static struct platform_driver udc_driver = {
+	.remove  = fsl_udc_remove,
+	/* these suspend and resume are not usb suspend and resume */
+	.suspend = fsl_udc_suspend,
+	.resume  = fsl_udc_resume,
+	.probe = fsl_udc_probe,
+	.driver  = {
+		.name = driver_name,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init udc_init(void)
+{
+	printk(KERN_INFO "%s (%s)\n", driver_desc, DRIVER_VERSION);
+	return platform_driver_register(&udc_driver);
+}
+static void __exit udc_exit(void)
+{
+	platform_driver_unregister(&udc_driver);
+	printk(KERN_INFO "%s unregistered \n", driver_desc);
+}
+#endif
+
+int usb_gadget_handle_interrupts(void)
+{
+	return fsl_udc_irq(0, udc_controller);
+}

+ 13 - 0
include/configs/vf610twr.h

@@ -27,6 +27,18 @@
 
 #define CONFIG_VF610
 
+#define CONFIG_USB_GADGET
+#define CONFIG_USB_GADGET_ARCOTG_UDC
+#define CONFIG_USB_GADGET_MASS_STORAGE
+#define CONFIG_USBDOWNLOAD_GADGET
+#define CONFIG_CMD_USB_MASS_STORAGE
+#define CONFIG_USB_GADGET_VBUS_DRAW 2
+#define CONFIG_SYS_CACHELINE_SIZE 32
+#define CONFIG_G_DNL_VENDOR_NUM 0x066f
+#define CONFIG_G_DNL_PRODUCT_NUM 0x37ff
+#define CONFIG_G_DNL_MANUFACTURER "Freescale"
+#define CONFIG_DFU_FUNCTION
+#if 0
 #define CONFIG_USB_DEVICE
 #define CONFIG_IMX_UDC                 1
 #define CONFIG_FASTBOOT                1
@@ -51,6 +63,7 @@
 #define CONFIG_ANDROID_SYSTEM_PARTITION_MMC 5
 #define CONFIG_ANDROID_RECOVERY_PARTITION_MMC 2
 #define CONFIG_ANDROID_CACHE_PARTITION_MMC 6
+#endif
 
 #define CONFIG_DISPLAY_CPUINFO
 #define CONFIG_DISPLAY_BOARDINFO

+ 763 - 0
include/usb/arcotg_udc.h

@@ -0,0 +1,763 @@
+/*
+ * Copyright (C) 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*!
+ * @file arcotg_udc.h
+ * @brief Freescale USB device/endpoint management registers
+ * @ingroup USB
+ */
+
+#ifndef __ARCOTG_UDC_H
+#define __ARCOTG_UDC_H
+
+#include <usb/fsl_xcvr.h>
+#include <usb/fsl_devices.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#define TRUE 1
+#define FALSE 0
+
+#define MSC_BULK_CB_WRAP_LEN 31
+#define USE_MSC_WR(len) false
+
+/* Iram patch */
+#ifdef CONFIG_USB_STATIC_IRAM_PPH
+/* size of 1 qTD's buffer,one is for BULK IN and other is BULK OUT */
+#define USB_IRAM_SIZE		SZ_8K
+#define IRAM_TD_PPH_SIZE	(USB_IRAM_SIZE / 2)
+#define IRAM_PPH_NTD	2	/* number of TDs in IRAM  */
+#else
+#define USB_IRAM_SIZE		0
+#define IRAM_TD_PPH_SIZE	0
+#define IRAM_PPH_NTD	0
+#endif
+
+#define NEED_IRAM(ep) ((g_iram_size) && \
+	((ep)->desc->bmAttributes == USB_ENDPOINT_XFER_BULK))
+
+#define POSTPONE_FREE_LAST_DTD
+
+/* ### define USB registers here
+ */
+#define USB_MAX_ENDPOINTS		8
+#define USB_MAX_PIPES			(USB_MAX_ENDPOINTS*2)
+#define USB_MAX_CTRL_PAYLOAD		64
+#define	USB_DR_SYS_OFFSET		0x400
+
+#define	USB_DR_OFFSET	0x3100
+
+#define  OTGSC_STS_USB_ID               (1 <<  8)       /* 0=A-device  1=B-device */
+int fsl_udc_probe(struct fsl_usb2_platform_data *pdata);
+int usb_gadget_handle_interrupts(void);
+
+struct usb_dr_device {
+	/* Capability register */
+	u32 id;
+	u32 res1[35];
+	u32 sbuscfg;		/* sbuscfg ahb burst */
+	u32 res11[27];
+	u16 caplength;		/* Capability Register Length */
+	u16 hciversion;		/* Host Controller Interface Version */
+	u32 hcsparams;		/* Host Controller Structual Parameters */
+	u32 hccparams;		/* Host Controller Capability Parameters */
+	u32 res2[5];
+	u32 dciversion;		/* Device Controller Interface Version */
+	u32 dccparams;		/* Device Controller Capability Parameters */
+	u32 res3[6];
+	/* Operation register */
+	u32 usbcmd;		/* USB Command Register */
+	u32 usbsts;		/* USB Status Register */
+	u32 usbintr;		/* USB Interrupt Enable Register */
+	u32 frindex;		/* Frame Index Register */
+	u32 res4;
+	u32 deviceaddr;		/* Device Address */
+	u32 endpointlistaddr;	/* Endpoint List Address Register */
+	u32 res5;
+	u32 burstsize;		/* Master Interface Data Burst Size Register */
+	u32 txttfilltuning;	/* Transmit FIFO Tuning Controls Register */
+	u32 res6[6];
+	u32 configflag;		/* Configure Flag Register */
+	u32 portsc1;		/* Port 1 Status and Control Register */
+	u32 res7[7];
+	u32 otgsc;		/* On-The-Go Status and Control */
+	u32 usbmode;		/* USB Mode Register */
+	u32 endptsetupstat;	/* Endpoint Setup Status Register */
+	u32 endpointprime;	/* Endpoint Initialization Register */
+	u32 endptflush;		/* Endpoint Flush Register */
+	u32 endptstatus;	/* Endpoint Status Register */
+	u32 endptcomplete;	/* Endpoint Complete Register */
+	u32 endptctrl[8 * 2];	/* Endpoint Control Registers */
+	u32 res8[256];
+#ifdef CONFIG_ARCH_MX5
+	u32 res9[128];		/* i.MX51 start from 0x800 */
+#endif
+	u32 usbctrl;
+	u32 otgmirror;
+	u32 phyctrl0;
+	u32 phyctrl1;
+	u32 ctrl1;
+	u32 uh2ctrl;
+};
+
+#define USB_OTGREGS_BASE        (OTG_BASE_ADDR + 0x000)
+#define USB_H1REGS_BASE         (OTG_BASE_ADDR + 0x200)
+#define USB_H2REGS_BASE         (OTG_BASE_ADDR + 0x400)
+#if (defined CONFIG_MX51 || defined CONFIG_MX50 || defined CONFIG_MX6Q \
+     || defined CONFIG_MX53 || defined CONFIG_MX6DL || defined CONFIG_MX6SL)
+#define USB_H3REGS_BASE         (OTG_BASE_ADDR + 0x600)
+#define USB_OTHERREGS_BASE      (OTG_BASE_ADDR + 0x800)
+#else
+#define USB_OTHERREGS_BASE      (OTG_BASE_ADDR + 0x600)
+#endif
+
+#define USBOTG_REG32(offset)    (USB_OTGREGS_BASE + (offset))
+#define USBOTG_REG16(offset)    (USB_OTGREGS_BASE + (offset))
+#define USBOTHER_REG(offset)    (USB_OTHERREGS_BASE + (offset))
+
+#define USB_ID               (OTG_BASE_ADDR + 0x0000)
+#define USB_HWGENERAL        (OTG_BASE_ADDR + 0x0004)
+#define USB_HWHOST           (OTG_BASE_ADDR + 0x0008)
+#define USB_HWDEVICE         (OTG_BASE_ADDR + 0x000C)
+#define USB_HWTXBUF          (OTG_BASE_ADDR + 0x0010)
+#define USB_HWRXBUF          (OTG_BASE_ADDR + 0x0014)
+#define USB_SBUSCFG          (OTG_BASE_ADDR + 0x0090)
+
+#define USB_CAPLENGTH        (OTG_BASE_ADDR + 0x0100) /* 8 bit */
+#define USB_HCIVERSION       (OTG_BASE_ADDR + 0x0102) /* 16 bit */
+#define USB_HCSPARAMS        (OTG_BASE_ADDR + 0x0104)
+#define USB_HCCPARAMS        (OTG_BASE_ADDR + 0x0108)
+#define USB_DCIVERSION       (OTG_BASE_ADDR + 0x0120) /* 16 bit */
+#define USB_DCCPARAMS        (OTG_BASE_ADDR + 0x0124)
+#define USB_USBCMD           (OTG_BASE_ADDR + 0x0140)
+#define USB_USBSTS           (OTG_BASE_ADDR + 0x0144)
+#define USB_USBINTR          (OTG_BASE_ADDR + 0x0148)
+#define USB_FRINDEX          (OTG_BASE_ADDR + 0x014C)
+#define USB_DEVICEADDR       (OTG_BASE_ADDR + 0x0154)
+#define USB_ENDPOINTLISTADDR (OTG_BASE_ADDR + 0x0158)
+#define USB_BURSTSIZE        (OTG_BASE_ADDR + 0x0160)
+#define USB_TXFILLTUNING     (OTG_BASE_ADDR + 0x0164)
+#define USB_ULPI_VIEWPORT    (OTG_BASE_ADDR + 0x0170)
+#define USB_ENDPTNAK         (OTG_BASE_ADDR + 0x0178)
+#define USB_ENDPTNAKEN       (OTG_BASE_ADDR + 0x017C)
+#define USB_PORTSC1          (OTG_BASE_ADDR + 0x0184)
+#define USB_OTGSC            (OTG_BASE_ADDR + 0x01A4)
+#define USB_USBMODE          (OTG_BASE_ADDR + 0x01A8)
+#define USB_ENDPTSETUPSTAT   (OTG_BASE_ADDR + 0x01AC)
+#define USB_ENDPTPRIME       (OTG_BASE_ADDR + 0x01B0)
+#define USB_ENDPTFLUSH       (OTG_BASE_ADDR + 0x01B4)
+#define USB_ENDPTSTAT        (OTG_BASE_ADDR + 0x01B8)
+#define USB_ENDPTCOMPLETE    (OTG_BASE_ADDR + 0x01BC)
+#define USB_ENDPTCTRL(n)     (OTG_BASE_ADDR + 0x01C0 + (4 * (n)))
+
+ /* non-EHCI USB system interface registers (Big Endian) */
+struct usb_sys_interface {
+	u32 snoop1;
+	u32 snoop2;
+	u32 age_cnt_thresh;	/* Age Count Threshold Register */
+	u32 pri_ctrl;		/* Priority Control Register */
+	u32 si_ctrl;		/* System Interface Control Register */
+	u8 res[236];
+	u32 control;		/* General Purpose Control Register */
+};
+
+/* ep0 transfer state */
+#define WAIT_FOR_SETUP          0
+#define DATA_STATE_XMIT         1
+#define DATA_STATE_NEED_ZLP     2
+#define WAIT_FOR_OUT_STATUS     3
+#define DATA_STATE_RECV         4
+
+/* Device Controller Capability Parameter register */
+#define DCCPARAMS_DC				0x00000080
+#define DCCPARAMS_DEN_MASK			0x0000001f
+
+/* Frame Index Register Bit Masks */
+#define	USB_FRINDEX_MASKS			(0x3fff)
+/* USB CMD  Register Bit Masks */
+#define  USB_CMD_RUN_STOP                     (0x00000001)
+#define  USB_CMD_CTRL_RESET                   (0x00000002)
+#define  USB_CMD_PERIODIC_SCHEDULE_EN         (0x00000010)
+#define  USB_CMD_ASYNC_SCHEDULE_EN            (0x00000020)
+#define  USB_CMD_INT_AA_DOORBELL              (0x00000040)
+#define  USB_CMD_ASP                          (0x00000300)
+#define  USB_CMD_ASYNC_SCH_PARK_EN            (0x00000800)
+#define  USB_CMD_SUTW                         (0x00002000)
+#define  USB_CMD_ATDTW                        (0x00004000)
+#define  USB_CMD_ITC                          (0x00FF0000)
+
+/* bit 15,3,2 are frame list size */
+#define  USB_CMD_FRAME_SIZE_1024              (0x00000000)
+#define  USB_CMD_FRAME_SIZE_512               (0x00000004)
+#define  USB_CMD_FRAME_SIZE_256               (0x00000008)
+#define  USB_CMD_FRAME_SIZE_128               (0x0000000C)
+#define  USB_CMD_FRAME_SIZE_64                (0x00008000)
+#define  USB_CMD_FRAME_SIZE_32                (0x00008004)
+#define  USB_CMD_FRAME_SIZE_16                (0x00008008)
+#define  USB_CMD_FRAME_SIZE_8                 (0x0000800C)
+
+/* bit 9-8 are async schedule park mode count */
+#define  USB_CMD_ASP_00                       (0x00000000)
+#define  USB_CMD_ASP_01                       (0x00000100)
+#define  USB_CMD_ASP_10                       (0x00000200)
+#define  USB_CMD_ASP_11                       (0x00000300)
+#define  USB_CMD_ASP_BIT_POS                  (8)
+
+/* bit 23-16 are interrupt threshold control */
+#define  USB_CMD_ITC_NO_THRESHOLD             (0x00000000)
+#define  USB_CMD_ITC_1_MICRO_FRM              (0x00010000)
+#define  USB_CMD_ITC_2_MICRO_FRM              (0x00020000)
+#define  USB_CMD_ITC_4_MICRO_FRM              (0x00040000)
+#define  USB_CMD_ITC_8_MICRO_FRM              (0x00080000)
+#define  USB_CMD_ITC_16_MICRO_FRM             (0x00100000)
+#define  USB_CMD_ITC_32_MICRO_FRM             (0x00200000)
+#define  USB_CMD_ITC_64_MICRO_FRM             (0x00400000)
+#define  USB_CMD_ITC_BIT_POS                  (16)
+
+/* USB STS Register Bit Masks */
+#define  USB_STS_INT                          (0x00000001)
+#define  USB_STS_ERR                          (0x00000002)
+#define  USB_STS_PORT_CHANGE                  (0x00000004)
+#define  USB_STS_FRM_LST_ROLL                 (0x00000008)
+#define  USB_STS_SYS_ERR                      (0x00000010)
+#define  USB_STS_IAA                          (0x00000020)
+#define  USB_STS_RESET                        (0x00000040)
+#define  USB_STS_SOF                          (0x00000080)
+#define  USB_STS_SUSPEND                      (0x00000100)
+#define  USB_STS_HC_HALTED                    (0x00001000)
+#define  USB_STS_RCL                          (0x00002000)
+#define  USB_STS_PERIODIC_SCHEDULE            (0x00004000)
+#define  USB_STS_ASYNC_SCHEDULE               (0x00008000)
+
+/* USB INTR Register Bit Masks */
+#define  USB_INTR_INT_EN                      (0x00000001)
+#define  USB_INTR_ERR_INT_EN                  (0x00000002)
+#define  USB_INTR_PTC_DETECT_EN               (0x00000004)
+#define  USB_INTR_FRM_LST_ROLL_EN             (0x00000008)
+#define  USB_INTR_SYS_ERR_EN                  (0x00000010)
+#define  USB_INTR_ASYN_ADV_EN                 (0x00000020)
+#define  USB_INTR_RESET_EN                    (0x00000040)
+#define  USB_INTR_SOF_EN                      (0x00000080)
+#define  USB_INTR_DEVICE_SUSPEND              (0x00000100)
+
+/* Device Address bit masks */
+#define  USB_DEVICE_ADDRESS_MASK              (0xFE000000)
+#define  USB_DEVICE_ADDRESS_BIT_POS           (25)
+#define  USB_DEVICE_ADDRESS_ADV_BIT_POS       (24)
+
+/* endpoint list address bit masks */
+#define USB_EP_LIST_ADDRESS_MASK              (0xfffff800)
+
+/* PORTSCX  Register Bit Masks */
+#define  PORTSCX_CURRENT_CONNECT_STATUS       (0x00000001)
+#define  PORTSCX_CONNECT_STATUS_CHANGE        (0x00000002)
+#define  PORTSCX_PORT_ENABLE                  (0x00000004)
+#define  PORTSCX_PORT_EN_DIS_CHANGE           (0x00000008)
+#define  PORTSCX_OVER_CURRENT_ACT             (0x00000010)
+#define  PORTSCX_OVER_CURRENT_CHG             (0x00000020)
+#define  PORTSCX_PORT_FORCE_RESUME            (0x00000040)
+#define  PORTSCX_PORT_SUSPEND                 (0x00000080)
+#define  PORTSCX_PORT_RESET                   (0x00000100)
+#define  PORTSCX_LINE_STATUS_BITS             (0x00000C00)
+#define  PORTSCX_PORT_POWER                   (0x00001000)
+#define  PORTSCX_PORT_INDICTOR_CTRL           (0x0000C000)
+#define  PORTSCX_PORT_TEST_CTRL               (0x000F0000)
+#define  PORTSCX_WAKE_ON_CONNECT_EN           (0x00100000)
+#define  PORTSCX_WAKE_ON_CONNECT_DIS          (0x00200000)
+#define  PORTSCX_WAKE_ON_OVER_CURRENT         (0x00400000)
+#define  PORTSCX_PHY_LOW_POWER_SPD            (0x00800000)
+#define  PORTSCX_PORT_FORCE_FULL_SPEED        (0x01000000)
+#define  PORTSCX_PORT_SPEED_MASK              (0x0C000000)
+#define  PORTSCX_PORT_WIDTH                   (0x10000000)
+#define  PORTSCX_PHY_TYPE_SEL                 (0xC0000000)
+
+/* bit 11-10 are line status */
+#define  PORTSCX_LINE_STATUS_SE0              (0x00000000)
+#define  PORTSCX_LINE_STATUS_KSTATE           (0x00000400)
+#define  PORTSCX_LINE_STATUS_JSTATE           (0x00000800)
+#define  PORTSCX_LINE_STATUS_UNDEF            (0x00000C00)
+#define  PORTSCX_LINE_STATUS_BIT_POS          (10)
+
+/* bit 15-14 are port indicator control */
+#define  PORTSCX_PIC_OFF                      (0x00000000)
+#define  PORTSCX_PIC_AMBER                    (0x00004000)
+#define  PORTSCX_PIC_GREEN                    (0x00008000)
+#define  PORTSCX_PIC_UNDEF                    (0x0000C000)
+#define  PORTSCX_PIC_BIT_POS                  (14)
+
+/* bit 19-16 are port test control */
+#define  PORTSCX_PTC_DISABLE                  (0x00000000)
+#define  PORTSCX_PTC_JSTATE                   (0x00010000)
+#define  PORTSCX_PTC_KSTATE                   (0x00020000)
+#define  PORTSCX_PTC_SEQNAK                   (0x00030000)
+#define  PORTSCX_PTC_PACKET                   (0x00040000)
+#define  PORTSCX_PTC_FORCE_EN                 (0x00050000)
+#define  PORTSCX_PTC_BIT_POS                  (16)
+
+/* bit 27-26 are port speed */
+#define  PORTSCX_PORT_SPEED_FULL              (0x00000000)
+#define  PORTSCX_PORT_SPEED_LOW               (0x04000000)
+#define  PORTSCX_PORT_SPEED_HIGH              (0x08000000)
+#define  PORTSCX_PORT_SPEED_UNDEF             (0x0C000000)
+#define  PORTSCX_SPEED_BIT_POS                (26)
+
+/* OTGSC Register Bit Masks */
+#define  OTGSC_ID_CHANGE_IRQ_STS                (1 << 16)
+#define  OTGSC_B_SESSION_VALID_IRQ_EN           (1 << 27)
+#define  OTGSC_B_SESSION_VALID_IRQ_STS          (1 << 19)
+#define  OTGSC_B_SESSION_VALID                  (1 << 11)
+#define  OTGSC_A_BUS_VALID			(1 << 9)
+
+/* bit 28 is parallel transceiver width for UTMI interface */
+#define  PORTSCX_PTW                          (0x10000000)
+#define  PORTSCX_PTW_8BIT                     (0x00000000)
+#define  PORTSCX_PTW_16BIT                    (0x10000000)
+
+/* bit 31-30 are port transceiver select */
+#define  PORTSCX_PTS_UTMI                     (0x00000000)
+#define  PORTSCX_PTS_ULPI                     (0x80000000)
+#define  PORTSCX_PTS_FSLS                     (0xC0000000)
+#define  PORTSCX_PTS_BIT_POS                  (30)
+
+/* USB MODE Register Bit Masks */
+#define  USB_MODE_CTRL_MODE_IDLE              (0x00000000)
+#define  USB_MODE_CTRL_MODE_DEVICE            (0x00000002)
+#define  USB_MODE_CTRL_MODE_HOST              (0x00000003)
+#define  USB_MODE_CTRL_MODE_MASK              0x00000003
+#define  USB_MODE_CTRL_MODE_RSV               (0x00000001)
+#define  USB_MODE_ES                          0x00000004 /* (big) Endian Sel */
+#define  USB_MODE_SETUP_LOCK_OFF              (0x00000008)
+#define  USB_MODE_STREAM_DISABLE              (0x00000010)
+/* Endpoint Flush Register */
+#define EPFLUSH_TX_OFFSET		      (0x00010000)
+#define EPFLUSH_RX_OFFSET		      (0x00000000)
+
+/* Endpoint Setup Status bit masks */
+#define  EP_SETUP_STATUS_MASK                 (0x0000003F)
+#define  EP_SETUP_STATUS_EP0		      (0x00000001)
+
+/* ENDPOINTCTRLx  Register Bit Masks */
+#define  EPCTRL_TX_ENABLE                     (0x00800000)
+#define  EPCTRL_TX_DATA_TOGGLE_RST            (0x00400000)	/* Not EP0 */
+#define  EPCTRL_TX_DATA_TOGGLE_INH            (0x00200000)	/* Not EP0 */
+#define  EPCTRL_TX_TYPE                       (0x000C0000)
+#define  EPCTRL_TX_DATA_SOURCE                (0x00020000)	/* Not EP0 */
+#define  EPCTRL_TX_EP_STALL                   (0x00010000)
+#define  EPCTRL_RX_ENABLE                     (0x00000080)
+#define  EPCTRL_RX_DATA_TOGGLE_RST            (0x00000040)	/* Not EP0 */
+#define  EPCTRL_RX_DATA_TOGGLE_INH            (0x00000020)	/* Not EP0 */
+#define  EPCTRL_RX_TYPE                       (0x0000000C)
+#define  EPCTRL_RX_DATA_SINK                  (0x00000002)	/* Not EP0 */
+#define  EPCTRL_RX_EP_STALL                   (0x00000001)
+
+/* bit 19-18 and 3-2 are endpoint type */
+#define  EPCTRL_EP_TYPE_CONTROL               (0)
+#define  EPCTRL_EP_TYPE_ISO                   (1)
+#define  EPCTRL_EP_TYPE_BULK                  (2)
+#define  EPCTRL_EP_TYPE_INTERRUPT             (3)
+#define  EPCTRL_TX_EP_TYPE_SHIFT              (18)
+#define  EPCTRL_RX_EP_TYPE_SHIFT              (2)
+
+/* SNOOPn Register Bit Masks */
+#define  SNOOP_ADDRESS_MASK                   (0xFFFFF000)
+#define  SNOOP_SIZE_ZERO                      (0x00)	/* snooping disable */
+#define  SNOOP_SIZE_4KB                       (0x0B)	/* 4KB snoop size */
+#define  SNOOP_SIZE_8KB                       (0x0C)
+#define  SNOOP_SIZE_16KB                      (0x0D)
+#define  SNOOP_SIZE_32KB                      (0x0E)
+#define  SNOOP_SIZE_64KB                      (0x0F)
+#define  SNOOP_SIZE_128KB                     (0x10)
+#define  SNOOP_SIZE_256KB                     (0x11)
+#define  SNOOP_SIZE_512KB                     (0x12)
+#define  SNOOP_SIZE_1MB                       (0x13)
+#define  SNOOP_SIZE_2MB                       (0x14)
+#define  SNOOP_SIZE_4MB                       (0x15)
+#define  SNOOP_SIZE_8MB                       (0x16)
+#define  SNOOP_SIZE_16MB                      (0x17)
+#define  SNOOP_SIZE_32MB                      (0x18)
+#define  SNOOP_SIZE_64MB                      (0x19)
+#define  SNOOP_SIZE_128MB                     (0x1A)
+#define  SNOOP_SIZE_256MB                     (0x1B)
+#define  SNOOP_SIZE_512MB                     (0x1C)
+#define  SNOOP_SIZE_1GB                       (0x1D)
+#define  SNOOP_SIZE_2GB                       (0x1E)	/* 2GB snoop size */
+
+/* pri_ctrl Register Bit Masks */
+#define  PRI_CTRL_PRI_LVL1                    (0x0000000C)
+#define  PRI_CTRL_PRI_LVL0                    (0x00000003)
+
+/* si_ctrl Register Bit Masks */
+#define  SI_CTRL_ERR_DISABLE                  (0x00000010)
+#define  SI_CTRL_IDRC_DISABLE                 (0x00000008)
+#define  SI_CTRL_RD_SAFE_EN                   (0x00000004)
+#define  SI_CTRL_RD_PREFETCH_DISABLE          (0x00000002)
+#define  SI_CTRL_RD_PREFEFETCH_VAL            (0x00000001)
+
+/* control Register Bit Masks */
+#define  USB_CTRL_IOENB                       (0x00000004)
+#define  USB_CTRL_ULPI_INT0EN                 (0x00000001)
+#define  USB_CTRL_OTG_WUIR                   (0x80000000)
+#define  USB_CTRL_OTG_WUIE                   (0x08000000)
+#define  USB_CTRL_OTG_VWUE			(0x00001000)
+#define  USB_CTRL_OTG_IWUE			(0x00100000)
+
+/* PHY control0 Register Bit Masks */
+#define	PHY_CTRL0_CONF2			(1 << 26)
+#define PHY_CTRL0_USBEN			(1 << 24) /* USB UTMI PHY Enable */
+
+/* USB UH2 CTRL Register Bits */
+#define USB_UH2_OVBWK_EN		(1 << 6) /* OTG VBUS Wakeup Enable */
+#define USB_UH2_OIDWK_EN		(1 << 5) /* OTG ID Wakeup Enable */
+/*!
+ * Endpoint Queue Head data struct
+ * Rem: all the variables of qh are LittleEndian Mode
+ * and NEXT_POINTER_MASK should operate on a LittleEndian, Phy Addr
+ */
+struct ep_queue_head {
+	/*!
+	 * Mult(31-30) , Zlt(29) , Max Pkt len  and IOS(15)
+	 */
+	u32 max_pkt_length;
+
+	/*!
+	 *  Current dTD Pointer(31-5)
+	 */
+	u32 curr_dtd_ptr;
+
+	/*!
+	 *  Next dTD Pointer(31-5), T(0)
+	 */
+	u32 next_dtd_ptr;
+
+	/*!
+	 *  Total bytes (30-16), IOC (15), MultO(11-10), STS (7-0)
+	 */
+	u32 size_ioc_int_sts;
+
+	/*!
+	 * Buffer pointer Page 0 (31-12)
+	 */
+	u32 buff_ptr0;
+
+	/*!
+	 * Buffer pointer Page 1 (31-12)
+	 */
+	u32 buff_ptr1;
+
+	/*!
+	 * Buffer pointer Page 2 (31-12)
+	 */
+	u32 buff_ptr2;
+
+	/*!
+	 * Buffer pointer Page 3 (31-12)
+	 */
+	u32 buff_ptr3;
+
+	/*!
+	 * Buffer pointer Page 4 (31-12)
+	 */
+	u32 buff_ptr4;
+
+	/*!
+	 * reserved field 1
+	 */
+	u32 res1;
+	/*!
+	 * Setup data 8 bytes
+	 */
+	u8 setup_buffer[8];	/* Setup data 8 bytes */
+
+	/*!
+	 * reserved field 2,pad out to 64 bytes
+	 */
+	u32 res2[4];
+};
+
+/* Endpoint Queue Head Bit Masks */
+#define  EP_QUEUE_HEAD_MULT_POS               (30)
+#define  EP_QUEUE_HEAD_ZLT_SEL                (0x20000000)
+#define  EP_QUEUE_HEAD_MAX_PKT_LEN_POS        (16)
+#define  EP_QUEUE_HEAD_MAX_PKT_LEN(ep_info)   (((ep_info)>>16)&0x07ff)
+#define  EP_QUEUE_HEAD_IOS                    (0x00008000)
+#define  EP_QUEUE_HEAD_NEXT_TERMINATE         (0x00000001)
+#define  EP_QUEUE_HEAD_IOC                    (0x00008000)
+#define  EP_QUEUE_HEAD_MULTO                  (0x00000C00)
+#define  EP_QUEUE_HEAD_STATUS_HALT	      (0x00000040)
+#define  EP_QUEUE_HEAD_STATUS_ACTIVE          (0x00000080)
+#define  EP_QUEUE_CURRENT_OFFSET_MASK         (0x00000FFF)
+#define  EP_QUEUE_HEAD_NEXT_POINTER_MASK      0xFFFFFFE0
+#define  EP_QUEUE_FRINDEX_MASK                (0x000007FF)
+#define  EP_MAX_LENGTH_TRANSFER               (0x4000)
+
+/*!
+ * Endpoint Transfer Descriptor data struct
+ *  Rem: all the variables of td are LittleEndian Mode
+ *       must be 32-byte aligned
+ */
+struct ep_td_struct {
+	/*!
+	 *  Next TD pointer(31-5), T(0) set indicate invalid
+	 */
+	u32 next_td_ptr;
+
+	/*!
+	 *  Total bytes (30-16), IOC (15),MultO(11-10), STS (7-0)
+	 */
+	u32 size_ioc_sts;
+
+	/*!
+	 * Buffer pointer Page 0
+	 */
+	u32 buff_ptr0;
+
+	/*!
+	 * Buffer pointer Page 1
+	 */
+	u32 buff_ptr1;
+
+	/*!
+	 * Buffer pointer Page 2
+	 */
+	u32 buff_ptr2;
+
+	/*!
+	 * Buffer pointer Page 3
+	 */
+	u32 buff_ptr3;
+
+	/*!
+	 * Buffer pointer Page 4
+	 */
+	u32 buff_ptr4;
+
+	/*!
+	 * dma address of this td
+	 * */
+	dma_addr_t td_dma;
+
+	/*!
+	 * virtual address of next td
+	 * */
+	struct ep_td_struct *next_td_virt;
+
+	/*!
+	 * make it an even 16 words
+	 * */
+	u32 res[7];
+};
+
+/*!
+ * Endpoint Transfer Descriptor bit Masks
+ */
+#define  DTD_NEXT_TERMINATE                   (0x00000001)
+#define  DTD_IOC                              (0x00008000)
+#define  DTD_STATUS_ACTIVE                    (0x00000080)
+#define  DTD_STATUS_HALTED                    (0x00000040)
+#define  DTD_STATUS_DATA_BUFF_ERR             (0x00000020)
+#define  DTD_STATUS_TRANSACTION_ERR           (0x00000008)
+#define  DTD_RESERVED_FIELDS                  (0x80007300)
+#define  DTD_ADDR_MASK                        0xFFFFFFE0
+#define  DTD_PACKET_SIZE                      (0x7FFF0000)
+#define  DTD_LENGTH_BIT_POS                   (16)
+#define  DTD_ERROR_MASK                       (DTD_STATUS_HALTED | \
+				DTD_STATUS_DATA_BUFF_ERR | \
+				DTD_STATUS_TRANSACTION_ERR)
+/* Alignment requirements; must be a power of two */
+#define DTD_ALIGNMENT				0x20
+#define QH_ALIGNMENT				2048
+
+/* Controller dma boundary */
+#define UDC_DMA_BOUNDARY			0x1000
+
+/* -----------------------------------------------------------------------*/
+/* ##### enum data
+*/
+typedef enum {
+	e_ULPI,
+	e_UTMI_8BIT,
+	e_UTMI_16BIT,
+	e_SERIAL
+} e_PhyInterface;
+
+/*-------------------------------------------------------------------------*/
+
+struct fsl_req {
+	struct usb_request req;
+	struct list_head queue;
+	/* ep_queue() func will add
+	   a request->queue into a udc_ep->queue 'd tail */
+	struct fsl_ep *ep;
+	unsigned mapped;
+
+	struct ep_td_struct *head, *tail;	/* For dTD List
+						   this is a BigEndian Virtual addr */
+	unsigned int dtd_count;
+	/* just for IRAM patch */
+	dma_addr_t oridma;	/* original dma */
+	size_t buffer_offset;	/* offset of user buffer */
+	int last_one;		/* mark if reach to last packet */
+	struct ep_td_struct *cur;	/* current tranfer dtd */
+};
+
+#define REQ_UNCOMPLETE		(1)
+
+struct fsl_ep {
+	struct usb_ep ep;
+	struct list_head queue;
+	struct fsl_udc *udc;
+	struct ep_queue_head *qh;
+	const struct usb_endpoint_descriptor *desc;
+	struct usb_gadget *gadget;
+
+	char name[14];
+	unsigned stopped:1;
+};
+
+#define EP_DIR_IN	1
+#define EP_DIR_OUT	0
+
+struct fsl_udc {
+	struct usb_gadget gadget;
+	struct usb_gadget_driver *driver;
+	struct fsl_usb2_platform_data *pdata;
+	struct fsl_ep *eps;
+	unsigned int max_ep;
+	unsigned int irq;
+
+	struct usb_ctrlrequest local_setup_buff;
+	u32 xcvr_type;
+	unsigned softconnect:1;
+	unsigned vbus_active:1;
+	unsigned remote_wakeup:1;
+	/* we must distinguish the stopped and suspended state,
+	 * stopped means the udc enter lowpower mode, suspended
+	 * means the udc is suspended by system pm or by otg
+	 * switching to host mode.if the udc in suspended state
+	 * it also in the stopped state, while if the udc in
+	 * stopped state,it may not be in the suspended state*/
+	unsigned stopped:1;
+	int suspended;
+
+	struct ep_queue_head *ep_qh;	/* Endpoints Queue-Head */
+	struct fsl_req *status_req;	/* ep0 status request */
+	struct fsl_req *data_req;	/* ep0 data request */
+	enum fsl_usb2_phy_modes phy_mode;
+
+	size_t ep_qh_size;		/* size after alignment adjustment*/
+	dma_addr_t ep_qh_dma;		/* dma address of QH */
+
+	u32 max_pipes;		/* Device max pipes */
+	u32 max_use_endpts;	/* Max endpointes to be used */
+	u32 bus_reset;		/* Device is bus reseting */
+	u32 resume_state;	/* USB state to resume */
+	u32 usb_state;		/* USB current state */
+	u32 usb_next_state;	/* USB next state */
+	u32 ep0_dir;		/* Endpoint zero direction: can be
+				   USB_DIR_IN or USB_DIR_OUT */
+	u32 usb_sof_count;	/* SOF count */
+	u32 errors;		/* USB ERRORs count */
+	u8 device_address;	/* Device USB address */
+
+	u32 iram_buffer[IRAM_PPH_NTD];
+	void *iram_buffer_v[IRAM_PPH_NTD];
+};
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#define DBG(fmt, args...) 	printk(KERN_DEBUG "[%s]  " fmt "\n", \
+				__func__, ## args)
+#else
+#define DBG(fmt, args...)	do {} while (0)
+#endif
+
+#if 0
+static void dump_msg(const char *label, const u8 * buf, unsigned int length)
+{
+	unsigned int start, num, i;
+	char line[52], *p;
+
+	if (length >= 512)
+		return;
+	pr_debug("udc: %s, length %u:\n", label, length);
+	start = 0;
+	while (length > 0) {
+		num = min(length, 16u);
+		p = line;
+		for (i = 0; i < num; ++i) {
+			if (i == 8)
+				*p++ = ' ';
+			sprintf(p, " %02x", buf[i]);
+			p += 3;
+		}
+		*p = 0;
+		printk(KERN_DEBUG "%6x: %s\n", start, line);
+		buf += num;
+		start += num;
+		length -= num;
+	}
+}
+#endif
+
+#ifdef VERBOSE
+#define VDBG		DBG
+#else
+#define VDBG(stuff...)	do {} while (0)
+#endif
+
+#define ERR(stuff...)		printk(KERN_ERR "udc: " stuff)
+#define INFO(stuff...)		printk(KERN_INFO "udc: " stuff)
+
+/*-------------------------------------------------------------------------*/
+
+/* ### Add board specific defines here
+ */
+
+/*
+ * ### pipe direction macro from device view
+ */
+#define USB_RECV	(0)	/* OUT EP */
+#define USB_SEND	(1)	/* IN EP */
+
+/*
+ * ### internal used help routines.
+ */
+#define ep_index(EP)         ((EP)->desc->bEndpointAddress&0xF)
+#define ep_maxpacket(EP)     ((EP)->ep.maxpacket)
+
+#define ep_is_in(EP)	((ep_index(EP) == 0) ? (EP->udc->ep0_dir == \
+				USB_DIR_IN) : ((EP)->desc->bEndpointAddress \
+				& USB_DIR_IN) == USB_DIR_IN)
+
+#define get_ep_by_pipe(udc, pipe)	((pipe == 1) ? &udc->eps[0] : \
+					&udc->eps[pipe])
+#define get_pipe_by_windex(windex)	((windex & USB_ENDPOINT_NUMBER_MASK) \
+					* 2 + ((windex & USB_DIR_IN) ? 1 : 0))
+
+/* Bulk only class request */
+#define USB_BULK_RESET_REQUEST          0xff
+
+#if defined(CONFIG_ARCH_MXC) || defined(CONFIG_ARCH_STMP3XXX) || \
+	defined(CONFIG_ARCH_MXS)
+#include <mach/fsl_usb_gadget.h>
+#elif defined (CONFIG_PPC32)
+#include <asm/fsl_usb_gadget.h>
+#endif
+
+#endif				/* __ARCOTG_UDC_H */

+ 171 - 0
include/usb/fsl_devices.h

@@ -0,0 +1,171 @@
+/*
+ * include/linux/fsl_devices.h
+ *
+ * Definitions for any platform device related flags or structures for
+ * Freescale processor devices
+ *
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
+ *
+ * Copyright 2004-2013 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+#ifndef _FSL_DEVICE_H_
+#define _FSL_DEVICE_H_
+
+/*
+ * Some conventions on how we handle peripherals on Freescale chips
+ *
+ * unique device: a platform_device entry in fsl_plat_devs[] plus
+ * associated device information in its platform_data structure.
+ *
+ * A chip is described by a set of unique devices.
+ *
+ * Each sub-arch has its own master list of unique devices and
+ * enumerates them by enum fsl_devices in a sub-arch specific header
+ *
+ * The platform data structure is broken into two parts.  The
+ * first is device specific information that help identify any
+ * unique features of a peripheral.  The second is any
+ * information that may be defined by the board or how the device
+ * is connected externally of the chip.
+ *
+ * naming conventions:
+ * - platform data structures: <driver>_platform_data
+ * - platform data device flags: FSL_<driver>_DEV_<FLAG>
+ * - platform data board flags: FSL_<driver>_BRD_<FLAG>
+ *
+ */
+
+enum fsl_usb2_operating_modes {
+	FSL_USB2_MPH_HOST,
+	FSL_USB2_DR_HOST,
+	FSL_USB2_DR_DEVICE,
+	FSL_USB2_DR_OTG,
+};
+
+/* this used for usb port type */
+enum fsl_usb2_modes {
+	FSL_USB_DR_HOST,
+	FSL_USB_DR_DEVICE,
+	FSL_USB_MPH_HOST1,
+	FSL_USB_MPH_HOST2,
+	FSL_USB_UNKNOWN, /* unkonwn status */
+};
+
+enum fsl_usb2_phy_modes {
+	FSL_USB2_PHY_NONE,
+	FSL_USB2_PHY_ULPI,
+	FSL_USB2_PHY_UTMI,
+	FSL_USB2_PHY_UTMI_WIDE,
+	FSL_USB2_PHY_SERIAL,
+	FSL_USB2_PHY_HSIC,
+};
+
+enum usb_wakeup_event {
+	WAKEUP_EVENT_INVALID,
+	WAKEUP_EVENT_VBUS,
+	WAKEUP_EVENT_ID,
+	WAKEUP_EVENT_DPDM, /* for remote wakeup */
+};
+
+struct clk;
+struct platform_device;
+struct fsl_usb2_wakeup_platform_data;
+
+struct fsl_usb2_platform_data {
+	/* board specific information */
+	enum fsl_usb2_operating_modes	operating_mode;
+	enum fsl_usb2_phy_modes		phy_mode;
+	unsigned int			port_enables;
+	unsigned int			workaround;
+
+	int		(*init)(struct fsl_usb2_platform_data *);
+	void		(*exit)(struct fsl_usb2_platform_data *);
+	void __iomem	*regs;		/* ioremap'd register base */
+	struct clk	*clk;
+	unsigned	power_budget;	/* hcd->power_budget */
+	unsigned	big_endian_mmio:1;
+	unsigned	big_endian_desc:1;
+	unsigned	es:1;		/* need USBMODE:ES */
+	unsigned	le_setup_buf:1;
+	unsigned	have_sysif_regs:1;
+	unsigned	invert_drvvbus:1;
+	unsigned	invert_pwr_fault:1;
+
+	unsigned	suspended:1;
+	unsigned	already_suspended:1;
+
+	/* Freescale private */
+	char		*name;
+	u32		phy_regs;	/* usb phy register base */
+	u32 		xcvr_type;	/* PORTSC_PTS_* */
+	char 		*transceiver;	/* transceiver name */
+	u32		id_gpio;
+
+	struct fsl_xcvr_ops *xcvr_ops;
+	struct fsl_xcvr_power *xcvr_pwr;
+	int (*gpio_usb_active) (void);
+	void (*gpio_usb_inactive) (void);
+	void (*usb_clock_for_pm) (bool);
+	void (*platform_suspend)(struct fsl_usb2_platform_data *);
+	void (*platform_resume)(struct fsl_usb2_platform_data *);
+	void (*wake_up_enable)(struct fsl_usb2_platform_data *, bool);
+	void (*phy_lowpower_suspend)(struct fsl_usb2_platform_data *, bool);
+	void (*platform_driver_vbus)(bool on); /* for vbus shutdown/open */
+	enum usb_wakeup_event (*is_wakeup_event)(struct fsl_usb2_platform_data *);
+	void (*wakeup_handler)(struct fsl_usb2_platform_data *);
+	void (*hsic_post_ops)(void);
+	void (*hsic_device_connected)(void);
+	/*
+	 * Some platforms, like i.mx6x needs to discharge dp/dm at device mode
+	 * or there is wakeup interrupt caused by dp/dm change when the cable
+	 * is disconnected with Host.
+	 */
+	void (*dr_discharge_line) (bool);
+	/* only set it when vbus lower very slow during OTG switch */
+	bool need_discharge_vbus;
+	void (*platform_rh_suspend)(struct fsl_usb2_platform_data *);
+	void (*platform_rh_resume)(struct fsl_usb2_platform_data *);
+	void (*platform_set_disconnect_det)(struct fsl_usb2_platform_data *, bool);
+	void (*platform_phy_power_on)(void);
+
+	struct fsl_usb2_wakeup_platform_data *wakeup_pdata;
+	unsigned	change_ahb_burst:1;
+	unsigned	ahb_burst_mode:3;
+	unsigned	lowpower:1;
+	unsigned	irq_delay:1;
+	enum usb_wakeup_event	wakeup_event;
+	u32		pmflags;	/* PM from otg or system */
+
+	void __iomem *charger_base_addr; /* used for i.mx6 usb charger detect */
+
+	/* register save area for suspend/resume */
+	u32		pm_command;
+	u32		pm_status;
+	u32		pm_intr_enable;
+	u32		pm_frame_index;
+	u32		pm_segment;
+	u32		pm_frame_list;
+	u32		pm_async_next;
+	u32		pm_configured_flag;
+	u32		pm_portsc;
+	u32		pm_usbgenctrl;
+};
+
+struct fsl_usb2_wakeup_platform_data {
+	char *name;
+	void (*usb_clock_for_pm) (bool);
+	void (*usb_wakeup_exhandle) (void);
+	struct fsl_usb2_platform_data *usb_pdata[3];
+	/* This flag is used to indicate the "usb_wakeup thread" is finished during
+	 * usb wakeup routine.
+	 */
+	bool usb_wakeup_is_pending;
+};
+
+#endif /* _FSL_DEVICE_H_ */

+ 55 - 0
include/usb/fsl_xcvr.h

@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU Lesser General
+ * Public License.  You may obtain a copy of the GNU Lesser General
+ * Public License Version 2.1 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/lgpl-license.html
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+#ifndef __LINUX_USB_FSL_XCVR_H
+#define __LINUX_USB_FSL_XCVR_H
+
+struct fsl_usb2_platform_data;
+
+enum usb_test_mode{
+	USB_TEST_J = 1,
+	USB_TEST_K = 2,
+};
+
+/**
+ * @name: transceiver name
+ * @xcvr_type: one of PORTSC_PTS_{UTMI,SERIAL,ULPI}
+ * @init: transceiver- and board-specific initialization function
+ * @uninit: transceiver- and board-specific uninitialization function
+ * @set_host:
+ * @set_device:
+ * @pullup: enable or disable D+ pullup
+ *
+ */
+struct fsl_xcvr_ops {
+	char *name;
+	u32 xcvr_type;
+
+	void (*init)(struct fsl_xcvr_ops *ops);
+	void (*uninit)(struct fsl_xcvr_ops *ops);
+	void (*suspend)(struct fsl_xcvr_ops *ops);
+	void (*set_host)(void);
+	void (*set_device)(void);
+	void (*set_vbus_power)(struct fsl_xcvr_ops *ops,
+			       struct fsl_usb2_platform_data *pdata, int on);
+	void (*set_vbus_draw)(struct fsl_xcvr_ops *ops,
+			struct fsl_usb2_platform_data *pdata, unsigned mA);
+	void (*set_remote_wakeup)(u32 *view);
+	void (*pullup)(int on);
+	void(*set_test_mode)(u32 *view, enum usb_test_mode mode);
+};
+
+struct fsl_xcvr_power {
+	struct regulator *regu1;
+	struct regulator *regu2;
+};
+#endif