linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] USB: gadget: Add Samsung S3C24xx USB HS controller driver
@ 2010-10-13  0:10 Sangbeom Kim
  2010-10-13  0:10 ` [PATCH 1/4] ARM: S3C2416: Add USB Phy register definitions Sangbeom Kim
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Sangbeom Kim @ 2010-10-13  0:10 UTC (permalink / raw)
  To: linux-arm-kernel

The Samsung's S3C2416, S3C2443 and S3C2450 includes a USB High-Speed
device controller module. This driver enables support for USB high-speed
gadget functionality for the Samsung S3C24xx SoC's that include this
controller.

The patch series contains:
[PATCH 1/4] ARM: S3C2416: Add USB Phy register definitions
[PATCH 2/4] ARM: S3C24XX: Add plaform device definition for USB High-Speed gadget controller.
[PATCH 3/4] USB: Gadget: Add Samsung S3C24XX USB High-Speed controller driver
[PATCH 4/4] ARM: S3C2416: Add support for USB 2.0 High-Speed gadget controller

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/4] ARM: S3C2416: Add USB Phy register definitions
  2010-10-13  0:10 [PATCH 0/4] USB: gadget: Add Samsung S3C24xx USB HS controller driver Sangbeom Kim
@ 2010-10-13  0:10 ` Sangbeom Kim
  2010-10-13  0:10 ` [PATCH 2/4] ARM: S3C24XX: Add plaform device definition for USB High-Speed gadget controller Sangbeom Kim
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Sangbeom Kim @ 2010-10-13  0:10 UTC (permalink / raw)
  To: linux-arm-kernel

From: Thomas Abraham <thomas.ab@samsung.com>

Add register definitions required to configure the USB Phy. The definitions
for PHYCTRL, PHYPWR, URSTCON and UCLKCON registers and corresponding bit
field definitions are added.

Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
Signed-off-by: Sangbeom Kim <sbkim73@samsung.com>
---
 .../mach-s3c2410/include/mach/regs-s3c2443-clock.h |   25 ++++++++++++++++++++
 1 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h b/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h
index 08ab9df..2c93d83 100644
--- a/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h
+++ b/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h
@@ -37,6 +37,10 @@
 #define S3C2443_SYSID			S3C2443_CLKREG(0x5C)
 #define S3C2443_PWRCFG			S3C2443_CLKREG(0x60)
 #define S3C2443_RSTCON			S3C2443_CLKREG(0x64)
+#define S3C2443_PHYCTRL			S3C2443_CLKREG(0x80)
+#define S3C2443_PHYPWR			S3C2443_CLKREG(0x84)
+#define S3C2443_URSTCON			S3C2443_CLKREG(0x88)
+#define S3C2443_UCLKCON			S3C2443_CLKREG(0x8C)
 
 #define S3C2443_SWRST_RESET		(0x533c2443)
 
@@ -118,6 +122,27 @@
 #define S3C2443_SCLKCON_UARTCLK		(1<<8)
 #define S3C2443_SCLKCON_USBHOST		(1<<1)
 
+#define S3C2443_PWRCFG_USBPHY		(1 << 4)
+
+#define S3C2443_URSTCON_FUNCRST		(1 << 2)
+#define S3C2443_URSTCON_PHYRST		(1 << 0)
+
+#define S3C2443_PHYCTRL_CLKSEL		(1 << 3)
+#define S3C2443_PHYCTRL_EXTCLK		(1 << 2)
+#define S3C2443_PHYCTRL_PLLSEL		(1 << 1)
+#define S3C2443_PHYCTRL_DSPORT		(1 << 0)
+
+#define S3C2443_PHYPWR_COMMON_ON	(1 << 31)
+#define S3C2443_PHYPWR_ANALOG_PD	(1 << 4)
+#define S3C2443_PHYPWR_PLL_REFCLK	(1 << 3)
+#define S3C2443_PHYPWR_XO_ON		(1 << 2)
+#define S3C2443_PHYPWR_PLL_PWRDN	(1 << 1)
+#define S3C2443_PHYPWR_FSUSPEND		(1 << 0)
+
+#define S3C2443_UCLKCON_DETECT_VBUS	(1 << 31)
+#define S3C2443_UCLKCON_FUNC_CLKEN	(1 << 2)
+#define S3C2443_UCLKCON_TCLKEN		(1 << 0)
+
 #include <asm/div64.h>
 
 static inline unsigned int
-- 
1.6.6.rc2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/4] ARM: S3C24XX: Add plaform device definition for USB High-Speed gadget controller.
  2010-10-13  0:10 [PATCH 0/4] USB: gadget: Add Samsung S3C24xx USB HS controller driver Sangbeom Kim
  2010-10-13  0:10 ` [PATCH 1/4] ARM: S3C2416: Add USB Phy register definitions Sangbeom Kim
@ 2010-10-13  0:10 ` Sangbeom Kim
  2010-10-13  0:10 ` [PATCH 3/4] USB: Gadget: Add Samsung S3C24XX USB High-Speed controller driver Sangbeom Kim
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Sangbeom Kim @ 2010-10-13  0:10 UTC (permalink / raw)
  To: linux-arm-kernel

From: Thomas Abraham <thomas.ab@samsung.com>

S3C2416, S3C2443 and S3C2450 includes a USB High-Speed Gadget controller module.
This patch adds the following for supporting this controller.

1. Definition for USB High-Speed controller base address.
2. Platform device instantiation.
3. Declaration for platform data structure.
4. Functionality to setup platform data for the controller.

Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
Signed-off-by: Sangbeom Kim <sbkim73@samsung.com>
---
 arch/arm/mach-s3c2410/include/mach/map.h  |    4 +++
 arch/arm/plat-s3c24xx/devs.c              |   41 +++++++++++++++++++++++++++++
 arch/arm/plat-s3c24xx/include/plat/udc.h  |   17 ++++++++++++
 arch/arm/plat-samsung/include/plat/devs.h |    1 +
 4 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-s3c2410/include/mach/map.h b/arch/arm/mach-s3c2410/include/mach/map.h
index cd3983a..0c6667f 100644
--- a/arch/arm/mach-s3c2410/include/mach/map.h
+++ b/arch/arm/mach-s3c2410/include/mach/map.h
@@ -21,6 +21,10 @@
 /* USB host controller */
 #define S3C2410_PA_USBHOST (0x49000000)
 
+/* S3C2416/S3C2443/S3C2450 High-Speed USB Gadget */
+#define S3C2416_PA_HSUDC	(0x49800000)
+#define S3C2416_SZ_HSUDC	(SZ_4K)
+
 /* DMA controller */
 #define S3C2410_PA_DMA	   (0x4B000000)
 #define S3C24XX_SZ_DMA	   SZ_1M
diff --git a/arch/arm/plat-s3c24xx/devs.c b/arch/arm/plat-s3c24xx/devs.c
index 452e184..481d9c9 100644
--- a/arch/arm/plat-s3c24xx/devs.c
+++ b/arch/arm/plat-s3c24xx/devs.c
@@ -22,6 +22,7 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -234,6 +235,46 @@ void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *pd)
 	}
 }
 
