diff --git a/Makefile b/Makefile
index 29e3dbb24ed102f8585236708542fb4b008e6339..bf8524d105086678fef8571971c15a31cd40612c 100644
--- a/Makefile
+++ b/Makefile
@@ -286,6 +286,7 @@ LIBS += drivers/usb/gadget/libusb_gadget.o
 LIBS += drivers/usb/host/libusb_host.o
 LIBS += drivers/usb/musb/libusb_musb.o
 LIBS += drivers/usb/phy/libusb_phy.o
+LIBS += drivers/usb/ulpi/libusb_ulpi.o
 LIBS += drivers/video/libvideo.o
 LIBS += drivers/watchdog/libwatchdog.o
 LIBS += common/libcommon.o
diff --git a/arch/arm/cpu/armv7/mx5/clock.c b/arch/arm/cpu/armv7/mx5/clock.c
index 933ce05b767e5b19804e380d1bf6b750a868b8ab..e92f10623a92bb6e72c2d4c3e947f58dffcce78b 100644
--- a/arch/arm/cpu/armv7/mx5/clock.c
+++ b/arch/arm/cpu/armv7/mx5/clock.c
@@ -50,6 +50,78 @@ struct mxc_pll_reg *mxc_plls[PLL_CLOCKS] = {
 
 struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)MXC_CCM_BASE;
 
+void set_usboh3_clk(void)
+{
+	unsigned int reg;
+
+	reg = readl(&mxc_ccm->cscmr1) &
+		 ~MXC_CCM_CSCMR1_USBOH3_CLK_SEL_MASK;
+	reg |= 1 << MXC_CCM_CSCMR1_USBOH3_CLK_SEL_OFFSET;
+	writel(reg, &mxc_ccm->cscmr1);
+
+	reg = readl(&mxc_ccm->cscdr1);
+	reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK;
+	reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK;
+	reg |= 4 << MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET;
+	reg |= 1 << MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET;
+
+	writel(reg, &mxc_ccm->cscdr1);
+}
+
+void enable_usboh3_clk(unsigned char enable)
+{
+	unsigned int reg;
+
+	reg = readl(&mxc_ccm->CCGR2);
+	if (enable)
+		reg |= 1 << MXC_CCM_CCGR2_CG14_OFFSET;
+	else
+		reg &= ~(1 << MXC_CCM_CCGR2_CG14_OFFSET);
+	writel(reg, &mxc_ccm->CCGR2);
+}
+
+void set_usb_phy1_clk(void)
+{
+	unsigned int reg;
+
+	reg = readl(&mxc_ccm->cscmr1);
+	reg &= ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL;
+	writel(reg, &mxc_ccm->cscmr1);
+}
+
+void enable_usb_phy1_clk(unsigned char enable)
+{
+	unsigned int reg;
+
+	reg = readl(&mxc_ccm->CCGR4);
+	if (enable)
+		reg |= 1 << MXC_CCM_CCGR4_CG5_OFFSET;
+	else
+		reg &= ~(1 << MXC_CCM_CCGR4_CG5_OFFSET);
+	writel(reg, &mxc_ccm->CCGR4);
+}
+
+void set_usb_phy2_clk(void)
+{
+	unsigned int reg;
+
+	reg = readl(&mxc_ccm->cscmr1);
+	reg &= ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL;
+	writel(reg, &mxc_ccm->cscmr1);
+}
+
+void enable_usb_phy2_clk(unsigned char enable)
+{
+	unsigned int reg;
+
+	reg = readl(&mxc_ccm->CCGR4);
+	if (enable)
+		reg |= 1 << MXC_CCM_CCGR4_CG6_OFFSET;
+	else
+		reg &= ~(1 << MXC_CCM_CCGR4_CG6_OFFSET);
+	writel(reg, &mxc_ccm->CCGR4);
+}
+
 /*
  * Calculate the frequency of PLLn.
  */
diff --git a/arch/arm/cpu/pxa/usb.c b/arch/arm/cpu/pxa/usb.c
index 83022e2e563aa64b4fde2e0074c07f048cb06f46..307fc6ceec3b819016a5f2e648a81bc2fece0b7b 100644
--- a/arch/arm/cpu/pxa/usb.c
+++ b/arch/arm/cpu/pxa/usb.c
@@ -55,7 +55,7 @@ int usb_cpu_init(void)
 	while (readl(UHCHR) & UHCHR_FSBIR)
 		udelay(1);
 
-#if defined(CONFIG_CPU_MONAHANS)
+#if defined(CONFIG_CPU_MONAHANS) || defined(CONFIG_PXA27X)
 	writel(readl(UHCHR) & ~UHCHR_SSEP0, UHCHR);
 #endif
 #if defined(CONFIG_CPU_PXA27X)
@@ -72,10 +72,10 @@ int usb_cpu_stop(void)
 	udelay(11);
 	writel(readl(UHCHR) & ~UHCHR_FHR, UHCHR);
 
-	writel(readl(UHCCOMS) | UHCHR_FHR, UHCCOMS);
+	writel(readl(UHCCOMS) | UHCCOMS_HCR, UHCCOMS);
 	udelay(10);
 
-#if defined(CONFIG_CPU_MONAHANS)
+#if defined(CONFIG_CPU_MONAHANS) || defined(CONFIG_PXA27X)
 	writel(readl(UHCHR) | UHCHR_SSEP0, UHCHR);
 #endif
 #if defined(CONFIG_CPU_PXA27X)
diff --git a/arch/arm/include/asm/arch-mx5/clock.h b/arch/arm/include/asm/arch-mx5/clock.h
index 1f8a537a56bf8857943b98aeb9eb3acb7331844a..ea972a398545169e060924155bded2eebbf19cf5 100644
--- a/arch/arm/include/asm/arch-mx5/clock.h
+++ b/arch/arm/include/asm/arch-mx5/clock.h
@@ -40,4 +40,9 @@ u32 imx_get_uartclk(void);
 u32 imx_get_fecclk(void);
 unsigned int mxc_get_clock(enum mxc_clock clk);
 
+void set_usb_phy2_clk(void);
+void enable_usb_phy2_clk(unsigned char enable);
+void set_usboh3_clk(void);
+void enable_usboh3_clk(unsigned char enable);
+
 #endif /* __ASM_ARCH_CLOCK_H */
diff --git a/arch/arm/include/asm/arch-mx5/crm_regs.h b/arch/arm/include/asm/arch-mx5/crm_regs.h
index fcc0e36fa5a66f9c532d70f1bef51084aebe7d6e..bdeafbc0df7b26ebe69838fcd79318e14bb301da 100644
--- a/arch/arm/include/asm/arch-mx5/crm_regs.h
+++ b/arch/arm/include/asm/arch-mx5/crm_regs.h
@@ -195,7 +195,10 @@ struct mxc_ccm_reg {
 /* Define the bits in register CCGRx */
 #define MXC_CCM_CCGR_CG_MASK				0x3
 
+#define MXC_CCM_CCGR4_CG5_OFFSET			10
+#define MXC_CCM_CCGR4_CG6_OFFSET			12
 #define MXC_CCM_CCGR5_CG5_OFFSET			10
+#define MXC_CCM_CCGR2_CG14_OFFSET			28
 
 /* Define the bits in register CLPCR */
 #define MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS                 (0x1 << 18)
diff --git a/arch/arm/include/asm/arch-pxa/pxa-regs.h b/arch/arm/include/asm/arch-pxa/pxa-regs.h
index 8527c68c812cb410f31787f1e9b7a3a750d315c5..b81b42c07c7479b49c05b2085cd6132899faffe4 100644
--- a/arch/arm/include/asm/arch-pxa/pxa-regs.h
+++ b/arch/arm/include/asm/arch-pxa/pxa-regs.h
@@ -645,7 +645,7 @@ typedef void		(*ExcpHndlr) (void) ;
 #define UDCOTGICR_IEIDR		(1 << 1)	/* OTG ID Change Rising Edge Interrupt Enable */
 #define UDCOTGICR_IEIDF		(1 << 0)	/* OTG ID Change Falling Edge Interrupt Enable */
 
-#define UDCCSN(x)	__REG2(0x40600100, (x) << 2)
+#define UDCCSN(x)	(0x40600100 + ((x) << 2))
 #define UDCCSR0		0x40600100 /* UDC Control/Status register - Endpoint 0 */
 
 #define UDCCSR0_SA	(1 << 7)	/* Setup Active */
@@ -693,7 +693,7 @@ typedef void		(*ExcpHndlr) (void) ;
 #define UDCCSR_PC	(1 << 1)	/* Packet Complete */
 #define UDCCSR_FS	(1 << 0)	/* FIFO needs service */
 
-#define UDCBCN(x)	__REG2(0x40600200, (x)<<2)
+#define UDCBCN(x)	(0x40600200 + ((x) << 2))
 #define UDCBCR0         0x40600200 /* Byte Count Register - EP0 */
 #define UDCBCRA         0x40600204 /* Byte Count Register - EPA */
 #define UDCBCRB         0x40600208 /* Byte Count Register - EPB */
@@ -719,7 +719,7 @@ typedef void		(*ExcpHndlr) (void) ;
 #define UDCBCRW         0x40600258 /* Byte Count Register - EPW */
 #define UDCBCRX         0x4060025C /* Byte Count Register - EPX */
 
-#define UDCDN(x)	__REG2(0x40600300, (x)<<2)
+#define UDCDN(x)	(0x40600300 + ((x) << 2))
 #define UDCDR0          0x40600300 /* Data Register - EP0 */
 #define UDCDRA          0x40600304 /* Data Register - EPA */
 #define UDCDRB          0x40600308 /* Data Register - EPB */
@@ -745,7 +745,7 @@ typedef void		(*ExcpHndlr) (void) ;
 #define UDCDRW          0x40600358 /* Data Register - EPW */
 #define UDCDRX          0x4060035C /* Data Register - EPX */
 
-#define UDCCN(x)	__REG2(0x40600400, (x)<<2)
+#define UDCCN(x)	(0x40600400 + ((x) << 2))
 #define UDCCRA          0x40600404 /* Configuration register EPA */
 #define UDCCRB          0x40600408 /* Configuration register EPB */
 #define UDCCRC          0x4060040C /* Configuration register EPC */
@@ -835,6 +835,8 @@ typedef void		(*ExcpHndlr) (void) ;
 #define UHCHIE		0x4C000068
 #define UHCHIT		0x4C00006C
 
+#define UHCCOMS_HCR	(1<<0)
+
 #define UHCHR_FSBIR	(1<<0)
 #define UHCHR_FHR	(1<<1)
 #define UHCHR_CGR	(1<<2)
diff --git a/arch/arm/include/asm/arch-s5pc1xx/cpu.h b/arch/arm/include/asm/arch-s5pc1xx/cpu.h
index e74959fe222e464cb3054f253a8dd86e8b7b45a4..e699fc47c04391de5f0df1255b4581bbe9627d5b 100644
--- a/arch/arm/include/asm/arch-s5pc1xx/cpu.h
+++ b/arch/arm/include/asm/arch-s5pc1xx/cpu.h
@@ -55,6 +55,10 @@
 #define S5PC110_VIC1_BASE	0xF2100000
 #define S5PC110_VIC2_BASE	0xF2200000
 #define S5PC110_VIC3_BASE	0xF2300000
+#define S5PC110_OTG_BASE	0xEC000000
+#define S5PC110_PHY_BASE	0xEC100000
+#define S5PC110_USB_PHY_CONTROL 0xE010E80C
+
 
 #ifndef __ASSEMBLY__
 #include <asm/io.h>
diff --git a/board/efikamx/Makefile b/board/efikamx/Makefile
index bd1056e00d9387dee6938b415b6816714de7264b..fdd188ecfc1eae6f33fe4731e8cdb758c5309881 100644
--- a/board/efikamx/Makefile
+++ b/board/efikamx/Makefile
@@ -29,6 +29,10 @@ LIB	= $(obj)lib$(BOARD).o
 
 COBJS	:= efikamx.o
 
+ifdef	CONFIG_CMD_USB
+COBJS	+= efikamx-usb.o
+endif
+
 SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(COBJS))
 SOBJS	:= $(addprefix $(obj),$(SOBJS))
diff --git a/board/efikamx/efikamx-usb.c b/board/efikamx/efikamx-usb.c
new file mode 100644
index 0000000000000000000000000000000000000000..840bd9aaa38b372f7b6003c7a4d12d7d5977fe25
--- /dev/null
+++ b/board/efikamx/efikamx-usb.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * (C) Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <usb.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/mx5x_pins.h>
+#include <asm/arch/iomux.h>
+#include <asm/gpio.h>
+#include <usb/ehci-fsl.h>
+#include <usb/ulpi.h>
+#include <errno.h>
+
+#include "../../drivers/usb/host/ehci.h"
+
+/* USB pin configuration */
+#define USB_PAD_CONFIG	(PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST | \
+			PAD_CTL_DRV_HIGH | PAD_CTL_100K_PU | \
+			PAD_CTL_HYS_ENABLE | PAD_CTL_PUE_PULL)
+
+/*
+ * Configure the USB H1 and USB H2 IOMUX
+ */
+void setup_iomux_usb(void)
+{
+	setup_iomux_usb_h1();
+
+	if (machine_is_efikasb())
+		setup_iomux_usb_h2();
+
+	/* USB PHY reset */
+	mxc_request_iomux(MX51_PIN_EIM_D27, IOMUX_CONFIG_ALT1);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D27, PAD_CTL_PKE_ENABLE |
+			PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH);
+
+	/* USB HUB reset */
+	mxc_request_iomux(MX51_PIN_GPIO1_5, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_GPIO1_5, PAD_CTL_PKE_ENABLE |
+			PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH);
+
+	/* WIFI EN (act low) */
+	mxc_request_iomux(MX51_PIN_EIM_A22, IOMUX_CONFIG_GPIO);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A22, 0);
+	/* WIFI RESET */
+	mxc_request_iomux(MX51_PIN_EIM_A16, IOMUX_CONFIG_GPIO);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A16, 0);
+	/* BT EN (act low) */
+	mxc_request_iomux(MX51_PIN_EIM_A17, IOMUX_CONFIG_GPIO);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A17, 0);
+}
+
+/*
+ * Enable devices connected to USB BUSes
+ */
+static void efika_usb_enable_devices(void)
+{
+	/* Enable Bluetooth */
+	gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A17), 0);
+	udelay(10000);
+	gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A17), 1);
+
+	/* Enable WiFi */
+	gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A22), 1);
+	udelay(10000);
+
+	/* Reset the WiFi chip */
+	gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A16), 0);
+	udelay(10000);
+	gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A16), 1);
+}
+
+/*
+ * Reset USB HUB (or HUBs on EfikaSB)
+ */
+static void efika_usb_hub_reset(void)
+{
+	/* HUB reset */
+	gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_GPIO1_5), 1);
+	udelay(1000);
+	gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_5), 0);
+	udelay(1000);
+	gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_5), 1);
+}
+
+/*
+ * Reset USB PHY (or PHYs on EfikaSB)
+ */
+static void efika_usb_phy_reset(void)
+{
+	/* SMSC 3317 PHY reset */
+	gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_D27), 0);
+	udelay(1000);
+	gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_D27), 1);
+}
+
+static void efika_ehci_init(struct usb_ehci *ehci, uint32_t stp_gpio,
+				uint32_t alt0, uint32_t alt1)
+{
+	int ret;
+	struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
+
+	mxc_request_iomux(stp_gpio, alt0);
+	mxc_iomux_set_pad(stp_gpio, PAD_CTL_DRV_HIGH |
+				PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST);
+	gpio_direction_output(IOMUX_TO_GPIO(stp_gpio), 0);
+	udelay(1000);
+	gpio_set_value(IOMUX_TO_GPIO(stp_gpio), 1);
+	udelay(1000);
+
+	mxc_request_iomux(stp_gpio, alt1);
+	mxc_iomux_set_pad(stp_gpio, USB_PAD_CONFIG);
+	udelay(10000);
+
+	ret = ulpi_init((u32)&ehci->ulpi_viewpoint);
+	if (ret) {
+		printf("Efika USB ULPI initialization failed\n");
+		return;
+	}
+
+	/* ULPI set flags */
+	ulpi_write((u32)&ehci->ulpi_viewpoint, &ulpi->otg_ctrl,
+			ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN |
+			ULPI_OTG_EXTVBUSIND);
+	ulpi_write((u32)&ehci->ulpi_viewpoint, &ulpi->function_ctrl,
+			ULPI_FC_FULL_SPEED | ULPI_FC_OPMODE_NORMAL |
+			ULPI_FC_SUSPENDM);
+	ulpi_write((u32)&ehci->ulpi_viewpoint, &ulpi->iface_ctrl, 0);
+
+	/* Set VBus */
+	ulpi_write((u32)&ehci->ulpi_viewpoint, &ulpi->otg_ctrl_set,
+			ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
+
+	/*
+	 * Set VBusChrg
+	 *
+	 * NOTE: This violates USB specification, but otherwise, USB on Efika
+	 * doesn't work.
+	 */
+	ulpi_write((u32)&ehci->ulpi_viewpoint, &ulpi->otg_ctrl_set,
+			ULPI_OTG_CHRGVBUS);
+}
+
+int board_ehci_hcd_init(int port)
+{
+	/* Init iMX51 EHCI */
+	efika_usb_phy_reset();
+	efika_usb_hub_reset();
+	efika_usb_enable_devices();
+
+	return 0;
+}
+
+void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
+{
+	uint32_t port = OTG_BASE_ADDR + (0x200 * CONFIG_MXC_USB_PORT);
+	struct usb_ehci *ehci = (struct usb_ehci *)port;
+	struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
+
+	ulpi_write((u32)&ehci->ulpi_viewpoint, &ulpi->otg_ctrl_set,
+			ULPI_OTG_CHRGVBUS);
+
+	wait_ms(50);
+
+	/* terminate the reset */
+	*reg = ehci_readl(status_reg);
+	*reg |= EHCI_PS_PE;
+}
+
+void board_ehci_hcd_postinit(struct usb_ehci *ehci, int port)
+{
+	uint32_t tmp;
+
+	if (port == 0) {
+		/* Adjust UTMI PHY frequency to 24MHz */
+		tmp = readl(OTG_BASE_ADDR + 0x80c);
+		tmp = (tmp & ~0x3) | 0x01;
+		writel(tmp, OTG_BASE_ADDR + 0x80c);
+	} else if (port == 1) {
+		efika_ehci_init(ehci, MX51_PIN_USBH1_STP,
+				IOMUX_CONFIG_ALT2, IOMUX_CONFIG_ALT0);
+	} else if ((port == 2) && machine_is_efikasb()) {
+		efika_ehci_init(ehci, MX51_PIN_EIM_A26,
+				IOMUX_CONFIG_ALT1, IOMUX_CONFIG_ALT2);
+	}
+
+	if (port)
+		mdelay(10);
+}
diff --git a/board/efikamx/efikamx.c b/board/efikamx/efikamx.c
index 3d2cc1a7f137f6d70fee78d1b38bf20ee1ad5c36..1f6c457e9909e41d14710cb38a05831533ec11b2 100644
--- a/board/efikamx/efikamx.c
+++ b/board/efikamx/efikamx.c
@@ -539,6 +539,15 @@ void setup_iomux_ata(void)
 static inline void setup_iomux_ata(void) { }
 #endif
 
+/*
+ * EHCI USB
+ */
+#ifdef	CONFIG_CMD_USB
+extern void setup_iomux_usb(void);
+#else
+static inline void setup_iomux_usb(void) { }
+#endif
+
 /*
  * LED configuration
  */
@@ -688,6 +697,12 @@ int board_late_init(void)
 
 	setup_iomux_led();
 	setup_iomux_ata();
+	setup_iomux_usb();
+
+	if (machine_is_efikasb())
+		setenv("preboot", "usb reset ; setenv stdin usbkbd\0");
+
+	setup_iomux_led();
 
 	efikamx_toggle_led(EFIKAMX_LED_BLUE);
 
diff --git a/board/freescale/mx51evk/mx51evk.c b/board/freescale/mx51evk/mx51evk.c
index e5b0929f65e0b4641373127e5072805f25713436..13c59413ecfddcd3c47d7928bb9b2c5b649a1dfb 100644
--- a/board/freescale/mx51evk/mx51evk.c
+++ b/board/freescale/mx51evk/mx51evk.c
@@ -35,6 +35,7 @@
 #include <pmic.h>
 #include <fsl_pmic.h>
 #include <mc13892.h>
+#include <usb/ehci-fsl.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -172,6 +173,64 @@ static void setup_iomux_spi(void)
 }
 #endif
 
+#ifdef CONFIG_USB_EHCI_MX5
+#define MX51EVK_USBH1_HUB_RST	IOMUX_TO_GPIO(MX51_PIN_GPIO1_7) /* GPIO1_7 */
+#define MX51EVK_USBH1_STP	IOMUX_TO_GPIO(MX51_PIN_USBH1_STP) /* GPIO1_27 */
+#define MX51EVK_USB_CLK_EN_B	IOMUX_TO_GPIO(MX51_PIN_EIM_D18) /* GPIO2_1 */
+#define MX51EVK_USB_PHY_RESET	IOMUX_TO_GPIO(MX51_PIN_EIM_D21) /* GPIO2_5 */
+
+#define USBH1_PAD	(PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH |		\
+			 PAD_CTL_100K_PU | PAD_CTL_PUE_PULL |		\
+			 PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE)
+#define GPIO_PAD	(PAD_CTL_DRV_HIGH | PAD_CTL_PKE_ENABLE |	\
+			 PAD_CTL_SRE_FAST)
+#define NO_PAD		(1 << 16)
+
+static void setup_usb_h1(void)
+{
+	setup_iomux_usb_h1();
+
+	/* GPIO_1_7 for USBH1 hub reset */
+	mxc_request_iomux(MX51_PIN_GPIO1_7, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_GPIO1_7, NO_PAD);
+
+	/* GPIO_2_1 */
+	mxc_request_iomux(MX51_PIN_EIM_D17, IOMUX_CONFIG_ALT1);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D17, GPIO_PAD);
+
+	/* GPIO_2_5 for USB PHY reset */
+	mxc_request_iomux(MX51_PIN_EIM_D21, IOMUX_CONFIG_ALT1);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D21, GPIO_PAD);
+}
+
+void board_ehci_hcd_init(int port)
+{
+	/* Set USBH1_STP to GPIO and toggle it */
+	mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_GPIO);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_STP, USBH1_PAD);
+
+	gpio_direction_output(MX51EVK_USBH1_STP, 0);
+	gpio_direction_output(MX51EVK_USB_PHY_RESET, 0);
+	mdelay(10);
+	gpio_set_value(MX51EVK_USBH1_STP, 1);
+
+	/* Set back USBH1_STP to be function */
+	mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_STP, USBH1_PAD);
+
+	/* De-assert USB PHY RESETB */
+	gpio_set_value(MX51EVK_USB_PHY_RESET, 1);
+
+	/* Drive USB_CLK_EN_B line low */
+	gpio_direction_output(MX51EVK_USB_CLK_EN_B, 0);
+
+	/* Reset USB hub */
+	gpio_direction_output(MX51EVK_USBH1_HUB_RST, 0);
+	mdelay(2);
+	gpio_set_value(MX51EVK_USBH1_HUB_RST, 1);
+}
+#endif
+
 static void power_init(void)
 {
 	unsigned int val;
@@ -394,6 +453,9 @@ int board_early_init_f(void)
 {
 	setup_iomux_uart();
 	setup_iomux_fec();
+#ifdef CONFIG_USB_EHCI_MX5
+	setup_usb_h1();
+#endif
 
 	return 0;
 }
diff --git a/board/freescale/mx53loco/mx53loco.c b/board/freescale/mx53loco/mx53loco.c
index 3cf4195b5e3e75496a27e14df9c288e8ed97ca81..57170ce0452cd0fd134831d5f9b7cafad37a24bf 100644
--- a/board/freescale/mx53loco/mx53loco.c
+++ b/board/freescale/mx53loco/mx53loco.c
@@ -78,6 +78,16 @@ static void setup_iomux_uart(void)
 				PAD_CTL_ODE_OPENDRAIN_ENABLE);
 }
 
+#ifdef CONFIG_USB_EHCI_MX5
+void board_ehci_hcd_init(int port)
+{
+	/* request VBUS power enable pin, GPIO[8}, gpio7 */
+	mxc_request_iomux(MX53_PIN_ATA_DA_2, IOMUX_CONFIG_ALT1);
+	gpio_direction_output(IOMUX_TO_GPIO(MX53_PIN_ATA_DA_2), 0);
+	gpio_set_value(IOMUX_TO_GPIO(MX53_PIN_ATA_DA_2), 1);
+}
+#endif
+
 static void setup_iomux_fec(void)
 {
 	/*FEC_MDIO*/
diff --git a/board/samsung/goni/goni.c b/board/samsung/goni/goni.c
index e191bfbd28ce4678f17866834ab8dc1be1ba80a7..e8fb1ea4130a740480cd685c0cb09d9c9d732d51 100644
--- a/board/samsung/goni/goni.c
+++ b/board/samsung/goni/goni.c
@@ -26,7 +26,9 @@
 #include <asm/arch/gpio.h>
 #include <asm/arch/mmc.h>
 #include <pmic.h>
-
+#include <usb/s3c_udc.h>
+#include <asm/arch/cpu.h>
+#include <max8998_pmic.h>
 DECLARE_GLOBAL_DATA_PTR;
 
 static struct s5pc110_gpio *s5pc110_gpio;
@@ -100,3 +102,47 @@ int board_mmc_init(bd_t *bis)
 	return s5p_mmc_init(0, 4);
 }
 #endif