+/* USB High Speed 2.0 Device (Gadget) */
+static struct resource s3c_hsudc_resource[] = {
+	[0] = {
+		.start	= S3C2416_PA_HSUDC,
+		.end	= S3C2416_PA_HSUDC + S3C2416_SZ_HSUDC - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_USBD,
+		.end	= IRQ_USBD,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static u64 s3c_hsudc_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device s3c_device_usb_hsudc = {
+	.name		= "s3c-hsudc",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(s3c_hsudc_resource),
+	.resource	= s3c_hsudc_resource,
+	.dev		= {
+		.dma_mask		= &s3c_hsudc_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+
+void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd)
+{
+	struct s3c24xx_hsudc_platdata *npd;
+
+	npd = kmalloc(sizeof(*npd), GFP_KERNEL);
+	if (npd) {
+		memcpy(npd, pd, sizeof(*npd));
+		s3c_device_usb_hsudc.dev.platform_data = npd;
+	} else {
+		printk(KERN_ERR "no memory for udc platform data\n");
+	}
+}
+
 /* IIS */
 
 static struct resource s3c_iis_resource[] = {
diff --git a/arch/arm/plat-s3c24xx/include/plat/udc.h b/arch/arm/plat-s3c24xx/include/plat/udc.h
index 546bb40..a3fc1be 100644
--- a/arch/arm/plat-s3c24xx/include/plat/udc.h
+++ b/arch/arm/plat-s3c24xx/include/plat/udc.h
@@ -33,4 +33,21 @@ struct s3c2410_udc_mach_info {
 
 extern void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *);
 
+/**
+ * s3c24xx_hsudc_platdata - Platform data for USB High-Speed gadget controller.
+ * @epnum: Number of endpoints to be instantiated by the controller driver.
+ * @gpio_init: Platform specific USB related GPIO initialization.
+ * @gpio_uninit: Platform specific USB releted GPIO uninitialzation.
+ *
+ * Representation of platform data for the S3C24XX USB 2.0 High Speed gadget
+ * controllers.
+ */
+struct s3c24xx_hsudc_platdata {
+	unsigned int	epnum;
+	void		(*gpio_init)(void);
+	void		(*gpio_uninit)(void);
+};
+
+extern void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd);
+
 #endif /* __ASM_ARM_ARCH_UDC_H */
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index 7d448e1..8221859 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -78,6 +78,7 @@ extern struct platform_device s3c64xx_device_onenand1;
 extern struct platform_device s5p_device_onenand;
 
 extern struct platform_device s3c_device_usbgadget;
+extern struct platform_device s3c_device_usb_hsudc;
 extern struct platform_device s3c_device_usb_hsotg;
 
 extern struct platform_device s5pv210_device_ac97;
-- 
1.6.6.rc2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/4] USB: Gadget: Add Samsung S3C24XX USB High-Speed controller driver
  2010-10-13  0:10 [PATCH 0/4] USB: gadget: Add Samsung S3C24xx USB HS controller driver Sangbeom Kim
  2010-10-13  0:10 ` [PATCH 1/4] ARM: S3C2416: Add USB Phy register definitions Sangbeom Kim
  2010-10-13  0:10 ` [PATCH 2/4] ARM: S3C24XX: Add plaform device definition for USB High-Speed gadget controller Sangbeom Kim
@ 2010-10-13  0:10 ` Sangbeom Kim
  2010-10-21 22:36   ` Ben Dooks
  2010-10-13  0:10 ` [PATCH 4/4] ARM: S3C2416: Add support for USB 2.0 High-Speed gadget controller Sangbeom Kim
  2010-10-21 22:37 ` [PATCH 0/4] USB: gadget: Add Samsung S3C24xx USB HS controller driver Ben Dooks
  4 siblings, 1 reply; 8+ messages in thread
From: Sangbeom Kim @ 2010-10-13  0:10 UTC (permalink / raw)
  To: linux-arm-kernel

From: Thomas Abraham <thomas.ab@samsung.com>

The Samsung's S3C2416, S3C2443 and S3C2450 includes a USB High-Speed
device controller module. This driver enables support for USB high-speed
gadget functionality for the Samsung S3C24xx SoC's that include this
controller.

Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
Signed-off-by: Sangbeom Kim <sbkim73@samsung.com>
---
 drivers/usb/gadget/Kconfig        |   17 +
 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/gadget_chips.h |    7 +
 drivers/usb/gadget/s3c-hsudc.c    | 1329 +++++++++++++++++++++++++++++++++++++
 4 files changed, 1354 insertions(+), 0 deletions(-)
 create mode 100644 drivers/usb/gadget/s3c-hsudc.c

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index cd27f9b..235d4db 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -348,6 +348,23 @@ config USB_S3C2410_DEBUG
 	boolean "S3C2410 udc debug messages"
 	depends on USB_GADGET_S3C2410
 
+config USB_GADGET_S3C_HSUDC
+	boolean "S3C2416, S3C2443 and S3C2450 USB Device Controller"
+	depends on ARCH_S3C2410
+	select USB_GADGET_DUALSPEED
+	help
+	  Samsung's S3C2416, S3C2443 and S3C2450 is an ARM9 based SoC
+	  integrated with dual speed USB 2.0 device controller. It has
+	  8 endpoints, as well as endpoint zero.
+
+	  This driver has been tested on S3C2416 and S3C2450 processors.
+
+config USB_S3C_HSUDC
+	tristate
+	depends on USB_GADGET_S3C_HSUDC
+	default USB_GADGET
+	select USB_GADGET_SELECTED
+
 #
 # Controllers available in both integrated and discrete versions
 #
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 27283df..76e3d67 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_USB_R8A66597)	+= r8a66597-udc.o
 obj-$(CONFIG_USB_FSL_QE)	+= fsl_qe_udc.o
 obj-$(CONFIG_USB_CI13XXX)	+= ci13xxx_udc.o
 obj-$(CONFIG_USB_S3C_HSOTG)	+= s3c-hsotg.o
+obj-$(CONFIG_USB_S3C_HSUDC)	+= s3c-hsudc.o
 obj-$(CONFIG_USB_LANGWELL)	+= langwell_udc.o
 
 #
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index e511fec..0b27f6f 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -142,6 +142,11 @@
 #define gadget_is_s3c_hsotg(g)    0
 #endif
 
+#ifdef CONFIG_USB_S3C_HSUDC
+#define gadget_is_s3c_hsudc(g) (!strcmp("s3c-hsudc", (g)->name))
+#else
+#define gadget_is_s3c_hsudc(g) 0
+#endif
 
 /**
  * usb_gadget_controller_number - support bcdDevice id convention
@@ -200,6 +205,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x25;
 	else if (gadget_is_s3c_hsotg(gadget))
 		return 0x26;
+	else if (gadget_is_s3c_hsudc(gadget))
+		return 0x27;
 	return -ENOENT;
 }
 
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
new file mode 100644
index 0000000..ebc4a10
--- /dev/null
+++ b/drivers/usb/gadget/s3c-hsudc.c
@@ -0,0 +1,1329 @@
+/* linux/drivers/usb/gadget/s3c-hsudc.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * S3C24XX USB 2.0 High-speed USB controller gadget driver
+ *
+ * The S3C24XX USB 2.0 high-speed USB controller supports upto 9 endpoints.
+ * Each endpoint can be configured as either in or out endpoint. Endpoints
+ * can be configured for Bulk or Interrupt transfer mode.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <mach/regs-s3c2443-clock.h>
+#include <plat/udc.h>
+
+#define S3C_HSUDC_REG(x)	(x)
+
+/* Non-Indexed Registers */
+#define S3C_IR				S3C_HSUDC_REG(0x00) /* Index Register */
+#define S3C_EIR				S3C_HSUDC_REG(0x04) /* EP Intr Status */
+#	define S3C_EIR_EP0		(1<<0)
+#define S3C_EIER			S3C_HSUDC_REG(0x08) /* EP Intr Enable */
+#define S3C_FAR				S3C_HSUDC_REG(0x0c) /* Gadget Address */
+#define S3C_FNR				S3C_HSUDC_REG(0x10) /* Frame Number */
+#define S3C_EDR				S3C_HSUDC_REG(0x14) /* EP Direction */
+#define S3C_TR				S3C_HSUDC_REG(0x18) /* Test Register */
+#define S3C_SSR				S3C_HSUDC_REG(0x1c) /* System Status */
+#	define S3C_SSR_DTZIEN_EN	(0xff8f)
+#	define S3C_SSR_ERR		(0xff80)
+#	define S3C_SSR_VBUSON		(1 << 8)
+#	define S3C_SSR_HSP		(1 << 4)
+#	define S3C_SSR_SDE		(1 << 3)
+#	define S3C_SSR_RESUME		(1 << 2)
+#	define S3C_SSR_SUSPEND		(1 << 1)
+#	define S3C_SSR_RESET		(1 << 0)
+#define S3C_SCR				S3C_HSUDC_REG(0x20) /* System Control */
+#	define S3C_SCR_DTZIEN_EN	(1 << 14)
+#	define S3C_SCR_RRD_EN		(1 << 5)
+#	define S3C_SCR_SUS_EN		(1 << 1)
+#	define S3C_SCR_RST_EN		(1 << 0)
+#define S3C_EP0SR			S3C_HSUDC_REG(0x24) /* EP0 Status */
+#	define S3C_EP0SR_EP0_LWO	(1 << 6)
+#	define S3C_EP0SR_STALL		(1 << 4)
+#	define S3C_EP0SR_TX_SUCCESS	(1 << 1)
+#	define S3C_EP0SR_RX_SUCCESS	(1 << 0)
+#define S3C_EP0CR			S3C_HSUDC_REG(0x28) /* EP0 Control */
+#define S3C_BR(_x)			S3C_HSUDC_REG(0x60 + (_x * 4))
+
+/* Indexed Registers */
+#define S3C_ESR				S3C_HSUDC_REG(0x2c) /* EPn Status */
+#	define S3C_ESR_FLUSH		(1 << 6)
+#	define S3C_ESR_STALL		(1 << 5)
+#	define S3C_ESR_LWO		(1 << 4)
+#	define S3C_ESR_PSIF_ONE		(1 << 2)
+#	define S3C_ESR_PSIF_TWO		(2 << 2)
+#	define S3C_ESR_TX_SUCCESS	(1 << 1)
+#	define S3C_ESR_RX_SUCCESS	(1 << 0)
+#define S3C_ECR				S3C_HSUDC_REG(0x30) /* EPn Control */
+#	define S3C_ECR_DUEN		(1 << 7)
+#	define S3C_ECR_FLUSH		(1 << 6)
+#	define S3C_ECR_STALL		(1 << 1)
+#	define S3C_ECR_IEMS		(1 << 0)
+#define S3C_BRCR			S3C_HSUDC_REG(0x34) /* Read Count */
+#define S3C_BWCR			S3C_HSUDC_REG(0x38) /* Write Count */
+#define S3C_MPR				S3C_HSUDC_REG(0x3c) /* Max Pkt Size */
+
+#define WAIT_FOR_SETUP			(0)
+#define DATA_STATE_XMIT			(1)
+#define DATA_STATE_RECV			(2)
+
+/**
+ * struct s3c_hsudc_ep - Endpoint representation used by driver.
+ * @ep: USB gadget layer representation of device endpoint.
+ * @name: Endpoint name (as required by ep autoconfiguration).
+ * @dev: Reference to the device controller to which this EP belongs.
+ * @desc: Endpoint descriptor obtained from the gadget driver.
+ * @queue: Transfer request queue for the endpoint.
+ * @stopped: Maintains state of endpoint, set if EP is halted.
+ * @bEndpointAddress: EP address (including direction bit).
+ * @fifo: Base address of EP FIFO.
+ */
+struct s3c_hsudc_ep {
+	struct usb_ep ep;
+	char name[20];
+	struct s3c_hsudc *dev;
+	const struct usb_endpoint_descriptor *desc;
+	struct list_head queue;
+	u8 stopped;
+	u8 bEndpointAddress;
+	u32 fifo;
+};
+
+/**
+ * struct s3c_hsudc_req - Driver encapsulation of USB gadget transfer request.
+ * @req: Reference to USB gadget transfer request.
+ * @queue: Used for inserting this request to the endpoint request queue.
+ */
+struct s3c_hsudc_req {
+	struct usb_request req;
+	struct list_head queue;
+};
+
+/**
+ * struct s3c_hsudc - Driver's abstraction of the device controller.
+ * @gadget: Instance of usb_gadget which is referenced by gadget driver.
+ * @driver: Reference to currenty active gadget driver.
+ * @dev: The device reference used by probe function.
+ * @lock: Lock to synchronize the usage of Endpoints (EP's are indexed).
+ * @regs: Remapped base address of controller's register space.
+ * @mem_rsrc: Device memory resource used for remapping device register space.
+ * irq: IRQ number used by the controller.
+ * uclk: Reference to the controller clock.
+ * ep0state: Current state of EP0.
+ * ep: List of endpoints supported by the controller.
+ */
+struct s3c_hsudc {
+	struct usb_gadget gadget;
+	struct usb_gadget_driver *driver;
+	struct device *dev;
+	struct s3c24xx_hsudc_platdata *pd;
+	spinlock_t lock;
+	void __iomem *regs;
+	struct resource *mem_rsrc;
+	int irq;
+	struct clk *uclk;
+	int ep0state;
+	struct s3c_hsudc_ep ep[];
+};
+
+#define ep_maxpacket(_ep)	((_ep)->ep.maxpacket)
+#define ep_is_in(_ep)		((_ep)->bEndpointAddress & USB_DIR_IN)
+#define ep_index(_ep)		((_ep)->bEndpointAddress & \
+					USB_ENDPOINT_NUMBER_MASK)
+
+static struct s3c_hsudc *the_controller;
+static const char driver_name[] = "s3c-udc";
+static const char ep0name[] = "ep0-control";
+
+static inline struct s3c_hsudc_req *our_req(struct usb_request *req)
+{
+	return container_of(req, struct s3c_hsudc_req, req);
+}
+
+static inline struct s3c_hsudc_ep *our_ep(struct usb_ep *ep)
+{
+	return container_of(ep, struct s3c_hsudc_ep, ep);
+}
+
+static inline struct s3c_hsudc *to_hsudc(struct usb_gadget *gadget)
+{
+	return container_of(gadget, struct s3c_hsudc, gadget);
+}
+
+static inline void set_index(struct s3c_hsudc *hsudc, int ep_addr)
+{
+	ep_addr &= USB_ENDPOINT_NUMBER_MASK;
+	__raw_writel(ep_addr, hsudc->regs + S3C_IR);
+}
+
+static inline void __orr32(void __iomem *ptr, u32 val)
+{
+	writel(readl(ptr) | val, ptr);
+}
+
+static void s3c_hsudc_init_phy(void)
+{
+	u32 cfg;
+
+	cfg = __raw_readl(S3C2443_PWRCFG) | S3C2443_PWRCFG_USBPHY;
+	__raw_writel(cfg, S3C2443_PWRCFG);
+
+	cfg = __raw_readl(S3C2443_URSTCON);
+	cfg |= (S3C2443_URSTCON_FUNCRST | S3C2443_URSTCON_PHYRST);
+	__raw_writel(cfg, S3C2443_URSTCON);
+	mdelay(1);
+
+	cfg = __raw_readl(S3C2443_URSTCON);
+	cfg &= ~(S3C2443_URSTCON_FUNCRST | S3C2443_URSTCON_PHYRST);
+	__raw_writel(cfg, S3C2443_URSTCON);
+
+	cfg = __raw_readl(S3C2443_PHYCTRL);
+	cfg &= ~(S3C2443_PHYCTRL_CLKSEL | S3C2443_PHYCTRL_DSPORT);
+	cfg |= (S3C2443_PHYCTRL_EXTCLK | S3C2443_PHYCTRL_PLLSEL);
+	__raw_writel(cfg, S3C2443_PHYCTRL);
+
+	cfg = __raw_readl(S3C2443_PHYPWR);
+	cfg &= ~(S3C2443_PHYPWR_FSUSPEND | S3C2443_PHYPWR_PLL_PWRDN |
+		S3C2443_PHYPWR_XO_ON | S3C2443_PHYPWR_PLL_REFCLK |
+		S3C2443_PHYPWR_ANALOG_PD);
+	cfg |= S3C2443_PHYPWR_COMMON_ON;
+	__raw_writel(cfg, S3C2443_PHYPWR);
+
+	cfg = __raw_readl(S3C2443_UCLKCON);
+	cfg |= (S3C2443_UCLKCON_DETECT_VBUS | S3C2443_UCLKCON_FUNC_CLKEN |
+		S3C2443_UCLKCON_TCLKEN);
+	__raw_writel(cfg, S3C2443_UCLKCON);
+}
+
+static void s3c_hsudc_uninit_phy(void)
+{
+	u32 cfg;
+
+	cfg = __raw_readl(S3C2443_PWRCFG) & ~S3C2443_PWRCFG_USBPHY;
+	__raw_writel(cfg, S3C2443_PWRCFG);
+
+	__raw_writel(S3C2443_PHYPWR_FSUSPEND, S3C2443_PHYPWR);
+
+	cfg = __raw_readl(S3C2443_UCLKCON) & ~S3C2443_UCLKCON_FUNC_CLKEN;
+	__raw_writel(cfg, S3C2443_UCLKCON);
+}
+
+/**
+ * s3c_hsudc_complete_request - Complete a transfer request.
+ * @hsep: Endpoint to which the request belongs.
+ * @hsreq: Transfer request to be completed.
+ * @status: Transfer completion status for the transfer request.
+ */
+static void s3c_hsudc_complete_request(struct s3c_hsudc_ep *hsep,
+				struct s3c_hsudc_req *hsreq, int status)
+{
+	unsigned int stopped = hsep->stopped;
+	struct s3c_hsudc *hsudc = hsep->dev;
+
+	list_del_init(&hsreq->queue);
+	hsreq->req.status = status;
+
+	if (!ep_index(hsep)) {
+		hsudc->ep0state = WAIT_FOR_SETUP;
+		hsep->bEndpointAddress &= ~USB_DIR_IN;
+	}
+
+	hsep->stopped = 1;
+	spin_unlock(&hsudc->lock);
+	if (hsreq->req.complete != NULL)
+		hsreq->req.complete(&hsep->ep, &hsreq->req);
+	spin_lock(&hsudc->lock);
+	hsep->stopped = stopped;
+}
+
+/**
+ * s3c_hsudc_nuke_ep - Terminate all requests queued for a endpoint.
+ * @hsep: Endpoint for which queued requests have to be terminated.
+ * @status: Transfer completion status for the transfer request.
+ */
+static void s3c_hsudc_nuke_ep(struct s3c_hsudc_ep *hsep, int status)
+{
+	struct s3c_hsudc_req *hsreq;
+
+	while (!list_empty(&hsep->queue)) {
+		hsreq = list_entry(hsep->queue.next,
+				struct s3c_hsudc_req, queue);
+		s3c_hsudc_complete_request(hsep, hsreq, status);
+	}
+}
+
+/**
+ * s3c_hsudc_stop_activity - Stop activity on all endpoints.
+ * @hsudc: Device controller for which EP activity is to be stopped.
+ * @driver: Reference to the gadget driver which is currently active.
+ *
+ * All the endpoints are stopped and any pending transfer requests if any on
+ * the endpoint are terminated.
+ */
+static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc,
+			  struct usb_gadget_driver *driver)
+{
+	struct s3c_hsudc_ep *hsep;
+	int epnum;
+
+	hsudc->gadget.speed = USB_SPEED_UNKNOWN;
+
+	for (epnum = 0; epnum < hsudc->pd->epnum; epnum++) {
+		hsep = &hsudc->ep[epnum];
+		hsep->stopped = 1;
+		s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN);
+	}
+
+	spin_unlock(&hsudc->lock);
+	driver->disconnect(&hsudc->gadget);
+	spin_lock(&hsudc->lock);
+}
+
+/**
+ * s3c_hsudc_read_setup_pkt - Read the received setup packet from EP0 fifo.
+ * @hsudc: Device controller from which setup packet is to be read.
+ * @buf: The buffer into which the setup packet is read.
+ *
+ * The setup packet received in the EP0 fifo is read and stored into a
+ * given buffer address.
+ */
+
+static void s3c_hsudc_read_setup_pkt(struct s3c_hsudc *hsudc, u16 *buf)
+{
+	int count;
+
+	count = __raw_readl(hsudc->regs + S3C_BRCR);
+	while (count--)
+		*buf++ = (u16)__raw_readl(hsudc->regs + S3C_BR(0));
+
+	__raw_writel(S3C_EP0SR_RX_SUCCESS, hsudc->regs + S3C_EP0SR);
+}
+
+/**
+ * s3c_hsudc_write_fifo - Write next chunk of transfer data to EP fifo.
+ * @hsep: Endpoint to which the data is to be written.
+ * @hsreq: Transfer request from which the next chunk of data is written.
+ *
+ * Write the next chunk of data from a transfer request to the endpoint FIFO.
+ * If the transfer request completes, 1 is returned, otherwise 0 is returned.
+ */
+static int s3c_hsudc_write_fifo(struct s3c_hsudc_ep *hsep,
+				struct s3c_hsudc_req *hsreq)
+{
+	u16 *buf;
+	u32 max = ep_maxpacket(hsep);
+	u32 count, length;
+	int is_last;
+	u32 fifo = hsep->fifo;
+
+	buf = hsreq->req.buf + hsreq->req.actual;
+	prefetch(buf);
+
+	length = hsreq->req.length - hsreq->req.actual;
+	length = min(length, max);
+	hsreq->req.actual += length;
+
+	__raw_writel(length, hsep->dev->regs + S3C_BWCR);
+	for (count = 0; count < length; count += 2)
+		__raw_writel(*buf++, fifo);
+
+	if (count != max) {
+		is_last = 1;
+	} else {
+		if (hsreq->req.length != hsreq->req.actual || hsreq->req.zero)
+			is_last = 0;
+		else
+			is_last = 1;
+	}
+
+	if (is_last) {
+		s3c_hsudc_complete_request(hsep, hsreq, 0);
+		return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * s3c_hsudc_read_fifo - Read the next chunk of data from EP fifo.
+ * @hsep: Endpoint from which the data is to be read.
+ * @hsreq: Transfer request to which the next chunk of data read is written.
+ *
+ * Read the next chunk of data from the endpoint FIFO and a write it to the
+ * transfer request buffer. If the transfer request completes, 1 is returned,
+ * otherwise 0 is returned.
+ */
+static int s3c_hsudc_read_fifo(struct s3c_hsudc_ep *hsep,
+				struct s3c_hsudc_req *hsreq)
+{
+	struct s3c_hsudc *hsudc = hsep->dev;
+	u32 csr, offset;
+	u16 *buf, word;
+	u32 buflen, rcnt, rlen;
+	u32 fifo = hsep->fifo;
+	u32 is_short = 0;
+
+	offset = (ep_index(hsep)) ? S3C_ESR : S3C_EP0SR;
+	csr = __raw_readl(hsudc->regs + offset);
+	if (!(csr & S3C_ESR_RX_SUCCESS))
+		return -EINVAL;
+
+	buf = hsreq->req.buf + hsreq->req.actual;
+	prefetchw(buf);
+	buflen = hsreq->req.length - hsreq->req.actual;
+
+	rcnt = __raw_readl(hsudc->regs + S3C_BRCR);
+	rlen = (csr & S3C_ESR_LWO) ? (rcnt * 2 - 1) : (rcnt * 2);
+
+	hsreq->req.actual += min(rlen, buflen);
+	is_short = (rlen < hsep->ep.maxpacket);
+
+	while (rcnt-- != 0) {
+		word = (u16)__raw_readl(fifo);
+		if (buflen) {
+			*buf++ = word;
+			buflen--;
+		} else {
+			hsreq->req.status = -EOVERFLOW;
+		}
+	}
+
+	__raw_writel(S3C_ESR_RX_SUCCESS, hsudc->regs + offset);
+
+	if (is_short || hsreq->req.actual == hsreq->req.length) {
+		s3c_hsudc_complete_request(hsep, hsreq, 0);
+		return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * s3c_hsudc_epin_intr - Handle in-endpoint interrupt.
+ * @hsudc - Device controller for which the interrupt is to be handled.
+ * @ep_idx - Endpoint number on which an interrupt is pending.
+ *
+ * Handles interrupt for a in-endpoint. The interrupts that are handled are
+ * stall and data transmit complete interrupt.
+ */
+static void s3c_hsudc_epin_intr(struct s3c_hsudc *hsudc, u32 ep_idx)
+{
+	struct s3c_hsudc_ep *hsep = &hsudc->ep[ep_idx];
+	struct s3c_hsudc_req *hsreq;
+	u32 csr;
+
+	csr = __raw_readl((u32)hsudc->regs + S3C_ESR);
+	if (csr & S3C_ESR_STALL) {
+		__raw_writel(S3C_ESR_STALL, hsudc->regs + S3C_ESR);
+		return;
+	}
+
+	if (csr & S3C_ESR_TX_SUCCESS) {
+		__raw_writel(S3C_ESR_TX_SUCCESS, hsudc->regs + S3C_ESR);
+		if (list_empty(&hsep->queue))
+			return;
+
+		hsreq = list_entry(hsep->queue.next,
+				struct s3c_hsudc_req, queue);
+		if ((s3c_hsudc_write_fifo(hsep, hsreq) == 0) &&
+				(csr & S3C_ESR_PSIF_TWO))
+			s3c_hsudc_write_fifo(hsep, hsreq);
+	}
+}
+
+/**
+ * s3c_hsudc_epout_intr - Handle out-endpoint interrupt.
+ * @hsudc - Device controller for which the interrupt is to be handled.
+ * @ep_idx - Endpoint number on which an interrupt is pending.
+ *
+ * Handles interrupt for a out-endpoint. The interrupts that are handled are
+ * stall, flush and data ready interrupt.
+ */
+static void s3c_hsudc_epout_intr(struct s3c_hsudc *hsudc, u32 ep_idx)
+{
+	struct s3c_hsudc_ep *hsep = &hsudc->ep[ep_idx];
+	struct s3c_hsudc_req *hsreq;
+	u32 csr;
+
+	csr = __raw_readl((u32)hsudc->regs + S3C_ESR);
+	if (csr & S3C_ESR_STALL) {
+		writel(S3C_ESR_STALL, hsudc->regs + S3C_ESR);
+		return;
+	}
+
+	if (csr & S3C_ESR_FLUSH) {
+		__orr32(hsudc->regs + S3C_ECR, S3C_ECR_FLUSH);
+		return;
+	}
+
+	if (csr & S3C_ESR_RX_SUCCESS) {
+		if (list_empty(&hsep->queue))
+			return;
+
+		hsreq = list_entry(hsep->queue.next,
+				struct s3c_hsudc_req, queue);
+		if (((s3c_hsudc_read_fifo(hsep, hsreq)) == 0) &&
+				(csr & S3C_ESR_PSIF_TWO))
+			s3c_hsudc_read_fifo(hsep, hsreq);
+	}
+}
+
+/** s3c_hsudc_set_halt - Set or clear a endpoint halt.
+ * @_ep: Endpoint on which halt has to be set or cleared.
+ * @value: 1 for setting halt on endpoint, 0 to clear halt.
+ *
+ * Set or clear endpoint halt. If halt is set, the endpoint is stopped.
+ * If halt is cleared, for in-endpoints, if there are any pending
+ * transfer requests, transfers are started.
+ */
+static int s3c_hsudc_set_halt(struct usb_ep *_ep, int value)
+{
+	struct s3c_hsudc_ep *hsep = our_ep(_ep);
+	struct s3c_hsudc *hsudc = hsep->dev;
+	struct s3c_hsudc_req *hsreq;
+	unsigned long irqflags;
+	u32 ecr;
+	u32 offset;
+
+	if (value && ep_is_in(hsep) && !list_empty(&hsep->queue))
+		return -EAGAIN;
+
+	spin_lock_irqsave(&hsudc->lock, irqflags);
+	set_index(hsudc, ep_index(hsep));
+	offset = (ep_index(hsep)) ? S3C_ECR : S3C_EP0CR;
+	ecr = __raw_readl(hsudc->regs + offset);
+
+	if (value) {
+		ecr |= S3C_ECR_STALL;
+		if (ep_index(hsep))
+			ecr |= S3C_ECR_FLUSH;
+		hsep->stopped = 1;
+	} else {
+		ecr &= ~S3C_ECR_STALL;
+		hsep->stopped = 0;
+	}
+	__raw_writel(ecr, hsudc->regs + offset);
+
+	if (ep_is_in(hsep) && !list_empty(&hsep->queue) && !value) {
+		hsreq = list_entry(hsep->queue.next,
+			struct s3c_hsudc_req, queue);
+		if (hsreq)
+			s3c_hsudc_write_fifo(hsep, hsreq);
+	}
+
+	spin_unlock_irqrestore(&hsudc->lock, irqflags);
+	return 0;
+}
+
+/** s3c_hsudc_handle_reqfeat - Handle set feature or clear feature requests.
+ * @_ep: Device controller on which the set/clear feature needs to be handled.
+ * @ctrl: Control request as received on the endpoint 0.
+ *
+ * Handle set feature or clear feature control requests on the control endpoint.
+ */
+static int s3c_hsudc_handle_reqfeat(struct s3c_hsudc *hsudc,
+					struct usb_ctrlrequest *ctrl)
+{
+	struct s3c_hsudc_ep *hsep;
+	bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE);
+	u8 ep_num = ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK;
+
+	if (ctrl->bRequestType == USB_RECIP_ENDPOINT) {
+		hsep = &hsudc->ep[ep_num];
+		switch (le16_to_cpu(ctrl->wValue)) {
+		case USB_ENDPOINT_HALT:
+			s3c_hsudc_set_halt(&hsep->ep, set);
+			return 0;
+		}
+	}
+
+	return -ENOENT;
+}
+
+/**
+ * s3c_hsudc_process_req_status - Handle get status control request.
+ * @hsudc: Device controller on which get status request has be handled.
+ * @ctrl: Control request as received on the endpoint 0.
+ *
+ * Handle get status control request received on control endpoint.
+ */
+static void s3c_hsudc_process_req_status(struct s3c_hsudc *hsudc,
+					struct usb_ctrlrequest *ctrl)
+{
+	struct s3c_hsudc_ep *hsep0 = &hsudc->ep[0];
+	struct s3c_hsudc_req hsreq;
+	struct s3c_hsudc_ep *hsep;
+	__le16 reply;
+	u8 epnum;
+
+	switch (ctrl->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_DEVICE:
+		reply = cpu_to_le16(0);
+		break;
+
+	case USB_RECIP_INTERFACE:
+		reply = cpu_to_le16(0);
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		epnum = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK;
+		hsep = &hsudc->ep[epnum];
+		reply = cpu_to_le16(hsep->stopped ? 1 : 0);
+		break;
+	}
+
+	INIT_LIST_HEAD(&hsreq.queue);
+	hsreq.req.length = 2;
+	hsreq.req.buf = &reply;
+	hsreq.req.actual = 0;
+	hsreq.req.complete = NULL;
+	s3c_hsudc_write_fifo(hsep0, &hsreq);
+}
+
+/**
+ * s3c_hsudc_process_setup - Process control request received on endpoint 0.
+ * @hsudc: Device controller on which control request has been received.
+ *
+ * Read the control request received on endpoint 0, decode it and handle
+ * the request.
+ */
+static void s3c_hsudc_process_setup(struct s3c_hsudc *hsudc)
+{
+	struct s3c_hsudc_ep *hsep = &hsudc->ep[0];
+	struct usb_ctrlrequest ctrl = {0};
+	int ret;
+
+	s3c_hsudc_nuke_ep(hsep, -EPROTO);
+	s3c_hsudc_read_setup_pkt(hsudc, (u16 *)&ctrl);
+
+	if (ctrl.bRequestType & USB_DIR_IN) {
+		hsep->bEndpointAddress |= USB_DIR_IN;
+		hsudc->ep0state = DATA_STATE_XMIT;
+	} else {
+		hsep->bEndpointAddress &= ~USB_DIR_IN;
+		hsudc->ep0state = DATA_STATE_RECV;
+	}
+
+	switch (ctrl.bRequest) {
+	case USB_REQ_SET_ADDRESS:
+		if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE))
+			break;
+		hsudc->ep0state = WAIT_FOR_SETUP;
+		return;
+
+	case USB_REQ_GET_STATUS:
+		if ((ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
+			break;
+		s3c_hsudc_process_req_status(hsudc, &ctrl);
+		return;
+
+	case USB_REQ_SET_FEATURE:
+	case USB_REQ_CLEAR_FEATURE:
+		if ((ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
+			break;
+		s3c_hsudc_handle_reqfeat(hsudc, &ctrl);
+		hsudc->ep0state = WAIT_FOR_SETUP;
+		return;
+	}
+
+	if (hsudc->driver) {
+		spin_unlock(&hsudc->lock);
+		ret = hsudc->driver->setup(&hsudc->gadget, &ctrl);
+		spin_lock(&hsudc->lock);
+
+		if (ctrl.bRequest == USB_REQ_SET_CONFIGURATION) {
+			hsep->bEndpointAddress &= ~USB_DIR_IN;
+			hsudc->ep0state = WAIT_FOR_SETUP;
+		}
+
+		if (ret < 0) {
+			dev_err(hsudc->dev, "setup failed, returned %d\n",
+						ret);
+			s3c_hsudc_set_halt(&hsep->ep, 1);
+			hsudc->ep0state = WAIT_FOR_SETUP;
+			hsep->bEndpointAddress &= ~USB_DIR_IN;
+		}
+	}
+}
+
+/** s3c_hsudc_handle_ep0_intr - Handle endpoint 0 interrupt.
+ * @hsudc: Device controller on which endpoint 0 interrupt has occured.
+ *
+ * Handle endpoint 0 interrupt when it occurs. EP0 interrupt could occur
+ * when a stall handshake is sent to host or data is sent/received on
+ * endpoint 0.
+ */
+static void s3c_hsudc_handle_ep0_intr(struct s3c_hsudc *hsudc)
+{
+	struct s3c_hsudc_ep *hsep = &hsudc->ep[0];
+	struct s3c_hsudc_req *hsreq;
+	u32 csr = __raw_readl(hsudc->regs + S3C_EP0SR);
+	u32 ecr;
+
+	if (csr & S3C_EP0SR_STALL) {
+		ecr = __raw_readl(hsudc->regs + S3C_EP0CR);
+		ecr &= ~(S3C_ECR_STALL | S3C_ECR_FLUSH);
+		__raw_writel(ecr, hsudc->regs + S3C_EP0CR);
+
+		__raw_writel(S3C_EP0SR_STALL, hsudc->regs + S3C_EP0SR);
+		hsep->stopped = 0;
+
+		s3c_hsudc_nuke_ep(hsep, -ECONNABORTED);
+		hsudc->ep0state = WAIT_FOR_SETUP;
+		hsep->bEndpointAddress &= ~USB_DIR_IN;
+		return;
+	}
+
+	if (csr & S3C_EP0SR_TX_SUCCESS) {
+		__raw_writel(S3C_EP0SR_TX_SUCCESS, hsudc->regs + S3C_EP0SR);
+		if (ep_is_in(hsep)) {
+			if (list_empty(&hsep->queue))
+				return;
+
+			hsreq = list_entry(hsep->queue.next,
+					struct s3c_hsudc_req, queue);
+			s3c_hsudc_write_fifo(hsep, hsreq);
+		}
+	}
+
+	if (csr & S3C_EP0SR_RX_SUCCESS) {
+		if (hsudc->ep0state == WAIT_FOR_SETUP)
+			s3c_hsudc_process_setup(hsudc);
+		else {
+			if (!ep_is_in(hsep)) {
+				if (list_empty(&hsep->queue))
+					return;
+				hsreq = list_entry(hsep->queue.next,
+					struct s3c_hsudc_req, queue);
+				s3c_hsudc_read_fifo(hsep, hsreq);
+			}
+		}
+	}
+}
+
+/**
+ * s3c_hsudc_ep_enable - Enable a endpoint.
+ * @_ep: The endpoint to be enabled.
+ * @desc: Endpoint descriptor.
+ *
+ * Enables a endpoint when called from the gadget driver. Endpoint stall if
+ * any is cleared, transfer type is configured and endpoint interrupt is
+ * enabled.
+ */
+static int s3c_hsudc_ep_enable(struct usb_ep *_ep,
+				const struct usb_endpoint_descriptor *desc)
+{
+	struct s3c_hsudc_ep *hsep;
+	struct s3c_hsudc *hsudc;
+	unsigned long flags;
+	u32 ecr = 0;
+
+	hsep = container_of(_ep, struct s3c_hsudc_ep, ep);
+	if (!_ep || !desc || hsep->desc || _ep->name == ep0name
+		|| desc->bDescriptorType != USB_DT_ENDPOINT
+		|| hsep->bEndpointAddress != desc->bEndpointAddress
+		|| ep_maxpacket(hsep) < le16_to_cpu(desc->wMaxPacketSize))
+		return -EINVAL;
+
+	if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
+		&& le16_to_cpu(desc->wMaxPacketSize) != ep_maxpacket(hsep))
+		|| !desc->wMaxPacketSize)
+		return -ERANGE;
+
+	hsudc = hsep->dev;
+	if (!hsudc->driver || hsudc->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	spin_lock_irqsave(&hsudc->lock, flags);
+
+	set_index(hsudc, hsep->bEndpointAddress);
+	ecr |= ((usb_endpoint_xfer_int(desc)) ? S3C_ECR_IEMS : S3C_ECR_DUEN);
+	writel(ecr, hsudc->regs + S3C_ECR);
+
+	hsep->stopped = 0;
+	hsep->desc = desc;
+	hsep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+
+	s3c_hsudc_set_halt(_ep, 0);
+	__set_bit(ep_index(hsep), hsudc->regs + S3C_EIER);
+
+	spin_unlock_irqrestore(&hsudc->lock, flags);
+	return 0;
+}
+
+/**
+ * s3c_hsudc_ep_disable - Disable a endpoint.
+ * @_ep: The endpoint to be disabled.
+ * @desc: Endpoint descriptor.
+ *
+ * Disables a endpoint when called from the gadget driver.
+ */
+static int s3c_hsudc_ep_disable(struct usb_ep *_ep)
+{
+	struct s3c_hsudc_ep *hsep = our_ep(_ep);
+	struct s3c_hsudc *hsudc = hsep->dev;
+	unsigned long flags;
+
+	hsep = container_of(_ep, struct s3c_hsudc_ep, ep);
+	if (!_ep || !hsep->desc)
+		return -EINVAL;
+
+	spin_lock_irqsave(&hsudc->lock, flags);
+
+	set_index(hsudc, hsep->bEndpointAddress);
+	__clear_bit(ep_index(hsep), hsudc->regs + S3C_EIER);
+
+	s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN);
+
+	hsep->desc = 0;
+	hsep->stopped = 1;
+
+	spin_unlock_irqrestore(&hsudc->lock, flags);
+	return 0;
+}
+
+/**
+ * s3c_hsudc_alloc_request - Allocate a new request.
+ * @_ep: Endpoint for which request is allocated (not used).
+ * @gfp_flags: Flags used for the allocation.
+ *
+ * Allocates a single transfer request structure when called from gadget driver.
+ */
+static struct usb_request *s3c_hsudc_alloc_request(struct usb_ep *_ep,
+						gfp_t gfp_flags)
+{
+	struct s3c_hsudc_req *hsreq;
+
+	hsreq = kzalloc(sizeof *hsreq, gfp_flags);
+	if (!hsreq)
+		return 0;
+
+	INIT_LIST_HEAD(&hsreq->queue);
+	return &hsreq->req;
+}
+
+/**
+ * s3c_hsudc_free_request - Deallocate a request.
+ * @ep: Endpoint for which request is deallocated (not used).
+ * @_req: Request to be deallocated.
+ *
+ * Allocates a single transfer request structure when called from gadget driver.
+ */
+static void s3c_hsudc_free_request(struct usb_ep *ep, struct usb_request *_req)
+{
+	struct s3c_hsudc_req *hsreq;
+
+	hsreq = container_of(_req, struct s3c_hsudc_req, req);
+	WARN_ON(!list_empty(&hsreq->queue));
+	kfree(hsreq);
+}
+
+/**
+ * s3c_hsudc_queue - Queue a transfer request for the endpoint.
+ * @_ep: Endpoint for which the request is queued.
+ * @_req: Request to be queued.
+ * @gfp_flags: Not used.
+ *
+ * Start or enqueue a request for a endpoint when called from gadget driver.
+ */
+static int s3c_hsudc_queue(struct usb_ep *_ep, struct usb_request *_req,
+			gfp_t gfp_flags)
+{
+	struct s3c_hsudc_req *hsreq;
+	struct s3c_hsudc_ep *hsep;
+	struct s3c_hsudc *hsudc;
+	unsigned long flags;
+	u32 offset;
+	u32 csr;
+
+	hsreq = container_of(_req, struct s3c_hsudc_req, req);
+	if ((!_req || !_req->complete || !_req->buf ||
+		!list_empty(&hsreq->queue)))
+		return -EINVAL;
+
+	hsep = container_of(_ep, struct s3c_hsudc_ep, ep);
+	hsudc = hsep->dev;
+	if (!hsudc->driver || hsudc->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	spin_lock_irqsave(&hsudc->lock, flags);
+	set_index(hsudc, hsep->bEndpointAddress);
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	if (!ep_index(hsep) && _req->length == 0) {
+		hsudc->ep0state = WAIT_FOR_SETUP;
+		s3c_hsudc_complete_request(hsep, hsreq, 0);
+		spin_unlock_irqrestore(&hsudc->lock, flags);
+		return 0;
+	}
+
+	if (list_empty(&hsep->queue) && !hsep->stopped) {
+		offset = (ep_index(hsep)) ? S3C_ESR : S3C_EP0SR;
+		if (ep_is_in(hsep)) {
+			csr = __raw_readl((u32)hsudc->regs + offset);
+			if (!(csr & S3C_ESR_TX_SUCCESS) &&
+				(s3c_hsudc_write_fifo(hsep, hsreq) == 1))
+				hsreq = 0;
+		} else {
+			csr = __raw_readl((u32)hsudc->regs + offset);
+			if ((csr & S3C_ESR_RX_SUCCESS)
+				   && (s3c_hsudc_read_fifo(hsep, hsreq) == 1))
+				hsreq = 0;
+		}
+	}
+
+	if (hsreq != 0)
+		list_add_tail(&hsreq->queue, &hsep->queue);
+
+	spin_unlock_irqrestore(&hsudc->lock, flags);
+	return 0;
+}
+
+/**
+ * s3c_hsudc_dequeue - Dequeue a transfer request from an endpoint.
+ * @_ep: Endpoint from which the request is dequeued.
+ * @_req: Request to be dequeued.
+ *
+ * Dequeue a request from a endpoint when called from gadget driver.
+ */
+static int s3c_hsudc_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct s3c_hsudc_ep *hsep = our_ep(_ep);
+	struct s3c_hsudc *hsudc = hsep->dev;
+	struct s3c_hsudc_req *hsreq;
+	unsigned long flags;
+
+	hsep = container_of(_ep, struct s3c_hsudc_ep, ep);
+	if (!_ep || hsep->ep.name == ep0name)
+		return -EINVAL;
+
+	spin_lock_irqsave(&hsudc->lock, flags);
+
+	list_for_each_entry(hsreq, &hsep->queue, queue) {
+		if (&hsreq->req == _req)
+			break;
+	}
+	if (&hsreq->req != _req) {
+		spin_unlock_irqrestore(&hsudc->lock, flags);
+		return -EINVAL;
+	}
+
+	set_index(hsudc, hsep->bEndpointAddress);
+	s3c_hsudc_complete_request(hsep, hsreq, -ECONNRESET);
+
+	spin_unlock_irqrestore(&hsudc->lock, flags);
+	return 0;
+}
+
+static struct usb_ep_ops s3c_hsudc_ep_ops = {
+	.enable = s3c_hsudc_ep_enable,
+	.disable = s3c_hsudc_ep_disable,
+	.alloc_request = s3c_hsudc_alloc_request,
+	.free_request = s3c_hsudc_free_request,
+	.queue = s3c_hsudc_queue,
+	.dequeue = s3c_hsudc_dequeue,
+	.set_halt = s3c_hsudc_set_halt,
+};
+
+/**
+ * s3c_hsudc_initep - Initialize a endpoint to default state.
+ * @hsudc - Reference to the device controller.
+ * @hsep - Endpoint to be initialized.
+ * @epnum - Address to be assigned to the endpoint.
+ *
+ * Initialize a endpoint with default configuration.
+ */
+static void s3c_hsudc_initep(struct s3c_hsudc *hsudc,
+				struct s3c_hsudc_ep *hsep, int epnum)
+{
+	char *dir;
+
+	if ((epnum % 2) == 0) {
+		dir = "out";
+	} else {
+		dir = "in";
+		hsep->bEndpointAddress = USB_DIR_IN;
+	}
+
+	hsep->bEndpointAddress |= epnum;
+	if (epnum)
+		snprintf(hsep->name, sizeof(hsep->name), "ep%d%s", epnum, dir);
+	else
+		snprintf(hsep->name, sizeof(hsep->name), "%s", ep0name);
+
+	INIT_LIST_HEAD(&hsep->queue);
+	INIT_LIST_HEAD(&hsep->ep.ep_list);
+	if (epnum)
+		list_add_tail(&hsep->ep.ep_list, &hsudc->gadget.ep_list);
+
+	hsep->dev = hsudc;
+	hsep->ep.name = hsep->name;
+	hsep->ep.maxpacket = epnum ? 512 : 64;
+	hsep->ep.ops = &s3c_hsudc_ep_ops;
+	hsep->fifo = (u32)(hsudc->regs + S3C_BR(epnum));
+	hsep->desc = 0;
+	hsep->stopped = 0;
+
+	set_index(hsudc, epnum);
+	__raw_writel(hsep->ep.maxpacket, hsudc->regs + S3C_MPR);
+}
+
+/**
+ * s3c_hsudc_setup_ep - Configure all endpoints to default state.
+ * @hsudc: Reference to device controller.
+ *
+ * Configures all endpoints to default state.
+ */
+static void s3c_hsudc_setup_ep(struct s3c_hsudc *hsudc)
+{
+	int epnum;
+
+	hsudc->ep0state = WAIT_FOR_SETUP;
+	INIT_LIST_HEAD(&hsudc->gadget.ep_list);
+	for (epnum = 0; epnum < hsudc->pd->epnum; epnum++)
+		s3c_hsudc_initep(hsudc, &hsudc->ep[epnum], epnum);
+}
+
+/**
+ * s3c_hsudc_reconfig - Reconfigure the device controller to default state.
+ * @hsudc: Reference to device controller.
+ *
+ * Reconfigures the device controller registers to a default state.
+ */
+static void s3c_hsudc_reconfig(struct s3c_hsudc *hsudc)
+{
+	__raw_writel(0xAA, hsudc->regs + S3C_EDR);
+	__raw_writel(1, hsudc->regs + S3C_EIER);
+	__raw_writel(0, hsudc->regs + S3C_TR);
+	__raw_writel(S3C_SCR_DTZIEN_EN | S3C_SCR_RRD_EN | S3C_SCR_SUS_EN |
+			S3C_SCR_RST_EN, hsudc->regs + S3C_SCR);
+	__raw_writel(0, hsudc->regs + S3C_EP0CR);
+
+	s3c_hsudc_setup_ep(hsudc);
+}
+
+/**
+ * s3c_hsudc_irq - Interrupt handler for device controller.
+ * @irq: Not used.
+ * @_dev: Reference to the device controller.
+ *
+ * Interrupt handler for the device controller. This handler handles controller
+ * interrupts and endpoint interrupts.
+ */
+static irqreturn_t s3c_hsudc_irq(int irq, void *_dev)
+{
+	struct s3c_hsudc *hsudc = _dev;
+	struct s3c_hsudc_ep *hsep;
+	u32 ep_intr;
+	u32 sys_status;
+	u32 ep_idx;
+
+	spin_lock(&hsudc->lock);
+
+	sys_status = __raw_readl(hsudc->regs + S3C_SSR);
+	ep_intr = __raw_readl(hsudc->regs + S3C_EIR) & 0x3FF;
+
+	if (!ep_intr && !(sys_status & S3C_SSR_DTZIEN_EN)) {
+		spin_unlock(&hsudc->lock);
+		return IRQ_HANDLED;
+	}
+
+	if (sys_status) {
+		if (sys_status & S3C_SSR_VBUSON)
+			__raw_writel(S3C_SSR_VBUSON, hsudc->regs + S3C_SSR);
+
+		if (sys_status & S3C_SSR_ERR)
+			__raw_writel(S3C_SSR_ERR, hsudc->regs + S3C_SSR);
+
+		if (sys_status & S3C_SSR_SDE) {
+			__raw_writel(S3C_SSR_SDE, hsudc->regs + S3C_SSR);
+			hsudc->gadget.speed = (sys_status & S3C_SSR_HSP) ?
+				USB_SPEED_HIGH : USB_SPEED_FULL;
+		}
+
+		if (sys_status & S3C_SSR_SUSPEND) {
+			__raw_writel(S3C_SSR_SUSPEND, hsudc->regs + S3C_SSR);
+			if (hsudc->gadget.speed != USB_SPEED_UNKNOWN
+				&& hsudc->driver && hsudc->driver->suspend)
+				hsudc->driver->suspend(&hsudc->gadget);
+		}
+
+		if (sys_status & S3C_SSR_RESUME) {
+			__raw_writel(S3C_SSR_RESUME, hsudc->regs + S3C_SSR);
+			if (hsudc->gadget.speed != USB_SPEED_UNKNOWN
+				&& hsudc->driver && hsudc->driver->resume)
+				hsudc->driver->resume(&hsudc->gadget);
+		}
+
+		if (sys_status & S3C_SSR_RESET) {
+			__raw_writel(S3C_SSR_RESET, hsudc->regs + S3C_SSR);
+			for (ep_idx = 0; ep_idx < hsudc->pd->epnum; ep_idx++) {
+				hsep = &hsudc->ep[ep_idx];
+				hsep->stopped = 1;
+				s3c_hsudc_nuke_ep(hsep, -ECONNRESET);
+			}
+			s3c_hsudc_reconfig(hsudc);
+			hsudc->ep0state = WAIT_FOR_SETUP;
+		}
+	}
+
+	if (ep_intr & S3C_EIR_EP0) {
+		__raw_writel(S3C_EIR_EP0, hsudc->regs + S3C_EIR);
+		set_index(hsudc, 0);
+		s3c_hsudc_handle_ep0_intr(hsudc);
+	}
+
+	ep_intr >>= 1;
+	ep_idx = 1;
+	while (ep_intr) {
+		if (ep_intr & 1)  {
+			hsep = &hsudc->ep[ep_idx];
+			set_index(hsudc, ep_idx);
+			__raw_writel(1 << ep_idx, hsudc->regs + S3C_EIR);
+			if (ep_is_in(hsep))
+				s3c_hsudc_epin_intr(hsudc, ep_idx);
+			else
+				s3c_hsudc_epout_intr(hsudc, ep_idx);
+		}
+		ep_intr >>= 1;
+		ep_idx++;
+	}
+
+	spin_unlock(&hsudc->lock);
+	return IRQ_HANDLED;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct s3c_hsudc *hsudc = the_controller;
+	int ret;
+
+	if (!driver
+		|| (driver->speed != USB_SPEED_FULL &&
+			driver->speed != USB_SPEED_HIGH)
+		|| !driver->bind
+		|| !driver->unbind || !driver->disconnect || !driver->setup)
+		return -EINVAL;
+
+	if (!hsudc)
+		return -ENODEV;
+
+	if (hsudc->driver)
+		return -EBUSY;
+
+	hsudc->driver = driver;
+	hsudc->gadget.dev.driver = &driver->driver;
+	hsudc->gadget.speed = USB_SPEED_UNKNOWN;
+	ret = device_add(&hsudc->gadget.dev);
+	if (ret) {
+		dev_err(hsudc->dev, "failed to register gadget device");
+		return ret;
+	}
+
+	ret = driver->bind(&hsudc->gadget);
+	if (ret) {
+		dev_err(hsudc->dev, "%s: bind failed\n", hsudc->gadget.name);
+		device_del(&hsudc->gadget.dev);
+
+		hsudc->driver = NULL;
+		hsudc->gadget.dev.driver = NULL;
+		return ret;
+	}
+
+	enable_irq(hsudc->irq);
+	dev_info(hsudc->dev, "bound driver %s\n", driver->driver.name);
+
+	s3c_hsudc_reconfig(hsudc);
+	s3c_hsudc_init_phy();
+	if (hsudc->pd->gpio_init)
+		hsudc->pd->gpio_init();
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct s3c_hsudc *hsudc = the_controller;
+	unsigned long flags;
+
+	if (!hsudc)
+		return -ENODEV;
+
+	if (!driver || driver != hsudc->driver || !driver->unbind)
+		return -EINVAL;
+
+	spin_lock_irqsave(&hsudc->lock, flags);
+	hsudc->driver = 0;
+	s3c_hsudc_uninit_phy();
+	if (hsudc->pd->gpio_uninit)
+		hsudc->pd->gpio_uninit();
+	s3c_hsudc_stop_activity(hsudc, driver);
+	spin_unlock_irqrestore(&hsudc->lock, flags);
+
+	driver->unbind(&hsudc->gadget);
+	device_del(&hsudc->gadget.dev);
+	disable_irq(hsudc->irq);
+
+	dev_info(hsudc->dev, "unregistered gadget driver '%s'\n",
+			driver->driver.name);
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+static inline u32 s3c_hsudc_read_frameno(struct s3c_hsudc *hsudc)
+{
+	return readl(hsudc->regs + S3C_FNR) & 0x3FF;
+}
+
+static int s3c_hsudc_gadget_getframe(struct usb_gadget *gadget)
+{
+	return s3c_hsudc_read_frameno(to_hsudc(gadget));
+}
+
+static struct usb_gadget_ops s3c_hsudc_gadget_ops = {
+	.get_frame	= s3c_hsudc_gadget_getframe,
+};
+
+static int s3c_hsudc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct s3c_hsudc *hsudc;
+	struct s3c24xx_hsudc_platdata *pd = pdev->dev.platform_data;
+	int ret;
+
+	hsudc = kzalloc(sizeof(struct s3c_hsudc) +
+			sizeof(struct s3c_hsudc_ep) * pd->epnum,
+			GFP_KERNEL);
+	if (!hsudc) {
+		dev_err(dev, "cannot allocate memory\n");
+		return -ENOMEM;
+	}
+
+	the_controller = hsudc;
+	platform_set_drvdata(pdev, dev);
+	hsudc->dev = dev;
+	hsudc->pd = pdev->dev.platform_data;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "unable to obtain driver resource data\n");
+		ret = -ENODEV;
+		goto err_res;
+	}
+
+	hsudc->mem_rsrc = request_mem_region(res->start, resource_size(res),
+				dev_name(&pdev->dev));
+	if (!hsudc->mem_rsrc) {
+		dev_err(dev, "failed to reserve register area\n");
+		ret = -ENODEV;
+		goto err_res;
+	}
+
+	hsudc->regs = ioremap(res->start, resource_size(res));
+	if (!hsudc->regs) {
+		dev_err(dev, "error mapping device register area\n");
+		ret = -EBUSY;
+		goto err_remap;
+	}
+
+	ret = platform_get_irq(pdev, 0);
+	if (ret < 0) {
+		dev_err(dev, "unable to obtain IRQ number\n");
+		goto err_irq;
+	}
+	hsudc->irq = ret;
+
+	ret = request_irq(hsudc->irq, s3c_hsudc_irq, 0, driver_name, hsudc);
+	if (ret < 0) {
+		dev_err(dev, "irq request failed\n");
+		goto err_irq;
+	}
+
+	spin_lock_init(&hsudc->lock);
+
+	device_initialize(&hsudc->gadget.dev);
+	dev_set_name(&hsudc->gadget.dev, "gadget");
+
+	hsudc->gadget.is_dualspeed = 1;
+	hsudc->gadget.ops = &s3c_hsudc_gadget_ops;
+	hsudc->gadget.name = dev_name(dev);
+	hsudc->gadget.dev.parent = dev;
+	hsudc->gadget.dev.dma_mask = dev->dma_mask;
+	hsudc->gadget.ep0 = &hsudc->ep[0].ep;
+
+	hsudc->gadget.is_otg = 0;
+	hsudc->gadget.is_a_peripheral = 0;
+
+	s3c_hsudc_setup_ep(hsudc);
+
+	hsudc->uclk = clk_get(&pdev->dev, "usb-device");
+	if (hsudc->uclk == NULL) {
+		dev_err(dev, "failed to find usb-device clock source\n");
+		return -ENOENT;
+	}
+	clk_enable(hsudc->uclk);
+
+	local_irq_disable();
+
+	disable_irq(hsudc->irq);
+	local_irq_enable();
+	return 0;
+
+err_irq:
+	iounmap(hsudc->regs);
+
+err_remap:
+	release_resource(hsudc->mem_rsrc);
+	kfree(hsudc->mem_rsrc);
+
+err_res:
+	kfree(hsudc);
+	return ret;
+}
+
+static struct platform_driver s3c_hsudc_driver = {
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "s3c-hsudc",
+	},
+	.probe		= s3c_hsudc_probe,
+};
+
+static int __init s3c_hsudc_modinit(void)
+{
+	return platform_driver_register(&s3c_hsudc_driver);
+}
+
+static void __exit s3c_hsudc_modexit(void)
+{
+	platform_driver_unregister(&s3c_hsudc_driver);
+}
+
+module_init(s3c_hsudc_modinit);
+module_exit(s3c_hsudc_modexit);
+
+MODULE_DESCRIPTION("Samsung S3C24XX USB high-speed controller driver");
+MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>");
+MODULE_LICENSE("GPL");
-- 
1.6.6.rc2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/4] ARM: S3C2416: Add support for USB 2.0 High-Speed gadget controller
  2010-10-13  0:10 [PATCH 0/4] USB: gadget: Add Samsung S3C24xx USB HS controller driver Sangbeom Kim
                   ` (2 preceding siblings ...)
  2010-10-13  0:10 ` [PATCH 3/4] USB: Gadget: Add Samsung S3C24XX USB High-Speed controller driver Sangbeom Kim