+
+#ifdef CONFIG_USB_GADGET
+static int s5pc1xx_phy_control(int on)
+{
+	int ret;
+	static int status;
+	struct pmic *p = get_pmic();
+
+	if (pmic_probe(p))
+		return -1;
+
+	if (on && !status) {
+		ret = pmic_set_output(p, MAX8998_REG_ONOFF1,
+				      MAX8998_LDO3, LDO_ON);
+		ret = pmic_set_output(p, MAX8998_REG_ONOFF2,
+				      MAX8998_LDO8, LDO_ON);
+		if (ret) {
+			puts("MAX8998 LDO setting error!\n");
+			return -1;
+		}
+		status = 1;
+	} else if (!on && status) {
+		ret = pmic_set_output(p, MAX8998_REG_ONOFF1,
+				      MAX8998_LDO3, LDO_OFF);
+		ret = pmic_set_output(p, MAX8998_REG_ONOFF2,
+				      MAX8998_LDO8, LDO_OFF);
+		if (ret) {
+			puts("MAX8998 LDO setting error!\n");
+			return -1;
+		}
+		status = 0;
+	}
+	udelay(10000);
+
+	return 0;
+}
+
+struct s3c_plat_otg_data s5pc110_otg_data = {
+	.phy_control = s5pc1xx_phy_control,
+	.regs_phy = S5PC110_PHY_BASE,
+	.regs_otg = S5PC110_OTG_BASE,
+	.usb_phy_ctrl = S5PC110_USB_PHY_CONTROL,
+};
+#endif
diff --git a/common/cmd_usb.c b/common/cmd_usb.c
index 8c87265668d73715bc1a8f872cc2af8514ac2111..d4ec2a291cddca5c340987b277290a9477bfda7a 100644
--- a/common/cmd_usb.c
+++ b/common/cmd_usb.c
@@ -700,11 +700,12 @@ int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 U_BOOT_CMD(
 	usb,	5,	1,	do_usb,
 	"USB sub-system",
-	"reset - reset (rescan) USB controller\n"
-	"usb stop [f]  - stop USB [f]=force stop\n"
-	"usb tree  - show USB device tree\n"
+	"start - start (scan) USB controller\n"
+	"usb reset - reset (rescan) USB controller\n"
+	"usb stop [f] - stop USB [f]=force stop\n"
+	"usb tree - show USB device tree\n"
 	"usb info [dev] - show available USB devices\n"
-	"usb storage  - show details of USB storage devices\n"
+	"usb storage - show details of USB storage devices\n"
 	"usb dev [dev] - show or set current USB storage device\n"
 	"usb part [dev] - print partition table of one or all USB storage"
 	" devices\n"
@@ -725,8 +726,9 @@ U_BOOT_CMD(
 U_BOOT_CMD(
 	usb,	5,	1,	do_usb,
 	"USB sub-system",
-	"reset - reset (rescan) USB controller\n"
-	"usb  tree  - show USB device tree\n"
-	"usb  info [dev] - show available USB devices"
+	"start - start (scan) USB controller\n"
+	"usb reset - reset (rescan) USB controller\n"
+	"usb tree - show USB device tree\n"
+	"usb info [dev] - show available USB devices"
 );
 #endif
diff --git a/common/usb_kbd.c b/common/usb_kbd.c
index 69939f06ac83e10c2f07d30cbcde1fa1bcd9e98e..75107c9a45d9e4397ac9897fbae63bb47ecd4631 100644
--- a/common/usb_kbd.c
+++ b/common/usb_kbd.c
@@ -25,12 +25,18 @@
  *
  */
 #include <common.h>
+#include <malloc.h>
 #include <stdio_dev.h>
 #include <asm/byteorder.h>
 
 #include <usb.h>
 
-#undef USB_KBD_DEBUG
+#ifdef	USB_KBD_DEBUG
+#define USB_KBD_PRINTF(fmt, args...)	printf(fmt, ##args)
+#else
+#define USB_KBD_PRINTF(fmt, args...)
+#endif
+
 /*
  * If overwrite_console returns 1, the stdin, stderr and stdout
  * are switched to the serial port, else the settings in the
@@ -45,743 +51,457 @@ int overwrite_console(void)
 }
 #endif
 
-#ifdef USB_KBD_DEBUG
-#define USB_KBD_PRINTF(fmt, args...)	printf(fmt, ##args)
-#else
-#define USB_KBD_PRINTF(fmt, args...)
-#endif
-
-
-#define REPEAT_RATE	(40/4)	/* 40msec -> 25cps */
-#define REPEAT_DELAY	10	/* 10 x REPEAT_RATE = 400msec */
+/* Keyboard sampling rate */
+#define REPEAT_RATE	(40 / 4)	/* 40msec -> 25cps */
+#define REPEAT_DELAY	10		/* 10 x REPEAT_RATE = 400msec */
 
 #define NUM_LOCK	0x53
 #define CAPS_LOCK	0x39
 #define SCROLL_LOCK	0x47
 
-
 /* Modifier bits */
-#define LEFT_CNTR		0
-#define LEFT_SHIFT		1
-#define LEFT_ALT		2
-#define LEFT_GUI		3
-#define RIGHT_CNTR		4
-#define RIGHT_SHIFT		5
-#define RIGHT_ALT		6
-#define RIGHT_GUI		7
-
-#define USB_KBD_BUFFER_LEN	0x20	/* size of the keyboardbuffer */
-
-static char usb_kbd_buffer[USB_KBD_BUFFER_LEN];
-static int usb_in_pointer;
-static int usb_out_pointer;
-
-unsigned char new[8];
-unsigned char old[8];
-int repeat_delay;
+#define LEFT_CNTR	(1 << 0)
+#define LEFT_SHIFT	(1 << 1)
+#define LEFT_ALT	(1 << 2)
+#define LEFT_GUI	(1 << 3)
+#define RIGHT_CNTR	(1 << 4)
+#define RIGHT_SHIFT	(1 << 5)
+#define RIGHT_ALT	(1 << 6)
+#define RIGHT_GUI	(1 << 7)
+
+/* Size of the keyboard buffer */
+#define USB_KBD_BUFFER_LEN	0x20
+
+/* Device name */
 #define DEVNAME			"usbkbd"
-static unsigned char num_lock;
-static unsigned char caps_lock;
-static unsigned char scroll_lock;
-static unsigned char ctrl;
-
-static unsigned char leds __attribute__((aligned(0x4)));
 
-static unsigned char usb_kbd_numkey[] = {
+/* Keyboard maps */
+static const unsigned char usb_kbd_numkey[] = {
 	'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
 	'\r', 0x1b, '\b', '\t', ' ', '-', '=', '[', ']',
 	'\\', '#', ';', '\'', '`', ',', '.', '/'
 };
-static unsigned char usb_kbd_numkey_shifted[] = {
+static const unsigned char usb_kbd_numkey_shifted[] = {
 	'!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
 	'\r', 0x1b, '\b', '\t', ' ', '_', '+', '{', '}',
 	'|', '~', ':', '"', '~', '<', '>', '?'
 };
 
-/******************************************************************
- * Queue handling
- ******************************************************************/
-/* puts character in the queue and sets up the in and out pointer */
-static void usb_kbd_put_queue(char data)
-{
-	if ((usb_in_pointer+1) == USB_KBD_BUFFER_LEN) {
-		if (usb_out_pointer == 0)
-			return; /* buffer full */
-		else
-			usb_in_pointer = 0;
-	} else {
-		if ((usb_in_pointer+1) == usb_out_pointer)
-			return; /* buffer full */
-		usb_in_pointer++;
-	}
-	usb_kbd_buffer[usb_in_pointer] = data;
-	return;
-}
+/*
+ * NOTE: It's important for the NUM, CAPS, SCROLL-lock bits to be in this
+ *       order. See usb_kbd_setled() function!
+ */
+#define USB_KBD_NUMLOCK		(1 << 0)
+#define USB_KBD_CAPSLOCK	(1 << 1)
+#define USB_KBD_SCROLLLOCK	(1 << 2)
+#define USB_KBD_CTRL		(1 << 3)
 
-/* test if a character is in the queue */
-static int usb_kbd_testc(void)
-{
-#ifdef CONFIG_SYS_USB_EVENT_POLL
-	usb_event_poll();
-#endif
-	if (usb_in_pointer == usb_out_pointer)
-		return 0; /* no data */
-	else
-		return 1;
-}
-/* gets the character from the queue */
-static int usb_kbd_getc(void)
-{
-	char c;
-	while (usb_in_pointer == usb_out_pointer) {
-#ifdef CONFIG_SYS_USB_EVENT_POLL
-		usb_event_poll();
-#endif
-	}
-	if ((usb_out_pointer+1) == USB_KBD_BUFFER_LEN)
-		usb_out_pointer = 0;
-	else
-		usb_out_pointer++;
-	c = usb_kbd_buffer[usb_out_pointer];
-	return (int)c;
+#define USB_KBD_LEDMASK		\
+	(USB_KBD_NUMLOCK | USB_KBD_CAPSLOCK | USB_KBD_SCROLLLOCK)
 
-}
+struct usb_kbd_pdata {
+	uint32_t	repeat_delay;
 
-/* forward decleration */
-static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum);
+	uint32_t	usb_in_pointer;
+	uint32_t	usb_out_pointer;
+	uint8_t		usb_kbd_buffer[USB_KBD_BUFFER_LEN];
 
-/* search for keyboard and register it if found */
-int drv_usb_kbd_init(void)
+	uint8_t		new[8];
+	uint8_t		old[8];
+
+	uint8_t		flags;
+};
+
+/* Generic keyboard event polling. */
+void usb_kbd_generic_poll(void)
 {
-	int error, i;
-	struct stdio_dev usb_kbd_dev, *old_dev;
-	struct usb_device *dev;
-	char *stdinname = getenv("stdin");
+	struct stdio_dev *dev;
+	struct usb_device *usb_kbd_dev;
+	struct usb_kbd_pdata *data;
+	struct usb_interface *iface;
+	struct usb_endpoint_descriptor *ep;
+	int pipe;
+	int maxp;
+
+	/* Get the pointer to USB Keyboard device pointer */
+	dev = stdio_get_by_name(DEVNAME);
+	usb_kbd_dev = (struct usb_device *)dev->priv;
+	data = usb_kbd_dev->privptr;
+	iface = &usb_kbd_dev->config.if_desc[0];
+	ep = &iface->ep_desc[0];
+	pipe = usb_rcvintpipe(usb_kbd_dev, ep->bEndpointAddress);
 
-	usb_in_pointer = 0;
-	usb_out_pointer = 0;
-	/* scan all USB Devices */
-	for (i = 0 ; i < USB_MAX_DEVICE ; i++) {
-		dev = usb_get_dev_index(i); /* get device */
-		if (dev == NULL)
-			return -1;
-		if (dev->devnum != -1) {
-			/* Ok, we found a keyboard */
-			if (usb_kbd_probe(dev, 0) == 1) {
-				/* check, if it is already registered */
-				USB_KBD_PRINTF("USB KBD found set up "
-						"device.\n");
-				old_dev = stdio_get_by_name(DEVNAME);
-				if (old_dev) {
-					/* already registered, just return ok */
-					USB_KBD_PRINTF("USB KBD is already "
-							"registered.\n");
-					return 1;
-				}
-				/* register the keyboard */
-				USB_KBD_PRINTF("USB KBD register.\n");
-				memset(&usb_kbd_dev, 0,
-						sizeof(struct stdio_dev));
-				strcpy(usb_kbd_dev.name, DEVNAME);
-				usb_kbd_dev.flags =  DEV_FLAGS_INPUT |
-							DEV_FLAGS_SYSTEM;
-				usb_kbd_dev.putc = NULL;
-				usb_kbd_dev.puts = NULL;
-				usb_kbd_dev.getc = usb_kbd_getc;
-				usb_kbd_dev.tstc = usb_kbd_testc;
-				usb_kbd_dev.priv = (void *)dev;
-				error = stdio_register(&usb_kbd_dev);
-				if (error == 0) {
-					/*
-					 * check if this is the standard
-					 * input device
-					 */
-					if (strcmp(stdinname, DEVNAME) == 0) {
-						/* reassign the console */
-						if (overwrite_console())
-							return 1;
-						error = console_assign(stdin,
-								DEVNAME);
-						if (error == 0)
-							return 1;
-						else
-							return error;
-					}
-					return 1;
-				}
-				return error;
-			}
-		}
-	}
-	/* no USB Keyboard found */
-	return -1;
+	/* Submit a interrupt transfer request */
+	maxp = usb_maxpacket(usb_kbd_dev, pipe);
+	usb_submit_int_msg(usb_kbd_dev, pipe, data->new,
+			maxp > 8 ? 8 : maxp, ep->bInterval);
 }
 
-
-/* deregistering the keyboard */
-int usb_kbd_deregister(void)
+/* Puts character in the queue and sets up the in and out pointer. */
+static void usb_kbd_put_queue(struct usb_kbd_pdata *data, char c)
 {
-#ifdef CONFIG_SYS_STDIO_DEREGISTER
-	return stdio_deregister(DEVNAME);
-#else
-	return 1;
-#endif
-}
+	if (data->usb_in_pointer == USB_KBD_BUFFER_LEN - 1) {
+		/* Check for buffer full. */
+		if (data->usb_out_pointer == 0)
+			return;
 
-/**************************************************************************
- * Low Level drivers
- */
+		data->usb_in_pointer = 0;
+	} else {
+		/* Check for buffer full. */
+		if (data->usb_in_pointer == data->usb_out_pointer - 1)
+			return;
+
+		data->usb_in_pointer++;
+	}
 
-/* set the LEDs. Since this is used in the irq routine, the control job
-   is issued with a timeout of 0. This means, that the job is queued without
-   waiting for job completion */
+	data->usb_kbd_buffer[data->usb_in_pointer] = c;
+}
 
+/*
+ * Set the LEDs. Since this is used in the irq routine, the control job is
+ * issued with a timeout of 0. This means, that the job is queued without
+ * waiting for job completion.
+ */
 static void usb_kbd_setled(struct usb_device *dev)
 {
-	struct usb_interface *iface;
-	iface = &dev->config.if_desc[0];
-	leds = 0;
-	if (scroll_lock != 0)
-		leds |= 1;
-	leds <<= 1;
-	if (caps_lock != 0)
-		leds |= 1;
-	leds <<= 1;
-	if (num_lock != 0)
-		leds |= 1;
+	struct usb_interface *iface = &dev->config.if_desc[0];
+	struct usb_kbd_pdata *data = dev->privptr;
+	uint32_t leds = data->flags & USB_KBD_LEDMASK;
+
 	usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 		USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 		0x200, iface->desc.bInterfaceNumber, (void *)&leds, 1, 0);
-
 }
 
-
-#define CAPITAL_MASK 0x20
+#define CAPITAL_MASK	0x20
 /* Translate the scancode in ASCII */
-static int usb_kbd_translate(unsigned char scancode, unsigned char modifier,
-				int pressed)
+static int usb_kbd_translate(struct usb_kbd_pdata *data, unsigned char scancode,
+				unsigned char modifier, int pressed)
 {
-	unsigned char keycode;
+	uint8_t keycode = 0;
 
+	/* Key released */
 	if (pressed == 0) {
-		/* key released */
-		repeat_delay = 0;
+		data->repeat_delay = 0;
 		return 0;
 	}
+
 	if (pressed == 2) {
-		repeat_delay++;
-		if (repeat_delay < REPEAT_DELAY)
+		data->repeat_delay++;
+		if (data->repeat_delay < REPEAT_DELAY)
 			return 0;
-		repeat_delay = REPEAT_DELAY;
+
+		data->repeat_delay = REPEAT_DELAY;
 	}
-	keycode = 0;
-	if ((scancode > 3) && (scancode <= 0x1d)) { /* alpha numeric values */
-		keycode = scancode - 4 + 0x61;
-		if (caps_lock)
-			/* switch to capital Letters */
+
+	/* Alphanumeric values */
+	if ((scancode > 3) && (scancode <= 0x1d)) {
+		keycode = scancode - 4 + 'a';
+
+		if (data->flags & USB_KBD_CAPSLOCK)
 			keycode &= ~CAPITAL_MASK;
-		if (((modifier&(1 << LEFT_SHIFT)) != 0) ||
-			((modifier&(1 << RIGHT_SHIFT)) != 0)) {
+
+		if (modifier & (LEFT_SHIFT | RIGHT_SHIFT)) {
+			/* Handle CAPSLock + Shift pressed simultaneously */
 			if (keycode & CAPITAL_MASK)
-				/* switch to capital Letters */
 				keycode &= ~CAPITAL_MASK;
 			else
-				/* switch to non capital Letters */
 				keycode |= CAPITAL_MASK;
 		}
 	}
-	if ((scancode > 0x1d) && (scancode < 0x3A)) {
-		if (((modifier&(1 << LEFT_SHIFT)) != 0) ||
-			((modifier&(1 << RIGHT_SHIFT)) != 0))  /* shifted */
-			keycode = usb_kbd_numkey_shifted[scancode-0x1e];
-		else /* non shifted */
-			keycode = usb_kbd_numkey[scancode-0x1e];
+
+	if ((scancode > 0x1d) && (scancode < 0x3a)) {
+		/* Shift pressed */
+		if (modifier & (LEFT_SHIFT | RIGHT_SHIFT))
+			keycode = usb_kbd_numkey_shifted[scancode - 0x1e];
+		else
+			keycode = usb_kbd_numkey[scancode - 0x1e];
 	}
 
-	if (ctrl)
+	if (data->flags & USB_KBD_CTRL)
 		keycode = scancode - 0x3;
 
 	if (pressed == 1) {
 		if (scancode == NUM_LOCK) {
-			num_lock = ~num_lock;
+			data->flags ^= USB_KBD_NUMLOCK;
 			return 1;
 		}
+
 		if (scancode == CAPS_LOCK) {
-			caps_lock = ~caps_lock;
+			data->flags ^= USB_KBD_CAPSLOCK;
 			return 1;
 		}
 		if (scancode == SCROLL_LOCK) {
-			scroll_lock = ~scroll_lock;
+			data->flags ^= USB_KBD_SCROLLLOCK;
 			return 1;
 		}
 	}
-	if (keycode != 0) {
+
+	/* Report keycode if any */
+	if (keycode) {
 		USB_KBD_PRINTF("%c", keycode);
-		usb_kbd_put_queue(keycode);
+		usb_kbd_put_queue(data, keycode);
 	}
+
 	return 0;
 }
 
+static uint32_t usb_kbd_service_key(struct usb_device *dev, int i, int up)
+{
+	uint32_t res = 0;
+	struct usb_kbd_pdata *data = dev->privptr;
+	uint8_t *new;
+	uint8_t *old;
+
+	if (up) {
+		new = data->old;
+		old = data->new;
+	} else {
+		new = data->new;
+		old = data->old;
+	}
+
+	if ((old[i] > 3) && (memscan(new + 2, old[i], 6) == new + 8))
+		res |= usb_kbd_translate(data, old[i], data->new[0], up);
+
+	return res;
+}
+
 /* Interrupt service routine */
-static int usb_kbd_irq(struct usb_device *dev)
+static int usb_kbd_irq_worker(struct usb_device *dev)
 {
-	int i, res;
+	struct usb_kbd_pdata *data = dev->privptr;
+	int i, res = 0;
+
+	/* No combo key pressed */
+	if (data->new[0] == 0x00)
+		data->flags &= ~USB_KBD_CTRL;
+	/* Left or Right Ctrl pressed */
+	else if ((data->new[0] == LEFT_CNTR) || (data->new[0] == RIGHT_CNTR))
+		data->flags |= USB_KBD_CTRL;
+
+	for (i = 2; i < 8; i++) {
+		res |= usb_kbd_service_key(dev, i, 0);
+		res |= usb_kbd_service_key(dev, i, 1);
+	}
+
+	/* Key is still pressed */
+	if ((data->new[2] > 3) && (data->old[2] == data->new[2]))
+		res |= usb_kbd_translate(data, data->new[2], data->new[0], 2);
+
+	if (res == 1)
+		usb_kbd_setled(dev);
 
+	memcpy(data->old, data->new, 8);
+
+	return 1;
+}
+
+/* Keyboard interrupt handler */
+static int usb_kbd_irq(struct usb_device *dev)
+{
 	if ((dev->irq_status != 0) || (dev->irq_act_len != 8)) {
-		USB_KBD_PRINTF("usb_keyboard Error %lX, len %d\n",
+		USB_KBD_PRINTF("USB KBD: Error %lX, len %d\n",
 				dev->irq_status, dev->irq_act_len);
 		return 1;
 	}
-	res = 0;
-
-	switch (new[0]) {
-	case 0x0:	/* No combo key pressed */
-		ctrl = 0;
-		break;
-	case 0x01:	/* Left Ctrl pressed */
-	case 0x10:	/* Right Ctrl pressed */
-		ctrl = 1;
-		break;
-	}
 
-	for (i = 2; i < 8; i++) {
-		if (old[i] > 3 && memscan(&new[2], old[i], 6) == &new[8])
-			res |= usb_kbd_translate(old[i], new[0], 0);
+	return usb_kbd_irq_worker(dev);
+}
 
-		if (new[i] > 3 && memscan(&old[2], new[i], 6) == &old[8])
-			res |= usb_kbd_translate(new[i], new[0], 1);
-	}
+/* Interrupt polling */
+static inline void usb_kbd_poll_for_event(struct usb_device *dev)
+{
+#if	defined(CONFIG_SYS_USB_EVENT_POLL)
+	usb_event_poll();
+	usb_kbd_irq_worker(dev);
+#elif	defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP)
+	struct usb_interface *iface;
+	struct usb_kbd_pdata *data = dev->privptr;
+	iface = &dev->config.if_desc[0];
+	usb_get_report(dev, iface->desc.bInterfaceNumber,
+			1, 1, data->new, sizeof(data->new));
+	if (memcmp(data->old, data->new, sizeof(data->new)))
+		usb_kbd_irq_worker(dev);
+#endif
+}
 
-	if ((new[2] > 3) && (old[2] == new[2])) /* still pressed */
-		res |= usb_kbd_translate(new[2], new[0], 2);
-	if (res == 1)
-		usb_kbd_setled(dev);
+/* test if a character is in the queue */
+static int usb_kbd_testc(void)
+{
+	struct stdio_dev *dev;
+	struct usb_device *usb_kbd_dev;
+	struct usb_kbd_pdata *data;
+
+	dev = stdio_get_by_name(DEVNAME);
+	usb_kbd_dev = (struct usb_device *)dev->priv;
+	data = usb_kbd_dev->privptr;
 
-	memcpy(&old[0], &new[0], 8);
+	usb_kbd_poll_for_event(usb_kbd_dev);
 
-	return 1; /* install IRQ Handler again */
+	return !(data->usb_in_pointer == data->usb_out_pointer);
 }
 
-/* probes the USB device dev for keyboard type */
+/* gets the character from the queue */
+static int usb_kbd_getc(void)
+{
+	struct stdio_dev *dev;
+	struct usb_device *usb_kbd_dev;
+	struct usb_kbd_pdata *data;
+
+	dev = stdio_get_by_name(DEVNAME);
+	usb_kbd_dev = (struct usb_device *)dev->priv;
+	data = usb_kbd_dev->privptr;
+
+	while (data->usb_in_pointer == data->usb_out_pointer)
+		usb_kbd_poll_for_event(usb_kbd_dev);
+
+	if (data->usb_out_pointer == USB_KBD_BUFFER_LEN - 1)
+		data->usb_out_pointer = 0;
+	else
+		data->usb_out_pointer++;
+
+	return data->usb_kbd_buffer[data->usb_out_pointer];
+}
+
+/* probes the USB device dev for keyboard type. */
 static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
 {
 	struct usb_interface *iface;
 	struct usb_endpoint_descriptor *ep;
+	struct usb_kbd_pdata *data;
 	int pipe, maxp;
 
 	if (dev->descriptor.bNumConfigurations != 1)
 		return 0;
+
 	iface = &dev->config.if_desc[ifnum];
 
 	if (iface->desc.bInterfaceClass != 3)
 		return 0;
+
 	if (iface->desc.bInterfaceSubClass != 1)
 		return 0;
+
 	if (iface->desc.bInterfaceProtocol != 1)
 		return 0;
+
 	if (iface->desc.bNumEndpoints != 1)
 		return 0;
 
 	ep = &iface->ep_desc[0];
 
+	/* Check if endpoint 1 is interrupt endpoint */
 	if (!(ep->bEndpointAddress & 0x80))
 		return 0;
+
 	if ((ep->bmAttributes & 3) != 3)
 		return 0;
-	USB_KBD_PRINTF("USB KBD found set protocol...\n");
-	/* ok, we found a USB Keyboard, install it */
-	/* usb_kbd_get_hid_desc(dev); */
-	usb_set_protocol(dev, iface->desc.bInterfaceNumber, 0);
-	USB_KBD_PRINTF("USB KBD found set idle...\n");
-	usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE, 0);
-	memset(&new[0], 0, 8);
-	memset(&old[0], 0, 8);
-	repeat_delay = 0;
-	pipe = usb_rcvintpipe(dev, ep->bEndpointAddress);
-	maxp = usb_maxpacket(dev, pipe);
-	dev->irq_handle = usb_kbd_irq;
-	USB_KBD_PRINTF("USB KBD enable interrupt pipe...\n");
-	usb_submit_int_msg(dev, pipe, &new[0], maxp > 8 ? 8 : maxp,
-				ep->bInterval);
-	return 1;
-}
 
+	USB_KBD_PRINTF("USB KBD: found set protocol...\n");
 
-#if 0
-struct usb_hid_descriptor {
-	unsigned char  bLength;
-	unsigned char  bDescriptorType; /* 0x21 for HID */
-	unsigned short bcdHID; /* release number */
-	unsigned char  bCountryCode;
-	unsigned char  bNumDescriptors;
-	unsigned char  bReportDescriptorType;
-	unsigned short wDescriptorLength;
-} __packed;
+	data = malloc(sizeof(struct usb_kbd_pdata));
+	if (!data) {
+		printf("USB KBD: Error allocating private data\n");
+		return 0;
+	}
 
-/*
- * We parse each description item into this structure. Short items data
- * values are expanded to 32-bit signed int, long items contain a pointer
- * into the data area.
- */
+	/* Clear private data */
+	memset(data, 0, sizeof(struct usb_kbd_pdata));
 
-struct hid_item {
-	unsigned char format;
-	unsigned char size;
-	unsigned char type;
-	unsigned char tag;
-	union {
-	    unsigned char   u8;
-	    char            s8;
-	    unsigned short  u16;
-	    short           s16;
-	    unsigned long   u32;
-	    long            s32;
-	    unsigned char  *longdata;
-	} data;
-};
+	/* Insert private data into USB device structure */
+	dev->privptr = data;
 
-/*
- * HID report item format
- */
-
-#define HID_ITEM_FORMAT_SHORT	0
-#define HID_ITEM_FORMAT_LONG	1
+	/* Set IRQ handler */
+	dev->irq_handle = usb_kbd_irq;
 
-/*
- * Special tag indicating long items
- */
+	pipe = usb_rcvintpipe(dev, ep->bEndpointAddress);
+	maxp = usb_maxpacket(dev, pipe);
 
-#define HID_ITEM_TAG_LONG	15
+	/* We found a USB Keyboard, install it. */
+	usb_set_protocol(dev, iface->desc.bInterfaceNumber, 0);
 
+	USB_KBD_PRINTF("USB KBD: found set idle...\n");
+	usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE, 0);
 
-static struct usb_hid_descriptor usb_kbd_hid_desc;
+	USB_KBD_PRINTF("USB KBD: enable interrupt pipe...\n");
+	usb_submit_int_msg(dev, pipe, data->new, maxp > 8 ? 8 : maxp,
+				ep->bInterval);
 
-void usb_kbd_display_hid(struct usb_hid_descriptor *hid)
-{
-	printf("USB_HID_DESC:\n");
-	printf("  bLenght               0x%x\n", hid->bLength);
-	printf("  bcdHID                0x%x\n", hid->bcdHID);
-	printf("  bCountryCode          %d\n", hid->bCountryCode);
-	printf("  bNumDescriptors       0x%x\n", hid->bNumDescriptors);
-	printf("  bReportDescriptorType 0x%x\n", hid->bReportDescriptorType);
-	printf("  wDescriptorLength     0x%x\n", hid->wDescriptorLength);
+	/* Success. */
+	return 1;
 }
 
-
-/*
- * Fetch a report description item from the data stream. We support long
- * items, though they are not used yet.
- */
-
-static int fetch_item(unsigned char *start, unsigned char *end,
-			struct hid_item *item)
+/* Search for keyboard and register it if found. */
+int drv_usb_kbd_init(void)
 {
-	if ((end - start) > 0) {
-		unsigned char b = *start++;
-		item->type = (b >> 2) & 3;
-		item->tag  = (b >> 4) & 15;
-		if (item->tag == HID_ITEM_TAG_LONG) {
-			item->format = HID_ITEM_FORMAT_LONG;
-			if ((end - start) >= 2) {
-				item->size = *start++;
-				item->tag  = *start++;
-				if ((end - start) >= item->size) {
-					item->data.longdata = start;
-					start += item->size;
-					return item->size;
-				}
-			}
-		} else {
-			item->format = HID_ITEM_FORMAT_SHORT;
-			item->size = b & 3;
-			switch (item->size) {
-			case 0:
-				return item->size;
-			case 1:
-				if ((end - start) >= 1) {
-					item->data.u8 = *start++;
-					return item->size;
-				}
-				break;
-			case 2:
-				if ((end - start) >= 2) {
-					item->data.u16 = le16_to_cpu(
-						(unsigned short *)start);
-					start += 2;
-					return item->size;
-				}
-			case 3:
-				item->size++;
-				if ((end - start) >= 4) {
-					item->data.u32 = le32_to_cpu(
-						(unsigned long *)start);
-					start += 4;
-					return item->size;
-				}
-			}
-		}
-	}
-	return -1;
-}
-
-/*
- * HID report descriptor item type (prefix bit 2, 3)
- */
-
-#define HID_ITEM_TYPE_MAIN		0
-#define HID_ITEM_TYPE_GLOBAL		1
-#define HID_ITEM_TYPE_LOCAL		2
-#define HID_ITEM_TYPE_RESERVED		3
-/*
- * HID report descriptor main item tags
- */
-
-#define HID_MAIN_ITEM_TAG_INPUT			8
-#define HID_MAIN_ITEM_TAG_OUTPUT		9
-#define HID_MAIN_ITEM_TAG_FEATURE		11
-#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION	10
-#define HID_MAIN_ITEM_TAG_END_COLLECTION	12
-/*
- * HID report descriptor main item contents
- */
-
-#define HID_MAIN_ITEM_CONSTANT		0x001
-#define HID_MAIN_ITEM_VARIABLE		0x002
-#define HID_MAIN_ITEM_RELATIVE		0x004
-#define HID_MAIN_ITEM_WRAP		0x008
-#define HID_MAIN_ITEM_NONLINEAR		0x010
-#define HID_MAIN_ITEM_NO_PREFERRED	0x020
-#define HID_MAIN_ITEM_NULL_STATE	0x040
-#define HID_MAIN_ITEM_VOLATILE		0x080
-#define HID_MAIN_ITEM_BUFFERED_BYTE	0x100
+	struct stdio_dev usb_kbd_dev, *old_dev;
+	struct usb_device *dev;
+	char *stdinname = getenv("stdin");
+	int error, i;
 
-/*
- * HID report descriptor collection item types
- */
+	/* Scan all USB Devices */
+	for (i = 0; i < USB_MAX_DEVICE; i++) {
+		/* Get USB device. */
+		dev = usb_get_dev_index(i);
+		if (!dev)
+			return -1;
 
-#define HID_COLLECTION_PHYSICAL		0
-#define HID_COLLECTION_APPLICATION	1
-#define HID_COLLECTION_LOGICAL		2
-/*
- * HID report descriptor global item tags
- */
+		if (dev->devnum == -1)
+			continue;
 
-#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE		0
-#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM	1
-#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM	2
-#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM	3
-#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM	4
-#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT	5
-#define HID_GLOBAL_ITEM_TAG_UNIT		6
-#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE		7
-#define HID_GLOBAL_ITEM_TAG_REPORT_ID		8
-#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT	9
-#define HID_GLOBAL_ITEM_TAG_PUSH		10
-#define HID_GLOBAL_ITEM_TAG_POP			11
+		/* Try probing the keyboard */
+		if (usb_kbd_probe(dev, 0) != 1)
+			continue;
 
-/*
- * HID report descriptor local item tags
- */
-
-#define HID_LOCAL_ITEM_TAG_USAGE		0
-#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM	1
-#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM	2
-#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX	3
-#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM	4
-#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM	5
-#define HID_LOCAL_ITEM_TAG_STRING_INDEX		7
-#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM	8
-#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM	9
-#define HID_LOCAL_ITEM_TAG_DELIMITER		10
+		/* We found a keyboard, check if it is already registered. */
+		USB_KBD_PRINTF("USB KBD: found set up device.\n");
+		old_dev = stdio_get_by_name(DEVNAME);
+		if (old_dev) {
+			/* Already registered, just return ok. */
+			USB_KBD_PRINTF("USB KBD: is already registered.\n");
+			return 1;
+		}
 
+		/* Register the keyboard */
+		USB_KBD_PRINTF("USB KBD: register.\n");
+		memset(&usb_kbd_dev, 0, sizeof(struct stdio_dev));
+		strcpy(usb_kbd_dev.name, DEVNAME);
+		usb_kbd_dev.flags =  DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
+		usb_kbd_dev.putc = NULL;
+		usb_kbd_dev.puts = NULL;
+		usb_kbd_dev.getc = usb_kbd_getc;
+		usb_kbd_dev.tstc = usb_kbd_testc;
+		usb_kbd_dev.priv = (void *)dev;
+		error = stdio_register(&usb_kbd_dev);
+		if (error)
+			return error;
+
+		/* Check if this is the standard input device. */
+		if (strcmp(stdinname, DEVNAME))
+			return 1;
 
-static void usb_kbd_show_item(struct hid_item *item)
-{
-	switch (item->type) {
-	case HID_ITEM_TYPE_MAIN:
-		switch (item->tag) {
-		case HID_MAIN_ITEM_TAG_INPUT:
-			printf("Main Input");
-			break;
-		case HID_MAIN_ITEM_TAG_OUTPUT:
-			printf("Main Output");
-			break;
-		case HID_MAIN_ITEM_TAG_FEATURE:
-			printf("Main Feature");
-			break;
-		case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
-			printf("Main Begin Collection");
-			break;
-		case HID_MAIN_ITEM_TAG_END_COLLECTION:
-			printf("Main End Collection");
-			break;
-		default:
-			printf("Main reserved %d", item->tag);
-			break;
-		}
-		break;
-	case HID_ITEM_TYPE_GLOBAL:
-		switch (item->tag) {
-		case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
-			printf("- Global Usage Page");
-			break;
-		case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
-			printf("- Global Logical Minimum");
-			break;
-		case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
-			printf("- Global Logical Maximum");
-			break;
-		case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
-			printf("- Global physical Minimum");
-			break;
-		case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
-			printf("- Global physical Maximum");
-			break;
-		case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
-			printf("- Global Unit Exponent");
-			break;
-		case HID_GLOBAL_ITEM_TAG_UNIT:
-			printf("- Global Unit");
-			break;
-		case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
-			printf("- Global Report Size");
-			break;
-		case HID_GLOBAL_ITEM_TAG_REPORT_ID:
-			printf("- Global Report ID");
-			break;
-		case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
-			printf("- Global Report Count");
-			break;
-		case HID_GLOBAL_ITEM_TAG_PUSH:
-			printf("- Global Push");
-			break;
-		case HID_GLOBAL_ITEM_TAG_POP:
-			printf("- Global Pop");
-			break;
-		default:
-			printf("- Global reserved %d", item->tag);
-			break;
-		}
-		break;
-	case HID_ITEM_TYPE_LOCAL:
-		switch (item->tag) {
-		case HID_LOCAL_ITEM_TAG_USAGE:
-			printf("-- Local Usage");
-			break;
-		case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
-			printf("-- Local Usage Minimum");
-			break;
-		case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
-			printf("-- Local Usage Maximum");
-			break;
-		case HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX:
-			printf("-- Local Designator Index");
-			break;
-		case HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM:
-			printf("-- Local Designator Minimum");
-			break;
-		case HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM:
-			printf("-- Local Designator Maximum");
-			break;
-		case HID_LOCAL_ITEM_TAG_STRING_INDEX:
-			printf("-- Local String Index");
-			break;
-		case HID_LOCAL_ITEM_TAG_STRING_MINIMUM:
-			printf("-- Local String Minimum");
-			break;
-		case HID_LOCAL_ITEM_TAG_STRING_MAXIMUM:
-			printf("-- Local String Maximum");
-			break;
-		case HID_LOCAL_ITEM_TAG_DELIMITER:
-			printf("-- Local Delimiter");
-			break;
-		default:
-			printf("-- Local reserved %d", item->tag);
-			break;
-		}
-		break;
-	default:
-		printf("--- reserved %d", item->type);
-		break;
-	}
-	switch (item->size) {
-	case 1:
-		printf("  %d", item->data.u8);
-		break;
-	case 2:
-		printf("  %d", item->data.u16);
-		break;
-	case 4:
-		printf("  %ld", item->data.u32);
-		break;
-	}
-	printf("\n");
-}
+		/* Reassign the console */
+		if (overwrite_console())
+			return 1;
 
+		error = console_assign(stdin, DEVNAME);
+		if (error)
+			return error;
 
-static int usb_kbd_get_hid_desc(struct usb_device *dev)
-{
-	unsigned char buffer[256];
-	struct usb_descriptor_header *head;
-	struct usb_config_descriptor *config;
-	int index, len, i;
-	unsigned char *start, *end;
-	struct hid_item item;
-
-	if (usb_get_configuration_no(dev, &buffer[0], 0) == -1)
-		return -1;
-	head = (struct usb_descriptor_header *)&buffer[0];
-	if (head->bDescriptorType != USB_DT_CONFIG) {
-		printf(" ERROR: NOT USB_CONFIG_DESC %x\n",
-				head->bDescriptorType);
-		return -1;
-	}
-	index = head->bLength;
-	config = (struct usb_config_descriptor *)&buffer[0];
-	len = le16_to_cpu(config->wTotalLength);
-	/*
-	 * Ok the first entry must be a configuration entry,
-	 * now process the others
-	 */
-	head = (struct usb_descriptor_header *)&buffer[index];
-	while (index+1 < len) {
-		if (head->bDescriptorType == USB_DT_HID) {
-			printf("HID desc found\n");
-			memcpy(&usb_kbd_hid_desc, &buffer[index],
-					buffer[index]);
-			le16_to_cpus(&usb_kbd_hid_desc.bcdHID);
-			le16_to_cpus(&usb_kbd_hid_desc.wDescriptorLength);
-			usb_kbd_display_hid(&usb_kbd_hid_desc);
-			len = 0;
-			break;
-		}
-		index += head->bLength;
-		head = (struct usb_descriptor_header *)&buffer[index];
-	}
-	if (len > 0)
-		return -1;
-	len = usb_kbd_hid_desc.wDescriptorLength;
-	index = usb_get_class_descriptor(dev, 0, USB_DT_REPORT, 0, &buffer[0],
-						len);
-	if (index < 0) {
-		printf("reading report descriptor failed\n");
-		return -1;
+		return 1;
 	}
-	printf(" report descriptor (size %u, read %d)\n", len, index);
-	start = &buffer[0];
-	end = &buffer[len];
-	i = 0;
-	do {
-		index = fetch_item(start, end, &item);
-		i += index;
-		i++;
-		if (index >= 0)
-			usb_kbd_show_item(&item);
-
-		start += index;
-		start++;
-	} while (index >= 0);
 
+	/* No USB Keyboard found */
+	return -1;
 }
 
+/* Deregister the keyboard. */
+int usb_kbd_deregister(void)
+{
+#ifdef CONFIG_SYS_STDIO_DEREGISTER
+	return stdio_deregister(DEVNAME);
+#else
+	return 1;
 #endif
+}
diff --git a/drivers/serial/usbtty.c b/drivers/serial/usbtty.c
index cffd5a2b25259d5018274b7144dec6ed40c34acc..e2e87fef6936619eaeecac0abc256467cf1b6b6d 100644
--- a/drivers/serial/usbtty.c
+++ b/drivers/serial/usbtty.c
@@ -554,11 +554,11 @@ int drv_usbtty_init (void)
 	usbtty_init_strings ();
 	usbtty_init_instances ();
 
+	usbtty_init_endpoints ();
+
 	udc_startup_events (device_instance);/* Enable dev, init udc pointers */
 	udc_connect ();		/* Enable pullup for host detection */
 
-	usbtty_init_endpoints ();
-
 	/* Device initialization */
 	memset (&usbttydev, 0, sizeof (usbttydev));
 
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 5e7271352c80f868878b1183288de20fa67a1844..64b091f4a1f2a40e9d036ee6aa2263fca05f6b3f 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -26,9 +26,14 @@ include $(TOPDIR)/config.mk
 LIB	:= $(obj)libusb_gadget.o
 
 # new USB gadget layer dependencies
+ifdef CONFIG_USB_GADGET
+COBJS-y += epautoconf.o config.o usbstring.o
+COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
+endif
 ifdef CONFIG_USB_ETHER
 COBJS-y += ether.o epautoconf.o config.o usbstring.o
 COBJS-$(CONFIG_USB_ETH_RNDIS) += rndis.o
+COBJS-$(CONFIG_MV_UDC)	+= mv_udc.o
 else
 # Devices not related to the new gadget layer depend on CONFIG_USB_DEVICE
 ifdef CONFIG_USB_DEVICE
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index 9bb7e2e77a36439c0fe3a3ea929f51cca850e999..5d7b638b38beb8525e50ef0f1b6270c5f0498189 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -150,6 +150,11 @@
 #define	gadget_is_m66592(g)	0
 #endif
 
+#ifdef CONFIG_USB_GADGET_MV
+#define gadget_is_mv(g)        (!strcmp("mv_udc", (g)->name))
+#else
+#define gadget_is_mv(g)        0
+#endif
 
 /*
  * CONFIG_USB_GADGET_SX2
@@ -216,5 +221,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x20;
 	else if (gadget_is_m66592(gadget))
 		return 0x21;
+	else if (gadget_is_mv(gadget))
+		return 0x22;
 	return -ENOENT;
 }
diff --git a/drivers/usb/gadget/mv_udc.c b/drivers/usb/gadget/mv_udc.c
new file mode 100644
index 0000000000000000000000000000000000000000..cdbdcfa91fbdc0b070f14be072f3be6033c3b563
--- /dev/null
+++ b/drivers/usb/gadget/mv_udc.c
@@ -0,0 +1,499 @@
+/*
+ * Copyright 2011, Marvell Semiconductor Inc.
+ * Lei Wen <leiwen@marvell.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Back ported to the 8xx platform (from the 8260 platform) by
+ * Murray.Jensen@cmst.csiro.au, 27-Jan-01.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <net.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <linux/types.h>
+#include <usb/mv_udc.h>
+
+#ifndef DEBUG
+#define DBG(x...) do {} while (0)
+#else
+#define DBG(x...) printf(x)
+static const char *reqname(unsigned r)
+{
+	switch (r) {
+	case USB_REQ_GET_STATUS: return "GET_STATUS";
+	case USB_REQ_CLEAR_FEATURE: return "CLEAR_FEATURE";
+	case USB_REQ_SET_FEATURE: return "SET_FEATURE";
+	case USB_REQ_SET_ADDRESS: return "SET_ADDRESS";
+	case USB_REQ_GET_DESCRIPTOR: return "GET_DESCRIPTOR";
+	case USB_REQ_SET_DESCRIPTOR: return "SET_DESCRIPTOR";
+	case USB_REQ_GET_CONFIGURATION: return "GET_CONFIGURATION";
+	case USB_REQ_SET_CONFIGURATION: return "SET_CONFIGURATION";
+	case USB_REQ_GET_INTERFACE: return "GET_INTERFACE";
+	case USB_REQ_SET_INTERFACE: return "SET_INTERFACE";
+	default: return "*UNKNOWN*";
+	}
+}
+#endif
+
+#define PAGE_SIZE	4096
+#define QH_MAXNUM	32
+static struct usb_endpoint_descriptor ep0_out_desc = {
+	.bLength = sizeof(struct usb_endpoint_descriptor),
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = 0,
+	.bmAttributes =	USB_ENDPOINT_XFER_CONTROL,
+};
+
+static struct usb_endpoint_descriptor ep0_in_desc = {
+	.bLength = sizeof(struct usb_endpoint_descriptor),
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = USB_DIR_IN,
+	.bmAttributes =	USB_ENDPOINT_XFER_CONTROL,
+};
+
+struct ept_queue_head *epts;
+struct ept_queue_item *items[2 * NUM_ENDPOINTS];
+static int mv_pullup(struct usb_gadget *gadget, int is_on);
+static int mv_ep_enable(struct usb_ep *ep,
+		const struct usb_endpoint_descriptor *desc);
+static int mv_ep_disable(struct usb_ep *ep);
+static int mv_ep_queue(struct usb_ep *ep,
+		struct usb_request *req, gfp_t gfp_flags);
+static struct usb_request *
+mv_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags);
+static void mv_ep_free_request(struct usb_ep *ep, struct usb_request *_req);
+
+static struct usb_gadget_ops mv_udc_ops = {
+	.pullup = mv_pullup,
+};
+
+static struct usb_ep_ops mv_ep_ops = {
+	.enable         = mv_ep_enable,
+	.disable        = mv_ep_disable,
+	.queue          = mv_ep_queue,
+	.alloc_request  = mv_ep_alloc_request,
+	.free_request   = mv_ep_free_request,
+};
+
+static struct mv_ep ep[2 * NUM_ENDPOINTS];
+static struct mv_drv controller = {
+	.gadget = {
+		.ep0 = &ep[0].ep,
+		.name = "mv_udc",
+	},
+};
+
+static struct usb_request *
+mv_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags)
+{
+	struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep);
+	return &mv_ep->req;
+}
+
+static void mv_ep_free_request(struct usb_ep *ep, struct usb_request *_req)
+{
+	return;
+}
+
+static void ep_enable(int num, int in)
+{
+	struct ept_queue_head *head;
+	struct mv_udc *udc = controller.udc;
+	unsigned n;
+	head = epts + 2*num + in;
+
+	n = readl(&udc->epctrl[num]);
+	if (in)
+		n |= (CTRL_TXE | CTRL_TXR | CTRL_TXT_BULK);
+	else
+		n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT_BULK);
+
+	if (num != 0)
+		head->config = CONFIG_MAX_PKT(EP_MAX_PACKET_SIZE) | CONFIG_ZLT;
+	writel(n, &udc->epctrl[num]);
+}
+
+static int mv_ep_enable(struct usb_ep *ep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep);
+	int num, in;
+	num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
+	ep_enable(num, in);
+	mv_ep->desc = desc;
+	return 0;
+}
+
+static int mv_ep_disable(struct usb_ep *ep)
+{
+	return 0;
+}
+
+static int mv_ep_queue(struct usb_ep *ep,
+		struct usb_request *req, gfp_t gfp_flags)
+{
+	struct mv_ep *mv_ep = container_of(ep, struct mv_ep, ep);
+	struct mv_udc *udc = controller.udc;
+	struct ept_queue_item *item;
+	struct ept_queue_head *head;
+	unsigned phys;
+	int bit, num, len, in;
+	num = mv_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	in = (mv_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
+	item = items[2 * num + in];
+	head = epts + 2 * num + in;
+	phys = (unsigned)req->buf;
+	len = req->length;
+
+	item->next = TERMINATE;
+	item->info = INFO_BYTES(len) | INFO_IOC | INFO_ACTIVE;
+	item->page0 = phys;
+	item->page1 = (phys & 0xfffff000) + 0x1000;
+
+	head->next = (unsigned) item;
+	head->info = 0;
+
+	DBG("ept%d %s queue len %x, buffer %x\n",
+			num, in ? "in" : "out", len, phys);
+
+	if (in)
+		bit = EPT_TX(num);
+	else
+		bit = EPT_RX(num);
+
+	flush_cache(phys, len);
+	flush_cache((unsigned long)item, sizeof(struct ept_queue_item));
+	writel(bit, &udc->epprime);
+
+	return 0;
+}
+
+static void handle_ep_complete(struct mv_ep *ep)
+{
+	struct ept_queue_item *item;
+	int num, in, len;
+	num = ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	in = (ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
+	if (num == 0)
+		ep->desc = &ep0_out_desc;
+	item = items[2 * num + in];
+
+	if (item->info & 0xff)
+		printf("EP%d/%s FAIL nfo=%x pg0=%x\n",
+			num, in ? "in" : "out", item->info, item->page0);
+
+	len = (item->info >> 16) & 0x7fff;
+	ep->req.length -= len;
+	DBG("ept%d %s complete %x\n",
+			num, in ? "in" : "out", len);
+	ep->req.complete(&ep->ep, &ep->req);
+	if (num == 0) {
+		ep->req.length = 0;
+		usb_ep_queue(&ep->ep, &ep->req, 0);
+		ep->desc = &ep0_in_desc;
+	}
+}
+
+#define SETUP(type, request) (((type) << 8) | (request))
+
+static void handle_setup(void)
+{
+	struct usb_request *req = &ep[0].req;
+	struct mv_udc *udc = controller.udc;
+	struct ept_queue_head *head;
+	struct usb_ctrlrequest r;
+	int status = 0;
+	int num, in, _num, _in, i;
+	char *buf;
+	head = epts;
+
+	flush_cache((unsigned long)head, sizeof(struct ept_queue_head));
+	memcpy(&r, head->setup_data, sizeof(struct usb_ctrlrequest));
+	writel(EPT_RX(0), &udc->epstat);
+	DBG("handle setup %s, %x, %x index %x value %x\n", reqname(r.bRequest),
+	    r.bRequestType, r.bRequest, r.wIndex, r.wValue);
+
+	switch (SETUP(r.bRequestType, r.bRequest)) {
+	case SETUP(USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE):
+		_num = r.wIndex & 15;
+		_in = !!(r.wIndex & 0x80);
+
+		if ((r.wValue == 0) && (r.wLength == 0)) {
+			req->length = 0;
+			for (i = 0; i < NUM_ENDPOINTS; i++) {
+				if (!ep[i].desc)
+					continue;
+				num = ep[i].desc->bEndpointAddress
+					& USB_ENDPOINT_NUMBER_MASK;
+				in = (ep[i].desc->bEndpointAddress
+						& USB_DIR_IN) != 0;
+				if ((num == _num) && (in == _in)) {
+					ep_enable(num, in);
+					usb_ep_queue(controller.gadget.ep0,
+							req, 0);
+					break;
+				}
+			}
+		}
+		return;
+
+	case SETUP(USB_RECIP_DEVICE, USB_REQ_SET_ADDRESS):
+		/*
+		 * write address delayed (will take effect
+		 * after the next IN txn)
+		 */
+		writel((r.wValue << 25) | (1 << 24), &udc->devaddr);
+		req->length = 0;
+		usb_ep_queue(controller.gadget.ep0, req, 0);
+		return;
+
+	case SETUP(USB_DIR_IN | USB_RECIP_DEVICE, USB_REQ_GET_STATUS):
+		req->length = 2;
+		buf = (char *)req->buf;
+		buf[0] = 1 << USB_DEVICE_SELF_POWERED;
+		buf[1] = 0;
+		usb_ep_queue(controller.gadget.ep0, req, 0);
+		return;
+	}
+	/* pass request up to the gadget driver */
+	if (controller.driver)
+		status = controller.driver->setup(&controller.gadget, &r);
+	else
+		status = -ENODEV;
+
+	if (!status)
+		return;
+	DBG("STALL reqname %s type %x value %x, index %x\n",
+	    reqname(r.bRequest), r.bRequestType, r.wValue, r.wIndex);
+	writel((1<<16) | (1 << 0), &udc->epctrl[0]);
+}
+
+static void stop_activity(void)
+{
+	int i, num, in;
+	struct ept_queue_head *head;
+	struct mv_udc *udc = controller.udc;
+	writel(readl(&udc->epcomp), &udc->epcomp);
+	writel(readl(&udc->epstat), &udc->epstat);
+	writel(0xffffffff, &udc->epflush);
+
+	/* error out any pending reqs */
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		if (i != 0)
+			writel(0, &udc->epctrl[i]);
+		if (ep[i].desc) {
+			num = ep[i].desc->bEndpointAddress
+				& USB_ENDPOINT_NUMBER_MASK;
+			in = (ep[i].desc->bEndpointAddress & USB_DIR_IN) != 0;
+			head = epts + (num * 2) + (in);
+			head->info = INFO_ACTIVE;
+		}
+	}
+}
+
+void udc_irq(void)
+{
+	struct mv_udc *udc = controller.udc;
+	unsigned n = readl(&udc->usbsts);
+	writel(n, &udc->usbsts);
+	int bit, i, num, in;
+
+	n &= (STS_SLI | STS_URI | STS_PCI | STS_UI | STS_UEI);
+	if (n == 0)
+		return;
+
+	if (n & STS_URI) {
+		DBG("-- reset --\n");
+		stop_activity();
+	}
+	if (n & STS_SLI)
+		DBG("-- suspend --\n");
+
+	if (n & STS_PCI) {
+		DBG("-- portchange --\n");
+		bit = (readl(&udc->portsc) >> 26) & 3;
+		if (bit == 2) {
+			controller.gadget.speed = USB_SPEED_HIGH;
+			for (i = 1; i < NUM_ENDPOINTS && n; i++)
+				if (ep[i].desc)
+					ep[i].ep.maxpacket = 512;
+		} else {
+			controller.gadget.speed = USB_SPEED_FULL;
+		}
+	}
+
+	if (n & STS_UEI)
+		printf("<UEI %x>\n", readl(&udc->epcomp));
+
+	if ((n & STS_UI) || (n & STS_UEI)) {
+		n = readl(&udc->epstat);
+		if (n & EPT_RX(0))
+			handle_setup();
+
+		n = readl(&udc->epcomp);
+		if (n != 0)
+			writel(n, &udc->epcomp);
+
+		for (i = 0; i < NUM_ENDPOINTS && n; i++) {
+			if (ep[i].desc) {
+				num = ep[i].desc->bEndpointAddress
+					& USB_ENDPOINT_NUMBER_MASK;
+				in = (ep[i].desc->bEndpointAddress
+						& USB_DIR_IN) != 0;
+				bit = (in) ? EPT_TX(num) : EPT_RX(num);
+				if (n & bit)
+					handle_ep_complete(&ep[i]);
+			}
+		}
+	}
+}
+
+int usb_gadget_handle_interrupts(void)
+{
+	u32 value;
+	struct mv_udc *udc = controller.udc;
+
+	value = readl(&udc->usbsts);
+	if (value)
+		udc_irq();
+
+	return value;
+}
+
+static int mv_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct mv_udc *udc = controller.udc;
+	if (is_on) {
+		/* RESET */
+		writel(USBCMD_ITC(MICRO_8FRAME) | USBCMD_RST, &udc->usbcmd);
+		udelay(200);
+
+		writel((unsigned) epts, &udc->epinitaddr);
+
+		/* select DEVICE mode */
+		writel(USBMODE_DEVICE, &udc->usbmode);
+
+		writel(0xffffffff, &udc->epflush);
+
+		/* Turn on the USB connection by enabling the pullup resistor */
+		writel(USBCMD_ITC(MICRO_8FRAME) | USBCMD_RUN, &udc->usbcmd);
+	} else {
+		stop_activity();
+		writel(USBCMD_FS2, &udc->usbcmd);
+		udelay(800);
+		if (controller.driver)
+			controller.driver->disconnect(gadget);
+	}
+
+	return 0;
+}
+
+void udc_disconnect(void)
+{
+	struct mv_udc *udc = controller.udc;
+	/* disable pullup */
+	stop_activity();
+	writel(USBCMD_FS2, &udc->usbcmd);
+	udelay(800);
+	if (controller.driver)
+		controller.driver->disconnect(&controller.gadget);
+}
+
+static int mvudc_probe(void)
+{
+	struct ept_queue_head *head;
+	int i;
+
+	controller.gadget.ops = &mv_udc_ops;
+	controller.udc = (struct mv_udc *)CONFIG_USB_REG_BASE;
+	epts = memalign(PAGE_SIZE, QH_MAXNUM * sizeof(struct ept_queue_head));
+	memset(epts, 0, QH_MAXNUM * sizeof(struct ept_queue_head));
+	for (i = 0; i < 2 * NUM_ENDPOINTS; i++) {
+		/*
+		 * For item0 and item1, they are served as ep0
+		 * out&in seperately
+		 */
+		head = epts + i;
+		if (i < 2)
+			head->config = CONFIG_MAX_PKT(EP0_MAX_PACKET_SIZE)
+				| CONFIG_ZLT | CONFIG_IOS;
+		else
+			head->config = CONFIG_MAX_PKT(EP_MAX_PACKET_SIZE)
+				| CONFIG_ZLT;
+		head->next = TERMINATE;
+		head->info = 0;
+
+		items[i] = memalign(PAGE_SIZE, sizeof(struct ept_queue_item));
+	}
+
+	INIT_LIST_HEAD(&controller.gadget.ep_list);
+	ep[0].ep.maxpacket = 64;
+	ep[0].ep.name = "ep0";
+	ep[0].desc = &ep0_in_desc;
+	INIT_LIST_HEAD(&controller.gadget.ep0->ep_list);
+	for (i = 0; i < 2 * NUM_ENDPOINTS; i++) {
+		if (i != 0) {
+			ep[i].ep.maxpacket = 512;
+			ep[i].ep.name = "ep-";
+			list_add_tail(&ep[i].ep.ep_list,
+				      &controller.gadget.ep_list);
+			ep[i].desc = NULL;
+		}
+		ep[i].ep.ops = &mv_ep_ops;
+	}
+	return 0;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct mv_udc *udc = controller.udc;
+	int             retval;
+
+	if (!driver
+			|| driver->speed < USB_SPEED_FULL
+			|| !driver->bind
+			|| !driver->setup) {
+		DBG("bad parameter.\n");
+		return -EINVAL;
+	}
+
+	if (!mvudc_probe()) {
+		usb_lowlevel_init();
+		/* select ULPI phy */
+		writel(PTS(PTS_ENABLE) | PFSC, &udc->portsc);
+	}
+	retval = driver->bind(&controller.gadget);
+	if (retval) {
+		DBG("driver->bind() returned %d\n", retval);
+		return retval;
+	}
+	controller.driver = driver;
+
+	return 0;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	return 0;
+}
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index e6ccd49ac0d35055f39b8bce1bf2d2ac2300df1d..0d3a9886f99fd063db05afa15bb686c5db988950 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -26,11 +26,13 @@
 #include <common.h>
 #include <config.h>
 #include <asm/byteorder.h>
-#include <usbdcore.h>
-#include <usbdcore_ep0.h>
+#include <usbdevice.h>
 #include <asm/arch/hardware.h>
+#include <asm/io.h>
 #include <usb/pxa27x_udc.h>
 
+#include "ep0.h"
+
 /* number of endpoints on this UDC */
 #define UDC_MAX_ENDPOINTS	24
 
@@ -50,7 +52,7 @@ static void udc_dump_buffer(char *name, u8 *buf, int len)
 
 static inline void udc_ack_int_UDCCR(int mask)
 {
-	USIR1	= mask | USIR1;
+	writel(readl(USIR1) | mask, USIR1);
 }
 
 /*
@@ -68,9 +70,7 @@ static int udc_write_urb(struct usb_endpoint_instance *endpoint)
 {
 	struct urb *urb = endpoint->tx_urb;
 	int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
-	u32 *addr32 = (u32 *) &UDCDN(ep_num);
 	u32 *data32 = (u32 *) urb->buffer;
-	u8  *addr8 = (u8 *) &UDCDN(ep_num);
 	u8  *data8 = (u8 *) urb->buffer;
 	unsigned int i, n, w, b, is_short;
 	int timeout = 2000;	/* 2ms */
@@ -98,26 +98,28 @@ static int udc_write_urb(struct usb_endpoint_instance *endpoint)
 
 	/* Prepare for data send */
 	if (ep_num)
-		UDCCSN(ep_num) = UDCCSR_PC;
+		writel(UDCCSR_PC ,UDCCSN(ep_num));
 
 	for (i = 0; i < w; i++)
-		*addr32 = data32[endpoint->sent/4 + i];
+		  writel(data32[endpoint->sent / 4 + i], UDCDN(ep_num));
+
 	for (i = 0; i < b; i++)
-		*addr8 = data8[endpoint->sent + w*4 + i];
+		  writeb(data8[endpoint->sent + w * 4 + i], UDCDN(ep_num));
 
 	/* Set "Packet Complete" if less data then tx_packetSize */
 	if (is_short)
-		UDCCSN(ep_num) = ep_num ? UDCCSR_SP : UDCCSR0_IPR;
+		writel(ep_num ? UDCCSR_SP : UDCCSR0_IPR, UDCCSN(ep_num));
 
 	/* Wait for data sent */
-	while (!(UDCCSN(ep_num) & (ep_num ? UDCCSR_PC : UDCCSR0_IPR))) {
-		if (ep_num) {
+	if (ep_num) {
+		while (!(readl(UDCCSN(ep_num)) & UDCCSR_PC)) {
 			if (timeout-- == 0)
 				return -1;
 			else
 				udelay(1);
-		};
+		}
 	}
+
 	endpoint->last = n;
 
 	if (ep_num) {
@@ -127,7 +129,7 @@ static int udc_write_urb(struct usb_endpoint_instance *endpoint)
 		endpoint->last -= n;
 	}
 
-	if ((endpoint->tx_urb->actual_length - endpoint->sent) <= 0) {
+	if (endpoint->sent >= urb->actual_length) {
 		urb->actual_length = 0;
 		endpoint->sent = 0;
 		endpoint->last = 0;
@@ -148,7 +150,6 @@ static int udc_read_urb(struct usb_endpoint_instance *endpoint)
 {
 	struct urb *urb = endpoint->rcv_urb;
 	int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
-	u32 *addr32 = (u32 *) &UDCDN(ep_num);
 	u32 *data32 = (u32 *) urb->buffer;
 	unsigned int i, n, is_short ;
 
@@ -160,15 +161,15 @@ static int udc_read_urb(struct usb_endpoint_instance *endpoint)
 		endpoint->rcv_packetSize);
 #endif
 
-	if (UDCCSN(ep_num) & UDCCSR_BNE)
-		n = UDCBCN(ep_num) & 0x3ff;
+	if (readl(UDCCSN(ep_num)) & UDCCSR_BNE)
+		n = readl(UDCBCN(ep_num)) & 0x3ff;
 	else /* zlp */
 		n = 0;
 	is_short = n != endpoint->rcv_packetSize;
 
 	usbdbg("n %d%s", n, is_short ? "-s" : "");
 	for (i = 0; i < n; i += 4)
-		data32[urb->actual_length/4 + i/4] = *addr32;
+		data32[urb->actual_length / 4 + i / 4] = readl(UDCDN(ep_num));
 
 	udc_dump_buffer("urb read", (u8 *) data32, urb->actual_length + n);
 	usbd_rcv_complete(endpoint, n, 0);
@@ -178,27 +179,35 @@ static int udc_read_urb(struct usb_endpoint_instance *endpoint)
 
 static int udc_read_urb_ep0(void)
 {
-	u32 *addr32 = (u32 *) &UDCDN(0);
 	u32 *data32 = (u32 *) ep0_urb->buffer;
-	u8 *addr8 = (u8 *) &UDCDN(0);
 	u8 *data8 = (u8 *) ep0_urb->buffer;
 	unsigned int i, n, w, b;
 
-	n = UDCBCR0;
+	usbdbg("read urb on ep 0");
+#if defined(USBDDBG) && defined(USBDPARANOIA)
+	usbdbg("urb: buf %p, buf_len %d, actual_len %d",
+		ep0_urb->buffer, ep0_urb->buffer_length, ep0_urb->actual_length);
+#endif
+
+	n = readl(UDCBCR0);
 	w = n / 4;
 	b = n % 4;
 
 	for (i = 0; i < w; i++) {
-		data32[ep0_urb->actual_length/4 + i] = *addr32;
-		ep0_urb->actual_length += 4;
+		data32[ep0_urb->actual_length / 4 + i] = readl(UDCDN(0));
+//		ep0_urb->actual_length += 4;
 	}
 
 	for (i = 0; i < b; i++) {
-		data8[ep0_urb->actual_length + w*4 + i] = *addr8;
-		ep0_urb->actual_length++;
+		data8[ep0_urb->actual_length + w * 4 + i] = readb(UDCDN(0));
+//		ep0_urb->actual_length++;
 	}
 
-	UDCCSR0 = UDCCSR0_OPC | UDCCSR0_IPR;
+	ep0_urb->actual_length += n;
+
+	udc_dump_buffer("urb read", (u8 *) data32, ep0_urb->actual_length);
+
+	writel(UDCCSR0_OPC | UDCCSR0_IPR, UDCCSR0);
 	if (ep0_urb->actual_length == ep0_urb->device_request.wLength)
 		return 1;
 
@@ -207,7 +216,7 @@ static int udc_read_urb_ep0(void)
 
 static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
 {
-	u32 udccsr0 = UDCCSR0;
+	u32 udccsr0 = readl(UDCCSR0);
 	u32 *data = (u32 *) &ep0_urb->device_request;
 	int i;
 
@@ -216,7 +225,7 @@ static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
 	/* Clear stall status */
 	if (udccsr0 & UDCCSR0_SST) {
 		usberr("clear stall status");
-		UDCCSR0 = UDCCSR0_SST;
+		writel(UDCCSR0_SST, UDCCSR0);
 		ep0state = EP0_IDLE;
 	}
 
@@ -227,8 +236,7 @@ static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
 	switch (ep0state) {
 
 	case EP0_IDLE:
-
-		udccsr0 = UDCCSR0;
+		udccsr0 = readl(UDCCSR0);
 		/* Start control request? */
 		if ((udccsr0 & (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE))
 			== (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)) {
@@ -238,15 +246,15 @@ static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
 			 */
 			usbdbg("try reading SETUP packet");
 			for (i = 0; i < 2; i++) {
-				if ((UDCCSR0 & UDCCSR0_RNE) == 0) {
+				if ((readl(UDCCSR0) & UDCCSR0_RNE) == 0) {
 					usberr("setup packet too short:%d", i);
 					goto stall;
 				}
-				data[i] = UDCDR0;
+				data[i] = readl(UDCDR0);
 			}
 
-			UDCCSR0 |= (UDCCSR0_OPC | UDCCSR0_SA);
-			if ((UDCCSR0 & UDCCSR0_RNE) != 0) {
+			writel(readl(UDCCSR0) | UDCCSR0_OPC | UDCCSR0_SA, UDCCSR0);
+			if ((readl(UDCCSR0) & UDCCSR0_RNE) != 0) {
 				usberr("setup packet too long");
 				goto stall;
 			}
@@ -261,7 +269,7 @@ static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
 								(u8 *)data, 8);
 					goto stall;
 				}
-				UDCCSR0 = UDCCSR0_IPR;
+				writel(UDCCSR0_IPR, UDCCSR0);
 				ep0state = EP0_IDLE;
 			} else {
 				/* Check direction */
@@ -274,7 +282,7 @@ static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
 					ep0_urb->buffer_length =
 						sizeof(ep0_urb->buffer_data);
 					ep0_urb->actual_length = 0;
-					UDCCSR0 = UDCCSR0_IPR;
+					writel(UDCCSR0_IPR, UDCCSR0);
 				} else {
 					/* The ep0_recv_setup function has
 					 * already placed our response packet
@@ -289,9 +297,9 @@ stall:
 							, (u8 *) data, 8);
 						ep0state = EP0_IDLE;
 
-						UDCCSR0 = UDCCSR0_SA |
+						writel(UDCCSR0_SA |
 						UDCCSR0_OPC | UDCCSR0_FST |
-						UDCCS0_FTF;
+						UDCCS0_FTF, UDCCSR0);
 
 						return;
 					}
@@ -317,7 +325,7 @@ stall:
 			 * - IPR cleared
 			 * - OPC got set, without SA (likely status stage)
 			 */
-			UDCCSR0 = udccsr0 & (UDCCSR0_SA | UDCCSR0_OPC);
+			writel(udccsr0 & (UDCCSR0_SA | UDCCSR0_OPC), UDCCSR0);
 		}
 		break;
 
@@ -351,7 +359,7 @@ read_complete:
 	case EP0_IN_DATA:
 		/* GET_DESCRIPTOR etc */
 		if (udccsr0 & UDCCSR0_OPC) {
-			UDCCSR0 = UDCCSR0_OPC | UDCCSR0_FTF;
+			writel(UDCCSR0_OPC | UDCCSR0_FTF, UDCCSR0);
 			usberr("ep0in premature status");
 			ep0state = EP0_IDLE;
 		} else {
@@ -364,14 +372,14 @@ read_complete:
 		break;
 
 	case EP0_XFER_COMPLETE:
-		UDCCSR0 = UDCCSR0_IPR;
+		writel(UDCCSR0_IPR, UDCCSR0);
 		ep0state = EP0_IDLE;
 		break;
 
 	default:
 		usbdbg("Default\n");
 	}
-	USIR0 = USIR0_IR0;
+	writel(USIR0_IR0, USIR0);
 }
 
 static void udc_handle_ep(struct usb_endpoint_instance *endpoint)
@@ -380,33 +388,33 @@ static void udc_handle_ep(struct usb_endpoint_instance *endpoint)
 	int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
 	int ep_isout = (ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT;
 
-	u32 flags = UDCCSN(ep_num) & (UDCCSR_SST | UDCCSR_TRN);
+	u32 flags = readl(UDCCSN(ep_num)) & (UDCCSR_SST | UDCCSR_TRN);
 	if (flags)
-		UDCCSN(ep_num) = flags;
+		writel(flags, UDCCSN(ep_num));
 
 	if (ep_isout)
 		udc_read_urb(endpoint);
 	else
 		udc_write_urb(endpoint);
 
-	UDCCSN(ep_num) = UDCCSR_PC;
+	writel(UDCCSR_PC, UDCCSN(ep_num));
 }
 
 static void udc_state_changed(void)
 {
 	int config, interface, alternate;
 
-	UDCCR |= UDCCR_SMAC;
+	writel(readl(UDCCR) | UDCCR_SMAC, UDCCR);
 
-	config = (UDCCR & UDCCR_ACN) >> UDCCR_ACN_S;
-	interface = (UDCCR & UDCCR_AIN) >> UDCCR_AIN_S;
-	alternate = (UDCCR & UDCCR_AAISN) >> UDCCR_AAISN_S;
+	config = (readl(UDCCR) & UDCCR_ACN) >> UDCCR_ACN_S;
+	interface = (readl(UDCCR) & UDCCR_AIN) >> UDCCR_AIN_S;
+	alternate = (readl(UDCCR) & UDCCR_AAISN) >> UDCCR_AAISN_S;
 
 	usbdbg("New UDC settings are: conf %d - inter %d - alter %d",
 		config, interface, alternate);
 
 	usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
-	UDCISR1 = UDCISR1_IRCC;
+	writel(UDCISR1_IRCC, UDCISR1);
 }
 
 void udc_irq(void)
@@ -419,7 +427,7 @@ void udc_irq(void)
 	do {
 		handled = 0;
 		/* Suspend Interrupt Request */
-		if (USIR1 & UDCCR_SUSIR) {
+		if (readl(USIR1) & UDCCR_SUSIR) {
 			usbdbg("Suspend\n");
 			udc_ack_int_UDCCR(UDCCR_SUSIR);
 			handled = 1;
@@ -427,35 +435,35 @@ void udc_irq(void)
 		}
 
 		/* Resume Interrupt Request */
-		if (USIR1 & UDCCR_RESIR) {
+		if (readl(USIR1) & UDCCR_RESIR) {
 			udc_ack_int_UDCCR(UDCCR_RESIR);
 			handled = 1;
 			usbdbg("USB resume\n");
 		}
 
-		if (USIR1 & (1<<31)) {
+		if (readl(USIR1) & (1<<31)) {
 			handled = 1;
 			udc_state_changed();
 		}
 
 		/* Reset Interrupt Request */
-		if (USIR1 & UDCCR_RSTIR) {
+		if (readl(USIR1) & UDCCR_RSTIR) {
 			udc_ack_int_UDCCR(UDCCR_RSTIR);
 			handled = 1;
 			usbdbg("Reset\n");
 			usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
 		} else {
-			if (USIR0)
-				usbdbg("UISR0: %x \n", USIR0);
+			if (readl(USIR0))
+				usbdbg("UISR0: %x \n", readl(USIR0));
 
-			if (USIR0 & 0x2)
-				USIR0 = 0x2;
+			if (readl(USIR0) & 0x2)
+				writel(0x2, USIR0);
 
 			/* Control traffic */
-			if (USIR0  & USIR0_IR0) {
+			if (readl(USIR0)  & USIR0_IR0) {
 				handled = 1;
+				writel(USIR0_IR0, USIR0);
 				udc_handle_ep0(udc_device->bus->endpoint_array);
-				USIR0 = USIR0_IR0;
 			}
 
 			endpoint = udc_device->bus->endpoint_array;
@@ -464,11 +472,11 @@ void udc_irq(void)
 						USB_ENDPOINT_NUMBER_MASK;
 				if (!ep_num)
 					continue;
-				udcisr0 = UDCISR0;
+				udcisr0 = readl(UDCISR0);
 				if (udcisr0 &
 					UDCISR_INT(ep_num, UDC_INT_PACKETCMP)) {
-					UDCISR0 = UDCISR_INT(ep_num,
-							 UDC_INT_PACKETCMP);
+					writel(UDCISR_INT(ep_num, UDC_INT_PACKETCMP),
+					       UDCISR0);
 					udc_handle_ep(&endpoint[i]);
 				}
 			}
@@ -485,21 +493,21 @@ void udc_irq(void)
 
 static inline void udc_set_mask_UDCCR(int mask)
 {
-    UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS);
+    writel((readl(UDCCR) & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS), UDCCR);
 }
 
 static inline void udc_clear_mask_UDCCR(int mask)
 {
-    UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS);
+    writel((readl(UDCCR) & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS), UDCCR);
 }
 
 static void pio_irq_enable(int ep_num)
 {
 	if (ep_num < 16)
-		UDCICR0 |= 3 << (ep_num * 2);
+		writel(readl(UDCICR0) | 3 << (ep_num * 2), UDCICR0);
 	else {
 		ep_num -= 16;
-		UDCICR1 |= 3 << (ep_num * 2);
+		writel(readl(UDCICR1) | 3 << (ep_num * 2), UDCICR1);
 	}
 }
 
@@ -589,22 +597,26 @@ void udc_setup_ep(struct usb_device_instance *device, unsigned int id,
 	tmp |= (ep_size << UDCCONR_MPS_S) & UDCCONR_MPS;
 	tmp |= UDCCONR_EE;
 
-	UDCCN(ep_num) = tmp;
+	writel(tmp, UDCCN(ep_num));
 
-	usbdbg("UDCCR%c = %x", 'A' + ep_num-1, UDCCN(ep_num));
-	usbdbg("UDCCSR%c = %x", 'A' + ep_num-1, UDCCSN(ep_num));
+	//usbdbg
+	usbdbg("UDCCR%c = %x", 'A' + ep_num-1, readl(UDCCN(ep_num)));
+	usbdbg("UDCCSR%c = %x", 'A' + ep_num-1, readl(UDCCSN(ep_num)));
 }
 
-#define CONFIG_USB_DEV_PULLUP_GPIO 87
-
 /* Connect the USB device to the bus */
 void udc_connect(void)
 {
 	usbdbg("UDC connect");
 
+#ifdef CONFIG_USB_DEV_PULLUP_GPIO
 	/* Turn on the USB connection by enabling the pullup resistor */
 	set_GPIO_mode(CONFIG_USB_DEV_PULLUP_GPIO | GPIO_OUT);
-	GPSR(CONFIG_USB_DEV_PULLUP_GPIO) = GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO);
+	writel(GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO), GPSR(CONFIG_USB_DEV_PULLUP_GPIO));
+#else
+	/* Host port 2 transceiver D+ pull up enable */
+	writel(readl(UP2OCR) | UP2OCR_DPPUE, UP2OCR);
+#endif
 }
 
 /* Disconnect the USB device to the bus */
@@ -612,8 +624,13 @@ void udc_disconnect(void)
 {
 	usbdbg("UDC disconnect");
 
+#ifdef CONFIG_USB_DEV_PULLUP_GPIO
 	/* Turn off the USB connection by disabling the pullup resistor */
-	GPCR(CONFIG_USB_DEV_PULLUP_GPIO) = GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO);
+	writel(GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO), GPCR(CONFIG_USB_DEV_PULLUP_GPIO));
+#else
+	/* Host port 2 transceiver D+ pull up disable */
+	writel(readl(UP2OCR) & ~UP2OCR_DPPUE, UP2OCR);
+#endif
 }
 
 /* Switch on the UDC */
@@ -621,15 +638,14 @@ void udc_enable(struct usb_device_instance *device)
 {
 
 	ep0state = EP0_IDLE;
-	CKEN |= CKEN11_USB;
 
 	/* enable endpoint 0, A, B's Packet Complete Interrupt. */
-	UDCICR0 = 0x0000003f;
-	UDCICR1 = 0xa8000000;
+	writel(0xffffffff, UDCICR0);
+	writel(0xa8000000, UDCICR1);
 
 	/* clear the interrupt status/control registers */
-	UDCISR0 = 0xffffffff;
-	UDCISR1 = 0xffffffff;
+	writel(0xffffffff, UDCISR0);
+	writel(0xffffffff, UDCISR1);
 
 	/* set UDC-enable */
 	udc_set_mask_UDCCR(UDCCR_UDE);
@@ -652,7 +668,7 @@ void udc_disable(void)
 	udc_clear_mask_UDCCR(UDCCR_UDE);
 
 	/* Disable clock for USB device */
-	CKEN &= ~CKEN11_USB;
+	writel(readl(CKEN) & ~CKEN11_USB, CKEN);
 
 	/* Free ep0 URB */
 	if (ep0_urb) {
@@ -689,14 +705,15 @@ int udc_init(void)
 	udc_device = NULL;
 	usbdbg("PXA27x usbd start");
 
+	/* Enable clock for USB device */
+	writel(readl(CKEN) | CKEN11_USB, CKEN);
+
 	/* Disable the UDC */
 	udc_clear_mask_UDCCR(UDCCR_UDE);
 
-	/* Disable clock for USB device */
-	CKEN &= ~CKEN11_USB;
-
 	/* Disable IRQs: we don't use them */
-	UDCICR0 = UDCICR1 = 0;
+	writel(0, UDCICR0);
+	writel(0, UDCICR1);
 
 	return 0;
 }
diff --git a/drivers/usb/gadget/regs-otg.h b/drivers/usb/gadget/regs-otg.h
new file mode 100644
index 0000000000000000000000000000000000000000..3737e452319b70f7e58d531a810793aa6f118031
--- /dev/null
+++ b/drivers/usb/gadget/regs-otg.h
@@ -0,0 +1,271 @@
+/* linux/arch/arm/plat-s3c/include/plat/regs-otg.h
+ *
+ * Copyright (C) 2004 Herbert Poetzl <herbert@13thfloor.at>
+ *
+ * Registers remapping:
+ * Lukasz Majewski <l.majewski@samsumg.com>
+ *
+ * This include file 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 __ASM_ARCH_REGS_USB_OTG_HS_H
+#define __ASM_ARCH_REGS_USB_OTG_HS_H
+
+/* USB2.0 OTG Controller register */
+struct s3c_usbotg_phy {
+	u32 phypwr;
+	u32 phyclk;
+	u32 rstcon;
+};
+
+/* Device Logical IN Endpoint-Specific Registers */
+struct s3c_dev_in_endp {
+	u32 diepctl;
+	u8  res1[4];
+	u32 diepint;
+	u8  res2[4];
+	u32 dieptsiz;
+	u32 diepdma;
+	u8  res3[4];
+	u32 diepdmab;
+};
+
+/* Device Logical OUT Endpoint-Specific Registers */
+struct s3c_dev_out_endp {
+	u32 doepctl;
+	u8  res1[4];
+	u32 doepint;
+	u8  res2[4];
+	u32 doeptsiz;
+	u32 doepdma;
+	u8  res3[4];
+	u32 doepdmab;
+};
+
+struct ep_fifo {
+	u32 fifo;
+	u8  res[4092];
+};
+
+/* USB2.0 OTG Controller register */
+struct s3c_usbotg_reg {
+	/* Core Global Registers */
+	u32 gotgctl; /* OTG Control & Status */
+	u32 gotgint; /* OTG Interrupt */
+	u32 gahbcfg; /* Core AHB Configuration */
+	u32 gusbcfg; /* Core USB Configuration */
+	u32 grstctl; /* Core Reset */
+	u32 gintsts; /* Core Interrupt */
+	u32 gintmsk; /* Core Interrupt Mask */
+	u32 grxstsr; /* Receive Status Debug Read/Status Read */
+	u32 grxstsp; /* Receive Status Debug Pop/Status Pop */
+	u32 grxfsiz; /* Receive FIFO Size */
+	u32 gnptxfsiz; /* Non-Periodic Transmit FIFO Size */
+	u8  res1[216];
+	u32 dieptxf[15]; /* Device Periodic Transmit FIFO size register */
+	u8  res2[1728];
+	/* Device Configuration */
+	u32 dcfg; /* Device Configuration Register */
+	u32 dctl; /* Device Control */
+	u32 dsts; /* Device Status */
+	u8  res3[4];
+	u32 diepmsk; /* Device IN Endpoint Common Interrupt Mask */
+	u32 doepmsk; /* Device OUT Endpoint Common Interrupt Mask */
+	u32 daint; /* Device All Endpoints Interrupt */
+	u32 daintmsk; /* Device All Endpoints Interrupt Mask */
+	u8  res4[224];
+	struct s3c_dev_in_endp in_endp[16];
+	struct s3c_dev_out_endp out_endp[16];
+	u8  res5[768];
+	struct ep_fifo ep[16];
+};
+
+/*===================================================================== */
+/*definitions related to CSR setting */
+
+/* S3C_UDC_OTG_GOTGCTL */
+#define B_SESSION_VALID		(0x1<<19)
+#define A_SESSION_VALID		(0x1<<18)
+
+/* S3C_UDC_OTG_GAHBCFG */
+#define PTXFE_HALF			(0<<8)
+#define PTXFE_ZERO			(1<<8)
+#define NPTXFE_HALF			(0<<7)
+#define NPTXFE_ZERO			(1<<7)
+#define MODE_SLAVE			(0<<5)
+#define MODE_DMA			(1<<5)
+#define BURST_SINGLE			(0<<1)
+#define BURST_INCR			(1<<1)
+#define BURST_INCR4			(3<<1)
+#define BURST_INCR8			(5<<1)
+#define BURST_INCR16			(7<<1)
+#define GBL_INT_UNMASK			(1<<0)
+#define GBL_INT_MASK			(0<<0)
+
+/* S3C_UDC_OTG_GRSTCTL */
+#define AHB_MASTER_IDLE		(1u<<31)
+#define CORE_SOFT_RESET		(0x1<<0)
+
+/* S3C_UDC_OTG_GINTSTS/S3C_UDC_OTG_GINTMSK core interrupt register */
+#define INT_RESUME			(1u<<31)
+#define INT_DISCONN			(0x1<<29)
+#define INT_CONN_ID_STS_CNG		(0x1<<28)
+#define INT_OUT_EP			(0x1<<19)
+#define INT_IN_EP			(0x1<<18)
+#define INT_ENUMDONE			(0x1<<13)
+#define INT_RESET			(0x1<<12)
+#define INT_SUSPEND			(0x1<<11)
+#define INT_EARLY_SUSPEND		(0x1<<10)
+#define INT_NP_TX_FIFO_EMPTY		(0x1<<5)
+#define INT_RX_FIFO_NOT_EMPTY		(0x1<<4)
+#define INT_SOF			(0x1<<3)
+#define INT_DEV_MODE			(0x0<<0)
+#define INT_HOST_MODE			(0x1<<1)
+#define INT_GOUTNakEff			(0x01<<7)
+#define INT_GINNakEff			(0x01<<6)
+
+#define FULL_SPEED_CONTROL_PKT_SIZE	8
+#define FULL_SPEED_BULK_PKT_SIZE	64
+
+#define HIGH_SPEED_CONTROL_PKT_SIZE	64
+#define HIGH_SPEED_BULK_PKT_SIZE	512
+
+#define RX_FIFO_SIZE			(1024*4)
+#define NPTX_FIFO_SIZE			(1024*4)
+#define PTX_FIFO_SIZE			(1536*1)
+
+#define DEPCTL_TXFNUM_0		(0x0<<22)
+#define DEPCTL_TXFNUM_1		(0x1<<22)
+#define DEPCTL_TXFNUM_2		(0x2<<22)
+#define DEPCTL_TXFNUM_3		(0x3<<22)
+#define DEPCTL_TXFNUM_4		(0x4<<22)
+
+/* Enumeration speed */
+#define USB_HIGH_30_60MHZ		(0x0<<1)
+#define USB_FULL_30_60MHZ		(0x1<<1)
+#define USB_LOW_6MHZ			(0x2<<1)
+#define USB_FULL_48MHZ			(0x3<<1)
+
+/* S3C_UDC_OTG_GRXSTSP STATUS */
+#define OUT_PKT_RECEIVED		(0x2<<17)
+#define OUT_TRANSFER_COMPLELTED	(0x3<<17)
+#define SETUP_TRANSACTION_COMPLETED	(0x4<<17)
+#define SETUP_PKT_RECEIVED		(0x6<<17)
+#define GLOBAL_OUT_NAK			(0x1<<17)
+
+/* S3C_UDC_OTG_DCTL device control register */
+#define NORMAL_OPERATION		(0x1<<0)
+#define SOFT_DISCONNECT		(0x1<<1)
+
+/* S3C_UDC_OTG_DAINT device all endpoint interrupt register */
+#define DAINT_OUT_BIT			(16)
+#define DAINT_MASK			(0xFFFF)
+
+/* S3C_UDC_OTG_DIEPCTL0/DOEPCTL0 device
+   control IN/OUT endpoint 0 control register */
+#define DEPCTL_EPENA			(0x1<<31)
+#define DEPCTL_EPDIS			(0x1<<30)
+#define DEPCTL_SETD1PID		(0x1<<29)
+#define DEPCTL_SETD0PID		(0x1<<28)
+#define DEPCTL_SNAK			(0x1<<27)
+#define DEPCTL_CNAK			(0x1<<26)
+#define DEPCTL_STALL			(0x1<<21)
+#define DEPCTL_TYPE_BIT		(18)
+#define DEPCTL_TYPE_MASK		(0x3<<18)
+#define DEPCTL_CTRL_TYPE		(0x0<<18)
+#define DEPCTL_ISO_TYPE		(0x1<<18)
+#define DEPCTL_BULK_TYPE		(0x2<<18)
+#define DEPCTL_INTR_TYPE		(0x3<<18)
+#define DEPCTL_USBACTEP		(0x1<<15)
+#define DEPCTL_NEXT_EP_BIT		(11)
+#define DEPCTL_MPS_BIT			(0)
+#define DEPCTL_MPS_MASK		(0x7FF)
+
+#define DEPCTL0_MPS_64			(0x0<<0)
+#define DEPCTL0_MPS_32			(0x1<<0)
+#define DEPCTL0_MPS_16			(0x2<<0)
+#define DEPCTL0_MPS_8			(0x3<<0)
+#define DEPCTL_MPS_BULK_512		(512<<0)
+#define DEPCTL_MPS_INT_MPS_16		(16<<0)
+
+#define DIEPCTL0_NEXT_EP_BIT		(11)
+
+
+/* S3C_UDC_OTG_DIEPMSK/DOEPMSK device IN/OUT endpoint
+   common interrupt mask register */
+/* S3C_UDC_OTG_DIEPINTn/DOEPINTn device IN/OUT endpoint interrupt register */
+#define BACK2BACK_SETUP_RECEIVED	(0x1<<6)
+#define INTKNEPMIS			(0x1<<5)
+#define INTKN_TXFEMP			(0x1<<4)
+#define NON_ISO_IN_EP_TIMEOUT		(0x1<<3)
+#define CTRL_OUT_EP_SETUP_PHASE_DONE	(0x1<<3)
+#define AHB_ERROR			(0x1<<2)
+#define EPDISBLD			(0x1<<1)
+#define TRANSFER_DONE			(0x1<<0)
+
+#define USB_PHY_CTRL_EN0                (0x1 << 0)
+
+/* OPHYPWR */
+#define PHY_0_SLEEP                     (0x1 << 5)
+#define OTG_DISABLE_0                   (0x1 << 4)
+#define ANALOG_PWRDOWN                  (0x1 << 3)
+#define FORCE_SUSPEND_0                 (0x1 << 0)
+
+/* URSTCON */
+#define HOST_SW_RST                     (0x1 << 4)
+#define PHY_SW_RST1                     (0x1 << 3)
+#define PHYLNK_SW_RST                   (0x1 << 2)
+#define LINK_SW_RST                     (0x1 << 1)
+#define PHY_SW_RST0                     (0x1 << 0)
+
+/* OPHYCLK */
+#define COMMON_ON_N1                    (0x1 << 7)
+#define COMMON_ON_N0                    (0x1 << 4)
+#define ID_PULLUP0                      (0x1 << 2)
+#define CLK_SEL_24MHZ                   (0x3 << 0)
+#define CLK_SEL_12MHZ                   (0x2 << 0)
+#define CLK_SEL_48MHZ                   (0x0 << 0)
+
+/* Device Configuration Register DCFG */
+#define DEV_SPEED_HIGH_SPEED_20         (0x0 << 0)
+#define DEV_SPEED_FULL_SPEED_20         (0x1 << 0)
+#define DEV_SPEED_LOW_SPEED_11          (0x2 << 0)
+#define DEV_SPEED_FULL_SPEED_11         (0x3 << 0)
+#define EP_MISS_CNT(x)                  (x << 18)
+#define DEVICE_ADDRESS(x)               (x << 4)
+
+/* Core Reset Register (GRSTCTL) */
+#define TX_FIFO_FLUSH                   (0x1 << 5)
+#define RX_FIFO_FLUSH                   (0x1 << 4)
+#define TX_FIFO_NUMBER(x)               (x << 6)
+#define TX_FIFO_FLUSH_ALL               TX_FIFO_NUMBER(0x10)
+
+/* Masks definitions */
+#define GINTMSK_INIT	(INT_OUT_EP | INT_IN_EP | INT_RESUME | INT_ENUMDONE\
+			| INT_RESET | INT_SUSPEND)
+#define DOEPMSK_INIT	(CTRL_OUT_EP_SETUP_PHASE_DONE | AHB_ERROR|TRANSFER_DONE)
+#define DIEPMSK_INIT	(NON_ISO_IN_EP_TIMEOUT|AHB_ERROR|TRANSFER_DONE)
+#define GAHBCFG_INIT	(PTXFE_HALF | NPTXFE_HALF | MODE_DMA | BURST_INCR4\
+			| GBL_INT_UNMASK)
+
+/* Device Endpoint X Transfer Size Register (DIEPTSIZX) */
+#define DIEPT_SIZ_PKT_CNT(x)                      (x << 19)
+#define DIEPT_SIZ_XFER_SIZE(x)                    (x << 0)
+
+/* Device OUT Endpoint X Transfer Size Register (DOEPTSIZX) */
+#define DOEPT_SIZ_PKT_CNT(x)                      (x << 19)
+#define DOEPT_SIZ_XFER_SIZE(x)                    (x << 0)
+#define DOEPT_SIZ_XFER_SIZE_MAX_EP0               (0x7F << 0)
+#define DOEPT_SIZ_XFER_SIZE_MAX_EP                (0x7FFF << 0)
+
+/* Device Endpoint-N Control Register (DIEPCTLn/DOEPCTLn) */
+#define DIEPCTL_TX_FIFO_NUM(x)                    (x << 22)
+#define DIEPCTL_TX_FIFO_NUM_MASK                  (~DIEPCTL_TX_FIFO_NUM(0xF))
+
+/* Device ALL Endpoints Interrupt Register (DAINT) */
+#define DAINT_IN_EP_INT(x)                        (x << 0)
+#define DAINT_OUT_EP_INT(x)                       (x << 16)
+#endif
diff --git a/drivers/usb/gadget/s3c_udc_otg.c b/drivers/usb/gadget/s3c_udc_otg.c
new file mode 100644
index 0000000000000000000000000000000000000000..5a3ac78ff26202859a47e7b0ad359d4091dfe837
--- /dev/null
+++ b/drivers/usb/gadget/s3c_udc_otg.c
@@ -0,0 +1,892 @@
+/*
+ * drivers/usb/gadget/s3c_udc_otg.c
+ * Samsung S3C on-chip full/high speed USB OTG 2.0 device controllers
+ *
+ * Copyright (C) 2008 for Samsung Electronics
+ *
+ * BSP Support for Samsung's UDC driver
+ * available at:
+ * git://git.kernel.org/pub/scm/linux/kernel/git/kki_ap/linux-2.6-samsung.git
+ *
+ * State machine bugfixes:
+ * Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * Ported to u-boot:
+ * Marek Szyprowski <m.szyprowski@samsung.com>
+ * Lukasz Majewski <l.majewski@samsumg.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#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/io.h>
+
+#include <asm/mach-types.h>
+#include <asm/arch/gpio.h>
+
+#include "regs-otg.h"
+#include <usb/s3c_udc.h>
+#include <usb/lin_gadget_compat.h>
+
+/***********************************************************/
+
+#define OTG_DMA_MODE		1
+
+#undef DEBUG_S3C_UDC_SETUP
+#undef DEBUG_S3C_UDC_EP0
+#undef DEBUG_S3C_UDC_ISR
+#undef DEBUG_S3C_UDC_OUT_EP
+#undef DEBUG_S3C_UDC_IN_EP
+#undef DEBUG_S3C_UDC
+
+/* #define DEBUG_S3C_UDC_SETUP */
+/* #define DEBUG_S3C_UDC_EP0 */
+/* #define DEBUG_S3C_UDC_ISR */
+/* #define DEBUG_S3C_UDC_OUT_EP */
+/* #define DEBUG_S3C_UDC_IN_EP */
+/* #define DEBUG_S3C_UDC */
+
+#include <usb/s3c_udc.h>
+
+#define EP0_CON		0
+#define EP_MASK		0xF
+
+#if defined(DEBUG_S3C_UDC_SETUP) || defined(DEBUG_S3C_UDC_ISR)	  \
+	|| defined(DEBUG_S3C_UDC_OUT_EP)
+static char *state_names[] = {
+	"WAIT_FOR_SETUP",
+	"DATA_STATE_XMIT",
+	"DATA_STATE_NEED_ZLP",
+	"WAIT_FOR_OUT_STATUS",
+	"DATA_STATE_RECV",
+	"WAIT_FOR_COMPLETE",
+	"WAIT_FOR_OUT_COMPLETE",
+	"WAIT_FOR_IN_COMPLETE",
+	"WAIT_FOR_NULL_COMPLETE",
+};
+#endif
+
+#define DRIVER_DESC "S3C HS USB OTG Device Driver, (c) Samsung Electronics"
+#define DRIVER_VERSION "15 March 2009"
+
+struct s3c_udc	*the_controller;
+
+static const char driver_name[] = "s3c-udc";
+static const char driver_desc[] = DRIVER_DESC;
+static const char ep0name[] = "ep0-control";
+
+/* Max packet size*/
+static unsigned int ep0_fifo_size = 64;
+static unsigned int ep_fifo_size =  512;
+static unsigned int ep_fifo_size2 = 1024;
+static int reset_available = 1;
+
+static struct usb_ctrlrequest *usb_ctrl;
+static dma_addr_t usb_ctrl_dma_addr;
+
+/*
+  Local declarations.
+*/
+static int s3c_ep_enable(struct usb_ep *ep,
+			 const struct usb_endpoint_descriptor *);
+static int s3c_ep_disable(struct usb_ep *ep);
+static struct usb_request *s3c_alloc_request(struct usb_ep *ep,
+					     gfp_t gfp_flags);
+static void s3c_free_request(struct usb_ep *ep, struct usb_request *);
+
+static int s3c_queue(struct usb_ep *ep, struct usb_request *, gfp_t gfp_flags);
+static int s3c_dequeue(struct usb_ep *ep, struct usb_request *);
+static int s3c_fifo_status(struct usb_ep *ep);
+static void s3c_fifo_flush(struct usb_ep *ep);
+static void s3c_ep0_read(struct s3c_udc *dev);
+static void s3c_ep0_kick(struct s3c_udc *dev, struct s3c_ep *ep);
+static void s3c_handle_ep0(struct s3c_udc *dev);
+static int s3c_ep0_write(struct s3c_udc *dev);
+static int write_fifo_ep0(struct s3c_ep *ep, struct s3c_request *req);
+static void done(struct s3c_ep *ep, struct s3c_request *req, int status);
+static void stop_activity(struct s3c_udc *dev,
+			  struct usb_gadget_driver *driver);
+static int udc_enable(struct s3c_udc *dev);
+static void udc_set_address(struct s3c_udc *dev, unsigned char address);
+static void reconfig_usbd(void);
+static void set_max_pktsize(struct s3c_udc *dev, enum usb_device_speed speed);
+static void nuke(struct s3c_ep *ep, int status);
+static int s3c_udc_set_halt(struct usb_ep *_ep, int value);
+static void s3c_udc_set_nak(struct s3c_ep *ep);
+
+static struct usb_ep_ops s3c_ep_ops = {
+	.enable = s3c_ep_enable,
+	.disable = s3c_ep_disable,
+
+	.alloc_request = s3c_alloc_request,
+	.free_request = s3c_free_request,
+
+	.queue = s3c_queue,
+	.dequeue = s3c_dequeue,
+
+	.set_halt = s3c_udc_set_halt,
+	.fifo_status = s3c_fifo_status,
+	.fifo_flush = s3c_fifo_flush,
+};
+
+#define create_proc_files() do {} while (0)
+#define remove_proc_files() do {} while (0)
+
+/***********************************************************/
+
+void __iomem		*regs_otg;
+struct s3c_usbotg_reg *reg;
+struct s3c_usbotg_phy *phy;
+static unsigned int usb_phy_ctrl;
+
+void otg_phy_init(struct s3c_udc *dev)
+{
+	dev->pdata->phy_control(1);
+
+	/*USB PHY0 Enable */
+	printf("USB PHY0 Enable\n");
+
+	/* Enable PHY */
+	writel(readl(usb_phy_ctrl) | USB_PHY_CTRL_EN0, usb_phy_ctrl);
+
+	if (dev->pdata->usb_flags == PHY0_SLEEP) /* C210 Universal */
+		writel((readl(&phy->phypwr)
+			&~(PHY_0_SLEEP | OTG_DISABLE_0 | ANALOG_PWRDOWN)
+			&~FORCE_SUSPEND_0), &phy->phypwr);
+	else /* C110 GONI */
+		writel((readl(&phy->phypwr) &~(OTG_DISABLE_0 | ANALOG_PWRDOWN)
+			&~FORCE_SUSPEND_0), &phy->phypwr);
+
+	writel((readl(&phy->phyclk) &~(ID_PULLUP0 | COMMON_ON_N0)) |
+	       CLK_SEL_24MHZ, &phy->phyclk); /* PLL 24Mhz */
+
+	writel((readl(&phy->rstcon) &~(LINK_SW_RST | PHYLNK_SW_RST))
+	       | PHY_SW_RST0, &phy->rstcon);
+	udelay(10);
+	writel(readl(&phy->rstcon)
+	       &~(PHY_SW_RST0 | LINK_SW_RST | PHYLNK_SW_RST), &phy->rstcon);
+	udelay(10);
+}
+
+void otg_phy_off(struct s3c_udc *dev)
+{
+	/* reset controller just in case */
+	writel(PHY_SW_RST0, &phy->rstcon);
+	udelay(20);
+	writel(readl(&phy->phypwr) &~PHY_SW_RST0, &phy->rstcon);
+	udelay(20);
+
+	writel(readl(&phy->phypwr) | OTG_DISABLE_0 | ANALOG_PWRDOWN
+	       | FORCE_SUSPEND_0, &phy->phypwr);
+
+	writel(readl(usb_phy_ctrl) &~USB_PHY_CTRL_EN0, usb_phy_ctrl);
+
+	writel((readl(&phy->phyclk) & ~(ID_PULLUP0 | COMMON_ON_N0)),
+	      &phy->phyclk);
+
+	udelay(10000);
+
+	dev->pdata->phy_control(0);
+}
+
+/***********************************************************/
+
+#include "s3c_udc_otg_xfer_dma.c"
+
+/*
+ *	udc_disable - disable USB device controller
+ */
+static void udc_disable(struct s3c_udc *dev)
+{
+	DEBUG_SETUP("%s: %p\n", __func__, dev);
+
+	udc_set_address(dev, 0);
+
+	dev->ep0state = WAIT_FOR_SETUP;
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+	dev->usb_address = 0;
+
+	otg_phy_off(dev);
+}
+
+/*
+ *	udc_reinit - initialize software state
+ */
+static void udc_reinit(struct s3c_udc *dev)
+{
+	unsigned int i;
+
+	DEBUG_SETUP("%s: %p\n", __func__, dev);
+
+	/* device/ep0 records init */
+	INIT_LIST_HEAD(&dev->gadget.ep_list);
+	INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+	dev->ep0state = WAIT_FOR_SETUP;
+
+	/* basic endpoint records init */
+	for (i = 0; i < S3C_MAX_ENDPOINTS; i++) {
+		struct s3c_ep *ep = &dev->ep[i];
+
+		if (i != 0)
+			list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
+
+		ep->desc = 0;
+		ep->stopped = 0;
+		INIT_LIST_HEAD(&ep->queue);
+		ep->pio_irqs = 0;
+	}
+
+	/* the rest was statically initialized, and is read-only */
+}
+
+#define BYTES2MAXP(x)	(x / 8)
+#define MAXP2BYTES(x)	(x * 8)
+
+/* until it's enabled, this UDC should be completely invisible
+ * to any USB host.
+ */
+static int udc_enable(struct s3c_udc *dev)
+{
+	DEBUG_SETUP("%s: %p\n", __func__, dev);
+
+	otg_phy_init(dev);
+	reconfig_usbd();
+
+	DEBUG_SETUP("S3C USB 2.0 OTG Controller Core Initialized : 0x%x\n",
+		    readl(&reg->gintmsk));
+
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+/*
+  Register entry point for the peripheral controller driver.
+*/
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct s3c_udc *dev = the_controller;
+	int retval = 0;
+	unsigned long flags;
+
+	DEBUG_SETUP("%s: %s\n", __func__, "no name");
+
+	if (!driver
+	    || (driver->speed != USB_SPEED_FULL
+		&& driver->speed != USB_SPEED_HIGH)
+	    || !driver->bind || !driver->disconnect || !driver->setup)
+		return -EINVAL;
+	if (!dev)
+		return -ENODEV;
+	if (dev->driver)
+		return -EBUSY;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	/* first hook up the driver ... */
+	dev->driver = driver;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	if (retval) { /* TODO */
+		printf("target device_add failed, error %d\n", retval);
+		return retval;
+	}
+
+	retval = driver->bind(&dev->gadget);
+	if (retval) {
+		DEBUG_SETUP("%s: bind to driver --> error %d\n",
+			    dev->gadget.name, retval);
+		dev->driver = 0;
+		return retval;
+	}
+
+	enable_irq(IRQ_OTG);
+
+	DEBUG_SETUP("Registered gadget driver %s\n", dev->gadget.name);
+	udc_enable(dev);
+
+	return 0;
+}
+
+/*
+ * Unregister entry point for the peripheral controller driver.
+ */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct s3c_udc *dev = the_controller;
+	unsigned long flags;
+
+	if (!dev)
+		return -ENODEV;
+	if (!driver || driver != dev->driver)
+		return -EINVAL;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->driver = 0;
+	stop_activity(dev, driver);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	driver->unbind(&dev->gadget);
+
+	disable_irq(IRQ_OTG);
+
+	udc_disable(dev);
+	return 0;
+}
+
+/*
+ *	done - retire a request; caller blocked irqs
+ */
+static void done(struct s3c_ep *ep, struct s3c_request *req, int status)
+{
+	unsigned int stopped = ep->stopped;
+
+	DEBUG("%s: %s %p, req = %p, stopped = %d\n",
+	      __func__, ep->ep.name, ep, &req->req, stopped);
+
+	list_del_init(&req->queue);
+
+	if (likely(req->req.status == -EINPROGRESS))
+		req->req.status = status;
+	else
+		status = req->req.status;
+
+	if (status && status != -ESHUTDOWN) {
+		DEBUG("complete %s req %p stat %d len %u/%u\n",
+		      ep->ep.name, &req->req, status,
+		      req->req.actual, req->req.length);
+	}
+
+	/* don't modify queue heads during completion callback */
+	ep->stopped = 1;
+
+#ifdef DEBUG_S3C_UDC
+	printf("calling complete callback\n");
+	{
+		int i, len = req->req.length;
+
+		printf("pkt[%d] = ", req->req.length);
+		if (len > 64)
+			len = 64;
+		for (i = 0; i < len; i++) {
+			printf("%02x", ((u8 *)req->req.buf)[i]);
+			if ((i & 7) == 7)
+				printf(" ");
+		}
+		printf("\n");
+	}
+#endif
+	spin_unlock(&ep->dev->lock);
+	req->req.complete(&ep->ep, &req->req);
+	spin_lock(&ep->dev->lock);
+
+	DEBUG("callback completed\n");
+
+	ep->stopped = stopped;
+}
+
+/*
+ *	nuke - dequeue ALL requests
+ */
+static void nuke(struct s3c_ep *ep, int status)
+{
+	struct s3c_request *req;
+
+	DEBUG("%s: %s %p\n", __func__, ep->ep.name, ep);
+
+	/* called with irqs blocked */
+	while (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct s3c_request, queue);
+		done(ep, req, status);
+	}
+}
+
+static void stop_activity(struct s3c_udc *dev,
+			  struct usb_gadget_driver *driver)
+{
+	int i;
+
+	/* don't disconnect drivers more than once */
+	if (dev->gadget.speed == USB_SPEED_UNKNOWN)
+		driver = 0;
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+	/* prevent new request submissions, kill any outstanding requests  */
+	for (i = 0; i < S3C_MAX_ENDPOINTS; i++) {
+		struct s3c_ep *ep = &dev->ep[i];
+		ep->stopped = 1;
+		nuke(ep, -ESHUTDOWN);
+	}
+
+	/* report disconnect; the driver is already quiesced */
+	if (driver) {
+		spin_unlock(&dev->lock);
+		driver->disconnect(&dev->gadget);
+		spin_lock(&dev->lock);
+	}
+
+	/* re-init driver-visible data structures */
+	udc_reinit(dev);
+}
+
+static void reconfig_usbd(void)
+{
+	/* 2. Soft-reset OTG Core and then unreset again. */
+	int i;
+	unsigned int uTemp = writel(CORE_SOFT_RESET, &reg->grstctl);
+
+	DEBUG(2, "Reseting OTG controller\n");
+
+	writel(0<<15		/* PHY Low Power Clock sel*/
+		|1<<14		/* Non-Periodic TxFIFO Rewind Enable*/
+		|0x5<<10	/* Turnaround time*/
+		|0<<9 | 0<<8	/* [0:HNP disable,1:HNP enable][ 0:SRP disable*/
+				/* 1:SRP enable] H1= 1,1*/
+		|0<<7		/* Ulpi DDR sel*/
+		|0<<6		/* 0: high speed utmi+, 1: full speed serial*/
+		|0<<4		/* 0: utmi+, 1:ulpi*/
+		|1<<3		/* phy i/f  0:8bit, 1:16bit*/
+		|0x7<<0,	/* HS/FS Timeout**/
+		&reg->gusbcfg);
+
+	/* 3. Put the OTG device core in the disconnected state.*/
+	uTemp = readl(&reg->dctl);
+	uTemp |= SOFT_DISCONNECT;
+	writel(uTemp, &reg->dctl);
+
+	udelay(20);
+
+	/* 4. Make the OTG device core exit from the disconnected state.*/
+	uTemp = readl(&reg->dctl);
+	uTemp = uTemp & ~SOFT_DISCONNECT;
+	writel(uTemp, &reg->dctl);
+
+	/* 5. Configure OTG Core to initial settings of device mode.*/
+	/* [][1: full speed(30Mhz) 0:high speed]*/
+	writel(EP_MISS_CNT(1) | DEV_SPEED_HIGH_SPEED_20, &reg->dcfg);
+
+	mdelay(1);
+
+	/* 6. Unmask the core interrupts*/
+	writel(GINTMSK_INIT, &reg->gintmsk);
+
+	/* 7. Set NAK bit of EP0, EP1, EP2*/
+	writel(DEPCTL_EPDIS|DEPCTL_SNAK, &reg->out_endp[EP0_CON].doepctl);
+	writel(DEPCTL_EPDIS|DEPCTL_SNAK, &reg->in_endp[EP0_CON].diepctl);
+
+	for (i = 1; i < S3C_MAX_ENDPOINTS; i++) {
+		writel(DEPCTL_EPDIS|DEPCTL_SNAK, &reg->out_endp[i].doepctl);
+		writel(DEPCTL_EPDIS|DEPCTL_SNAK, &reg->in_endp[i].diepctl);
+	}
+
+	/* 8. Unmask EPO interrupts*/
+	writel(((1 << EP0_CON) << DAINT_OUT_BIT)
+	       | (1 << EP0_CON), &reg->daintmsk);
+
+	/* 9. Unmask device OUT EP common interrupts*/
+	writel(DOEPMSK_INIT, &reg->doepmsk);
+
+	/* 10. Unmask device IN EP common interrupts*/
+	writel(DIEPMSK_INIT, &reg->diepmsk);
+
+	/* 11. Set Rx FIFO Size (in 32-bit words) */
+	writel(RX_FIFO_SIZE >> 2, &reg->grxfsiz);
+
+	/* 12. Set Non Periodic Tx FIFO Size */
+	writel((NPTX_FIFO_SIZE >> 2) << 16 | ((RX_FIFO_SIZE >> 2)) << 0,
+	       &reg->gnptxfsiz);
+
+	for (i = 1; i < S3C_MAX_HW_ENDPOINTS; i++)
+		writel((PTX_FIFO_SIZE >> 2) << 16 |
+		       ((RX_FIFO_SIZE + NPTX_FIFO_SIZE +
+			 PTX_FIFO_SIZE*(i-1)) >> 2) << 0,
+		       &reg->dieptxf[i-1]);
+
+	/* Flush the RX FIFO */
+	writel(RX_FIFO_FLUSH, &reg->grstctl);
+	while (readl(&reg->grstctl) & RX_FIFO_FLUSH)
+		DEBUG("%s: waiting for S3C_UDC_OTG_GRSTCTL\n", __func__);
+
+	/* Flush all the Tx FIFO's */
+	writel(TX_FIFO_FLUSH_ALL, &reg->grstctl);
+	writel(TX_FIFO_FLUSH_ALL | TX_FIFO_FLUSH, &reg->grstctl);
+	while (readl(&reg->grstctl) & TX_FIFO_FLUSH)
+		DEBUG("%s: waiting for S3C_UDC_OTG_GRSTCTL\n", __func__);
+
+	/* 13. Clear NAK bit of EP0, EP1, EP2*/
+	/* For Slave mode*/
+	/* EP0: Control OUT */
+	writel(DEPCTL_EPDIS | DEPCTL_CNAK,
+	       &reg->out_endp[EP0_CON].doepctl);
+
+	/* 14. Initialize OTG Link Core.*/
+	writel(GAHBCFG_INIT, &reg->gahbcfg);
+}
+
+static void set_max_pktsize(struct s3c_udc *dev, enum usb_device_speed speed)
+{
+	unsigned int ep_ctrl;
+	int i;
+
+	if (speed == USB_SPEED_HIGH) {
+		ep0_fifo_size = 64;
+		ep_fifo_size = 512;
+		ep_fifo_size2 = 1024;
+		dev->gadget.speed = USB_SPEED_HIGH;
+	} else {
+		ep0_fifo_size = 64;
+		ep_fifo_size = 64;
+		ep_fifo_size2 = 64;
+		dev->gadget.speed = USB_SPEED_FULL;
+	}
+
+	dev->ep[0].ep.maxpacket = ep0_fifo_size;
+	for (i = 1; i < S3C_MAX_ENDPOINTS; i++)
+		dev->ep[i].ep.maxpacket = ep_fifo_size;
+
+	/* EP0 - Control IN (64 bytes)*/
+	ep_ctrl = readl(&reg->in_endp[EP0_CON].diepctl);
+	writel(ep_ctrl|(0<<0), &reg->in_endp[EP0_CON].diepctl);
+
+	/* EP0 - Control OUT (64 bytes)*/
+	ep_ctrl = readl(&reg->out_endp[EP0_CON].doepctl);
+	writel(ep_ctrl|(0<<0), &reg->out_endp[EP0_CON].doepctl);
+}
+
+static int s3c_ep_enable(struct usb_ep *_ep,
+			 const struct usb_endpoint_descriptor *desc)
+{
+	struct s3c_ep *ep;
+	struct s3c_udc *dev;
+	unsigned long flags;
+
+	DEBUG("%s: %p\n", __func__, _ep);
+
+	ep = container_of(_ep, struct s3c_ep, ep);
+	if (!_ep || !desc || ep->desc || _ep->name == ep0name
+	    || desc->bDescriptorType != USB_DT_ENDPOINT
+	    || ep->bEndpointAddress != desc->bEndpointAddress
+	    || ep_maxpacket(ep) < le16_to_cpu(desc->wMaxPacketSize)) {
+
+		DEBUG("%s: bad ep or descriptor\n", __func__);
+		return -EINVAL;
+	}
+
+	/* xfer types must match, except that interrupt ~= bulk */
+	if (ep->bmAttributes != desc->bmAttributes
+	    && ep->bmAttributes != USB_ENDPOINT_XFER_BULK
+	    && desc->bmAttributes != USB_ENDPOINT_XFER_INT) {
+
+		DEBUG("%s: %s type mismatch\n", __func__, _ep->name);
+		return -EINVAL;
+	}
+
+	/* hardware _could_ do smaller, but driver doesn't */
+	if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
+	     && le16_to_cpu(desc->wMaxPacketSize) != ep_maxpacket(ep))
+	    || !desc->wMaxPacketSize) {
+
+		DEBUG("%s: bad %s maxpacket\n", __func__, _ep->name);
+		return -ERANGE;
+	}
+
+	dev = ep->dev;
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
+
+		DEBUG("%s: bogus device state\n", __func__);
+		return -ESHUTDOWN;
+	}
+
+	ep->stopped = 0;
+	ep->desc = desc;
+	ep->pio_irqs = 0;
+	ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+
+	/* Reset halt state */
+	s3c_udc_set_nak(ep);
+	s3c_udc_set_halt(_ep, 0);
+
+	spin_lock_irqsave(&ep->dev->lock, flags);
+	s3c_udc_ep_activate(ep);
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+	DEBUG("%s: enabled %s, stopped = %d, maxpacket = %d\n",
+	      __func__, _ep->name, ep->stopped, ep->ep.maxpacket);
+	return 0;
+}
+
+/*
+ * Disable EP
+ */
+static int s3c_ep_disable(struct usb_ep *_ep)
+{
+	struct s3c_ep *ep;
+	unsigned long flags;
+
+	DEBUG("%s: %p\n", __func__, _ep);
+
+	ep = container_of(_ep, struct s3c_ep, ep);
+	if (!_ep || !ep->desc) {
+		DEBUG("%s: %s not enabled\n", __func__,
+		      _ep ? ep->ep.name : NULL);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&ep->dev->lock, flags);
+
+	/* Nuke all pending requests */
+	nuke(ep, -ESHUTDOWN);
+
+	ep->desc = 0;
+	ep->stopped = 1;
+
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+	DEBUG("%s: disabled %s\n", __func__, _ep->name);
+	return 0;
+}
+
+static struct usb_request *s3c_alloc_request(struct usb_ep *ep,
+					     gfp_t gfp_flags)
+{
+	struct s3c_request *req;
+
+	DEBUG("%s: %s %p\n", __func__, ep->name, ep);
+
+	req = kmalloc(sizeof *req, gfp_flags);
+	if (!req)
+		return 0;
+
+	memset(req, 0, sizeof *req);
+	INIT_LIST_HEAD(&req->queue);
+
+	return &req->req;
+}
+
+static void s3c_free_request(struct usb_ep *ep, struct usb_request *_req)
+{
+	struct s3c_request *req;
+
+	DEBUG("%s: %p\n", __func__, ep);
+
+	req = container_of(_req, struct s3c_request, req);
+	WARN_ON(!list_empty(&req->queue));
+	kfree(req);
+}
+
+/* dequeue JUST ONE request */
+static int s3c_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct s3c_ep *ep;
+	struct s3c_request *req;
+	unsigned long flags;
+
+	DEBUG("%s: %p\n", __func__, _ep);
+
+	ep = container_of(_ep, struct s3c_ep, ep);
+	if (!_ep || ep->ep.name == ep0name)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ep->dev->lock, flags);
+
+	/* 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) {
+		spin_unlock_irqrestore(&ep->dev->lock, flags);
+		return -EINVAL;
+	}
+
+	done(ep, req, -ECONNRESET);
+
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+	return 0;
+}
+
+/*
+ * Return bytes in EP FIFO
+ */
+static int s3c_fifo_status(struct usb_ep *_ep)
+{
+	int count = 0;
+	struct s3c_ep *ep;
+
+	ep = container_of(_ep, struct s3c_ep, ep);
+	if (!_ep) {
+		DEBUG("%s: bad ep\n", __func__);
+		return -ENODEV;
+	}
+
+	DEBUG("%s: %d\n", __func__, ep_index(ep));
+
+	/* LPD can't report unclaimed bytes from IN fifos */
+	if (ep_is_in(ep))
+		return -EOPNOTSUPP;
+
+	return count;
+}
+
+/*
+ * Flush EP FIFO
+ */
+static void s3c_fifo_flush(struct usb_ep *_ep)
+{
+	struct s3c_ep *ep;
+
+	ep = container_of(_ep, struct s3c_ep, ep);
+	if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+		DEBUG("%s: bad ep\n", __func__);
+		return;
+	}
+
+	DEBUG("%s: %d\n", __func__, ep_index(ep));
+}
+
+static const struct usb_gadget_ops s3c_udc_ops = {
+	/* current versions must always be self-powered */
+};
+
+static struct s3c_udc memory = {
+	.usb_address = 0,
+	.gadget = {
+		.ops = &s3c_udc_ops,
+		.ep0 = &memory.ep[0].ep,
+		.name = driver_name,
+	},
+
+	/* control endpoint */
+	.ep[0] = {
+		.ep = {
+			.name = ep0name,
+			.ops = &s3c_ep_ops,
+			.maxpacket = EP0_FIFO_SIZE,
+		},
+		.dev = &memory,
+
+		.bEndpointAddress = 0,
+		.bmAttributes = 0,
+
+		.ep_type = ep_control,
+	},
+
+	/* first group of endpoints */
+	.ep[1] = {
+		.ep = {
+			.name = "ep1in-bulk",
+			.ops = &s3c_ep_ops,
+			.maxpacket = EP_FIFO_SIZE,
+		},
+		.dev = &memory,
+
+		.bEndpointAddress = USB_DIR_IN | 1,
+		.bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+		.ep_type = ep_bulk_out,
+		.fifo_num = 1,
+	},
+
+	.ep[2] = {
+		.ep = {
+			.name = "ep2out-bulk",
+			.ops = &s3c_ep_ops,
+			.maxpacket = EP_FIFO_SIZE,
+		},
+		.dev = &memory,
+
+		.bEndpointAddress = USB_DIR_OUT | 2,
+		.bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+		.ep_type = ep_bulk_in,
+		.fifo_num = 2,
+	},
+
+	.ep[3] = {
+		.ep = {
+			.name = "ep3in-int",
+			.ops = &s3c_ep_ops,
+			.maxpacket = EP_FIFO_SIZE,
+		},
+		.dev = &memory,
+
+		.bEndpointAddress = USB_DIR_IN | 3,
+		.bmAttributes = USB_ENDPOINT_XFER_INT,
+
+		.ep_type = ep_interrupt,
+		.fifo_num = 3,
+	},
+};
+
+/*
+ *	probe - binds to the platform device
+ */
+
+int s3c_udc_probe(struct s3c_plat_otg_data *pdata)
+{
+	struct s3c_udc *dev = &memory;
+	int retval = 0, i;
+
+	DEBUG("%s: %p\n", __func__, pdata);
+
+	dev->pdata = pdata;
+
+	phy = (struct s3c_usbotg_phy *)pdata->regs_phy;
+	reg = (struct s3c_usbotg_reg *)pdata->regs_otg;
+	usb_phy_ctrl = pdata->usb_phy_ctrl;
+
+	/* regs_otg = (void *)pdata->regs_otg; */
+
+	dev->gadget.is_dualspeed = 1;	/* Hack only*/
+	dev->gadget.is_otg = 0;
+	dev->gadget.is_a_peripheral = 0;
+	dev->gadget.b_hnp_enable = 0;
+	dev->gadget.a_hnp_support = 0;
+	dev->gadget.a_alt_hnp_support = 0;
+
+	the_controller = dev;
+
+	for (i = 0; i < S3C_MAX_ENDPOINTS+1; i++) {
+		dev->dma_buf[i] = kmalloc(DMA_BUFFER_SIZE, GFP_KERNEL);
+		dev->dma_addr[i] = (dma_addr_t) dev->dma_buf[i];
+		invalidate_dcache_range((unsigned long) dev->dma_buf[i],
+					(unsigned long) (dev->dma_buf[i]
+							 + DMA_BUFFER_SIZE));
+	}
+	usb_ctrl = dev->dma_buf[0];
+	usb_ctrl_dma_addr = dev->dma_addr[0];
+
+	udc_reinit(dev);
+
+	return retval;
+}
+
+int usb_gadget_handle_interrupts()
+{
+	u32 intr_status = readl(&reg->gintsts);
+	u32 gintmsk = readl(&reg->gintmsk);
+
+	if (intr_status & gintmsk)
+		return s3c_udc_irq(1, (void *)the_controller);
+	return 0;
+}
diff --git a/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c b/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c
new file mode 100644
index 0000000000000000000000000000000000000000..255385750ebfb8724bd6993abb5d48fae9f217d4
--- /dev/null
+++ b/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c
@@ -0,0 +1,1444 @@
+/*
+ * drivers/usb/gadget/s3c_udc_otg_xfer_dma.c
+ * Samsung S3C on-chip full/high speed USB OTG 2.0 device controllers
+ *
+ * Copyright (C) 2009 for Samsung Electronics
+ *
+ * BSP Support for Samsung's UDC driver
+ * available at:
+ * git://git.kernel.org/pub/scm/linux/kernel/git/kki_ap/linux-2.6-samsung.git
+ *
+ * State machine bugfixes:
+ * Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * Ported to u-boot:
+ * Marek Szyprowski <m.szyprowski@samsung.com>
+ * Lukasz Majewski <l.majewski@samsumg.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+static u8 clear_feature_num;
+int clear_feature_flag;
+
+/* Bulk-Only Mass Storage Reset (class-specific request) */
+#define GET_MAX_LUN_REQUEST	0xFE
+#define BOT_RESET_REQUEST	0xFF
+
+static inline void s3c_udc_ep0_zlp(struct s3c_udc *dev)
+{
+	u32 ep_ctrl;
+
+	flush_dcache_range((unsigned long) usb_ctrl_dma_addr,
+			   (unsigned long) usb_ctrl_dma_addr
+			   + DMA_BUFFER_SIZE);
+
+	writel(usb_ctrl_dma_addr, &reg->in_endp[EP0_CON].diepdma);
+	writel(DIEPT_SIZ_PKT_CNT(1), &reg->in_endp[EP0_CON].dieptsiz);
+
+	ep_ctrl = readl(&reg->in_endp[EP0_CON].diepctl);
+	writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK,
+	       &reg->in_endp[EP0_CON].diepctl);
+
+	DEBUG_EP0("%s:EP0 ZLP DIEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->in_endp[EP0_CON].diepctl));
+	dev->ep0state = WAIT_FOR_IN_COMPLETE;
+}
+
+void s3c_udc_pre_setup(void)
+{
+	u32 ep_ctrl;
+
+	DEBUG_IN_EP("%s : Prepare Setup packets.\n", __func__);
+
+	invalidate_dcache_range((unsigned long) usb_ctrl_dma_addr,
+				(unsigned long) usb_ctrl_dma_addr
+				+ DMA_BUFFER_SIZE);
+
+	writel(DOEPT_SIZ_PKT_CNT(1) | sizeof(struct usb_ctrlrequest),
+	       &reg->out_endp[EP0_CON].doeptsiz);
+	writel(usb_ctrl_dma_addr, &reg->out_endp[EP0_CON].doepdma);
+
+	ep_ctrl = readl(&reg->out_endp[EP0_CON].doepctl);
+	writel(ep_ctrl|DEPCTL_EPENA, &reg->out_endp[EP0_CON].doepctl);
+
+	DEBUG_EP0("%s:EP0 ZLP DIEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->in_endp[EP0_CON].diepctl));
+	DEBUG_EP0("%s:EP0 ZLP DOEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->out_endp[EP0_CON].doepctl));
+
+}
+
+static inline void s3c_ep0_complete_out(void)
+{
+	u32 ep_ctrl;
+
+	DEBUG_EP0("%s:EP0 ZLP DIEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->in_endp[EP0_CON].diepctl));
+	DEBUG_EP0("%s:EP0 ZLP DOEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->out_endp[EP0_CON].doepctl));
+
+	DEBUG_IN_EP("%s : Prepare Complete Out packet.\n", __func__);
+
+	invalidate_dcache_range((unsigned long) usb_ctrl_dma_addr,
+				(unsigned long) usb_ctrl_dma_addr
+				+ DMA_BUFFER_SIZE);
+
+	writel(DOEPT_SIZ_PKT_CNT(1) | sizeof(struct usb_ctrlrequest),
+	       &reg->out_endp[EP0_CON].doeptsiz);
+	writel(usb_ctrl_dma_addr, &reg->out_endp[EP0_CON].doepdma);
+
+	ep_ctrl = readl(&reg->out_endp[EP0_CON].doepctl);
+	writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK,
+	       &reg->out_endp[EP0_CON].doepctl);
+
+	DEBUG_EP0("%s:EP0 ZLP DIEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->in_endp[EP0_CON].diepctl));
+	DEBUG_EP0("%s:EP0 ZLP DOEPCTL0 = 0x%x\n",
+		__func__, readl(&reg->out_endp[EP0_CON].doepctl));
+
+}
+
+
+static int setdma_rx(struct s3c_ep *ep, struct s3c_request *req)
+{
+	u32 *buf, ctrl;
+	u32 length, pktcnt;
+	u32 ep_num = ep_index(ep);
+
+	buf = req->req.buf + req->req.actual;
+
+	length = min(req->req.length - req->req.actual, (int)ep->ep.maxpacket);
+
+	ep->len = length;
+	ep->dma_buf = buf;
+
+	invalidate_dcache_range((unsigned long) ep->dev->dma_buf[ep_num],
+				(unsigned long) ep->dev->dma_buf[ep_num]
+				+ DMA_BUFFER_SIZE);
+
+	if (length == 0)
+		pktcnt = 1;
+	else
+		pktcnt = (length - 1)/(ep->ep.maxpacket) + 1;
+
+	pktcnt = 1;
+	ctrl =  readl(&reg->out_endp[ep_num].doepctl);
+
+	writel(the_controller->dma_addr[ep_index(ep)+1],
+	       &reg->out_endp[ep_num].doepdma);
+	writel(DOEPT_SIZ_PKT_CNT(pktcnt) | DOEPT_SIZ_XFER_SIZE(length),
+	       &reg->out_endp[ep_num].doeptsiz);
+	writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, &reg->out_endp[ep_num].doepctl);
+
+	DEBUG_OUT_EP("%s: EP%d RX DMA start : DOEPDMA = 0x%x,"
+		     "DOEPTSIZ = 0x%x, DOEPCTL = 0x%x\n"
+		     "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n",
+		     __func__, ep_num,
+		     readl(&reg->out_endp[ep_num].doepdma),
+		     readl(&reg->out_endp[ep_num].doeptsiz),
+		     readl(&reg->out_endp[ep_num].doepctl),
+		     buf, pktcnt, length);
+	return 0;
+
+}
+
+int setdma_tx(struct s3c_ep *ep, struct s3c_request *req)
+{
+	u32 *buf, ctrl = 0;
+	u32 length, pktcnt;
+	u32 ep_num = ep_index(ep);
+	u32 *p = the_controller->dma_buf[ep_index(ep)+1];
+
+	buf = req->req.buf + req->req.actual;
+	length = req->req.length - req->req.actual;
+
+	if (ep_num == EP0_CON)
+		length = min_t(length, (u32)ep_maxpacket(ep));
+
+	ep->len = length;
+	ep->dma_buf = buf;
+	memcpy(p, ep->dma_buf, length);
+
+	flush_dcache_range((unsigned long) p ,
+			   (unsigned long) p + DMA_BUFFER_SIZE);
+
+	if (length == 0)
+		pktcnt = 1;
+	else
+		pktcnt = (length - 1)/(ep->ep.maxpacket) + 1;
+
+	/* Flush the endpoint's Tx FIFO */
+	writel(TX_FIFO_NUMBER(ep->fifo_num), &reg->grstctl);
+	writel(TX_FIFO_NUMBER(ep->fifo_num) | TX_FIFO_FLUSH, &reg->grstctl);
+	while (readl(&reg->grstctl) & TX_FIFO_FLUSH)
+		;
+
+	writel(the_controller->dma_addr[ep_index(ep)+1],
+	       &reg->in_endp[ep_num].diepdma);
+	writel(DIEPT_SIZ_PKT_CNT(pktcnt) | DIEPT_SIZ_XFER_SIZE(length),
+	       &reg->in_endp[ep_num].dieptsiz);
+
+	ctrl = readl(&reg->in_endp[ep_num].diepctl);
+
+	/* Write the FIFO number to be used for this endpoint */
+	ctrl &= DIEPCTL_TX_FIFO_NUM_MASK;
+	ctrl |= DIEPCTL_TX_FIFO_NUM(ep->fifo_num);
+
+	/* Clear reserved (Next EP) bits */
+	ctrl = (ctrl&~(EP_MASK<<DEPCTL_NEXT_EP_BIT));
+
+	writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, &reg->in_endp[ep_num].diepctl);
+
+	DEBUG_IN_EP("%s:EP%d TX DMA start : DIEPDMA0 = 0x%x,"
+		    "DIEPTSIZ0 = 0x%x, DIEPCTL0 = 0x%x\n"
+		    "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n",
+		    __func__, ep_num,
+		    readl(&reg->in_endp[ep_num].diepdma),
+		    readl(&reg->in_endp[ep_num].dieptsiz),
+		    readl(&reg->in_endp[ep_num].diepctl),
+		    buf, pktcnt, length);
+
+	return length;
+}
+
+static void complete_rx(struct s3c_udc *dev, u8 ep_num)
+{
+	struct s3c_ep *ep = &dev->ep[ep_num];
+	struct s3c_request *req = NULL;
+	u32 ep_tsr = 0, xfer_size = 0, is_short = 0;
+	u32 *p = the_controller->dma_buf[ep_index(ep)+1];
+
+	if (list_empty(&ep->queue)) {
+		DEBUG_OUT_EP("%s: RX DMA done : NULL REQ on OUT EP-%d\n",
+					__func__, ep_num);
+		return;
+
+	}
+
+	req = list_entry(ep->queue.next, struct s3c_request, queue);
+	ep_tsr = readl(&reg->out_endp[ep_num].doeptsiz);
+
+	if (ep_num == EP0_CON)
+		xfer_size = (ep_tsr & DOEPT_SIZ_XFER_SIZE_MAX_EP0);
+	else
+		xfer_size = (ep_tsr & DOEPT_SIZ_XFER_SIZE_MAX_EP);
+
+	xfer_size = ep->len - xfer_size;
+
+	invalidate_dcache_range((unsigned long) p,
+				(unsigned long) p + DMA_BUFFER_SIZE);
+
+	memcpy(ep->dma_buf, p, ep->len);
+
+	req->req.actual += min(xfer_size, req->req.length - req->req.actual);
+	is_short = (xfer_size < ep->ep.maxpacket);
+
+	DEBUG_OUT_EP("%s: RX DMA done : ep = %d, rx bytes = %d/%d, "
+		     "is_short = %d, DOEPTSIZ = 0x%x, remained bytes = %d\n",
+			__func__, ep_num, req->req.actual, req->req.length,
+			is_short, ep_tsr, xfer_size);
+
+	if (is_short || req->req.actual == req->req.length) {
+		if (ep_num == EP0_CON && dev->ep0state == DATA_STATE_RECV) {
+			DEBUG_OUT_EP("	=> Send ZLP\n");
+			s3c_udc_ep0_zlp(dev);
+			/* packet will be completed in complete_tx() */
+			dev->ep0state = WAIT_FOR_IN_COMPLETE;
+		} else {
+			done(ep, req, 0);
+
+			if (!list_empty(&ep->queue)) {
+				req = list_entry(ep->queue.next,
+					struct s3c_request, queue);
+				DEBUG_OUT_EP("%s: Next Rx request start...\n",
+					 __func__);
+				setdma_rx(ep, req);
+			}
+		}
+	} else
+		setdma_rx(ep, req);
+}
+
+static void complete_tx(struct s3c_udc *dev, u8 ep_num)
+{
+	struct s3c_ep *ep = &dev->ep[ep_num];
+	struct s3c_request *req;
+	u32 ep_tsr = 0, xfer_size = 0, is_short = 0;
+	u32 last;
+
+	if (dev->ep0state == WAIT_FOR_NULL_COMPLETE) {
+		dev->ep0state = WAIT_FOR_OUT_COMPLETE;
+		s3c_ep0_complete_out();
+		return;
+	}
+
+	if (list_empty(&ep->queue)) {
+		DEBUG_IN_EP("%s: TX DMA done : NULL REQ on IN EP-%d\n",
+					__func__, ep_num);
+		return;
+
+	}
+
+	req = list_entry(ep->queue.next, struct s3c_request, queue);
+
+	ep_tsr = readl(&reg->in_endp[ep_num].dieptsiz);
+
+	xfer_size = ep->len;
+	is_short = (xfer_size < ep->ep.maxpacket);
+	req->req.actual += min(xfer_size, req->req.length - req->req.actual);
+
+	DEBUG_IN_EP("%s: TX DMA done : ep = %d, tx bytes = %d/%d, "
+		     "is_short = %d, DIEPTSIZ = 0x%x, remained bytes = %d\n",
+			__func__, ep_num, req->req.actual, req->req.length,
+			is_short, ep_tsr, xfer_size);
+
+	if (ep_num == 0) {
+		if (dev->ep0state == DATA_STATE_XMIT) {
+			DEBUG_IN_EP("%s: ep_num = %d, ep0stat =="
+				    "DATA_STATE_XMIT\n",
+				    __func__, ep_num);
+			last = write_fifo_ep0(ep, req);
+			if (last)
+				dev->ep0state = WAIT_FOR_COMPLETE;
+		} else if (dev->ep0state == WAIT_FOR_IN_COMPLETE) {
+			DEBUG_IN_EP("%s: ep_num = %d, completing request\n",
+				    __func__, ep_num);
+			done(ep, req, 0);
+			dev->ep0state = WAIT_FOR_SETUP;
+		} else if (dev->ep0state == WAIT_FOR_COMPLETE) {
+			DEBUG_IN_EP("%s: ep_num = %d, completing request\n",
+				    __func__, ep_num);
+			done(ep, req, 0);
+			dev->ep0state = WAIT_FOR_OUT_COMPLETE;
+			s3c_ep0_complete_out();
+		} else {
+			DEBUG_IN_EP("%s: ep_num = %d, invalid ep state\n",
+				    __func__, ep_num);
+		}
+		return;
+	}
+
+	if (req->req.actual == req->req.length)
+		done(ep, req, 0);
+
+	if (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct s3c_request, queue);
+		DEBUG_IN_EP("%s: Next Tx request start...\n", __func__);
+		setdma_tx(ep, req);
+	}
+}
+
+static inline void s3c_udc_check_tx_queue(struct s3c_udc *dev, u8 ep_num)
+{
+	struct s3c_ep *ep = &dev->ep[ep_num];
+	struct s3c_request *req;
+
+	DEBUG_IN_EP("%s: Check queue, ep_num = %d\n", __func__, ep_num);
+
+	if (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct s3c_request, queue);
+		DEBUG_IN_EP("%s: Next Tx request(0x%p) start...\n",
+			    __func__, req);
+
+		if (ep_is_in(ep))
+			setdma_tx(ep, req);
+		else
+			setdma_rx(ep, req);
+	} else {
+		DEBUG_IN_EP("%s: NULL REQ on IN EP-%d\n", __func__, ep_num);
+
+		return;
+	}
+
+}
+
+static void process_ep_in_intr(struct s3c_udc *dev)
+{
+	u32 ep_intr, ep_intr_status;
+	u8 ep_num = 0;
+
+	ep_intr = readl(&reg->daint);
+	DEBUG_IN_EP("*** %s: EP In interrupt : DAINT = 0x%x\n",
+				__func__, ep_intr);
+
+	ep_intr &= DAINT_MASK;
+
+	while (ep_intr) {
+		if (ep_intr & DAINT_IN_EP_INT(1)) {
+			ep_intr_status = readl(&reg->in_endp[ep_num].diepint);
+			DEBUG_IN_EP("\tEP%d-IN : DIEPINT = 0x%x\n",
+						ep_num, ep_intr_status);
+
+			/* Interrupt Clear */
+			writel(ep_intr_status, &reg->in_endp[ep_num].diepint);
+
+			if (ep_intr_status & TRANSFER_DONE) {
+				complete_tx(dev, ep_num);
+
+				if (ep_num == 0) {
+					if (dev->ep0state ==
+					    WAIT_FOR_IN_COMPLETE)
+						dev->ep0state = WAIT_FOR_SETUP;
+
+					if (dev->ep0state == WAIT_FOR_SETUP)
+						s3c_udc_pre_setup();
+
+					/* continue transfer after
+					   set_clear_halt for DMA mode */
+					if (clear_feature_flag == 1) {
+						s3c_udc_check_tx_queue(dev,
+							clear_feature_num);
+						clear_feature_flag = 0;
+					}
+				}
+			}
+		}
+		ep_num++;
+		ep_intr >>= 1;
+	}
+}
+
+static void process_ep_out_intr(struct s3c_udc *dev)
+{
+	u32 ep_intr, ep_intr_status;
+	u8 ep_num = 0;
+
+	ep_intr = readl(&reg->daint);
+	DEBUG_OUT_EP("*** %s: EP OUT interrupt : DAINT = 0x%x\n",
+				__func__, ep_intr);
+
+	ep_intr = (ep_intr >> DAINT_OUT_BIT) & DAINT_MASK;
+
+	while (ep_intr) {
+		if (ep_intr & 0x1) {
+			ep_intr_status = readl(&reg->out_endp[ep_num].doepint);
+			DEBUG_OUT_EP("\tEP%d-OUT : DOEPINT = 0x%x\n",
+						ep_num, ep_intr_status);
+
+			/* Interrupt Clear */
+			writel(ep_intr_status, &reg->out_endp[ep_num].doepint);
+
+			if (ep_num == 0) {
+				if (ep_intr_status & TRANSFER_DONE) {
+					if (dev->ep0state !=
+					    WAIT_FOR_OUT_COMPLETE)
+						complete_rx(dev, ep_num);
+					else {
+						dev->ep0state = WAIT_FOR_SETUP;
+						s3c_udc_pre_setup();
+					}
+				}
+
+				if (ep_intr_status &
+				    CTRL_OUT_EP_SETUP_PHASE_DONE) {
+					DEBUG_OUT_EP("SETUP packet arrived\n");
+					s3c_handle_ep0(dev);
+				}
+			} else {
+				if (ep_intr_status & TRANSFER_DONE)
+					complete_rx(dev, ep_num);
+			}
+		}
+		ep_num++;
+		ep_intr >>= 1;
+	}
+}
+
+/*
+ *	usb client interrupt handler.
+ */
+static int s3c_udc_irq(int irq, void *_dev)
+{
+	struct s3c_udc *dev = _dev;
+	u32 intr_status;
+	u32 usb_status, gintmsk;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	intr_status = readl(&reg->gintsts);
+	gintmsk = readl(&reg->gintmsk);
+
+	DEBUG_ISR("\n*** %s : GINTSTS=0x%x(on state %s), GINTMSK : 0x%x,"
+		  "DAINT : 0x%x, DAINTMSK : 0x%x\n",
+		  __func__, intr_status, state_names[dev->ep0state], gintmsk,
+		  readl(&reg->daint), readl(&reg->daintmsk));
+
+	if (!intr_status) {
+		spin_unlock_irqrestore(&dev->lock, flags);
+		return IRQ_HANDLED;
+	}
+
+	if (intr_status & INT_ENUMDONE) {
+		DEBUG_ISR("\tSpeed Detection interrupt\n");
+
+		writel(INT_ENUMDONE, &reg->gintsts);
+		usb_status = (readl(&reg->dsts) & 0x6);
+
+		if (usb_status & (USB_FULL_30_60MHZ | USB_FULL_48MHZ)) {
+			DEBUG_ISR("\t\tFull Speed Detection\n");
+			set_max_pktsize(dev, USB_SPEED_FULL);
+
+		} else {
+			DEBUG_ISR("\t\tHigh Speed Detection : 0x%x\n",
+				  usb_status);
+			set_max_pktsize(dev, USB_SPEED_HIGH);
+		}
+	}
+
+	if (intr_status & INT_EARLY_SUSPEND) {
+		DEBUG_ISR("\tEarly suspend interrupt\n");
+		writel(INT_EARLY_SUSPEND, &reg->gintsts);
+	}
+
+	if (intr_status & INT_SUSPEND) {
+		usb_status = readl(&reg->dsts);
+		DEBUG_ISR("\tSuspend interrupt :(DSTS):0x%x\n", usb_status);
+		writel(INT_SUSPEND, &reg->gintsts);
+
+		if (dev->gadget.speed != USB_SPEED_UNKNOWN
+		    && dev->driver) {
+			if (dev->driver->suspend)
+				dev->driver->suspend(&dev->gadget);
+
+			/* HACK to let gadget detect disconnected state */
+			if (dev->driver->disconnect) {
+				spin_unlock_irqrestore(&dev->lock, flags);
+				dev->driver->disconnect(&dev->gadget);
+				spin_lock_irqsave(&dev->lock, flags);
+			}
+		}
+	}
+
+	if (intr_status & INT_RESUME) {
+		DEBUG_ISR("\tResume interrupt\n");
+		writel(INT_RESUME, &reg->gintsts);
+
+		if (dev->gadget.speed != USB_SPEED_UNKNOWN
+		    && dev->driver
+		    && dev->driver->resume) {
+
+			dev->driver->resume(&dev->gadget);
+		}
+	}
+
+	if (intr_status & INT_RESET) {
+		usb_status = readl(&reg->gotgctl);
+		DEBUG_ISR("\tReset interrupt - (GOTGCTL):0x%x\n", usb_status);
+		writel(INT_RESET, &reg->gintsts);
+
+		if ((usb_status & 0xc0000) == (0x3 << 18)) {
+			if (reset_available) {
+				DEBUG_ISR("\t\tOTG core got reset (%d)!!\n",
+					  reset_available);
+				reconfig_usbd();
+				dev->ep0state = WAIT_FOR_SETUP;
+				reset_available = 0;
+				s3c_udc_pre_setup();
+			} else
+				reset_available = 1;
+
+		} else {
+			reset_available = 1;
+			DEBUG_ISR("\t\tRESET handling skipped\n");
+		}
+	}
+
+	if (intr_status & INT_IN_EP)
+		process_ep_in_intr(dev);
+
+	if (intr_status & INT_OUT_EP)
+		process_ep_out_intr(dev);
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+/** Queue one request
+ *  Kickstart transfer if needed
+ */
+static int s3c_queue(struct usb_ep *_ep, struct usb_request *_req,
+			 gfp_t gfp_flags)
+{
+	struct s3c_request *req;
+	struct s3c_ep *ep;
+	struct s3c_udc *dev;
+	unsigned long flags;
+	u32 ep_num, gintsts;
+
+	req = container_of(_req, struct s3c_request, req);
+	if (unlikely(!_req || !_req->complete || !_req->buf
+		     || !list_empty(&req->queue))) {
+
+		DEBUG("%s: bad params\n", __func__);
+		return -EINVAL;
+	}
+
+	ep = container_of(_ep, struct s3c_ep, ep);
+
+	if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+
+		DEBUG("%s: bad ep: %s, %d, %x\n", __func__,
+		      ep->ep.name, !ep->desc, _ep);
+		return -EINVAL;
+	}
+
+	ep_num = ep_index(ep);
+	dev = ep->dev;
+	if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+
+		DEBUG("%s: bogus device state %p\n", __func__, dev->driver);
+		return -ESHUTDOWN;
+	}
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	/* kickstart this i/o queue? */
+	DEBUG("\n*** %s: %s-%s req = %p, len = %d, buf = %p"
+		"Q empty = %d, stopped = %d\n",
+		__func__, _ep->name, ep_is_in(ep) ? "in" : "out",
+		_req, _req->length, _req->buf,
+		list_empty(&ep->queue), ep->stopped);
+
+#ifdef DEBUG_S3C_UDC
+	{
+		int i, len = _req->length;
+
+		printf("pkt = ");
+		if (len > 64)
+			len = 64;
+		for (i = 0; i < len; i++) {
+			printf("%02x", ((u8 *)_req->buf)[i]);
+			if ((i & 7) == 7)
+				printf(" ");
+		}
+		printf("\n");
+	}
+#endif
+
+	if (list_empty(&ep->queue) && !ep->stopped) {
+
+		if (ep_num == 0) {
+			/* EP0 */
+			list_add_tail(&req->queue, &ep->queue);
+			s3c_ep0_kick(dev, ep);
+			req = 0;
+
+		} else if (ep_is_in(ep)) {
+			gintsts = readl(&reg->gintsts);
+			DEBUG_IN_EP("%s: ep_is_in, S3C_UDC_OTG_GINTSTS=0x%x\n",
+						__func__, gintsts);
+
+			setdma_tx(ep, req);
+		} else {
+			gintsts = readl(&reg->gintsts);
+			DEBUG_OUT_EP("%s:ep_is_out, S3C_UDC_OTG_GINTSTS=0x%x\n",
+				__func__, gintsts);
+
+			setdma_rx(ep, req);
+		}
+	}
+
+	/* pio or dma irq handler advances the queue. */
+	if (likely(req != 0))
+		list_add_tail(&req->queue, &ep->queue);
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return 0;
+}
+
+/****************************************************************/
+/* End Point 0 related functions                                */
+/****************************************************************/
+
+/* return:  0 = still running, 1 = completed, negative = errno */
+static int write_fifo_ep0(struct s3c_ep *ep, struct s3c_request *req)
+{
+	u32 max;
+	unsigned count;
+	int is_last;
+
+	max = ep_maxpacket(ep);
+
+	DEBUG_EP0("%s: max = %d\n", __func__, max);
+
+	count = setdma_tx(ep, req);
+
+	/* last packet is usually short (or a zlp) */
+	if (likely(count != max))
+		is_last = 1;
+	else {
+		if (likely(req->req.length != req->req.actual + count)
+		    || req->req.zero)
+			is_last = 0;
+		else
+			is_last = 1;
+	}
+
+	DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __func__,
+		  ep->ep.name, count,
+		  is_last ? "/L" : "",
+		  req->req.length - req->req.actual - count, req);
+
+	/* requests complete when all IN data is in the FIFO */
+	if (is_last) {
+		ep->dev->ep0state = WAIT_FOR_SETUP;
+		return 1;
+	}
+
+	return 0;
+}
+
+int s3c_fifo_read(struct s3c_ep *ep, u32 *cp, int max)
+{
+	u32 bytes;
+
+	bytes = sizeof(struct usb_ctrlrequest);
+
+	invalidate_dcache_range((unsigned long) ep->dev->dma_buf[ep_index(ep)],
+				(unsigned long) ep->dev->dma_buf[ep_index(ep)]
+				+ DMA_BUFFER_SIZE);
+
+	DEBUG_EP0("%s: bytes=%d, ep_index=%d %p\n", __func__,
+		  bytes, ep_index(ep), ep->dev->dma_buf[ep_index(ep)]);
+
+	return bytes;
+}
+
+/**
+ * udc_set_address - set the USB address for this device
+ * @address:
+ *
+ * Called from control endpoint function
+ * after it decodes a set address setup packet.
+ */
+static void udc_set_address(struct s3c_udc *dev, unsigned char address)
+{
+	u32 ctrl = readl(&reg->dcfg);
+	writel(DEVICE_ADDRESS(address) | ctrl, &reg->dcfg);
+
+	s3c_udc_ep0_zlp(dev);
+
+	DEBUG_EP0("%s: USB OTG 2.0 Device address=%d, DCFG=0x%x\n",
+		__func__, address, readl(&reg->dcfg));
+
+	dev->usb_address = address;
+}
+
+static inline void s3c_udc_ep0_set_stall(struct s3c_ep *ep)
+{
+	struct s3c_udc *dev;
+	u32		ep_ctrl = 0;
+
+	dev = ep->dev;
+	ep_ctrl = readl(&reg->in_endp[EP0_CON].diepctl);
+
+	/* set the disable and stall bits */
+	if (ep_ctrl & DEPCTL_EPENA)
+		ep_ctrl |= DEPCTL_EPDIS;
+
+	ep_ctrl |= DEPCTL_STALL;
+
+	writel(ep_ctrl, &reg->in_endp[EP0_CON].diepctl);
+
+	DEBUG_EP0("%s: set ep%d stall, DIEPCTL0 = 0x%x\n",
+		__func__, ep_index(ep), &reg->in_endp[EP0_CON].diepctl);
+	/*
+	 * The application can only set this bit, and the core clears it,
+	 * when a SETUP token is received for this endpoint
+	 */
+	dev->ep0state = WAIT_FOR_SETUP;
+
+	s3c_udc_pre_setup();
+}
+
+static void s3c_ep0_read(struct s3c_udc *dev)
+{
+	struct s3c_request *req;
+	struct s3c_ep *ep = &dev->ep[0];
+	int ret;
+
+	if (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct s3c_request, queue);
+
+	} else {
+		DEBUG("%s: ---> BUG\n", __func__);
+		BUG();
+		return;
+	}
+
+	DEBUG_EP0("%s: req = %p, req.length = 0x%x, req.actual = 0x%x\n",
+		__func__, req, req->req.length, req->req.actual);
+
+	if (req->req.length == 0) {
+		/* zlp for Set_configuration, Set_interface,
+		 * or Bulk-Only mass storge reset */
+
+		ep->len = 0;
+		s3c_udc_ep0_zlp(dev);
+
+		DEBUG_EP0("%s: req.length = 0, bRequest = %d\n",
+			  __func__, usb_ctrl->bRequest);
+		return;
+	}
+
+	ret = setdma_rx(ep, req);
+}
+
+/*
+ * DATA_STATE_XMIT
+ */
+static int s3c_ep0_write(struct s3c_udc *dev)
+{
+	struct s3c_request *req;
+	struct s3c_ep *ep = &dev->ep[0];
+	int ret, need_zlp = 0;
+
+	if (list_empty(&ep->queue))
+		req = 0;
+	else
+		req = list_entry(ep->queue.next, struct s3c_request, queue);
+
+	if (!req) {
+		DEBUG_EP0("%s: NULL REQ\n", __func__);
+		return 0;
+	}
+
+	DEBUG_EP0("%s: req = %p, req.length = 0x%x, req.actual = 0x%x\n",
+		__func__, req, req->req.length, req->req.actual);
+
+	if (req->req.length - req->req.actual == ep0_fifo_size) {
+		/* Next write will end with the packet size, */
+		/* so we need Zero-length-packet */
+		need_zlp = 1;
+	}
+
+	ret = write_fifo_ep0(ep, req);
+
+	if ((ret == 1) && !need_zlp) {
+		/* Last packet */
+		dev->ep0state = WAIT_FOR_COMPLETE;
+		DEBUG_EP0("%s: finished, waiting for status\n", __func__);
+
+	} else {
+		dev->ep0state = DATA_STATE_XMIT;
+		DEBUG_EP0("%s: not finished\n", __func__);
+	}
+
+	return 1;
+}
+
+u16	g_status;
+
+int s3c_udc_get_status(struct s3c_udc *dev,
+		struct usb_ctrlrequest *crq)
+{
+	u8 ep_num = crq->wIndex & 0x7F;
+	u32 ep_ctrl;
+	u32 *p = the_controller->dma_buf[1];
+
+	DEBUG_SETUP("%s: *** USB_REQ_GET_STATUS\n", __func__);
+	printf("crq->brequest:0x%x\n", crq->bRequestType & USB_RECIP_MASK);
+	switch (crq->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_INTERFACE:
+		g_status = 0;
+		DEBUG_SETUP("\tGET_STATUS:USB_RECIP_INTERFACE, g_stauts = %d\n",
+			    g_status);
+		break;
+
+	case USB_RECIP_DEVICE:
+		g_status = 0x1; /* Self powered */
+		DEBUG_SETUP("\tGET_STATUS: USB_RECIP_DEVICE, g_stauts = %d\n",
+			    g_status);
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		if (crq->wLength > 2) {
+			DEBUG_SETUP("\tGET_STATUS:Not support EP or wLength\n");
+			return 1;
+		}
+
+		g_status = dev->ep[ep_num].stopped;
+		DEBUG_SETUP("\tGET_STATUS: USB_RECIP_ENDPOINT, g_stauts = %d\n",
+			    g_status);
+
+		break;
+
+	default:
+		return 1;
+	}
+
+	memcpy(p, &g_status, sizeof(g_status));
+
+	flush_dcache_range((unsigned long) p,
+			   (unsigned long) p + DMA_BUFFER_SIZE);
+
+	writel(the_controller->dma_addr[1], &reg->in_endp[EP0_CON].diepdma);
+	writel(DIEPT_SIZ_PKT_CNT(1) | DIEPT_SIZ_XFER_SIZE(2),
+	       &reg->in_endp[EP0_CON].dieptsiz);
+
+	ep_ctrl = readl(&reg->in_endp[EP0_CON].diepctl);
+	writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK,
+	       &reg->in_endp[EP0_CON].diepctl);
+	dev->ep0state = WAIT_FOR_NULL_COMPLETE;
+
+	return 0;
+}
+
+static void s3c_udc_set_nak(struct s3c_ep *ep)
+{
+	u8		ep_num;
+	u32		ep_ctrl = 0;
+
+	ep_num = ep_index(ep);
+	DEBUG("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type);
+
+	if (ep_is_in(ep)) {
+		ep_ctrl = readl(&reg->in_endp[ep_num].diepctl);
+		ep_ctrl |= DEPCTL_SNAK;
+		writel(ep_ctrl, &reg->in_endp[ep_num].diepctl);
+		DEBUG("%s: set NAK, DIEPCTL%d = 0x%x\n",
+			__func__, ep_num, readl(&reg->in_endp[ep_num].diepctl));
+	} else {
+		ep_ctrl = readl(&reg->out_endp[ep_num].doepctl);
+		ep_ctrl |= DEPCTL_SNAK;
+		writel(ep_ctrl, &reg->out_endp[ep_num].doepctl);
+		DEBUG("%s: set NAK, DOEPCTL%d = 0x%x\n",
+		      __func__, ep_num, readl(&reg->out_endp[ep_num].doepctl));
+	}
+
+	return;
+}
+
+
+void s3c_udc_ep_set_stall(struct s3c_ep *ep)
+{
+	u8		ep_num;
+	u32		ep_ctrl = 0;
+
+	ep_num = ep_index(ep);
+	DEBUG("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type);
+
+	if (ep_is_in(ep)) {
+		ep_ctrl = readl(&reg->in_endp[ep_num].diepctl);
+
+		/* set the disable and stall bits */
+		if (ep_ctrl & DEPCTL_EPENA)
+			ep_ctrl |= DEPCTL_EPDIS;
+
+		ep_ctrl |= DEPCTL_STALL;
+
+		writel(ep_ctrl, &reg->in_endp[ep_num].diepctl);
+		DEBUG("%s: set stall, DIEPCTL%d = 0x%x\n",
+		      __func__, ep_num, readl(&reg->in_endp[ep_num].diepctl));
+
+	} else {
+		ep_ctrl = readl(&reg->out_endp[ep_num].doepctl);
+
+		/* set the stall bit */
+		ep_ctrl |= DEPCTL_STALL;
+
+		writel(ep_ctrl, &reg->out_endp[ep_num].doepctl);
+		DEBUG("%s: set stall, DOEPCTL%d = 0x%x\n",
+		      __func__, ep_num, readl(&reg->out_endp[ep_num].doepctl));
+	}
+
+	return;
+}
+
+void s3c_udc_ep_clear_stall(struct s3c_ep *ep)
+{
+	u8		ep_num;
+	u32		ep_ctrl = 0;
+
+	ep_num = ep_index(ep);
+	DEBUG("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type);
+
+	if (ep_is_in(ep)) {
+		ep_ctrl = readl(&reg->in_endp[ep_num].diepctl);
+
+		/* clear stall bit */
+		ep_ctrl &= ~DEPCTL_STALL;
+
+		/*
+		 * USB Spec 9.4.5: For endpoints using data toggle, regardless
+		 * of whether an endpoint has the Halt feature set, a
+		 * ClearFeature(ENDPOINT_HALT) request always results in the
+		 * data toggle being reinitialized to DATA0.
+		 */
+		if (ep->bmAttributes == USB_ENDPOINT_XFER_INT
+		    || ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
+			ep_ctrl |= DEPCTL_SETD0PID; /* DATA0 */
+		}
+
+		writel(ep_ctrl, &reg->in_endp[ep_num].diepctl);
+		DEBUG("%s: cleared stall, DIEPCTL%d = 0x%x\n",
+			__func__, ep_num, readl(&reg->in_endp[ep_num].diepctl));
+
+	} else {
+		ep_ctrl = readl(&reg->out_endp[ep_num].doepctl);
+
+		/* clear stall bit */
+		ep_ctrl &= ~DEPCTL_STALL;
+
+		if (ep->bmAttributes == USB_ENDPOINT_XFER_INT
+		    || ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
+			ep_ctrl |= DEPCTL_SETD0PID; /* DATA0 */
+		}
+
+		writel(ep_ctrl, &reg->out_endp[ep_num].doepctl);
+		DEBUG("%s: cleared stall, DOEPCTL%d = 0x%x\n",
+		      __func__, ep_num, readl(&reg->out_endp[ep_num].doepctl));
+	}
+
+	return;
+}
+
+static int s3c_udc_set_halt(struct usb_ep *_ep, int value)
+{
+	struct s3c_ep	*ep;
+	struct s3c_udc	*dev;
+	unsigned long	flags;
+	u8		ep_num;
+
+	ep = container_of(_ep, struct s3c_ep, ep);
+	ep_num = ep_index(ep);
+
+	if (unlikely(!_ep || !ep->desc || ep_num == EP0_CON ||
+		     ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC)) {
+		DEBUG("%s: %s bad ep or descriptor\n", __func__, ep->ep.name);
+		return -EINVAL;
+	}
+
+	/* Attempt to halt IN ep will fail if any transfer requests
+	 * are still queue */
+	if (value && ep_is_in(ep) && !list_empty(&ep->queue)) {
+		DEBUG("%s: %s queue not empty, req = %p\n",
+			__func__, ep->ep.name,
+			list_entry(ep->queue.next, struct s3c_request, queue));
+
+		return -EAGAIN;
+	}
+
+	dev = ep->dev;
+	DEBUG("%s: ep_num = %d, value = %d\n", __func__, ep_num, value);
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	if (value == 0) {
+		ep->stopped = 0;
+		s3c_udc_ep_clear_stall(ep);
+	} else {
+		if (ep_num == 0)
+			dev->ep0state = WAIT_FOR_SETUP;
+
+		ep->stopped = 1;
+		s3c_udc_ep_set_stall(ep);
+	}
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return 0;
+}
+
+void s3c_udc_ep_activate(struct s3c_ep *ep)
+{
+	u8 ep_num;
+	u32 ep_ctrl = 0, daintmsk = 0;
+
+	ep_num = ep_index(ep);
+
+	/* Read DEPCTLn register */
+	if (ep_is_in(ep)) {
+		ep_ctrl = readl(&reg->in_endp[ep_num].diepctl);
+		daintmsk = 1 << ep_num;
+	} else {
+		ep_ctrl = readl(&reg->out_endp[ep_num].doepctl);
+		daintmsk = (1 << ep_num) << DAINT_OUT_BIT;
+	}
+
+	DEBUG("%s: EPCTRL%d = 0x%x, ep_is_in = %d\n",
+		__func__, ep_num, ep_ctrl, ep_is_in(ep));
+
+	/* If the EP is already active don't change the EP Control
+	 * register. */
+	if (!(ep_ctrl & DEPCTL_USBACTEP)) {
+		ep_ctrl = (ep_ctrl & ~DEPCTL_TYPE_MASK) |
+			(ep->bmAttributes << DEPCTL_TYPE_BIT);
+		ep_ctrl = (ep_ctrl & ~DEPCTL_MPS_MASK) |
+			(ep->ep.maxpacket << DEPCTL_MPS_BIT);
+		ep_ctrl |= (DEPCTL_SETD0PID | DEPCTL_USBACTEP | DEPCTL_SNAK);
+
+		if (ep_is_in(ep)) {
+			writel(ep_ctrl, &reg->in_endp[ep_num].diepctl);
+			DEBUG("%s: USB Ative EP%d, DIEPCTRL%d = 0x%x\n",
+			      __func__, ep_num, ep_num,
+			      readl(&reg->in_endp[ep_num].diepctl));
+		} else {
+			writel(ep_ctrl, &reg->out_endp[ep_num].doepctl);
+			DEBUG("%s: USB Ative EP%d, DOEPCTRL%d = 0x%x\n",
+			      __func__, ep_num, ep_num,
+			      readl(&reg->out_endp[ep_num].doepctl));
+		}
+	}
+
+	/* Unmask EP Interrtupt */
+	writel(readl(&reg->daintmsk)|daintmsk, &reg->daintmsk);
+	DEBUG("%s: DAINTMSK = 0x%x\n", __func__, readl(&reg->daintmsk));
+
+}
+
+static int s3c_udc_clear_feature(struct usb_ep *_ep)
+{
+	struct s3c_udc	*dev;
+	struct s3c_ep	*ep;
+	u8		ep_num;
+
+	ep = container_of(_ep, struct s3c_ep, ep);
+	ep_num = ep_index(ep);
+
+	dev = ep->dev;
+	DEBUG_SETUP("%s: ep_num = %d, is_in = %d, clear_feature_flag = %d\n",
+		__func__, ep_num, ep_is_in(ep), clear_feature_flag);
+
+	if (usb_ctrl->wLength != 0) {
+		DEBUG_SETUP("\tCLEAR_FEATURE: wLength is not zero.....\n");
+		return 1;
+	}
+
+	switch (usb_ctrl->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_DEVICE:
+		switch (usb_ctrl->wValue) {
+		case USB_DEVICE_REMOTE_WAKEUP:
+			DEBUG_SETUP("\tOFF:USB_DEVICE_REMOTE_WAKEUP\n");
+			break;
+
+		case USB_DEVICE_TEST_MODE:
+			DEBUG_SETUP("\tCLEAR_FEATURE: USB_DEVICE_TEST_MODE\n");
+			/** @todo Add CLEAR_FEATURE for TEST modes. */
+			break;
+		}
+
+		s3c_udc_ep0_zlp(dev);
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		DEBUG_SETUP("\tCLEAR_FEATURE:USB_RECIP_ENDPOINT, wValue = %d\n",
+				usb_ctrl->wValue);
+
+		if (usb_ctrl->wValue == USB_ENDPOINT_HALT) {
+			if (ep_num == 0) {
+				s3c_udc_ep0_set_stall(ep);
+				return 0;
+			}
+
+			s3c_udc_ep0_zlp(dev);
+
+			s3c_udc_ep_clear_stall(ep);
+			s3c_udc_ep_activate(ep);
+			ep->stopped = 0;
+
+			clear_feature_num = ep_num;
+			clear_feature_flag = 1;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static int s3c_udc_set_feature(struct usb_ep *_ep)
+{
+	struct s3c_udc	*dev;
+	struct s3c_ep	*ep;
+	u8		ep_num;
+
+	ep = container_of(_ep, struct s3c_ep, ep);
+	ep_num = ep_index(ep);
+	dev = ep->dev;
+
+	DEBUG_SETUP("%s: *** USB_REQ_SET_FEATURE , ep_num = %d\n",
+		    __func__, ep_num);
+
+	if (usb_ctrl->wLength != 0) {
+		DEBUG_SETUP("\tSET_FEATURE: wLength is not zero.....\n");
+		return 1;
+	}
+
+	switch (usb_ctrl->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_DEVICE:
+		switch (usb_ctrl->wValue) {
+		case USB_DEVICE_REMOTE_WAKEUP:
+			DEBUG_SETUP("\tSET_FEATURE:USB_DEVICE_REMOTE_WAKEUP\n");
+			break;
+		case USB_DEVICE_B_HNP_ENABLE:
+			DEBUG_SETUP("\tSET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");
+			break;
+
+		case USB_DEVICE_A_HNP_SUPPORT:
+			/* RH port supports HNP */
+			DEBUG_SETUP("\tSET_FEATURE:USB_DEVICE_A_HNP_SUPPORT\n");
+			break;
+
+		case USB_DEVICE_A_ALT_HNP_SUPPORT:
+			/* other RH port does */
+			DEBUG_SETUP("\tSET: USB_DEVICE_A_ALT_HNP_SUPPORT\n");
+			break;
+		}
+
+		s3c_udc_ep0_zlp(dev);
+		return 0;
+
+	case USB_RECIP_INTERFACE:
+		DEBUG_SETUP("\tSET_FEATURE: USB_RECIP_INTERFACE\n");
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		DEBUG_SETUP("\tSET_FEATURE: USB_RECIP_ENDPOINT\n");
+		if (usb_ctrl->wValue == USB_ENDPOINT_HALT) {
+			if (ep_num == 0) {
+				s3c_udc_ep0_set_stall(ep);
+				return 0;
+			}
+			ep->stopped = 1;
+			s3c_udc_ep_set_stall(ep);
+		}
+
+		s3c_udc_ep0_zlp(dev);
+		return 0;
+	}
+
+	return 1;
+}
+
+/*
+ * WAIT_FOR_SETUP (OUT_PKT_RDY)
+ */
+void s3c_ep0_setup(struct s3c_udc *dev)
+{
+	struct s3c_ep *ep = &dev->ep[0];
+	int i, bytes, is_in;
+	u8 ep_num;
+
+	/* Nuke all previous transfers */
+	nuke(ep, -EPROTO);
+
+	/* read control req from fifo (8 bytes) */
+	bytes = s3c_fifo_read(ep, (u32 *)usb_ctrl, 8);
+
+	DEBUG_SETUP("%s: bRequestType = 0x%x(%s), bRequest = 0x%x"
+		    "\twLength = 0x%x, wValue = 0x%x, wIndex= 0x%x\n",
+		    __func__, usb_ctrl->bRequestType,
+		    (usb_ctrl->bRequestType & USB_DIR_IN) ? "IN" : "OUT",
+		    usb_ctrl->bRequest,
+		    usb_ctrl->wLength, usb_ctrl->wValue, usb_ctrl->wIndex);
+
+#ifdef DEBUG_S3C_UDC
+	{
+		int i, len = sizeof(*usb_ctrl);
+		char *p = usb_ctrl;
+
+		printf("pkt = ");
+		for (i = 0; i < len; i++) {
+			printf("%02x", ((u8 *)p)[i]);
+			if ((i & 7) == 7)
+				printf(" ");
+		}
+		printf("\n");
+	}
+#endif
+
+	if (usb_ctrl->bRequest == GET_MAX_LUN_REQUEST &&
+	    usb_ctrl->wLength != 1) {
+		DEBUG_SETUP("\t%s:GET_MAX_LUN_REQUEST:invalid",
+			      __func__);
+		DEBUG_SETUP("wLength = %d, setup returned\n",
+			    usb_ctrl->wLength);
+
+		s3c_udc_ep0_set_stall(ep);
+		dev->ep0state = WAIT_FOR_SETUP;
+
+		return;
+	} else if (usb_ctrl->bRequest == BOT_RESET_REQUEST &&
+		 usb_ctrl->wLength != 0) {
+		/* Bulk-Only *mass storge reset of class-specific request */
+		DEBUG_SETUP("%s:BOT Rest:invalid wLength =%d, setup returned\n",
+			    __func__, usb_ctrl->wLength);
+
+		s3c_udc_ep0_set_stall(ep);
+		dev->ep0state = WAIT_FOR_SETUP;
+
+		return;
+	}
+
+	/* Set direction of EP0 */
+	if (likely(usb_ctrl->bRequestType & USB_DIR_IN)) {
+		ep->bEndpointAddress |= USB_DIR_IN;
+		is_in = 1;
+
+	} else {
+		ep->bEndpointAddress &= ~USB_DIR_IN;
+		is_in = 0;
+	}
+	/* cope with automagic for some standard requests. */
+	dev->req_std = (usb_ctrl->bRequestType & USB_TYPE_MASK)
+		== USB_TYPE_STANDARD;
+	dev->req_config = 0;
+	dev->req_pending = 1;
+
+	/* Handle some SETUP packets ourselves */
+	if (dev->req_std) {
+		switch (usb_ctrl->bRequest) {
+		case USB_REQ_SET_ADDRESS:
+		DEBUG_SETUP("%s: *** USB_REQ_SET_ADDRESS (%d)\n",
+				__func__, usb_ctrl->wValue);
+			if (usb_ctrl->bRequestType
+				!= (USB_TYPE_STANDARD | USB_RECIP_DEVICE))
+				break;
+
+			udc_set_address(dev, usb_ctrl->wValue);
+			return;
+
+		case USB_REQ_SET_CONFIGURATION:
+			DEBUG_SETUP("=====================================\n");
+			DEBUG_SETUP("%s: USB_REQ_SET_CONFIGURATION (%d)\n",
+					__func__, usb_ctrl->wValue);
+
+			if (usb_ctrl->bRequestType == USB_RECIP_DEVICE) {
+				reset_available = 1;
+				dev->req_config = 1;
+			}
+			break;
+
+		case USB_REQ_GET_DESCRIPTOR:
+			DEBUG_SETUP("%s: *** USB_REQ_GET_DESCRIPTOR\n",
+				    __func__);
+			break;
+
+		case USB_REQ_SET_INTERFACE:
+			DEBUG_SETUP("%s: *** USB_REQ_SET_INTERFACE (%d)\n",
+					__func__, usb_ctrl->wValue);
+
+			if (usb_ctrl->bRequestType == USB_RECIP_INTERFACE) {
+				reset_available = 1;
+				dev->req_config = 1;
+			}
+			break;
+
+		case USB_REQ_GET_CONFIGURATION:
+			DEBUG_SETUP("%s: *** USB_REQ_GET_CONFIGURATION\n",
+				    __func__);
+			break;
+
+		case USB_REQ_GET_STATUS:
+			if (!s3c_udc_get_status(dev, usb_ctrl))
+				return;
+
+			break;
+
+		case USB_REQ_CLEAR_FEATURE:
+			ep_num = usb_ctrl->wIndex & 0x7f;
+
+			if (!s3c_udc_clear_feature(&dev->ep[ep_num].ep))
+				return;
+
+			break;
+
+		case USB_REQ_SET_FEATURE:
+			ep_num = usb_ctrl->wIndex & 0x7f;
+
+			if (!s3c_udc_set_feature(&dev->ep[ep_num].ep))
+				return;
+
+			break;
+
+		default:
+			DEBUG_SETUP("%s: *** Default of usb_ctrl->bRequest=0x%x"
+				"happened.\n", __func__, usb_ctrl->bRequest);
+			break;
+		}
+	}
+
+
+	if (likely(dev->driver)) {
+		/* device-2-host (IN) or no data setup command,
+		 * process immediately */
+		DEBUG_SETUP("%s:usb_ctrlreq will be passed to fsg_setup()\n",
+			    __func__);
+
+		spin_unlock(&dev->lock);
+		i = dev->driver->setup(&dev->gadget, usb_ctrl);
+		spin_lock(&dev->lock);
+
+		if (i < 0) {
+			if (dev->req_config) {
+				DEBUG_SETUP("\tconfig change 0x%02x fail %d?\n",
+					(u32)usb_ctrl->bRequest, i);
+				return;
+			}
+
+			/* setup processing failed, force stall */
+			s3c_udc_ep0_set_stall(ep);
+			dev->ep0state = WAIT_FOR_SETUP;
+
+			DEBUG_SETUP("\tdev->driver->setup failed (%d),"
+				    " bRequest = %d\n",
+				i, usb_ctrl->bRequest);
+
+
+		} else if (dev->req_pending) {
+			dev->req_pending = 0;
+			DEBUG_SETUP("\tdev->req_pending...\n");
+		}
+
+		DEBUG_SETUP("\tep0state = %s\n", state_names[dev->ep0state]);
+
+	}
+}
+
+/*
+ * handle ep0 interrupt
+ */
+static void s3c_handle_ep0(struct s3c_udc *dev)
+{
+	if (dev->ep0state == WAIT_FOR_SETUP) {
+		DEBUG_OUT_EP("%s: WAIT_FOR_SETUP\n", __func__);
+		s3c_ep0_setup(dev);
+
+	} else {
+		DEBUG_OUT_EP("%s: strange state!!(state = %s)\n",
+			__func__, state_names[dev->ep0state]);
+	}
+}
+
+static void s3c_ep0_kick(struct s3c_udc *dev, struct s3c_ep *ep)
+{
+	DEBUG_EP0("%s: ep_is_in = %d\n", __func__, ep_is_in(ep));
+	if (ep_is_in(ep)) {
+		dev->ep0state = DATA_STATE_XMIT;
+		s3c_ep0_write(dev);
+
+	} else {
+		dev->ep0state = DATA_STATE_RECV;
+		s3c_ep0_read(dev);
+	}
+}
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 09abb754d46703116158862cf741ca6a85170045..77e217f34fa3712b80c74f0a3941bb72a426cb7c 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -42,6 +42,7 @@ COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
 endif
 COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
 COBJS-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o
+COBJS-$(CONFIG_USB_EHCI_MX5) += ehci-mx5.o
 COBJS-$(CONFIG_USB_EHCI_PPC4XX) += ehci-ppc4xx.o
 COBJS-$(CONFIG_USB_EHCI_IXP4XX) += ehci-ixp.o
 COBJS-$(CONFIG_USB_EHCI_KIRKWOOD) += ehci-kirkwood.o
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 2197119cf7d656c5c97fdd44b93217e2d3a21faf..3f7bc2cef6ba1c96a1563b9c295f59263d0069f9 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -26,6 +26,10 @@
 #include <asm/io.h>
 #include <malloc.h>
 #include <watchdog.h>
+#ifdef CONFIG_USB_KEYBOARD
+#include <stdio_dev.h>
+extern unsigned char new[];
+#endif
 
 #include "ehci.h"
 
@@ -48,7 +52,7 @@ static struct descriptor {
 		0x29,		/* bDescriptorType: hub descriptor */
 		2,		/* bNrPorts -- runtime modified */
 		0,		/* wHubCharacteristics */
-		0xff,		/* bPwrOn2PwrGood */
+		10,		/* bPwrOn2PwrGood */
 		0,		/* bHubCntrCurrent */
 		{},		/* Device removable */
 		{}		/* at most 7 ports! XXX */
@@ -201,6 +205,14 @@ static inline void ehci_invalidate_dcache(struct QH *qh)
 }
 #endif /* CONFIG_EHCI_DCACHE */
 
+void __ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
+{
+	mdelay(50);
+}
+
+void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
+	__attribute__((weak, alias("__ehci_powerup_fixup")));
+
 static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
 {
 	uint32_t result;
@@ -709,8 +721,8 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 				 * usb 2.0 specification say 50 ms resets on
 				 * root
 				 */
-				wait_ms(50);
-				/* terminate the reset */
+				ehci_powerup_fixup(status_reg, &reg);
+
 				ehci_writel(status_reg, reg & ~EHCI_PS_PR);
 				/*
 				 * A host controller must terminate the reset
@@ -895,5 +907,32 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 
 	debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d",
 	      dev, pipe, buffer, length, interval);
-	return -1;
+	return ehci_submit_async(dev, pipe, buffer, length, NULL);
+}
+
+#ifdef CONFIG_SYS_USB_EVENT_POLL
+/*
+ * This function polls for USB keyboard data.
+ */
+void usb_event_poll()
+{
+	struct stdio_dev *dev;
+	struct usb_device *usb_kbd_dev;
+	struct usb_interface *iface;
+	struct usb_endpoint_descriptor *ep;
+	int pipe;
+	int maxp;
+
+	/* Get the pointer to USB Keyboard device pointer */
+	dev = stdio_get_by_name("usbkbd");
+	usb_kbd_dev = (struct usb_device *)dev->priv;
+	iface = &usb_kbd_dev->config.if_desc[0];
+	ep = &iface->ep_desc[0];
+	pipe = usb_rcvintpipe(usb_kbd_dev, ep->bEndpointAddress);
+
+	/* Submit a interrupt transfer request */
+	maxp = usb_maxpacket(usb_kbd_dev, pipe);
+	usb_submit_int_msg(usb_kbd_dev, pipe, &new[0],
+			maxp > 8 ? 8 : maxp, ep->bInterval);
 }
+#endif /* CONFIG_SYS_USB_EVENT_POLL */
diff --git a/drivers/usb/host/ehci-mx5.c b/drivers/usb/host/ehci-mx5.c
new file mode 100644
index 0000000000000000000000000000000000000000..68a673e7212c135872e27b57eb16160c56e2a970
--- /dev/null
+++ b/drivers/usb/host/ehci-mx5.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ * Copyright (C) 2010 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.
+ *
+ * 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.
+ */
+
+#include <common.h>
+#include <usb.h>
+#include <errno.h>
+#include <linux/compiler.h>
+#include <usb/ehci-fsl.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/mx5x_pins.h>
+#include <asm/arch/iomux.h>
+
+#include "ehci.h"
+#include "ehci-core.h"
+
+#define MX5_USBOTHER_REGS_OFFSET 0x800
+
+
+#define MXC_OTG_OFFSET		0
+#define MXC_H1_OFFSET		0x200
+#define MXC_H2_OFFSET		0x400
+
+#define MXC_USBCTRL_OFFSET		0
+#define MXC_USB_PHY_CTR_FUNC_OFFSET	0x8
+#define MXC_USB_PHY_CTR_FUNC2_OFFSET	0xc
+#define MXC_USB_CTRL_1_OFFSET		0x10
+#define MXC_USBH2CTRL_OFFSET		0x14
+
+/* USB_CTRL */
+#define MXC_OTG_UCTRL_OWIE_BIT	(1 << 27) /* OTG wakeup intr enable */
+#define MXC_OTG_UCTRL_OPM_BIT	(1 << 24) /* OTG power mask */
+#define MXC_H1_UCTRL_H1UIE_BIT	(1 << 12) /* Host1 ULPI interrupt enable */
+#define MXC_H1_UCTRL_H1WIE_BIT	(1 << 11) /* HOST1 wakeup intr enable */
+#define MXC_H1_UCTRL_H1PM_BIT	(1 << 8) /* HOST1 power mask */
+
+/* USB_PHY_CTRL_FUNC */
+#define MXC_OTG_PHYCTRL_OC_DIS_BIT (1 << 8) /* OTG Disable Overcurrent Event */
+#define MXC_H1_OC_DIS_BIT	(1 << 5) /* UH1 Disable Overcurrent Event */
+
+/* USBH2CTRL */
+#define MXC_H2_UCTRL_H2UIE_BIT	(1 << 8)
+#define MXC_H2_UCTRL_H2WIE_BIT	(1 << 7)
+#define MXC_H2_UCTRL_H2PM_BIT	(1 << 4)
+
+/* USB_CTRL_1 */
+#define MXC_USB_CTRL_UH1_EXT_CLK_EN		(1 << 25)
+
+/* USB pin configuration */
+#define USB_PAD_CONFIG	(PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST | \
+			PAD_CTL_DRV_HIGH | PAD_CTL_100K_PU | \
+			PAD_CTL_HYS_ENABLE | PAD_CTL_PUE_PULL)
+
+#ifdef CONFIG_MX51
+/*
+ * Configure the MX51 USB H1 IOMUX
+ */
+void setup_iomux_usb_h1(void)
+{
+	mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_STP, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_CLK, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_CLK, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_DIR, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_DIR, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_NXT, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_NXT, USB_PAD_CONFIG);
+
+	mxc_request_iomux(MX51_PIN_USBH1_DATA0, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_DATA0, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_DATA1, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_DATA1, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_DATA2, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_DATA2, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_DATA3, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_DATA3, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_DATA4, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_DATA4, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_DATA5, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_DATA5, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_DATA6, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_DATA6, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_USBH1_DATA7, IOMUX_CONFIG_ALT0);
+	mxc_iomux_set_pad(MX51_PIN_USBH1_DATA7, USB_PAD_CONFIG);
+}
+
+/*
+ * Configure the MX51 USB H2 IOMUX
+ */
+void setup_iomux_usb_h2(void)
+{
+	mxc_request_iomux(MX51_PIN_EIM_A24, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A24, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_A25, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A25, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_A26, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A26, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_A27, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_A27, USB_PAD_CONFIG);
+
+	mxc_request_iomux(MX51_PIN_EIM_D16, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D16, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_D17, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D17, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_D18, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D18, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_D19, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D19, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_D20, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D20, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_D21, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D21, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_D22, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D22, USB_PAD_CONFIG);
+	mxc_request_iomux(MX51_PIN_EIM_D23, IOMUX_CONFIG_ALT2);
+	mxc_iomux_set_pad(MX51_PIN_EIM_D23, USB_PAD_CONFIG);
+}
+#endif
+
+int mxc_set_usbcontrol(int port, unsigned int flags)
+{
+	unsigned int v;
+	void __iomem *usb_base = (void __iomem *)OTG_BASE_ADDR;
+	void __iomem *usbother_base;
+	int ret = 0;
+
+	usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
+
+	switch (port) {
+	case 0:	/* OTG port */
+		if (flags & MXC_EHCI_INTERNAL_PHY) {
+			v = __raw_readl(usbother_base +
+					MXC_USB_PHY_CTR_FUNC_OFFSET);
+			if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+				/* OC/USBPWR is not used */
+				v |= MXC_OTG_PHYCTRL_OC_DIS_BIT;
+			else
+				/* OC/USBPWR is used */
+				v &= ~MXC_OTG_PHYCTRL_OC_DIS_BIT;
+			__raw_writel(v, usbother_base +
+					MXC_USB_PHY_CTR_FUNC_OFFSET);
+
+			v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET);
+			if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+				v |= MXC_OTG_UCTRL_OPM_BIT;
+			else
+				v &= ~MXC_OTG_UCTRL_OPM_BIT;
+			__raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET);
+		}
+		break;
+	case 1:	/* Host 1 Host ULPI */
+#ifdef CONFIG_MX51
+		/* The clock for the USBH1 ULPI port will come externally
+		   from the PHY. */
+		v = __raw_readl(usbother_base + MXC_USB_CTRL_1_OFFSET);
+		__raw_writel(v | MXC_USB_CTRL_UH1_EXT_CLK_EN, usbother_base +
+				MXC_USB_CTRL_1_OFFSET);
+#endif
+
+		v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET);
+		if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+			v &= ~MXC_H1_UCTRL_H1PM_BIT; /* HOST1 power mask used */
+		else
+			v |= MXC_H1_UCTRL_H1PM_BIT; /* HOST1 power mask used */
+		__raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET);
+
+		v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
+		if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+			v &= ~MXC_H1_OC_DIS_BIT; /* OC is used */
+		else
+			v |= MXC_H1_OC_DIS_BIT; /* OC is not used */
+		__raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
+
+		break;
+	case 2: /* Host 2 ULPI */
+		v = __raw_readl(usbother_base + MXC_USBH2CTRL_OFFSET);
+		if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+			v &= ~MXC_H2_UCTRL_H2PM_BIT; /* HOST2 power mask used */
+		else
+			v |= MXC_H2_UCTRL_H2PM_BIT; /* HOST2 power mask used */
+
+		__raw_writel(v, usbother_base + MXC_USBH2CTRL_OFFSET);
+		break;
+	}
+
+	return ret;
+}
+
+void __board_ehci_hcd_postinit(struct usb_ehci *ehci, int port)
+{
+}
+
+void board_ehci_hcd_postinit(struct usb_ehci *ehci, int port)
+	__attribute((weak, alias("__board_ehci_hcd_postinit")));
+
+int ehci_hcd_init(void)
+{
+	struct usb_ehci *ehci;
+#ifdef CONFIG_MX53
+	struct clkctl *sc_regs = (struct clkctl *)CCM_BASE_ADDR;
+	u32 reg;
+
+	reg = __raw_readl(&sc_regs->cscmr1) & ~(1 << 26);
+	/* derive USB PHY clock multiplexer from PLL3 */
+	reg |= 1 << 26;
+	__raw_writel(reg, &sc_regs->cscmr1);
+#endif
+
+	set_usboh3_clk();
+	enable_usboh3_clk(1);
+	set_usb_phy2_clk();
+	enable_usb_phy2_clk(1);
+	mdelay(1);
+
+	/* Do board specific initialization */
+	board_ehci_hcd_init(CONFIG_MXC_USB_PORT);
+
+	ehci = (struct usb_ehci *)(OTG_BASE_ADDR +
+		(0x200 * CONFIG_MXC_USB_PORT));
+	hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
+	hcor = (struct ehci_hcor *)((uint32_t)hccr +
+			HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+	setbits_le32(&ehci->usbmode, CM_HOST);
+
+	__raw_writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc);
+	setbits_le32(&ehci->portsc, USB_EN);
+
+	mxc_set_usbcontrol(CONFIG_MXC_USB_PORT, CONFIG_MXC_USB_FLAGS);
+	mdelay(10);
+
+	/* Do board specific post-initialization */
+	board_ehci_hcd_postinit(ehci, CONFIG_MXC_USB_PORT);
+
+	return 0;
+}
+
+int ehci_hcd_stop(void)
+{
+	return 0;
+}
+
+
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 60c9595268744102e2e8a68e460986dc18d8f55a..cf906b47ca35625960b47d99d06a0aea896a4836 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1262,12 +1262,19 @@ static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
 	int len = 0;
 	int stat = 0;
 	__u32 datab[4];
-	__u8 *data_buf = (__u8 *)datab;
+	union {
+		void *ptr;
+		__u8 *u8;
+		__u16 *u16;
+		__u32 *u32;
+	} databuf;
 	__u16 bmRType_bReq;
 	__u16 wValue;
 	__u16 wIndex;
 	__u16 wLength;
 
+	databuf.u32 = (__u32 *)datab;
+
 #ifdef DEBUG
 pkt_print(NULL, dev, pipe, buffer, transfer_len,
 	  cmd, "SUB(rh)", usb_pipein(pipe));
@@ -1297,20 +1304,20 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
 	*/
 
 	case RH_GET_STATUS:
-		*(__u16 *) data_buf = cpu_to_le16(1);
+		databuf.u16[0] = cpu_to_le16(1);
 		OK(2);
 	case RH_GET_STATUS | RH_INTERFACE:
-		*(__u16 *) data_buf = cpu_to_le16(0);
+		databuf.u16[0] = cpu_to_le16(0);
 		OK(2);
 	case RH_GET_STATUS | RH_ENDPOINT:
-		*(__u16 *) data_buf = cpu_to_le16(0);
+		databuf.u16[0] = cpu_to_le16(0);
 		OK(2);
 	case RH_GET_STATUS | RH_CLASS:
-		*(__u32 *) data_buf = cpu_to_le32(
+		databuf.u32[0] = cpu_to_le32(
 				RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
 		OK(4);
 	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
-		*(__u32 *) data_buf = cpu_to_le32(RD_RH_PORTSTAT);
+		databuf.u32[0] = cpu_to_le32(RD_RH_PORTSTAT);
 		OK(4);
 
 	case RH_CLEAR_FEATURE | RH_ENDPOINT:
@@ -1374,14 +1381,14 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
 					min_t(unsigned int,
 					sizeof(root_hub_dev_des),
 					wLength));
-			data_buf = root_hub_dev_des; OK(len);
+			databuf.ptr = root_hub_dev_des; OK(len);
 		case (0x02): /* configuration descriptor */
 			len = min_t(unsigned int,
 					leni,
 					min_t(unsigned int,
 					sizeof(root_hub_config_des),
 					wLength));
-			data_buf = root_hub_config_des; OK(len);
+			databuf.ptr = root_hub_config_des; OK(len);
 		case (0x03): /* string descriptors */
 			if (wValue == 0x0300) {
 				len = min_t(unsigned int,
@@ -1389,7 +1396,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
 						min_t(unsigned int,
 						sizeof(root_hub_str_index0),
 						wLength));
-				data_buf = root_hub_str_index0;
+				databuf.ptr = root_hub_str_index0;
 				OK(len);
 			}
 			if (wValue == 0x0301) {
@@ -1398,7 +1405,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
 						min_t(unsigned int,
 						sizeof(root_hub_str_index1),
 						wLength));
-				data_buf = root_hub_str_index1;
+				databuf.ptr = root_hub_str_index1;
 				OK(len);
 		}
 		default:
@@ -1410,41 +1417,45 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
 	{
 		__u32 temp = roothub_a(&gohci);
 
-		data_buf [0] = 9;		/* min length; */
-		data_buf [1] = 0x29;
-		data_buf [2] = temp & RH_A_NDP;
+		databuf.u8[0] = 9;		/* min length; */
+		databuf.u8[1] = 0x29;
+		databuf.u8[2] = temp & RH_A_NDP;
 #ifdef CONFIG_AT91C_PQFP_UHPBUG
-		data_buf [2] = (data_buf [2] == 2) ? 1:0;
+		databuf.u8[2] = (databuf.u8[2] == 2) ? 1 : 0;
 #endif
-		data_buf [3] = 0;
+		databuf.u8[3] = 0;
 		if (temp & RH_A_PSM)	/* per-port power switching? */
-			data_buf [3] |= 0x1;
+			databuf.u8[3] |= 0x1;
 		if (temp & RH_A_NOCP)	/* no overcurrent reporting? */
-			data_buf [3] |= 0x10;
+			databuf.u8[3] |= 0x10;
 		else if (temp & RH_A_OCPM)/* per-port overcurrent reporting? */
-			data_buf [3] |= 0x8;
+			databuf.u8[3] |= 0x8;
 
-		/* corresponds to data_buf[4-7] */
-		datab [1] = 0;
-		data_buf [5] = (temp & RH_A_POTPGT) >> 24;
+		/* corresponds to databuf.u8[4-7] */
+		databuf.u8[1] = 0;
+		databuf.u8[5] = (temp & RH_A_POTPGT) >> 24;
 		temp = roothub_b(&gohci);
-		data_buf [7] = temp & RH_B_DR;
-		if (data_buf [2] < 7) {
-			data_buf [8] = 0xff;
+		databuf.u8[7] = temp & RH_B_DR;
+		if (databuf.u8[2] < 7) {
+			databuf.u8[8] = 0xff;
 		} else {
-			data_buf [0] += 2;
-			data_buf [8] = (temp & RH_B_DR) >> 8;
-			data_buf [10] = data_buf [9] = 0xff;
+			databuf.u8[0] += 2;
+			databuf.u8[8] = (temp & RH_B_DR) >> 8;
+			databuf.u8[10] = databuf.u8[9] = 0xff;
 		}
 
 		len = min_t(unsigned int, leni,
-			    min_t(unsigned int, data_buf [0], wLength));
+			    min_t(unsigned int, databuf.u8[0], wLength));
 		OK(len);
 	}
 
-	case RH_GET_CONFIGURATION:	*(__u8 *) data_buf = 0x01; OK(1);
+	case RH_GET_CONFIGURATION:
+		databuf.u8[0] = 0x01;
+		OK(1);
 
-	case RH_SET_CONFIGURATION:	WR_RH_STAT(0x10000); OK(0);
+	case RH_SET_CONFIGURATION:
+		WR_RH_STAT(0x10000);
+		OK(0);
 
 	default:
 		dbg("unsupported root hub command");
@@ -1458,8 +1469,8 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
 #endif
 
 	len = min_t(int, len, leni);
-	if (data != data_buf)
-	    memcpy(data, data_buf, len);
+	if (data != databuf.ptr)
+		memcpy(data, databuf.ptr, len);
 	dev->act_len = len;
 	dev->status = stat;
 
diff --git a/drivers/usb/ulpi/Makefile b/drivers/usb/ulpi/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..d43b2293e1f0badb0db008a25017b53df253b823
--- /dev/null
+++ b/drivers/usb/ulpi/Makefile
@@ -0,0 +1,44 @@
+#
+# Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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.
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	:= $(obj)libusb_ulpi.o
+
+COBJS-$(CONFIG_USB_ULPI)		+= ulpi.o
+COBJS-$(CONFIG_USB_ULPI_VIEWPORT)	+= ulpi-viewport.o
+
+COBJS	:= $(COBJS-y)
+SRCS	:= $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+
+all:	$(LIB)
+
+$(LIB):	$(obj).depend $(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/drivers/usb/ulpi/ulpi-viewport.c b/drivers/usb/ulpi/ulpi-viewport.c
new file mode 100644
index 0000000000000000000000000000000000000000..fa2e004a6c912e864dc27e592be5218e15632899
--- /dev/null
+++ b/drivers/usb/ulpi/ulpi-viewport.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
+ * Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il>
+ *
+ * Authors: Jana Rapava <fermata7@gmail.com>
+ *	    Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * Based on:
+ * linux/drivers/usb/otg/ulpi_viewport.c
+ *
+ * Original Copyright follow:
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <usb/ulpi.h>
+
+/* ULPI viewport control bits */
+#define ULPI_SS		(1 << 27)
+#define ULPI_RWCTRL	(1 << 29)
+#define ULPI_RWRUN	(1 << 30)
+#define ULPI_WU		(1 << 31)
+
+/*
+ * Wait for the ULPI request to complete
+ *
+ * @ulpi_viewport	- the address of the viewport
+ * @mask		- expected value to wait for
+ *
+ * returns 0 on mask match, ULPI_ERROR on time out.
+ */
+static int ulpi_wait(u32 ulpi_viewport, u32 mask)
+{
+	int timeout = CONFIG_USB_ULPI_TIMEOUT;
+
+	/* Wait for the bits in mask to become zero. */
+	while (--timeout) {
+		if ((readl(ulpi_viewport) & mask) == 0)
+			return 0;
+
+		udelay(1);
+	}
+
+	return ULPI_ERROR;
+}
+
+/*
+ * Wake the ULPI PHY up for communication
+ *
+ * returns 0 on success.
+ */
+static int ulpi_wakeup(u32 ulpi_viewport)
+{
+	int err;
+
+	if (readl(ulpi_viewport) & ULPI_SS)
+		return 0; /* already awake */
+
+	writel(ULPI_WU, ulpi_viewport);
+
+	err = ulpi_wait(ulpi_viewport, ULPI_WU);
+	if (err)
+		printf("ULPI wakeup timed out\n");
+
+	return err;
+}
+
+/*
+ * Issue a ULPI read/write request
+ *
+ * @value - the ULPI request
+ */
+static int ulpi_request(u32 ulpi_viewport, u32 value)
+{
+	int err;
+
+	err = ulpi_wakeup(ulpi_viewport);
+	if (err)
+		return err;
+
+	writel(value, ulpi_viewport);
+
+	err = ulpi_wait(ulpi_viewport, ULPI_RWRUN);
+	if (err)
+		printf("ULPI request timed out\n");
+
+	return err;
+}
+
+u32 ulpi_write(u32 ulpi_viewport, u8 *reg, u32 value)
+{
+	u32 val = ULPI_RWRUN | ULPI_RWCTRL | ((u32)reg << 16) | (value & 0xff);
+
+	return ulpi_request(ulpi_viewport, val);
+}
+
+u32 ulpi_read(u32 ulpi_viewport, u8 *reg)
+{
+	u32 err;
+	u32 val = ULPI_RWRUN | ((u32)reg << 16);
+
+	err = ulpi_request(ulpi_viewport, val);
+	if (err)
+		return err;
+
+	return (readl(ulpi_viewport) >> 8) & 0xff;
+}
diff --git a/drivers/usb/ulpi/ulpi.c b/drivers/usb/ulpi/ulpi.c
new file mode 100644
index 0000000000000000000000000000000000000000..805e29d76c4d945d8668e76936f98ffb02ca5a16
--- /dev/null
+++ b/drivers/usb/ulpi/ulpi.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
+ * Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il>
+ *
+ * Authors: Jana Rapava <fermata7@gmail.com>
+ *	    Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * Based on:
+ * linux/drivers/usb/otg/ulpi.c
+ * Generic ULPI USB transceiver support
+ *
+ * Original Copyright follow:
+ * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ * Based on sources from
+ *
+ *   Sascha Hauer <s.hauer@pengutronix.de>
+ *   Freescale Semiconductors
+ *
+ * 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.
+ */
+
+#include <common.h>
+#include <exports.h>
+#include <usb/ulpi.h>
+
+#define ULPI_ID_REGS_COUNT	4
+#define ULPI_TEST_VALUE		0x55	/* 0x55 == 0b01010101 */
+
+static struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
+
+static int ulpi_integrity_check(u32 ulpi_viewport)
+{
+	u32 err, val, tval = ULPI_TEST_VALUE;
+	int i;
+
+	/* Use the 'special' test value to check all bits */
+	for (i = 0; i < 2; i++, tval <<= 1) {
+		err = ulpi_write(ulpi_viewport, &ulpi->scratch, tval);
+		if (err)
+			return err;
+
+		val = ulpi_read(ulpi_viewport, &ulpi->scratch);
+		if (val != tval) {
+			printf("ULPI integrity check failed\n");
+			return val;
+		}
+	}
+
+	return 0;
+}
+
+int ulpi_init(u32 ulpi_viewport)
+{
+	u32 val, id = 0;
+	u8 *reg = &ulpi->product_id_high;
+	int i;
+
+	/* Assemble ID from four ULPI ID registers (8 bits each). */
+	for (i = 0; i < ULPI_ID_REGS_COUNT; i++) {
+		val = ulpi_read(ulpi_viewport, reg - i);
+		if (val == ULPI_ERROR)
+			return val;
+
+		id = (id << 8) | val;
+	}
+
+	/* Split ID into vendor and product ID. */
+	debug("ULPI transceiver ID 0x%04x:0x%04x\n", id >> 16, id & 0xffff);
+
+	return ulpi_integrity_check(ulpi_viewport);
+}
+
+int ulpi_select_transceiver(u32 ulpi_viewport, u8 speed)
+{
+	u8 tspeed = ULPI_FC_FULL_SPEED;
+	u32 val;
+
+	switch (speed) {
+	case ULPI_FC_HIGH_SPEED:
+	case ULPI_FC_FULL_SPEED:
+	case ULPI_FC_LOW_SPEED:
+	case ULPI_FC_FS4LS:
+		tspeed = speed;
+		break;
+	default:
+		printf("ULPI: %s: wrong transceiver speed specified, "
+			"falling back to full speed\n", __func__);
+	}
+
+	val = ulpi_read(ulpi_viewport, &ulpi->function_ctrl);
+	if (val == ULPI_ERROR)
+		return val;
+
+	/* clear the previous speed setting */
+	val = (val & ~ULPI_FC_XCVRSEL_MASK) | tspeed;
+
+	return ulpi_write(ulpi_viewport, &ulpi->function_ctrl, val);
+}
+
+int ulpi_set_vbus(u32 ulpi_viewport, int on, int ext_power, int ext_ind)
+{
+	u32 flags = ULPI_OTG_DRVVBUS;
+	u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
+
+	if (ext_power)
+		flags |= ULPI_OTG_DRVVBUS_EXT;
+	if (ext_ind)
+		flags |= ULPI_OTG_EXTVBUSIND;
+
+	return ulpi_write(ulpi_viewport, reg, flags);
+}
+
+int ulpi_set_pd(u32 ulpi_viewport, int enable)
+{
+	u32 val = ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN;
+	u8 *reg = enable ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
+
+	return ulpi_write(ulpi_viewport, reg, val);
+}
+
+int ulpi_opmode_sel(u32 ulpi_viewport, u8 opmode)
+{
+	u8 topmode = ULPI_FC_OPMODE_NORMAL;
+	u32 val;
+
+	switch (opmode) {
+	case ULPI_FC_OPMODE_NORMAL:
+	case ULPI_FC_OPMODE_NONDRIVING:
+	case ULPI_FC_OPMODE_DISABLE_NRZI:
+	case ULPI_FC_OPMODE_NOSYNC_NOEOP:
+		topmode = opmode;
+		break;
+	default:
+		printf("ULPI: %s: wrong OpMode specified, "
+			"falling back to OpMode Normal\n", __func__);
+	}
+
+	val = ulpi_read(ulpi_viewport, &ulpi->function_ctrl);
+	if (val == ULPI_ERROR)
+		return val;
+
+	/* clear the previous opmode setting */
+	val = (val & ~ULPI_FC_OPMODE_MASK) | topmode;
+
+	return ulpi_write(ulpi_viewport, &ulpi->function_ctrl, val);
+}
+
+int ulpi_serial_mode_enable(u32 ulpi_viewport, u8 smode)
+{
+	switch (smode) {
+	case ULPI_IFACE_6_PIN_SERIAL_MODE:
+	case ULPI_IFACE_3_PIN_SERIAL_MODE:
+		break;
+	default:
+		printf("ULPI: %s: unrecognized Serial Mode specified\n",
+			__func__);
+		return ULPI_ERROR;
+	}
+
+	return ulpi_write(ulpi_viewport, &ulpi->iface_ctrl_set, smode);
+}
+
+int ulpi_suspend(u32 ulpi_viewport)
+{
+	u32 err;
+
+	err = ulpi_write(ulpi_viewport, &ulpi->function_ctrl_clear,
+			ULPI_FC_SUSPENDM);
+	if (err)
+		printf("ULPI: %s: failed writing the suspend bit\n", __func__);
+
+	return err;
+}
+
+/*
+ * Wait for ULPI PHY reset to complete.
+ * Actual wait for reset must be done in a view port specific way,
+ * because it involves checking the DIR line.
+ */
+static int __ulpi_reset_wait(u32 ulpi_viewport)
+{
+	u32 val;
+	int timeout = CONFIG_USB_ULPI_TIMEOUT;
+
+	/* Wait for the RESET bit to become zero */
+	while (--timeout) {
+		/*
+		 * This function is generic and suppose to work
+		 * with any viewport, so we cheat here and don't check
+		 * for the error of ulpi_read(), if there is one, then
+		 * there will be a timeout.
+		 */
+		val = ulpi_read(ulpi_viewport, &ulpi->function_ctrl);
+		if (!(val & ULPI_FC_RESET))
+			return 0;
+
+		udelay(1);
+	}
+
+	printf("ULPI: %s: reset timed out\n", __func__);
+
+	return ULPI_ERROR;
+}
+int ulpi_reset_wait(u32) __attribute__((weak, alias("__ulpi_reset_wait")));
+
+int ulpi_reset(u32 ulpi_viewport)
+{
+	u32 err;
+
+	err = ulpi_write(ulpi_viewport,
+			&ulpi->function_ctrl_set, ULPI_FC_RESET);
+	if (err) {
+		printf("ULPI: %s: failed writing reset bit\n", __func__);
+		return err;
+	}
+
+	return ulpi_reset_wait(ulpi_viewport);
+}
diff --git a/include/configs/efikamx.h b/include/configs/efikamx.h
index 2b069d6b7a3badb74b162b7f001bde6f314c169d..522487b3955ca236c47aee9723d2e2edac124fe6 100644
--- a/include/configs/efikamx.h
+++ b/include/configs/efikamx.h
@@ -44,6 +44,10 @@
 
 #define CONFIG_SYS_TEXT_BASE		0x97800000
 
+#define	CONFIG_L2_OFF
+#define	CONFIG_SYS_ICACHE_OFF
+#define	CONFIG_SYS_DCACHE_OFF
+
 /*
  * Bootloader Components Configuration
  */
@@ -53,6 +57,8 @@
 #define CONFIG_CMD_FAT
 #define CONFIG_CMD_EXT2
 #define CONFIG_CMD_IDE
+#define CONFIG_CMD_NET
+#define CONFIG_CMD_DATE
 #undef CONFIG_CMD_IMLS
 
 /*
@@ -174,18 +180,47 @@
 #define CONFIG_MXC_ATA_PIO_MODE		4
 #endif
 
+/*
+ * USB
+ */
+#define	CONFIG_CMD_USB
+#ifdef	CONFIG_CMD_USB
+#define	CONFIG_USB_EHCI			/* Enable EHCI USB support */
+#define	CONFIG_USB_EHCI_MX5
+#define	CONFIG_USB_ULPI
+#define	CONFIG_USB_ULPI_VIEWPORT
+#define	CONFIG_MXC_USB_PORT	1
+#if	(CONFIG_MXC_USB_PORT == 0)
+#define	CONFIG_MXC_USB_PORTSC	(1 << 28)
+#define	CONFIG_MXC_USB_FLAGS	MXC_EHCI_INTERNAL_PHY
+#else
+#define	CONFIG_MXC_USB_PORTSC	(2 << 30)
+#define	CONFIG_MXC_USB_FLAGS	0
+#endif
+#define	CONFIG_EHCI_IS_TDI
+#define	CONFIG_USB_STORAGE
+#define	CONFIG_USB_HOST_ETHER
+#define	CONFIG_USB_KEYBOARD
+#define	CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP
+#define CONFIG_PREBOOT
+/* USB NET */
+#ifdef	CONFIG_CMD_NET
+#define	CONFIG_USB_ETHER_ASIX
+#define	CONFIG_NET_MULTI
+#define	CONFIG_CMD_PING
+#define	CONFIG_CMD_DHCP
+#endif
+#endif /* CONFIG_CMD_USB */
+
 /*
  * Filesystems
  */
 #ifdef CONFIG_CMD_FAT
 #define CONFIG_DOS_PARTITION
+#ifdef	CONFIG_CMD_NET
+#define	CONFIG_CMD_NFS
+#endif
 #endif
-
-#undef CONFIG_CMD_PING
-#undef CONFIG_CMD_DHCP
-#undef CONFIG_CMD_NET
-#undef CONFIG_CMD_NFS
-#define CONFIG_CMD_DATE
 
 /*
  * Miscellaneous configurable options
diff --git a/include/configs/mx51evk.h b/include/configs/mx51evk.h
index dd53f48b9aab4d077cbe1e25ccb522b632887a14..3b18a18d3e84a083dbd4221ccc51982317f4cb90 100644
--- a/include/configs/mx51evk.h
+++ b/include/configs/mx51evk.h
@@ -110,6 +110,19 @@
 #define CONFIG_CMD_MII
 #define CONFIG_CMD_NET
 
+/* USB Configs */
+#define CONFIG_CMD_USB
+#define CONFIG_CMD_FAT
+#define CONFIG_USB_EHCI
+#define CONFIG_USB_EHCI_MX5
+#define CONFIG_USB_STORAGE
+#define CONFIG_USB_HOST_ETHER
+#define CONFIG_USB_ETHER_ASIX
+#define CONFIG_USB_ETHER_SMSC95XX
+#define CONFIG_MXC_USB_PORT	1
+#define CONFIG_MXC_USB_PORTSC	PORT_PTS_ULPI
+#define CONFIG_MXC_USB_FLAGS	MXC_EHCI_POWER_PINS_ENABLED
+
 /* allow to overwrite serial and ethaddr */
 #define CONFIG_ENV_OVERWRITE
 #define CONFIG_CONS_INDEX		1
diff --git a/include/configs/mx53loco.h b/include/configs/mx53loco.h
index 537649ee164f0fec1c915177968213ededca7494..34a4edd41e921f038bc82716f9ad7b21af0c1f59 100644
--- a/include/configs/mx53loco.h
+++ b/include/configs/mx53loco.h
@@ -72,6 +72,19 @@
 #define CONFIG_CMD_MII
 #define CONFIG_CMD_NET
 
+/* USB Configs */
+#define CONFIG_CMD_USB
+#define CONFIG_CMD_FAT
+#define CONFIG_USB_EHCI
+#define CONFIG_USB_EHCI_MX5
+#define CONFIG_USB_STORAGE
+#define CONFIG_USB_HOST_ETHER
+#define CONFIG_USB_ETHER_ASIX
+#define CONFIG_USB_ETHER_SMSC95XX
+#define CONFIG_MXC_USB_PORT	1
+#define CONFIG_MXC_USB_PORTSC	(PORT_PTS_UTMI | PORT_PTS_PTW)
+#define CONFIG_MXC_USB_FLAGS	0
+
 /* allow to overwrite serial and ethaddr */
 #define CONFIG_ENV_OVERWRITE
 #define CONFIG_CONS_INDEX		1
diff --git a/include/configs/s5p_goni.h b/include/configs/s5p_goni.h
index 3434de7f779598781b996623f04d0dcb56343558..56b5547fd27d8794a19338ecc22f1edbdeb67075 100644
--- a/include/configs/s5p_goni.h
+++ b/include/configs/s5p_goni.h
@@ -237,5 +237,8 @@
 #define CONFIG_SYS_I2C_SPEED	50000
 #define CONFIG_I2C_MULTI_BUS
 #define CONFIG_SYS_MAX_I2C_BUS	7
+#define CONFIG_USB_GADGET
+#define CONFIG_USB_GADGET_S3C_UDC_OTG
+#define CONFIG_USB_GADGET_DUALSPEED
 
 #endif	/* __CONFIG_H */
diff --git a/include/usb/ehci-fsl.h b/include/usb/ehci-fsl.h
index 67600ed522817f36ced4f29f2a577b2a140d754d..28693020ece477934a03eb5caa1c63ac80dfddf4 100644
--- a/include/usb/ehci-fsl.h
+++ b/include/usb/ehci-fsl.h
@@ -186,35 +186,36 @@ struct usb_ehci {
 	u32     gptimer1_ctrl;	/* 0x08C - General Purpose Timer 1 control */
 	u32	sbuscfg;	/* 0x090 - System Bus Interface Control */
 	u8	res2[0x6C];
-	u16	caplength;	/* 0x100 - Capability Register Length */
+	u8	caplength;	/* 0x100 - Capability Register Length */
+	u8	res3[0x1];
 	u16	hciversion;	/* 0x102 - Host Interface Version */
 	u32	hcsparams;	/* 0x104 - Host Structural Parameters */
 	u32	hccparams;	/* 0x108 - Host Capability Parameters */
-	u8	res3[0x14];
+	u8	res4[0x14];
 	u32	dciversion;	/* 0x120 - Device Interface Version */
 	u32	dciparams;	/* 0x124 - Device Controller Params */
-	u8	res4[0x18];
+	u8	res5[0x18];
 	u32	usbcmd;		/* 0x140 - USB Command */
 	u32	usbsts;		/* 0x144 - USB Status */
 	u32	usbintr;	/* 0x148 - USB Interrupt Enable */
 	u32	frindex;	/* 0x14C - USB Frame Index */
-	u8	res5[0x4];
+	u8	res6[0x4];
 	u32	perlistbase;	/* 0x154 - Periodic List Base
 					 - USB Device Address */
 	u32	ep_list_addr;	/* 0x158 - Next Asynchronous List
 					 - End Point Address */
-	u8	res6[0x4];
+	u8	res7[0x4];
 	u32	burstsize;	/* 0x160 - Programmable Burst Size */
 #define FSL_EHCI_TXPBURST(X)	((X) << 8)
 #define FSL_EHCI_RXPBURST(X)	(X)
 	u32	txfilltuning;	/* 0x164 - Host TT Transmit
 					   pre-buffer packet tuning */
-	u8	res7[0x8];
+	u8	res8[0x8];
 	u32	ulpi_viewpoint;	/* 0x170 - ULPI Reister Access */
-	u8	res8[0xc];
+	u8	res9[0xc];
 	u32	config_flag;	/* 0x180 - Configured Flag Register */
 	u32	portsc;		/* 0x184 - Port status/control */
-	u8	res9[0x1C];
+	u8	res10[0x1C];
 	u32	otgsc;		/* 0x1a4 - Oo-The-Go status and control */
 	u32	usbmode;	/* 0x1a8 - USB Device Mode */
 	u32	epsetupstat;	/* 0x1ac - End Point Setup Status */
@@ -228,18 +229,34 @@ struct usb_ehci {
 	u32	epctrl3;	/* 0x1cc - End Point Control 3 */
 	u32	epctrl4;	/* 0x1d0 - End Point Control 4 */
 	u32	epctrl5;	/* 0x1d4 - End Point Control 5 */
-	u8	res10[0x28];
+	u8	res11[0x28];
 	u32	usbgenctrl;	/* 0x200 - USB General Control */
 	u32	isiphyctrl;	/* 0x204 - On-Chip PHY Control */
-	u8	res11[0x1F8];
+	u8	res12[0x1F8];
 	u32	snoop1;		/* 0x400 - Snoop 1 */
 	u32	snoop2;		/* 0x404 - Snoop 2 */
 	u32	age_cnt_limit;	/* 0x408 - Age Count Threshold */
 	u32	prictrl;	/* 0x40c - Priority Control */
 	u32	sictrl;		/* 0x410 - System Interface Control */
-	u8	res12[0xEC];
+	u8	res13[0xEC];
 	u32	control;	/* 0x500 - Control */
-	u8	res13[0xafc];
+	u8	res14[0xafc];
 };
 
+/*
+ * For MXC SOCs
+ */
+#define MXC_EHCI_POWER_PINS_ENABLED	(1 << 5)
+#define MXC_EHCI_TTL_ENABLED		(1 << 6)
+#define MXC_EHCI_INTERNAL_PHY		(1 << 7)
+
+/* Board-specific initialization */
+int board_ehci_hcd_init(int port);
+
+/* CPU-specific abstracted-out IOMUX init */
+#ifdef CONFIG_MX51
+void setup_iomux_usb_h1(void);
+void setup_iomux_usb_h2(void);
+#endif
+
 #endif /* _EHCI_FSL_H */
diff --git a/include/usb/lin_gadget_compat.h b/include/usb/lin_gadget_compat.h
new file mode 100644
index 0000000000000000000000000000000000000000..9b315118d5e94ec7489f6304c305bc53fc64491f
--- /dev/null
+++ b/include/usb/lin_gadget_compat.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics
+ * Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * This is a Linux kernel compatibility layer for USB Gadget
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __LIN_COMPAT_H__
+#define __LIN_COMPAT_H__
+
+/* common */
+#define spin_lock_init(...)
+#define spin_lock(...)
+#define spin_lock_irqsave(lock, flags) do {flags = 1; } while (0)
+#define spin_unlock(...)
+#define spin_unlock_irqrestore(lock, flags) do {flags = 0; } while (0)
+#define disable_irq(...)
+#define enable_irq(...)
+
+#define mutex_init(...)
+#define mutex_lock(...)
+#define mutex_unlock(...)
+
+#define WARN_ON(x) if (x) {printf("WARNING in %s line %d\n" \
+				  , __FILE__, __LINE__); }
+
+#define KERN_WARNING
+#define KERN_ERR
+#define KERN_NOTICE
+#define KERN_DEBUG
+
+#define GFP_KERNEL	0
+
+#define IRQ_HANDLED	1
+
+#define ENOTSUPP	524	/* Operation is not supported */
+
+#define kmalloc(size, type) memalign(CONFIG_SYS_CACHELINE_SIZE, size)
+#define kfree(addr) free(addr)
+#define mdelay(n) ({unsigned long msec = (n); while (msec--) udelay(1000); })
+
+#define __iomem
+#define min_t min
+#define dma_cache_maint(addr, size, mode) cache_flush()
+void cache_flush(void);
+
+#endif /* __LIN_COMPAT_H__ */
diff --git a/include/usb/mv_udc.h b/include/usb/mv_udc.h
new file mode 100644
index 0000000000000000000000000000000000000000..51d36c3f343ef5e99fb05c73781d443022ba5009
--- /dev/null
+++ b/include/usb/mv_udc.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2011, Marvell Semiconductor Inc.
+ * Lei Wen <leiwen@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+#ifndef __MV_UDC_H__
+#define __MV_UDC_H__
+
+#include <asm/byteorder.h>
+#include <asm/errno.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/* Endpoint 0 states */
+#define EP0_IDLE		0
+#define EP0_IN_DATA		1
+#define EP0_OUT_DATA		2
+#define EP0_XFER_COMPLETE	3
+
+
+/* Endpoint parameters */
+#define MAX_ENDPOINTS		4
+#define EP_MAX_PACKET_SIZE	0x200
+
+#define EP0_MAX_PACKET_SIZE	64
+#define UDC_OUT_ENDPOINT        0x02
+#define UDC_OUT_PACKET_SIZE	EP_MAX_PACKET_SIZE
+#define UDC_IN_ENDPOINT         0x01
+#define UDC_IN_PACKET_SIZE      EP_MAX_PACKET_SIZE
+#define UDC_INT_ENDPOINT        0x05
+#define UDC_INT_PACKET_SIZE     EP_MAX_PACKET_SIZE
+#define UDC_BULK_PACKET_SIZE    EP_MAX_PACKET_SIZE
+
+#define        NUM_ENDPOINTS   6
+#define		REQ_COUNT	12
+struct mv_ep {
+	struct usb_ep ep;
+	struct usb_request req;
+	struct list_head queue;
+	const struct usb_endpoint_descriptor *desc;
+};
+
+struct mv_udc {
+	u32 pad0[80];
+#define MICRO_8FRAME	0x8
+#define USBCMD_ITC(x)	(((x > 0xff) ? 0xff : x) << 16)
+#define USBCMD_FS2	(1 << 15)
+#define USBCMD_RST	(1 << 1)
+#define USBCMD_RUN	(1)
+	u32 usbcmd;		/* 0x140 */
+#define STS_SLI		(1 << 8)
+#define STS_URI		(1 << 6)
+#define STS_PCI		(1 << 2)
+#define STS_UEI		(1 << 1)
+#define STS_UI		(1 << 0)
+	u32 usbsts;		/* 0x144 */
+	u32 pad1[3];
+	u32 devaddr;		/* 0x154 */
+	u32 epinitaddr;		/* 0x158 */
+	u32 pad2[10];
+#define PTS_ENABLE	2
+#define PTS(x)		((x & 0x3) << 30)
+#define PFSC		(1 << 24)
+	u32 portsc;		/* 0x184 */
+	u32 pad3[8];
+#define USBMODE_DEVICE	2
+	u32 usbmode;		/* 0x1a8 */
+	u32 epstat;		/* 0x1ac */
+#define EPT_TX(x)	(1 << ((x & 0xffff) + 16))
+#define EPT_RX(x)	(1 << (x & 0xffff))
+	u32 epprime;		/* 0x1b0 */
+	u32 epflush;		/* 0x1b4 */
+	u32 pad4;
+	u32 epcomp;		/* 0x1bc */
+#define CTRL_TXE              (1 << 23)
+#define CTRL_TXR              (1 << 22)
+#define CTRL_RXE              (1 << 7)
+#define CTRL_RXR              (1 << 6)
+#define CTRL_TXT_BULK         (2 << 18)
+#define CTRL_RXT_BULK         (2 << 2)
+	u32 epctrl[16];		/* 0x1c0 */
+};
+
+struct mv_drv {
+	struct usb_gadget		gadget;
+	struct usb_gadget_driver		*driver;
+	struct mv_udc			*udc;
+};
+
+struct ept_queue_head {
+	unsigned config;
+	unsigned current; /* read-only */
+
+	unsigned next;
+	unsigned info;
+	unsigned page0;
+	unsigned page1;
+	unsigned page2;
+	unsigned page3;
+	unsigned page4;
+	unsigned reserved_0;
+
+	unsigned char setup_data[8];
+
+	unsigned reserved_1;
+	unsigned reserved_2;
+	unsigned reserved_3;
+	unsigned reserved_4;
+};
+
+#define CONFIG_MAX_PKT(n)     ((n) << 16)
+#define CONFIG_ZLT            (1 << 29)    /* stop on zero-len xfer */
+#define CONFIG_IOS            (1 << 15)    /* IRQ on setup */
+
+struct ept_queue_item {
+	unsigned next;
+	unsigned info;
+	unsigned page0;
+	unsigned page1;
+	unsigned page2;
+	unsigned page3;
+	unsigned page4;
+	unsigned reserved;
+};
+
+#define TERMINATE 1
+#define INFO_BYTES(n)         ((n) << 16)
+#define INFO_IOC              (1 << 15)
+#define INFO_ACTIVE           (1 << 7)
+#define INFO_HALTED           (1 << 6)
+#define INFO_BUFFER_ERROR     (1 << 5)
+#define INFO_TX_ERROR         (1 << 3)
+
+extern int usb_lowlevel_init(void);
+#endif /* __MV_UDC_H__ */
diff --git a/include/usb/s3c_udc.h b/include/usb/s3c_udc.h
new file mode 100644
index 0000000000000000000000000000000000000000..14dadc8b0538cddf281fc205e7d1827b91d052e7
--- /dev/null
+++ b/include/usb/s3c_udc.h
@@ -0,0 +1,175 @@
+/*
+ * drivers/usb/gadget/s3c_udc.h
+ * Samsung S3C on-chip full/high speed USB device controllers
+ * Copyright (C) 2005 for Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __S3C_USB_GADGET
+#define __S3C_USB_GADGET
+
+#include <asm/errno.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/list.h>
+#include <usb/lin_gadget_compat.h>
+
+#define PHY0_SLEEP              (1 << 5)
+
+/*-------------------------------------------------------------------------*/
+/* DMA bounce buffer size, 16K is enough even for mass storage */
+#define DMA_BUFFER_SIZE	(4096*4)
+
+#define EP0_FIFO_SIZE		64
+#define EP_FIFO_SIZE		512
+#define EP_FIFO_SIZE2		1024
+/* ep0-control, ep1in-bulk, ep2out-bulk, ep3in-int */
+#define S3C_MAX_ENDPOINTS	4
+#define S3C_MAX_HW_ENDPOINTS	16
+
+#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
+#define WAIT_FOR_COMPLETE	5
+#define WAIT_FOR_OUT_COMPLETE	6
+#define WAIT_FOR_IN_COMPLETE	7
+#define WAIT_FOR_NULL_COMPLETE	8
+
+#define TEST_J_SEL		0x1
+#define TEST_K_SEL		0x2
+#define TEST_SE0_NAK_SEL	0x3
+#define TEST_PACKET_SEL		0x4
+#define TEST_FORCE_ENABLE_SEL	0x5
+
+/* ************************************************************************* */
+/* IO
+ */
+
+enum ep_type {
+	ep_control, ep_bulk_in, ep_bulk_out, ep_interrupt
+};
+
+struct s3c_ep {
+	struct usb_ep ep;
+	struct s3c_udc *dev;
+
+	const struct usb_endpoint_descriptor *desc;
+	struct list_head queue;
+	unsigned long pio_irqs;
+	int len;
+	void *dma_buf;
+
+	u8 stopped;
+	u8 bEndpointAddress;
+	u8 bmAttributes;
+
+	enum ep_type ep_type;
+	int fifo_num;
+};
+
+struct s3c_request {
+	struct usb_request req;
+	struct list_head queue;
+};
+
+struct s3c_udc {
+	struct usb_gadget gadget;
+	struct usb_gadget_driver *driver;
+
+	struct s3c_plat_otg_data *pdata;
+
+	void *dma_buf[S3C_MAX_ENDPOINTS+1];
+	dma_addr_t dma_addr[S3C_MAX_ENDPOINTS+1];
+
+	int ep0state;
+	struct s3c_ep ep[S3C_MAX_ENDPOINTS];
+
+	unsigned char usb_address;
+
+	unsigned req_pending:1, req_std:1, req_config:1;
+};
+
+extern struct s3c_udc *the_controller;
+
+#define ep_is_in(EP) (((EP)->bEndpointAddress&USB_DIR_IN) == USB_DIR_IN)
+#define ep_index(EP) ((EP)->bEndpointAddress&0xF)
+#define ep_maxpacket(EP) ((EP)->ep.maxpacket)
+
+/*-------------------------------------------------------------------------*/
+/* #define DEBUG_UDC */
+#ifdef DEBUG_UDC
+#define DBG(stuff...)		printf("udc: " stuff)
+#else
+#define DBG(stuff...)		do {} while (0)
+#endif
+
+#ifdef DEBUG_S3C_UDC_SETUP
+#define DEBUG_SETUP(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG_SETUP(fmt, args...) do {} while (0)
+#endif
+
+#ifdef DEBUG_S3C_UDC_EP0
+#define DEBUG_EP0(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG_EP0(fmt, args...) do {} while (0)
+#endif
+
+#ifdef DEBUG_S3C_UDC
+#define DEBUG(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG(fmt, args...) do {} while (0)
+#endif
+
+#ifdef DEBUG_S3C_UDC_ISR
+#define DEBUG_ISR(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG_ISR(fmt, args...) do {} while (0)
+#endif
+
+#ifdef DEBUG_S3C_UDC_OUT_EP
+#define DEBUG_OUT_EP(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG_OUT_EP(fmt, args...) do {} while (0)
+#endif
+
+#ifdef DEBUG_S3C_UDC_IN_EP
+#define DEBUG_IN_EP(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG_IN_EP(fmt, args...) do {} while (0)
+#endif
+
+#define ERR(stuff...)		printf("ERR udc: " stuff)
+#define WARN(stuff...)		printf("WARNING udc: " stuff)
+#define INFO(stuff...)		printf("INFO udc: " stuff)
+
+extern void otg_phy_init(struct s3c_udc *dev);
+extern void otg_phy_off(struct s3c_udc *dev);
+
+extern void s3c_udc_ep_set_stall(struct s3c_ep *ep);
+extern int s3c_udc_probe(struct s3c_plat_otg_data *pdata);
+
+struct s3c_plat_otg_data {
+	int		(*phy_control)(int on);
+	unsigned int	regs_phy;
+	unsigned int	regs_otg;
+	unsigned int    usb_phy_ctrl;
+	unsigned int    usb_flags;
+};
+#endif
diff --git a/include/usb/ulpi.h b/include/usb/ulpi.h
new file mode 100644
index 0000000000000000000000000000000000000000..d8712908716f04b9a90792b8ac8b13b51c59d2e6
--- /dev/null
+++ b/include/usb/ulpi.h
@@ -0,0 +1,298 @@
+/*
+ * Generic ULPI interface.
+ *
+ * Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
+ * Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il>
+ *
+ * Authors: Jana Rapava <fermata7@gmail.com>
+ *	    Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * Register offsets taken from:
+ * linux/include/linux/usb/ulpi.h
+ *
+ * Original Copyrights follow:
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * This software is distributed under the terms of the GNU General
+ * Public License ("GPL") as published by the Free Software Foundation,
+ * version 2 of that License.
+ */
+
+#ifndef __USB_ULPI_H__
+#define __USB_ULPI_H__
+
+#define ULPI_ERROR	(1 << 8) /* overflow from any register value */
+
+#ifndef CONFIG_USB_ULPI_TIMEOUT
+#define CONFIG_USB_ULPI_TIMEOUT 1000	/* timeout in us */
+#endif
+
+/*
+ * Initialize the ULPI transciever and check the interface integrity.
+ * @ulpi_viewport -  the address of the ULPI viewport register.
+ *
+ * returns 0 on success, ULPI_ERROR on failure.
+ */
+int ulpi_init(u32 ulpi_viewport);
+
+/*
+ * Select transceiver speed.
+ * @speed	- ULPI_FC_HIGH_SPEED, ULPI_FC_FULL_SPEED (default),
+ *                ULPI_FC_LOW_SPEED,  ULPI_FC_FS4LS
+ * returns 0 on success, ULPI_ERROR on failure.
+ */
+int ulpi_select_transceiver(u32 ulpi_viewport, u8 speed);
+
+/*
+ * Enable/disable VBUS.
+ * @ext_power		- external VBUS supply is used (default is false)
+ * @ext_indicator	- external VBUS over-current indicator is used
+ *
+ * returns 0 on success, ULPI_ERROR on failure.
+ */
+int ulpi_enable_vbus(u32 ulpi_viewport, int on, int ext_power, int ext_ind);
+
+/*
+ * Enable/disable pull-down resistors on D+ and D- USB lines.
+ *
+ * returns 0 on success, ULPI_ERROR on failure.
+ */
+int ulpi_set_pd(u32 ulpi_viewport, int enable);
+
+/*
+ * Select OpMode.
+ * @opmode	- ULPI_FC_OPMODE_NORMAL (default), ULPI_FC_OPMODE_NONDRIVING,
+ *		  ULPI_FC_OPMODE_DISABLE_NRZI,	   ULPI_FC_OPMODE_NOSYNC_NOEOP
+ *
+ * returns 0 on success, ULPI_ERROR on failure.
+ */
+int ulpi_opmode_sel(u32 ulpi_viewport, u8 opmode);
+
+/*
+ * Switch to Serial Mode.
+ * @smode	- ULPI_IFACE_6_PIN_SERIAL_MODE or ULPI_IFACE_3_PIN_SERIAL_MODE
+ *
+ * returns 0 on success, ULPI_ERROR on failure.
+ *
+ * Notes:
+ * Switches immediately to Serial Mode.
+ * To return from Serial Mode, STP line needs to be asserted.
+ */
+int ulpi_serial_mode_enable(u32 ulpi_viewport, u8 smode);
+
+/*
+ * Put PHY into low power mode.
+ *
+ * returns 0 on success, ULPI_ERROR on failure.
+ *
+ * Notes:
+ * STP line must be driven low to keep the PHY in suspend.
+ * To resume the PHY, STP line needs to be asserted.
+ */
+int ulpi_suspend(u32 ulpi_viewport);
+
+/*
+ * Reset the transceiver. ULPI interface and registers are not affected.
+ *
+ * returns 0 on success, ULPI_ERROR on failure.
+ */
+int ulpi_reset(u32 ulpi_viewport);
+
+
+/* ULPI access methods below must be implemented for each ULPI viewport. */
+
+/*
+ * Write to the ULPI PHY register via the viewport.
+ * @reg		- the ULPI register (one of the fields in struct ulpi_regs).
+ * @value	- the value - only 8 lower bits are used, others ignored.
+ *
+ * returns 0 on success, ULPI_ERROR on failure.
+ */
+u32 ulpi_write(u32 ulpi_viewport, u8 *reg, u32 value);
+
+/*
+ * Read the ULPI PHY register content via the viewport.
+ * @reg		- the ULPI register (one of the fields in struct ulpi_regs).
+ *
+ * returns register content on success, ULPI_ERROR on failure.
+ */
+u32 ulpi_read(u32 ulpi_viewport, u8 *reg);
+
+/*
+ * Wait for the reset to complete.
+ * The Link must not attempt to access the PHY until the reset has
+ * completed and DIR line is de-asserted.
+ */
+int ulpi_reset_wait(u32 ulpi_viewport);
+
+/* Access Extended Register Set (indicator) */
+#define ACCESS_EXT_REGS_OFFSET	0x2f	/* read-write */
+/* Vendor-specific */
+#define VENDOR_SPEC_OFFSET	0x30
+
+/*
+ * Extended Register Set
+ *
+ * Addresses 0x00-0x3F map directly to Immediate Register Set.
+ * Addresses 0x40-0x7F are reserved.
+ * Addresses 0x80-0xff are vendor-specific.
+ */
+#define EXT_VENDOR_SPEC_OFFSET	0x80
+
+/* ULPI registers, bits and offsets definitions */
+struct ulpi_regs {
+	/* Vendor ID and Product ID: 0x00 - 0x03 Read-only */
+	u8	vendor_id_low;
+	u8	vendor_id_high;
+	u8	product_id_low;
+	u8	product_id_high;
+	/* Function Control: 0x04 - 0x06 Read */
+	u8	function_ctrl;		/* 0x04 Write */
+	u8	function_ctrl_set;	/* 0x05 Set */
+	u8	function_ctrl_clear;	/* 0x06 Clear */
+	/* Interface Control: 0x07 - 0x09 Read */
+	u8	iface_ctrl;		/* 0x07 Write */
+	u8	iface_ctrl_set;		/* 0x08 Set */
+	u8	iface_ctrl_clear;	/* 0x09 Clear */
+	/* OTG Control: 0x0A - 0x0C Read */
+	u8	otg_ctrl;		/* 0x0A Write */
+	u8	otg_ctrl_set;		/* 0x0B Set */
+	u8	otg_ctrl_clear;		/* 0x0C Clear */
+	/* USB Interrupt Enable Rising: 0x0D - 0x0F Read */
+	u8	usb_ie_rising;		/* 0x0D Write */
+	u8	usb_ie_rising_set;	/* 0x0E Set */
+	u8	usb_ie_rising_clear;	/* 0x0F Clear */
+	/* USB Interrupt Enable Falling: 0x10 - 0x12 Read */
+	u8	usb_ie_falling;		/* 0x10 Write */
+	u8	usb_ie_falling_set;	/* 0x11 Set */
+	u8	usb_ie_falling_clear;	/* 0x12 Clear */
+	/* USB Interrupt Status: 0x13 Read-only */
+	u8	usb_int_status;
+	/* USB Interrupt Latch: 0x14 Read-only with auto-clear */
+	u8	usb_int_latch;
+	/* Debug: 0x15 Read-only */
+	u8	debug;
+	/* Scratch Register: 0x16 - 0x18 Read */
+	u8	scratch;		/* 0x16 Write */
+	u8	scratch_set;		/* 0x17 Set */
+	u8	scratch_clear;		/* 0x18 Clear */
+	/*
+	 * Optional Carkit registers:
+	 * Carkit Control: 0x19 - 0x1B Read
+	 */
+	u8	carkit_ctrl;		/* 0x19 Write */
+	u8	carkit_ctrl_set;	/* 0x1A Set */
+	u8	carkit_ctrl_clear;	/* 0x1B Clear */
+	/* Carkit Interrupt Delay: 0x1C Read, Write */
+	u8	carkit_int_delay;
+	/* Carkit Interrupt Enable: 0x1D - 0x1F Read */
+	u8	carkit_ie;		/* 0x1D Write */
+	u8	carkit_ie_set;		/* 0x1E Set */
+	u8	carkit_ie_clear;	/* 0x1F Clear */
+	/* Carkit Interrupt Status: 0x20 Read-only */
+	u8	carkit_int_status;
+	/* Carkit Interrupt Latch: 0x21 Read-only with auto-clear */
+	u8	carkit_int_latch;
+	/* Carkit Pulse Control: 0x22 - 0x24 Read */
+	u8	carkit_pulse_ctrl;		/* 0x22 Write */
+	u8	carkit_pulse_ctrl_set;		/* 0x23 Set */
+	u8	carkit_pulse_ctrl_clear;	/* 0x24 Clear */
+	/*
+	 * Other optional registers:
+	 * Transmit Positive Width: 0x25 Read, Write
+	 */
+	u8	transmit_pos_width;
+	/* Transmit Negative Width: 0x26 Read, Write */
+	u8	transmit_neg_width;
+	/* Receive Polarity Recovery: 0x27 Read, Write */
+	u8	recv_pol_recovery;
+	/*
+	 * Addresses 0x28 - 0x2E are reserved, so we use offsets
+	 * for immediate registers with higher addresses
+	 */
+};
+
+/*
+ * Register Bits
+ */
+
+/* Function Control */
+#define ULPI_FC_XCVRSEL_MASK		(3 << 0)
+#define ULPI_FC_HIGH_SPEED		(0 << 0)
+#define ULPI_FC_FULL_SPEED		(1 << 0)
+#define ULPI_FC_LOW_SPEED		(2 << 0)
+#define ULPI_FC_FS4LS			(3 << 0)
+#define ULPI_FC_TERMSELECT		(1 << 2)
+#define ULPI_FC_OPMODE_MASK		(3 << 3)
+#define ULPI_FC_OPMODE_NORMAL		(0 << 3)
+#define ULPI_FC_OPMODE_NONDRIVING	(1 << 3)
+#define ULPI_FC_OPMODE_DISABLE_NRZI	(2 << 3)
+#define ULPI_FC_OPMODE_NOSYNC_NOEOP	(3 << 3)
+#define ULPI_FC_RESET			(1 << 5)
+#define ULPI_FC_SUSPENDM		(1 << 6)
+
+/* Interface Control */
+#define ULPI_IFACE_6_PIN_SERIAL_MODE	(1 << 0)
+#define ULPI_IFACE_3_PIN_SERIAL_MODE	(1 << 1)
+#define ULPI_IFACE_CARKITMODE		(1 << 2)
+#define ULPI_IFACE_CLOCKSUSPENDM	(1 << 3)
+#define ULPI_IFACE_AUTORESUME		(1 << 4)
+#define ULPI_IFACE_EXTVBUS_COMPLEMENT	(1 << 5)
+#define ULPI_IFACE_PASSTHRU		(1 << 6)
+#define ULPI_IFACE_PROTECT_IFC_DISABLE	(1 << 7)
+
+/* OTG Control */
+#define ULPI_OTG_ID_PULLUP		(1 << 0)
+#define ULPI_OTG_DP_PULLDOWN		(1 << 1)
+#define ULPI_OTG_DM_PULLDOWN		(1 << 2)
+#define ULPI_OTG_DISCHRGVBUS		(1 << 3)
+#define ULPI_OTG_CHRGVBUS		(1 << 4)
+#define ULPI_OTG_DRVVBUS		(1 << 5)
+#define ULPI_OTG_DRVVBUS_EXT		(1 << 6)
+#define ULPI_OTG_EXTVBUSIND		(1 << 7)
+
+/*
+ * USB Interrupt Enable Rising,
+ * USB Interrupt Enable Falling,
+ * USB Interrupt Status and
+ * USB Interrupt Latch
+ */
+#define ULPI_INT_HOST_DISCONNECT	(1 << 0)
+#define ULPI_INT_VBUS_VALID		(1 << 1)
+#define ULPI_INT_SESS_VALID		(1 << 2)
+#define ULPI_INT_SESS_END		(1 << 3)
+#define ULPI_INT_IDGRD			(1 << 4)
+
+/* Debug */
+#define ULPI_DEBUG_LINESTATE0		(1 << 0)
+#define ULPI_DEBUG_LINESTATE1		(1 << 1)
+
+/* Carkit Control */
+#define ULPI_CARKIT_CTRL_CARKITPWR		(1 << 0)
+#define ULPI_CARKIT_CTRL_IDGNDDRV		(1 << 1)
+#define ULPI_CARKIT_CTRL_TXDEN			(1 << 2)
+#define ULPI_CARKIT_CTRL_RXDEN			(1 << 3)
+#define ULPI_CARKIT_CTRL_SPKLEFTEN		(1 << 4)
+#define ULPI_CARKIT_CTRL_SPKRIGHTEN		(1 << 5)
+#define ULPI_CARKIT_CTRL_MICEN			(1 << 6)
+
+/* Carkit Interrupt Enable */
+#define ULPI_CARKIT_INT_EN_IDFLOAT_RISE		(1 << 0)
+#define ULPI_CARKIT_INT_EN_IDFLOAT_FALL		(1 << 1)
+#define ULPI_CARKIT_INT_EN_CARINTDET		(1 << 2)
+#define ULPI_CARKIT_INT_EN_DP_RISE		(1 << 3)
+#define ULPI_CARKIT_INT_EN_DP_FALL		(1 << 4)
+
+/* Carkit Interrupt Status and Latch */
+#define ULPI_CARKIT_INT_IDFLOAT			(1 << 0)
+#define ULPI_CARKIT_INT_CARINTDET		(1 << 1)
+#define ULPI_CARKIT_INT_DP			(1 << 2)
+
+/* Carkit Pulse Control*/
+#define ULPI_CARKIT_PLS_CTRL_TXPLSEN		(1 << 0)
+#define ULPI_CARKIT_PLS_CTRL_RXPLSEN		(1 << 1)
+#define ULPI_CARKIT_PLS_CTRL_SPKRLEFT_BIASEN	(1 << 2)
+#define ULPI_CARKIT_PLS_CTRL_SPKRRIGHT_BIASEN	(1 << 3)
+
+
+#endif /* __USB_ULPI_H__ */
diff --git a/include/usbdescriptors.h b/include/usbdescriptors.h
index 2dec3b93d65438cfc5c16ec4a1f04ee62a469ac7..392fcf53780162fc87f6fbb58fdcb8496009111f 100644
--- a/include/usbdescriptors.h
+++ b/include/usbdescriptors.h
@@ -199,7 +199,7 @@ struct usb_endpoint_descriptor {
 	u8 bmAttributes;
 	u16 wMaxPacketSize;
 	u8 bInterval;
-} __attribute__ ((packed));
+} __attribute__ ((packed)) __attribute__ ((aligned(2)));
 
 struct usb_interface_descriptor {
 	u8 bLength;