@ 2010-10-13  0:10 ` Sangbeom Kim
  2010-10-21 22:37 ` [PATCH 0/4] USB: gadget: Add Samsung S3C24xx USB HS controller driver Ben Dooks
  4 siblings, 0 replies; 8+ messages in thread
From: Sangbeom Kim @ 2010-10-13  0:10 UTC (permalink / raw)
  To: linux-arm-kernel

From: Thomas Abraham <thomas.ab@samsung.com>

Add support for USB 2.0 High-Speed gadget controller driver for Samsung's
S3C2416 processor.

Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
Signed-off-by: Sangbeom Kim <sbkim73@samsung.com>
---
 arch/arm/mach-s3c2416/mach-smdk2416.c |   27 +++++++++++++++++++++++++++
 1 files changed, 27 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-s3c2416/mach-smdk2416.c b/arch/arm/mach-s3c2416/mach-smdk2416.c
index 5fc3f67..429e720 100644
--- a/arch/arm/mach-s3c2416/mach-smdk2416.c
+++ b/arch/arm/mach-s3c2416/mach-smdk2416.c
@@ -23,6 +23,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/gpio.h>
 #include <linux/fb.h>
+#include <linux/delay.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -35,6 +36,7 @@
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-lcd.h>
+#include <mach/regs-s3c2443-clock.h>
 
 #include <mach/idle.h>
 #include <mach/leds-gpio.h>
@@ -46,6 +48,7 @@
 #include <plat/devs.h>
 #include <plat/cpu.h>
 #include <plat/nand.h>
+#include <plat/udc.h>

 #include <plat/regs-fb-v4.h>
 #include <plat/fb.h>
@@ -113,6 +116,27 @@ static struct s3c2410_uartcfg smdk2416_uartcfgs[] __initdata = {
 	}
 };
 
+void smdk2416_hsudc_gpio_init(void)
+{
+	s3c_gpio_setpull(S3C2410_GPH(14), S3C_GPIO_PULL_UP);
+	s3c_gpio_setpull(S3C2410_GPF(2), S3C_GPIO_PULL_NONE);
+	s3c_gpio_cfgpin(S3C2410_GPH(14), S3C_GPIO_SFN(1));
+	s3c2410_modify_misccr(S3C2416_MISCCR_SEL_SUSPND, 0);
+}
+
+void smdk2416_hsudc_gpio_uninit(void)
+{
+	s3c2410_modify_misccr(S3C2416_MISCCR_SEL_SUSPND, 1);
+	s3c_gpio_setpull(S3C2410_GPH(14), S3C_GPIO_PULL_NONE);
+	s3c_gpio_cfgpin(S3C2410_GPH(14), S3C_GPIO_SFN(0));
+}
+
+struct s3c24xx_hsudc_platdata smdk2416_hsudc_platdata = {
+	.epnum = 9,
+	.gpio_init = smdk2416_hsudc_gpio_init,
+	.gpio_uninit = smdk2416_hsudc_gpio_uninit,
+};
+
 struct s3c_fb_pd_win smdk2416_fb_win[] = {
 	[0] = {
 		/* think this is the same as the smdk6410 */
@@ -166,6 +190,7 @@ static struct platform_device *smdk2416_devices[] __initdata = {
 	&s3c_device_i2c0,
 	&s3c_device_hsmmc0,
 	&s3c_device_hsmmc1,
+	&s3c_device_usb_hsudc,
 };
 
 static void __init smdk2416_map_io(void)
@@ -180,6 +205,8 @@ static void __init smdk2416_machine_init(void)
 	s3c_i2c0_set_platdata(NULL);
 	s3c_fb_set_platdata(&smdk2416_fb_platdata);
 
+	s3c24xx_hsudc_set_platdata(&smdk2416_hsudc_platdata);
+
 	gpio_request(S3C2410_GPB(4), "USBHost Power");
 	gpio_direction_output(S3C2410_GPB(4), 1);
 
-- 
1.6.6.rc2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/4] USB: Gadget: Add Samsung S3C24XX USB High-Speed controller driver
  2010-10-13  0:10 ` [PATCH 3/4] USB: Gadget: Add Samsung S3C24XX USB High-Speed controller driver Sangbeom Kim
@ 2010-10-21 22:36   ` Ben Dooks
  0 siblings, 0 replies; 8+ messages in thread
From: Ben Dooks @ 2010-10-21 22:36 UTC (permalink / raw)
  To: linux-arm-kernel

On 13/10/10 01:10, Sangbeom Kim wrote:
> From: Thomas Abraham <thomas.ab@samsung.com>
> 
> The Samsung's S3C2416, S3C2443 and S3C2450 includes a USB High-Speed
> device controller module. This driver enables support for USB high-speed
> gadget functionality for the Samsung S3C24xx SoC's that include this
> controller.
> 
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> Signed-off-by: Sangbeom Kim <sbkim73@samsung.com>
> ---
>  drivers/usb/gadget/Kconfig        |   17 +
>  drivers/usb/gadget/Makefile       |    1 +
>  drivers/usb/gadget/gadget_chips.h |    7 +
>  drivers/usb/gadget/s3c-hsudc.c    | 1329 +++++++++++++++++++++++++++++++++++++
>  4 files changed, 1354 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/usb/gadget/s3c-hsudc.c
> 
> diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
> index cd27f9b..235d4db 100644
> --- a/drivers/usb/gadget/Kconfig
> +++ b/drivers/usb/gadget/Kconfig
> @@ -348,6 +348,23 @@ config USB_S3C2410_DEBUG
>  	boolean "S3C2410 udc debug messages"
>  	depends on USB_GADGET_S3C2410
>  
> +config USB_GADGET_S3C_HSUDC
> +	boolean "S3C2416, S3C2443 and S3C2450 USB Device Controller"
> +	depends on ARCH_S3C2410
> +	select USB_GADGET_DUALSPEED
> +	help
> +	  Samsung's S3C2416, S3C2443 and S3C2450 is an ARM9 based SoC
> +	  integrated with dual speed USB 2.0 device controller. It has
> +	  8 endpoints, as well as endpoint zero.
> +
> +	  This driver has been tested on S3C2416 and S3C2450 processors.
> +
> +config USB_S3C_HSUDC
> +	tristate
> +	depends on USB_GADGET_S3C_HSUDC
> +	default USB_GADGET
> +	select USB_GADGET_SELECTED
> +
>  #
>  # Controllers available in both integrated and discrete versions
>  #
> diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
> index 27283df..76e3d67 100644
> --- a/drivers/usb/gadget/Makefile
> +++ b/drivers/usb/gadget/Makefile
> @@ -27,6 +27,7 @@ obj-$(CONFIG_USB_R8A66597)	+= r8a66597-udc.o
>  obj-$(CONFIG_USB_FSL_QE)	+= fsl_qe_udc.o
>  obj-$(CONFIG_USB_CI13XXX)	+= ci13xxx_udc.o
>  obj-$(CONFIG_USB_S3C_HSOTG)	+= s3c-hsotg.o
> +obj-$(CONFIG_USB_S3C_HSUDC)	+= s3c-hsudc.o
>  obj-$(CONFIG_USB_LANGWELL)	+= langwell_udc.o
>  
>  #
> diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
> index e511fec..0b27f6f 100644
> --- a/drivers/usb/gadget/gadget_chips.h
> +++ b/drivers/usb/gadget/gadget_chips.h
> @@ -142,6 +142,11 @@
>  #define gadget_is_s3c_hsotg(g)    0
>  #endif
>  
> +#ifdef CONFIG_USB_S3C_HSUDC
> +#define gadget_is_s3c_hsudc(g) (!strcmp("s3c-hsudc", (g)->name))
> +#else
> +#define gadget_is_s3c_hsudc(g) 0
> +#endif
>  
>  /**
>   * usb_gadget_controller_number - support bcdDevice id convention
> @@ -200,6 +205,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
>  		return 0x25;
>  	else if (gadget_is_s3c_hsotg(gadget))
>  		return 0x26;
> +	else if (gadget_is_s3c_hsudc(gadget))
> +		return 0x27;
>  	return -ENOENT;
>  }
>  
> diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
> new file mode 100644
> index 0000000..ebc4a10
> --- /dev/null
> +++ b/drivers/usb/gadget/s3c-hsudc.c
> @@ -0,0 +1,1329 @@
> +/* linux/drivers/usb/gadget/s3c-hsudc.c
> + *
> + * Copyright (c) 2010 Samsung Electronics Co., Ltd.
> + *		http://www.samsung.com/
> + *
> + * S3C24XX USB 2.0 High-speed USB controller gadget driver
> + *
> + * The S3C24XX USB 2.0 high-speed USB controller supports upto 9 endpoints.
> + * Each endpoint can be configured as either in or out endpoint. Endpoints
> + * can be configured for Bulk or Interrupt transfer mode.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> +*/
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/spinlock.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/slab.h>
> +#include <linux/clk.h>
> +#include <linux/usb/ch9.h>
> +#include <linux/usb/gadget.h>
> +
> +#include <mach/regs-s3c2443-clock.h>

hmm, do you really need to include the clock
registers? surely the clk_ api should be doing
the work for you.

> +#include <plat/udc.h>
> +
> +#define S3C_HSUDC_REG(x)	(x)
> +
> +/* Non-Indexed Registers */
> +#define S3C_IR				S3C_HSUDC_REG(0x00) /* Index Register */
> +#define S3C_EIR				S3C_HSUDC_REG(0x04) /* EP Intr Status */
> +#	define S3C_EIR_EP0		(1<<0)
> +#define S3C_EIER			S3C_HSUDC_REG(0x08) /* EP Intr Enable */
> +#define S3C_FAR				S3C_HSUDC_REG(0x0c) /* Gadget Address */
> +#define S3C_FNR				S3C_HSUDC_REG(0x10) /* Frame Number */
> +#define S3C_EDR				S3C_HSUDC_REG(0x14) /* EP Direction */
> +#define S3C_TR				S3C_HSUDC_REG(0x18) /* Test Register */
> +#define S3C_SSR				S3C_HSUDC_REG(0x1c) /* System Status */
> +#	define S3C_SSR_DTZIEN_EN	(0xff8f)
> +#	define S3C_SSR_ERR		(0xff80)
> +#	define S3C_SSR_VBUSON		(1 << 8)
> +#	define S3C_SSR_HSP		(1 << 4)
> +#	define S3C_SSR_SDE		(1 << 3)
> +#	define S3C_SSR_RESUME		(1 << 2)
> +#	define S3C_SSR_SUSPEND		(1 << 1)
> +#	define S3C_SSR_RESET		(1 << 0)
> +#define S3C_SCR				S3C_HSUDC_REG(0x20) /* System Control */
> +#	define S3C_SCR_DTZIEN_EN	(1 << 14)
> +#	define S3C_SCR_RRD_EN		(1 << 5)
> +#	define S3C_SCR_SUS_EN		(1 << 1)
> +#	define S3C_SCR_RST_EN		(1 << 0)
> +#define S3C_EP0SR			S3C_HSUDC_REG(0x24) /* EP0 Status */
> +#	define S3C_EP0SR_EP0_LWO	(1 << 6)
> +#	define S3C_EP0SR_STALL		(1 << 4)
> +#	define S3C_EP0SR_TX_SUCCESS	(1 << 1)
> +#	define S3C_EP0SR_RX_SUCCESS	(1 << 0)
> +#define S3C_EP0CR			S3C_HSUDC_REG(0x28) /* EP0 Control */
> +#define S3C_BR(_x)			S3C_HSUDC_REG(0x60 + (_x * 4))
> +
> +/* Indexed Registers */
> +#define S3C_ESR				S3C_HSUDC_REG(0x2c) /* EPn Status */
> +#	define S3C_ESR_FLUSH		(1 << 6)
> +#	define S3C_ESR_STALL		(1 << 5)
> +#	define S3C_ESR_LWO		(1 << 4)
> +#	define S3C_ESR_PSIF_ONE		(1 << 2)
> +#	define S3C_ESR_PSIF_TWO		(2 << 2)
> +#	define S3C_ESR_TX_SUCCESS	(1 << 1)
> +#	define S3C_ESR_RX_SUCCESS	(1 << 0)
> +#define S3C_ECR				S3C_HSUDC_REG(0x30) /* EPn Control */
> +#	define S3C_ECR_DUEN		(1 << 7)
> +#	define S3C_ECR_FLUSH		(1 << 6)
> +#	define S3C_ECR_STALL		(1 << 1)
> +#	define S3C_ECR_IEMS		(1 << 0)
> +#define S3C_BRCR			S3C_HSUDC_REG(0x34) /* Read Count */
> +#define S3C_BWCR			S3C_HSUDC_REG(0x38) /* Write Count */
> +#define S3C_MPR				S3C_HSUDC_REG(0x3c) /* Max Pkt Size */

hmm, the formatting is a bit non-standard.

> +
> +static inline void __orr32(void __iomem *ptr, u32 val)
> +{
> +	writel(readl(ptr) | val, ptr);
> +}
> +
> +static void s3c_hsudc_init_phy(void)
> +{
> +	u32 cfg;
> +
> +	cfg = __raw_readl(S3C2443_PWRCFG) | S3C2443_PWRCFG_USBPHY;
> +	__raw_writel(cfg, S3C2443_PWRCFG);
> +
> +	cfg = __raw_readl(S3C2443_URSTCON);
> +	cfg |= (S3C2443_URSTCON_FUNCRST | S3C2443_URSTCON_PHYRST);
> +	__raw_writel(cfg, S3C2443_URSTCON);
> +	mdelay(1);
> +
> +	cfg = __raw_readl(S3C2443_URSTCON);
> +	cfg &= ~(S3C2443_URSTCON_FUNCRST | S3C2443_URSTCON_PHYRST);
> +	__raw_writel(cfg, S3C2443_URSTCON);
> +
> +	cfg = __raw_readl(S3C2443_PHYCTRL);
> +	cfg &= ~(S3C2443_PHYCTRL_CLKSEL | S3C2443_PHYCTRL_DSPORT);
> +	cfg |= (S3C2443_PHYCTRL_EXTCLK | S3C2443_PHYCTRL_PLLSEL);
> +	__raw_writel(cfg, S3C2443_PHYCTRL);
> +
> +	cfg = __raw_readl(S3C2443_PHYPWR);
> +	cfg &= ~(S3C2443_PHYPWR_FSUSPEND | S3C2443_PHYPWR_PLL_PWRDN |
> +		S3C2443_PHYPWR_XO_ON | S3C2443_PHYPWR_PLL_REFCLK |
> +		S3C2443_PHYPWR_ANALOG_PD);
> +	cfg |= S3C2443_PHYPWR_COMMON_ON;
> +	__raw_writel(cfg, S3C2443_PHYPWR);
> +
> +	cfg = __raw_readl(S3C2443_UCLKCON);
> +	cfg |= (S3C2443_UCLKCON_DETECT_VBUS | S3C2443_UCLKCON_FUNC_CLKEN |
> +		S3C2443_UCLKCON_TCLKEN);
> +	__raw_writel(cfg, S3C2443_UCLKCON);
> +}
> +
> +static void s3c_hsudc_uninit_phy(void)
> +{
> +	u32 cfg;
> +
> +	cfg = __raw_readl(S3C2443_PWRCFG) & ~S3C2443_PWRCFG_USBPHY;
> +	__raw_writel(cfg, S3C2443_PWRCFG);
> +
> +	__raw_writel(S3C2443_PHYPWR_FSUSPEND, S3C2443_PHYPWR);
> +
> +	cfg = __raw_readl(S3C2443_UCLKCON) & ~S3C2443_UCLKCON_FUNC_CLKEN;
> +	__raw_writel(cfg, S3C2443_UCLKCON);
> +}

I suppose this has to be here.


> +/**
> + * s3c_hsudc_read_setup_pkt - Read the received setup packet from EP0 fifo.
> + * @hsudc: Device controller from which setup packet is to be read.
> + * @buf: The buffer into which the setup packet is read.
> + *
> + * The setup packet received in the EP0 fifo is read and stored into a
> + * given buffer address.
> + */
> +
> +static void s3c_hsudc_read_setup_pkt(struct s3c_hsudc *hsudc, u16 *buf)
> +{
> +	int count;
> +
> +	count = __raw_readl(hsudc->regs + S3C_BRCR);
> +	while (count--)
> +		*buf++ = (u16)__raw_readl(hsudc->regs + S3C_BR(0));

hmm, __raw_readl() shouldn't be being used for ioremaped addresses?

> +	__raw_writel(S3C_EP0SR_RX_SUCCESS, hsudc->regs + S3C_EP0SR);
> +}
> +
> +/**
> + * s3c_hsudc_write_fifo - Write next chunk of transfer data to EP fifo.
> + * @hsep: Endpoint to which the data is to be written.
> + * @hsreq: Transfer request from which the next chunk of data is written.
> + *
> + * Write the next chunk of data from a transfer request to the endpoint FIFO.
> + * If the transfer request completes, 1 is returned, otherwise 0 is returned.
> + */
> +static int s3c_hsudc_write_fifo(struct s3c_hsudc_ep *hsep,
> +				struct s3c_hsudc_req *hsreq)
> +{
> +	u16 *buf;
> +	u32 max = ep_maxpacket(hsep);
> +	u32 count, length;
> +	int is_last;

this could be a bool.

> +	u32 fifo = hsep->fifo;
> +
> +	buf = hsreq->req.buf + hsreq->req.actual;
> +	prefetch(buf);
> +
> +	length = hsreq->req.length - hsreq->req.actual;
> +	length = min(length, max);
> +	hsreq->req.actual += length;
> +
> +	__raw_writel(length, hsep->dev->regs + S3C_BWCR);
> +	for (count = 0; count < length; count += 2)
> +		__raw_writel(*buf++, fifo);
> +
> +	if (count != max) {
> +		is_last = 1;
> +	} else {
> +		if (hsreq->req.length != hsreq->req.actual || hsreq->req.zero)
> +			is_last = 0;
> +		else
> +			is_last = 1;
> +	}
> +
> +	if (is_last) {
> +		s3c_hsudc_complete_request(hsep, hsreq, 0);
> +		return 1;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * s3c_hsudc_read_fifo - Read the next chunk of data from EP fifo.
> + * @hsep: Endpoint from which the data is to be read.
> + * @hsreq: Transfer request to which the next chunk of data read is written.
> + *
> + * Read the next chunk of data from the endpoint FIFO and a write it to the
> + * transfer request buffer. If the transfer request completes, 1 is returned,
> + * otherwise 0 is returned.
> + */
> +static int s3c_hsudc_read_fifo(struct s3c_hsudc_ep *hsep,
> +				struct s3c_hsudc_req *hsreq)
> +{
> +	struct s3c_hsudc *hsudc = hsep->dev;
> +	u32 csr, offset;
> +	u16 *buf, word;
> +	u32 buflen, rcnt, rlen;
> +	u32 fifo = hsep->fifo;

if this is an ioaddr, it should be void __iomem *.

> +	u32 is_short = 0;
> +
> +	offset = (ep_index(hsep)) ? S3C_ESR : S3C_EP0SR;
> +	csr = __raw_readl(hsudc->regs + offset);
> +	if (!(csr & S3C_ESR_RX_SUCCESS))
> +		return -EINVAL;
> +
> +	buf = hsreq->req.buf + hsreq->req.actual;
> +	prefetchw(buf);
> +	buflen = hsreq->req.length - hsreq->req.actual;
> +
> +	rcnt = __raw_readl(hsudc->regs + S3C_BRCR);
> +	rlen = (csr & S3C_ESR_LWO) ? (rcnt * 2 - 1) : (rcnt * 2);
> +
> +	hsreq->req.actual += min(rlen, buflen);
> +	is_short = (rlen < hsep->ep.maxpacket);
> +
> +	while (rcnt-- != 0) {
> +		word = (u16)__raw_readl(fifo);
> +		if (buflen) {
> +			*buf++ = word;
> +			buflen--;
> +		} else {
> +			hsreq->req.status = -EOVERFLOW;
> +		}
> +	}
> +
> +	__raw_writel(S3C_ESR_RX_SUCCESS, hsudc->regs + offset);
> +
> +	if (is_short || hsreq->req.actual == hsreq->req.length) {
> +		s3c_hsudc_complete_request(hsep, hsreq, 0);
> +		return 1;
> +	}
> +
> +	return 0;
> +}

> +/**
> + * s3c_hsudc_ep_disable - Disable a endpoint.
> + * @_ep: The endpoint to be disabled.
> + * @desc: Endpoint descriptor.
> + *
> + * Disables a endpoint when called from the gadget driver.
> + */
> +static int s3c_hsudc_ep_disable(struct usb_ep *_ep)
> +{
> +	struct s3c_hsudc_ep *hsep = our_ep(_ep);
> +	struct s3c_hsudc *hsudc = hsep->dev;
> +	unsigned long flags;
> +
> +	hsep = container_of(_ep, struct s3c_hsudc_ep, ep);

hmm, you've got hsep assigned twice?

> +	if (!_ep || !hsep->desc)
> +		return -EINVAL;
> +
> +	spin_lock_irqsave(&hsudc->lock, flags);
> +
> +	set_index(hsudc, hsep->bEndpointAddress);
> +	__clear_bit(ep_index(hsep), hsudc->regs + S3C_EIER);
> +
> +	s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN);
> +
> +	hsep->desc = 0;
> +	hsep->stopped = 1;
> +
> +	spin_unlock_irqrestore(&hsudc->lock, flags);
> +	return 0;
> +}

> +	local_irq_disable();
> +
> +	disable_irq(hsudc->irq);
> +	local_irq_enable();

hmm, why are you disabling the irqs around this call?

> +	return 0;

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 0/4] USB: gadget: Add Samsung S3C24xx USB HS controller driver
  2010-10-13  0:10 [PATCH 0/4] USB: gadget: Add Samsung S3C24xx USB HS controller driver Sangbeom Kim
                   ` (3 preceding siblings ...)
  2010-10-13  0:10 ` [PATCH 4/4] ARM: S3C2416: Add support for USB 2.0 High-Speed gadget controller Sangbeom Kim
@ 2010-10-21 22:37 ` Ben Dooks
  2010-10-22  6:15   ` Thomas Abraham
  4 siblings, 1 reply; 8+ messages in thread
From: Ben Dooks @ 2010-10-21 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

On 13/10/10 01:10, Sangbeom Kim wrote:
> The Samsung's S3C2416, S3C2443 and S3C2450 includes a USB High-Speed
> device controller module. This driver enables support for USB high-speed
> gadget functionality for the Samsung S3C24xx SoC's that include this
> controller.
> 
> The patch series contains:
> [PATCH 1/4] ARM: S3C2416: Add USB Phy register definitions
> [PATCH 2/4] ARM: S3C24XX: Add plaform device definition for USB High-Speed gadget controller.
> [PATCH 3/4] USB: Gadget: Add Samsung S3C24XX USB High-Speed controller driver
> [PATCH 4/4] ARM: S3C2416: Add support for USB 2.0 High-Speed gadget controller

patch 3/4 needs a bit of work, otherwise looks ok.

I'll look at applying the s3c24xx items in the next day or so.

-- 
Ben

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 0/4] USB: gadget: Add Samsung S3C24xx USB HS controller driver
  2010-10-21 22:37 ` [PATCH 0/4] USB: gadget: Add Samsung S3C24xx USB HS controller driver Ben Dooks
@ 2010-10-22  6:15   ` Thomas Abraham
  0 siblings, 0 replies; 8+ messages in thread
From: Thomas Abraham @ 2010-10-22  6:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 22, 2010 at 4:07 AM, Ben Dooks <ben-linux@fluff.org> wrote:
> On 13/10/10 01:10, Sangbeom Kim wrote:
>> The Samsung's S3C2416, S3C2443 and S3C2450 includes a USB High-Speed
>> device controller module. This driver enables support for USB high-speed
>> gadget functionality for the Samsung S3C24xx SoC's that include this
>> controller.
>>
>> The patch series contains:
>> [PATCH 1/4] ARM: S3C2416: Add USB Phy register definitions
>> [PATCH 2/4] ARM: S3C24XX: Add plaform device definition for USB High-Speed gadget controller.
>> [PATCH 3/4] USB: Gadget: Add Samsung S3C24XX USB High-Speed controller driver
>> [PATCH 4/4] ARM: S3C2416: Add support for USB 2.0 High-Speed gadget controller
>
> patch 3/4 needs a bit of work, otherwise looks ok.
>
> I'll look at applying the s3c24xx items in the next day or so.

Hi Ben,

Thanks for your review. I will update patch 3/4 as per your comments.

Regards,
Thomas.

>
> --
> Ben
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2010-10-22  6:15 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-10-13  0:10 [PATCH 0/4] USB: gadget: Add Samsung S3C24xx USB HS controller driver Sangbeom Kim
2010-10-13  0:10 ` [PATCH 1/4] ARM: S3C2416: Add USB Phy register definitions Sangbeom Kim
2010-10-13  0:10 ` [PATCH 2/4] ARM: S3C24XX: Add plaform device definition for USB High-Speed gadget controller Sangbeom Kim
2010-10-13  0:10 ` [PATCH 3/4] USB: Gadget: Add Samsung S3C24XX USB High-Speed controller driver Sangbeom Kim
2010-10-21 22:36   ` Ben Dooks
2010-10-13  0:10 ` [PATCH 4/4] ARM: S3C2416: Add support for USB 2.0 High-Speed gadget controller Sangbeom Kim
2010-10-21 22:37 ` [PATCH 0/4] USB: gadget: Add Samsung S3C24xx USB HS controller driver Ben Dooks
2010-10-22  6:15   ` Thomas Abraham

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).