All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] USB device driver of Topcliff PCH
@ 2010-09-07  7:49 Masayuki Ohtake
  2010-09-07 12:53 ` Maurus Cuelenaere
                   ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Masayuki Ohtake @ 2010-09-07  7:49 UTC (permalink / raw)
  To: Randy Dunlap, Peter Korsgaard, Nicolas Ferre, Michal Nazarewicz,
	Maurus Cuelenaere, linux-usb, Laurent Pinchart,
	Greg Kroah-Hartman, Fabien Chouteau, david Brownell,
	Christoph Egger, LKML, MeeGo
  Cc: Wang, Qi, Wang, Yong Y, Andrew, Intel OTC, Foster, Margie, Arjan,
	Toshiharu Okada, Masayuki Ohtake, Takahiro Shimizu,
	Tomoya Morinaga

This patch adds the USB device driver of Topcliff PCH.

Topcliff PCH is the platform controller hub that is going to be used in
Intel's upcoming general embedded platform. All IO peripherals in
Topcliff PCH are actually devices sitting on AMBA bus. 
Topcliff PCH has USB device I/F. Using this I/F, it is able to access system
devices connected to USB device.

Signed-off-by: Masayuki Ohtake <masa-korg@dsn.okisemi.com>
---
 drivers/usb/gadget/Kconfig        |   24 +
 drivers/usb/gadget/Makefile       |    2 +-
 drivers/usb/gadget/gadget_chips.h |    7 +
 drivers/usb/gadget/pch_udc.c      | 3153 +++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/pch_udc.h      |  495 ++++++
 5 files changed, 3680 insertions(+), 1 deletions(-)
 create mode 100755 drivers/usb/gadget/pch_udc.c
 create mode 100755 drivers/usb/gadget/pch_udc.h

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 591ae9f..3bc839d 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -220,6 +220,30 @@ config USB_OTG
 
 	   Select this only if your OMAP board has a Mini-AB connector.
 
+config USB_GADGET_PCH
+	boolean "PCH USB Dev"
+	depends on PCI
+	select USB_GADGET_DUALSPEED
+	help
+	  This is a USB device driver for Topcliff PCH.
+	  Topcliff PCH is the platform controller hub that is used in Intel's
+	  general embedded platform.
+	  Topcliff PCH has USB device interface.
+	  Using this interface, it is able to access system devices connected
+	  to USB device.
+	  This driver enables USB device function.
+	  USB device is a USB peripheral controller which
+	  supports both full and high speed USB 2.0 data transfers.
+	  This driver supports for control transfer, and bulk transfer modes.
+	  This driver dose not support interrupt transfer, and isochronous
+	  transfer modes.
+
+config PCH_USBDEV
+	tristate
+	depends on USB_GADGET_PCH
+	default USB_GADGET
+	select USB_GADGET_SELECTED
+
 config USB_GADGET_PXA25X
 	boolean "PXA 25x or IXP 4xx"
 	depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 9bcde11..9473430 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -63,4 +63,4 @@ obj-$(CONFIG_USB_G_HID)		+= g_hid.o
 obj-$(CONFIG_USB_G_MULTI)	+= g_multi.o
 obj-$(CONFIG_USB_G_NOKIA)	+= g_nokia.o
 obj-$(CONFIG_USB_G_WEBCAM)	+= g_webcam.o
-
+obj-$(CONFIG_PCH_USBDEV) += pch_udc.o
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index e511fec..f67dd29 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_GADGET_PCH
+#define	gadget_is_pch(g)	(!strcmp("pch_udc", (g)->name))
+#else
+#define	gadget_is_pch(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_pch(gadget))
+		return 0x27;
 	return -ENOENT;
 }
 
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
new file mode 100755
index 0000000..2065c11
--- /dev/null
+++ b/drivers/usb/gadget/pch_udc.c
@@ -0,0 +1,3153 @@
+/*
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/dmapool.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/byteorder.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+/* gadget stack */
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include "pch_udc.h"
+
+
+/* macro to set a specified bit(mask) at the specified address */
+#define PCH_UDC_BIT_SET(reg, bitmask) \
+		 iowrite32(((ioread32((reg)) | (bitmask))), (reg))
+/* macro to clear a specified bit(mask) at the specified address */
+#define PCH_UDC_BIT_CLR(reg, bitMask) \
+		iowrite32((ioread32((reg)) & (~(bitMask))), (reg))
+
+#define MAX_LOOP				200
+#define PCH_UDC_PCI_BAR			1
+#define PCI_VENDOR_ID_INTEL			0x8086
+#define PCI_DEVICE_ID_INTEL_PCH1_UDC	0x8808
+
+const char	ep0_string[] = "ep0in";
+static DEFINE_SPINLOCK(udc_stall_spinlock);	/* stall spin lock */
+static u32 pch_udc_base;
+static union pch_udc_setup_data setup_data;	/* received setup data */
+static unsigned long ep0out_buf[64];
+static dma_addr_t dma_addr;
+struct pch_udc_dev *pch_udc;		/* pointer to device object */
+int speed_fs;
+
+module_param_named(speed_fs, speed_fs, bool, S_IRUGO);
+MODULE_PARM_DESC(speed_fs, "true for Full speed operation");
+MODULE_DESCRIPTION("OKISEMI PCH UDC - USB Device Controller");
+MODULE_LICENSE("GPL");
+
+/**
+ * pch_udc_write_csr - Write the command and status registers.
+ * @val:	value to be written to CSR register
+ * @addr:	address of CSR register
+ */
+inline void pch_udc_write_csr(unsigned long val, unsigned long addr)
+{
+	int count = MAX_LOOP;
+
+	/* Wait till idle */
+	while ((count > 0) &&\
+		(ioread32((u32 *)(PCH_UDC_CSR_BUSY_ADDR + pch_udc_base)) &
+		PCH_UDC_CSR_BUSY))
+		count--;
+
+	if (count < 0)
+		pr_debug("%s: wait error; count = %x", __func__, count);
+
+	iowrite32(val, (u32 *)addr);
+	/* Wait till idle */
+	count = MAX_LOOP;
+	while ((count > 0) &&
+		(ioread32((u32 *)(PCH_UDC_CSR_BUSY_ADDR + pch_udc_base)) &
+		PCH_UDC_CSR_BUSY))
+		count--;
+
+	if (count < 0)
+		pr_debug("%s: wait error; count = %x", __func__, count);
+
+}
+
+/**
+ * pch_udc_read_csr - Read the command and status registers.
+ * @addr:	address of CSR register
+ * Returns
+ *	content of CSR register
+ */
+inline u32 pch_udc_read_csr(unsigned long addr)
+{
+	int count = MAX_LOOP;
+
+	/* Wait till idle */
+	while ((count > 0) &&
+		(ioread32((u32 *)(PCH_UDC_CSR_BUSY_ADDR + pch_udc_base)) &
+		PCH_UDC_CSR_BUSY))
+		count--;
+
+	if (count < 0)
+		pr_debug("%s: wait error; count = %x", __func__, count);
+	/* Dummy read */
+	ioread32((u32 *)addr);
+	count = MAX_LOOP;
+	/* Wait till idle */
+	while ((count > 0) &&
+		(ioread32((u32 *)(PCH_UDC_CSR_BUSY_ADDR + pch_udc_base)) &
+		PCH_UDC_CSR_BUSY))
+		count--;
+	/* actual read */
+	if (count < 0)
+		pr_debug("%s: wait error; count = %x", __func__, count);
+
+	return ioread32((u32 *)addr);
+}
+
+/**
+ * pch_udc_rmt_wakeup - Initiate for remote wakeup
+ * @dev:	Reference to pch_udc_regs structure
+ */
+inline void pch_udc_rmt_wakeup(struct pch_udc_regs *dev)
+{
+	PCH_UDC_BIT_SET(&dev->devctl, 1 << UDC_DEVCTL_RES);
+	mdelay(1);
+	PCH_UDC_BIT_CLR(&dev->devctl, 1 << UDC_DEVCTL_RES);
+}
+
+/**
+ * pch_udc_get_frame - Get the current frame from device status register
+ * @dev:	Reference to pch_udc_regs structure
+ * Retern	current frame
+ */
+inline int pch_udc_get_frame(struct pch_udc_regs *dev)
+{
+	u32 frame;
+
+	frame = ioread32(&dev->devsts);
+	return (frame & UDC_DEVSTS_TS_MASK) >> UDC_DEVSTS_TS_OFS;
+}
+
+/**
+ * pch_udc_clear_selfpowered - Clear the self power control
+ * @dev:	Reference to pch_udc_regs structure
+ */
+inline void pch_udc_clear_selfpowered(struct pch_udc_regs __iomem *dev)
+{
+	PCH_UDC_BIT_CLR(&dev->devcfg, 1 << UDC_DEVCFG_SP);
+}
+
+/**
+ * pch_udc_set_selfpowered - Set the self power control
+ * @dev:	Reference to pch_udc_regs structure
+ */
+inline void pch_udc_set_selfpowered(struct pch_udc_regs __iomem *dev)
+{
+	PCH_UDC_BIT_SET(&dev->devcfg, 1 << UDC_DEVCFG_SP);
+}
+
+/**
+ * pch_udc_set_disconnect - Set the disconnect status.
+ * @dev:	Reference to pch_udc_regs structure
+ */
+inline void pch_udc_set_disconnect(struct pch_udc_regs __iomem *dev)
+{
+	PCH_UDC_BIT_SET(&dev->devctl, 1 << UDC_DEVCTL_SD);
+}
+
+/**
+ * pch_udc_get_speed - Return the speed status
+ * @dev:	Reference to pch_udc_regs structure
+ * Retern	The speed(LOW=1, FULL=2, HIGH=3)
+ */
+inline int pch_udc_get_speed(struct pch_udc_regs __iomem *dev)
+{
+	u32 val;
+
+	val = ioread32(&dev->devsts);
+	return (val & UDC_DEVSTS_ENUM_SPEED_MASK) >> UDC_DEVSTS_ENUM_SPEED_OFS;
+}
+
+/**
+ * pch_udc_clear_disconnect - Clear the disconnect status.
+ * @dev:	Reference to pch_udc_regs structure
+ */
+void pch_udc_clear_disconnect(struct pch_udc_regs __iomem *dev)
+{
+	/* Clear the disconnect */
+	PCH_UDC_BIT_SET(&dev->devctl, 1 << UDC_DEVCTL_RES);
+	PCH_UDC_BIT_CLR(&dev->devctl, 1 << UDC_DEVCTL_SD);
+	mdelay(1);
+	/* Resume USB signalling */
+	PCH_UDC_BIT_CLR(&dev->devctl, 1 << UDC_DEVCTL_RES);
+}
+
+/**
+ * pch_udc_vbus_session - set or clearr the disconnect status.
+ * @dev:	Reference to pch_udc_regs structure
+ * @is_active:	Parameter specifying the action
+ *		- is_active = 0   indicating VBUS power is ending
+ *		- is_active != 0  indicating VBUS power is starting
+ */
+inline void pch_udc_vbus_session(struct pch_udc_regs __iomem *dev,
+					int is_active)
+{
+	if (is_active == 0)
+		pch_udc_set_disconnect(dev);
+	else
+		pch_udc_clear_disconnect(dev);
+}
+
+/**
+ * pch_udc_ep_set_stall - Set the stall of endpoint
+ * @ep:		Reference to structure of type pch_udc_ep_regs
+ */
+void pch_udc_ep_set_stall(struct pch_udc_ep_regs __iomem *ep)
+{
+	if (EP_IS_IN(ep)) {
+		PCH_UDC_BIT_SET(&ep->epctl, 1 << UDC_EPCTL_F);
+		PCH_UDC_BIT_SET(&ep->epctl, 1 << UDC_EPCTL_S);
+	} else {
+		PCH_UDC_BIT_SET(&ep->epctl, 1 << UDC_EPCTL_S);
+	}
+}
+
+/**
+ * pch_udc_ep_clear_stall - Clear the stall of endpoint
+ * @ep:		Reference to structure of type pch_udc_ep_regs
+ */
+inline void pch_udc_ep_clear_stall(struct pch_udc_ep_regs __iomem *ep)
+{
+	/* Clear the stall */
+	PCH_UDC_BIT_CLR(&ep->epctl, 1 << UDC_EPCTL_S);
+	/* clear NAK by writing CNAK */
+	PCH_UDC_BIT_SET(&ep->epctl, 1 << UDC_EPCTL_CNAK);
+}
+
+/**
+ * pch_udc_ep_set_trfr_type - Set the transfer type of endpoint
+ * @ep:		Reference to structure of type pch_udc_ep_regs
+ * @type:	Type of endpoint
+ */
+inline void pch_udc_ep_set_trfr_type(struct pch_udc_ep_regs __iomem *ep,
+					u8 type)
+{
+	iowrite32(((type << UDC_EPCTL_ET_OFS) & UDC_EPCTL_ET_MASK),
+		   &ep->epctl);
+}
+
+/**
+ * pch_udc_ep_set_bufsz - Set the maximum packet size for the endpoint
+ * @ep:		Reference to structure of type pch_udc_ep_regs
+ * @buf_size:	The buffer size
+ */
+void pch_udc_ep_set_bufsz(struct pch_udc_ep_regs __iomem *ep,
+						 u32 buf_size, u32 ep_in)
+{
+	u32 data;
+	if (ep_in) {
+		data = ioread32(&ep->bufin_framenum);
+		data = (data & 0xffff0000) | (buf_size & 0xffff);
+		iowrite32(data, &ep->bufin_framenum);
+	} else {
+		data = ioread32(&ep->bufout_maxpkt);
+		data = (buf_size << 16) | (data & 0xffff);
+		iowrite32(data, &ep->bufout_maxpkt);
+	}
+}
+
+/**
+ * pch_udc_ep_set_maxpkt - Set the Max packet size for the endpoint
+ * @ep:		Reference to structure of type pch_udc_ep_regs
+ * @pkt_size:	The packet size
+ */
+void pch_udc_ep_set_maxpkt(struct pch_udc_ep_regs __iomem *ep, u32 pkt_size)
+{
+	u32 data;
+	data = ioread32(&ep->bufout_maxpkt);
+	data = (data & 0xffff0000) | (pkt_size & 0xffff);
+	iowrite32(data, &ep->bufout_maxpkt);
+}
+
+/**
+ * pch_udc_ep_set_subptr - Set the Setup buffer pointer for the endpoint
+ * @ep:		Reference to structure of type pch_udc_ep_regs
+ * @addr:	Address of the register
+ */
+inline void pch_udc_ep_set_subptr(struct pch_udc_ep_regs __iomem *ep,
+					u32 addr)
+{
+	iowrite32(addr, &ep->subptr);
+}
+
+/**
+ * pch_udc_ep_set_ddptr - Set the Data descriptor pointer for the endpoint
+ * @ep:		Reference to structure of type pch_udc_ep_regs
+ * @addr:	Address of the register
+ */
+inline void pch_udc_ep_set_ddptr(struct pch_udc_ep_regs __iomem *ep, u32 addr)
+{
+	iowrite32(addr, &ep->desptr);
+}
+
+/**
+ * pch_udc_ep_set_pd - Set the poll demand bit for the endpoint
+ * @ep:		Reference to structure of type pch_udc_ep_regs
+ */
+inline void pch_udc_ep_set_pd(struct pch_udc_ep_regs __iomem *ep)
+{
+	PCH_UDC_BIT_SET(&ep->epctl, 1 << UDC_EPCTL_P);
+}
+
+/**
+ * pch_udc_ep_set_rrdy - Set the receive ready bit for the endpoint
+ * @ep:		Reference to structure of type pch_udc_ep_regs
+ */
+inline void pch_udc_ep_set_rrdy(struct pch_udc_ep_regs __iomem *ep)
+{
+	PCH_UDC_BIT_SET(&ep->epctl, 1 << UDC_EPCTL_RRDY);
+}
+
+/**
+ * pch_udc_ep_clear_rrdy - Clear the receive ready bit for the endpoint
+ * @ep:		Reference to structure of type pch_udc_ep_regs
+ */
+inline void pch_udc_ep_clear_rrdy(struct pch_udc_ep_regs __iomem *ep)
+{
+	PCH_UDC_BIT_CLR(&ep->epctl, 1 << UDC_EPCTL_RRDY);
+}
+
+/**
+ * pch_udc_set_dma - Set the 'TDE' or RDE bit of device control
+ *			register depending on the direction specified
+ * @dev:	Reference to structure of type pch_udc_regs
+ * @dir:	whether Tx or Rx
+ *			- dir = DMA_DIR_RX Receive
+ *			- dir = DMA_DIR_TX Transmit
+ */
+inline void pch_udc_set_dma(struct pch_udc_regs __iomem *dev, int dir)
+{
+	if (dir == DMA_DIR_RX)
+		PCH_UDC_BIT_SET(&dev->devctl, 1 << UDC_DEVCTL_RDE);
+	else if (dir == DMA_DIR_TX)
+		PCH_UDC_BIT_SET(&dev->devctl, (1 << UDC_DEVCTL_TDE));
+
+}
+
+/**
+ * pch_udc_clear_dma - Clear the 'TDE' or RDE bit of device control
+ *				 register depending on the direction specified
+ * @dev:	Reference to structure of type pch_udc_regs
+ * @dir:	Whether Tx or Rx
+ *		- dir = DMA_DIR_RX Receive
+ *		- dir = DMA_DIR_TX Transmit
+ */
+inline void pch_udc_clear_dma(struct pch_udc_regs __iomem *dev, int dir)
+{
+	if (dir == DMA_DIR_RX)
+		PCH_UDC_BIT_CLR(&dev->devctl, 1 << UDC_DEVCTL_RDE);
+	else if (dir == DMA_DIR_TX)
+		PCH_UDC_BIT_CLR(&dev->devctl, 1 << UDC_DEVCTL_TDE);
+
+}
+
+/**
+ * pch_udc_set_csr_done - Set the device control register
+ *				CSR done field (bit 13)
+ * @dev:	reference to structure of type pch_udc_regs
+ */
+inline void pch_udc_set_csr_done(struct pch_udc_regs __iomem *dev)
+{
+	PCH_UDC_BIT_SET(&dev->devctl, 1 << UDC_DEVCTL_CSR_DONE);
+}
+
+/**
+ * pch_udc_set_burst_length - The main tasks done by this method are:
+ *			- Set the device control register burst length field
+ *			- Enable the bust mode
+ * @dev:	Reference to structure of type pch_udc_regs
+ * @len:	Burst length
+ */
+void pch_udc_set_burst_length(struct pch_udc_regs __iomem *dev, u8 len)
+{
+	PCH_UDC_BIT_CLR(&dev->devctl, (0xff << UDC_DEVCTL_BRLEN_OFS));
+	/* set Burst length  and enable burst mode*/
+	PCH_UDC_BIT_SET(&dev->devctl, (len << UDC_DEVCTL_BRLEN_OFS) |
+					  (1 << UDC_DEVCTL_BREN));
+}
+
+/**
+ * pch_udc_set_threshold_length - Set the device control register threshold
+ *				length field
+ *				- Enable the threshold mode
+ * @dev:	Reference to structure of type pch_udc_regs
+ * @len:	Burst length
+ */
+inline void pch_udc_set_threshold_length(struct pch_udc_regs __iomem *dev,
+					      u8 len)
+{
+	PCH_UDC_BIT_CLR(&dev->devctl, (0xff << UDC_DEVCTL_THLEN_OFS));
+	/* set Burst Threshold length and enable threshold mode*/
+	PCH_UDC_BIT_SET(&dev->devctl, (len << UDC_DEVCTL_THLEN_OFS) |
+					  (1 << UDC_DEVCTL_THE));
+}
+
+/**
+ * pch_udc_disable_interrupts - Disables the specified interrupts
+ * @dev:	Reference to structure of type pch_udc_regs
+ * @mask:	Mask to disable interrupts
+ */
+inline void pch_udc_disable_interrupts(struct pch_udc_regs __iomem *dev,
+					    u32 mask)
+{
+	PCH_UDC_BIT_SET(&dev->devirqmsk, mask);
+}
+
+/**
+ * pch_udc_enable_interrupts - Enable the specified interrupts
+ * @dev:	Reference to structure of type pch_udc_regs
+ * @mask:	Mask to enable interrupts
+ */
+inline void pch_udc_enable_interrupts(struct pch_udc_regs __iomem *dev,
+					   u32 mask)
+{
+	PCH_UDC_BIT_CLR(&dev->devirqmsk, mask);
+}
+
+/**
+ * pch_udc_disable_ep_interrupts - Disable endpoint interrupts
+ * @dev:	Reference to structure of type pch_udc_regs
+ * @mask:	Mask to disable interrupts
+ */
+inline void pch_udc_disable_ep_interrupts(struct pch_udc_regs __iomem *dev,
+						u32 mask)
+{
+	PCH_UDC_BIT_SET(&dev->epirqmsk, mask);
+}
+
+/**
+ * pch_udc_enable_ep_interrupts - Enable endpoint interrupts
+ * @dev:	Reference to structure of type pch_udc_regs
+ * @mask:	Mask to enable interrupts
+ */
+inline void pch_udc_enable_ep_interrupts(struct pch_udc_regs __iomem *dev,
+					      u32 mask)
+{
+	PCH_UDC_BIT_CLR(&dev->epirqmsk, mask);
+}
+
+/**
+ * pch_udc_read_device_interrupts - Read the device interrupts
+ * @dev:	Reference to structure of type pch_udc_regs
+ * Retern	The device interrupts
+ */
+inline u32 pch_udc_read_device_interrupts(struct pch_udc_regs __iomem *dev)
+{
+	return ioread32(&dev->devirqsts);
+}
+
+/**
+ * pch_udc_write_device_interrupts - Write device interrupts
+ * @dev:	Reference to structure of type pch_udc_regs
+ * @val:	The value to be written to interrupt register
+ */
+inline void pch_udc_write_device_interrupts(struct pch_udc_regs __iomem *dev,
+						  u32 val)
+{
+	iowrite32(val, &dev->devirqsts);
+}
+
+/**
+ * pch_udc_read_ep_interrupts - Read the endpoint interrupts
+ * @dev:	Reference to structure of type pch_udc_regs
+ * Retern	The endpoint interrupt
+ */
+inline u32 pch_udc_read_ep_interrupts(struct pch_udc_regs __iomem *dev)
+{
+	return ioread32(&dev->epirqsts);
+}
+
+/**
+ * pch_udc_write_ep_interrupts - Clear endpoint interupts
+ * @dev:	Reference to structure of type pch_udc_regs
+ * @val:	The value to be written to interrupt register
+ */
+inline void pch_udc_write_ep_interrupts(struct pch_udc_regs __iomem *dev,
+					     u32 val)
+{
+	iowrite32(val, &dev->epirqsts);
+}
+
+/**
+ * pch_udc_read_device_status - Read the device status
+ * @dev:	Reference to structure of type pch_udc_regs
+ * Retern	The device status
+ */
+inline u32 pch_udc_read_device_status(struct pch_udc_regs __iomem *dev)
+{
+	return ioread32(&dev->devsts);
+}
+
+/**
+ * pch_udc_read_ep_control - Read the endpoint control
+ * @ep:		Reference to structure of type pch_udc_ep_regs
+ * Retern	The endpoint control register value
+ */
+inline u32 pch_udc_read_ep_control(struct pch_udc_ep_regs __iomem *ep)
+{
+	return ioread32(&ep->epctl);
+}
+
+/**
+ * pch_udc_clear_ep_control - Clear the endpoint control register
+ * @ep:		Reference to structure of type pch_udc_ep_regs
+ * Retern	The endpoint control register value
+ */
+inline void pch_udc_clear_ep_control(struct pch_udc_ep_regs __iomem *ep)
+{
+	return iowrite32(0, &ep->epctl);
+}
+
+/**
+ * pch_udc_read_ep_status - Read the endpoint status
+ * @ep:		Reference to structure of type pch_udc_ep_regs
+ * Retern	The endpoint status
+ */
+inline u32 pch_udc_read_ep_status(struct pch_udc_ep_regs __iomem *ep)
+{
+	return ioread32(&ep->epsts);
+}
+
+/**
+ * pch_udc_clear_ep_status - Clear the endpoint status
+ * @ep:		Reference to structure of type pch_udc_ep_regs
+ * @stat:	Endpoint status
+ */
+inline void pch_udc_clear_ep_status(struct pch_udc_ep_regs __iomem *ep,
+					 u32 stat)
+{
+	return iowrite32(stat, &ep->epsts);
+}
+
+/**
+ * pch_udc_ep_set_nak - Set the bit 7 (SNAK field)
+ *				of the endpoint control register
+ * @ep:		Reference to structure of type pch_udc_ep_regs
+ */
+inline void pch_udc_ep_set_nak(struct pch_udc_ep_regs __iomem *ep)
+{
+	PCH_UDC_BIT_SET(&ep->epctl, 1 << UDC_EPCTL_SNAK);
+}
+
+/**
+ * pch_udc_ep_clear_nak - Set the bit 8 (CNAK field)
+ *				of the endpoint control register
+ * @ep:		reference to structure of type pch_udc_ep_regs
+ */
+void pch_udc_ep_clear_nak(struct pch_udc_ep_regs __iomem *ep)
+{
+	unsigned int loopcnt = 0;
+
+	if (ioread32(&ep->epctl) & (1 << UDC_EPCTL_NAK)) {
+		if (!(EP_IS_IN(ep))) {
+			while ((pch_udc_read_ep_status(ep) &
+					 (1 << UDC_EPSTS_MRXFIFO_EMP)) == 0) {
+				if (loopcnt++ > 100000) {
+					pr_debug("%s: RxFIFO not Empty "
+						  "loop count = %d",
+						  __func__, loopcnt);
+					break;
+				}
+				udelay(100);
+			}
+		}
+		while (ioread32(&ep->epctl) & (1 << UDC_EPCTL_NAK)) {
+			PCH_UDC_BIT_SET(&ep->epctl, 1 << UDC_EPCTL_CNAK);
+			udelay(5);
+			if (loopcnt++ >= 25) {
+				pr_debug("%s: Clear NAK not set for"
+					  "ep%d%s: counter=%d",
+					  __func__, EP_NUM(ep),
+					  (EP_IS_IN(ep) ? "in" : "out"),
+					  loopcnt);
+				break;
+			}
+		}
+	}
+}
+
+/**
+ * pch_udc_ep_fifo_flush - Flush the endpoint fifo
+ * @ep:	reference to structure of type pch_udc_ep_regs
+ * @dir:	direction of endpoint
+ *		- dir = 0 endpoint is OUT
+ *		- dir != 0 endpoint is IN
+ */
+void pch_udc_ep_fifo_flush(struct pch_udc_ep_regs __iomem *ep, int dir)
+{
+	unsigned int loopcnt = 0;
+
+	pr_debug("%s: ep%d%s", __func__, EP_NUM(ep),
+						 (EP_IS_IN(ep) ? "in" : "out"));
+	if (dir) {	/* IN ep */
+		PCH_UDC_BIT_SET(&ep->epctl, 1 << UDC_EPCTL_F);
+	} else {
+		if ((pch_udc_read_ep_status(ep) &
+		    (1 << UDC_EPSTS_MRXFIFO_EMP)) == 0) {
+			PCH_UDC_BIT_SET(&ep->epctl, 1 << UDC_EPCTL_MRXFLUSH);
+			/* Wait for RxFIFO Empty */
+			while ((pch_udc_read_ep_status(ep) &
+				(1 << UDC_EPSTS_MRXFIFO_EMP)) == 0) {
+				if (loopcnt++ > 1000000) {
+					pr_debug("RxFIFO not Empty loop"
+						  " count = %d", loopcnt);
+					break;
+				}
+				udelay(100);
+			}
+			PCH_UDC_BIT_CLR(&ep->epctl, 1 << UDC_EPCTL_MRXFLUSH);
+		}
+	}
+}
+
+/**
+ * pch_udc_ep_enable - This api enables endpoint
+ * @regs:	Reference to structure pch_udc_ep_regs
+ * @desc:	endpoint descriptor
+ */
+void pch_udc_ep_enable(struct pch_udc_ep_regs __iomem *regs,
+			  struct pch_udc_cfg_data *cfg,
+			  const struct usb_endpoint_descriptor *desc)
+{
+	u32 ep_num = EP_NUM(regs);
+	u32 ep_in = EP_IS_IN(regs);
+	u32 val = 0;
+	u32 buff_size = 0;
+
+	pr_debug("%s: ep%x%s  bmAttributes = %d wMaxPacketSize = %d", __func__,
+		  ep_num, (ep_in ? "in" : "out"), desc->bmAttributes,
+		  desc->wMaxPacketSize);
+	/* set traffic type */
+	pch_udc_ep_set_trfr_type(regs, desc->bmAttributes);
+	/* Set buff size */
+	if (ep_in)
+		buff_size = UDC_EPIN_BUFF_SIZE;
+	else
+		buff_size = UDC_EPOUT_BUFF_SIZE;
+
+	pch_udc_ep_set_bufsz(regs, buff_size, ep_in);
+	/* Set max packet size */
+	pch_udc_ep_set_maxpkt(regs, le16_to_cpu(desc->wMaxPacketSize));
+	/* Set NAK */
+	pch_udc_ep_set_nak(regs);
+	/* Flush fifo */
+	pch_udc_ep_fifo_flush(regs, ep_in);
+	/* Configure the endpoint */
+	val = ep_num << UDC_CSR_NE_NUM_OFS | ep_in << UDC_CSR_NE_DIR_OFS |
+	      ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) <<
+		UDC_CSR_NE_TYPE_OFS) |
+	      (cfg->cur_cfg << UDC_CSR_NE_CFG_OFS) |
+	      (cfg->cur_intf << UDC_CSR_NE_INTF_OFS) |
+	      (cfg->cur_alt << UDC_CSR_NE_ALT_OFS) |
+	      le16_to_cpu(desc->wMaxPacketSize) << UDC_CSR_NE_MAX_PKT_OFS;
+
+	if (ep_in)
+		pch_udc_write_csr(val, (u32) (pch_udc_base + UDC_CSR_ADDR +
+						  (ep_num * 2) * 4));
+	else
+		pch_udc_write_csr(val, (u32) (pch_udc_base + UDC_CSR_ADDR +
+						  (ep_num * 2 + 1) * 4));
+
+	pr_debug("%s: Endpoint register = 0x%08x", __func__, val);
+}
+
+
+/**
+ * pch_udc_ep_disable - This api disables endpoint
+ * @regs:	Reference to structure pch_udc_ep_regs
+ */
+void pch_udc_ep_disable(struct pch_udc_ep_regs __iomem *regs)
+{
+	pr_debug("%s: enter", __func__);
+	if (EP_IS_IN(regs)) {
+		/* flush the fifo */
+		iowrite32(1 << UDC_EPCTL_F, &regs->epctl);
+		/* set NAK */
+		iowrite32(1 << UDC_EPCTL_SNAK, &regs->epctl);
+
+		PCH_UDC_BIT_SET(&regs->epsts, 1 << UDC_EPSTS_IN);
+	} else {
+		/* set NAK */
+		iowrite32(1 << UDC_EPCTL_SNAK, &regs->epctl);
+	}
+	/* reset desc pointer */
+	iowrite32(0, &regs->desptr);
+}
+
+
+/**
+ * pch_udc_init - This API initializes usb device controller
+ * @dev:	Rreference to pch_udc_regs structure
+ */
+void pch_udc_init(struct pch_udc_regs *dev)
+{
+	u32 reset_reg;
+
+	pr_debug("%s: enter", __func__);
+	if (NULL == dev) {
+		pr_err("%s: Invalid address", __func__);
+		return;
+	}
+	/* Set the UDC_Global variable */
+	pch_udc_base = (u32) dev - UDC_DEVCFG_ADDR;
+	/* Soft Reset and Reset PHY */
+	reset_reg = (pch_udc_base + PCH_UDC_SRST_ADDR);
+	iowrite32((1 << PCH_UDC_SRST), (u32 *)(reset_reg));
+	iowrite32((1 << PCH_UDC_SRST) | (1 << PCH_UDC_PSRST),
+		   (u32 *)(reset_reg));
+	mdelay(1);
+	iowrite32((1 << PCH_UDC_SRST), (u32 *)(reset_reg));
+	iowrite32(0x00, (u32 *)(reset_reg));
+	mdelay(1);
+
+	/* mask and clear all device interrupts */
+	PCH_UDC_BIT_SET(&dev->devirqmsk, UDC_DEVINT_MSK);
+	PCH_UDC_BIT_SET(&dev->devirqsts, UDC_DEVINT_MSK);
+
+	/* mask and clear all ep interrupts */
+	PCH_UDC_BIT_SET(&dev->epirqmsk, UDC_EPINT_MSK_DISABLE_ALL);
+	PCH_UDC_BIT_SET(&dev->epirqsts, UDC_EPINT_MSK_DISABLE_ALL);
+
+	/* enable dynamic CSR programmingi, self powered and device speed */
+	if (speed_fs) {
+		PCH_UDC_BIT_SET(&dev->devcfg, (1 << UDC_DEVCFG_CSR_PRG) |
+				(1 << UDC_DEVCFG_SP) | /* set self powered */
+				UDC_DEVCFG_SPD_FS); /* program speed - full */
+	} else { /* defaul high speed */
+		PCH_UDC_BIT_SET(&dev->devcfg, (1 << UDC_DEVCFG_CSR_PRG) |
+				(1 << UDC_DEVCFG_SP) | /* set self powered */
+				UDC_DEVCFG_SPD_HS); /* program speed - high */
+	}
+#ifdef DMA_PPB_WITH_DESC_UPDATE
+	PCH_UDC_BIT_SET(&dev->devctl,
+			  (PCH_UDC_THLEN << UDC_DEVCTL_THLEN_OFS) |
+			  (PCH_UDC_BRLEN << UDC_DEVCTL_BRLEN_OFS) |
+			  (1 << UDC_DEVCTL_MODE) | (1 << UDC_DEVCTL_BREN) |
+			  (1 << UDC_DEVCTL_DU) |
+			  (1 << UDC_DEVCTL_THE));
+#else
+	PCH_UDC_BIT_SET(&dev->devctl,
+			  (PCH_UDC_THLEN << UDC_DEVCTL_THLEN_OFS) |
+			  (PCH_UDC_BRLEN << UDC_DEVCTL_BRLEN_OFS) |
+			  (1 << UDC_DEVCTL_MODE) | (1 << UDC_DEVCTL_BREN) |
+			  (1 << UDC_DEVCTL_THE));
+#endif
+}
+
+/**
+ * pch_udc_exit - This API exit usb device controller
+ * @dev:	Reference to pch_udc_regs structure
+ */
+void pch_udc_exit(struct pch_udc_regs *dev)
+{
+	/* mask all device interrupts */
+	PCH_UDC_BIT_SET(&dev->devirqmsk, UDC_DEVINT_MSK);
+	/* mask all ep interrupts */
+	PCH_UDC_BIT_SET(&dev->epirqmsk, UDC_EPINT_MSK_DISABLE_ALL);
+	/* put device in disconnected state */
+	pch_udc_set_disconnect(dev);
+}
+
+/**
+ * pch_udc_pcd_get_frame - This API is invoked to get the current frame number
+ * @gadget:	Reference to the gadget driver
+ * Returns
+ *	0:		Success
+ *	-EINVAL:	If the gadget passed is NULL
+ */
+static int pch_udc_pcd_get_frame(struct usb_gadget *gadget)
+{
+	struct pch_udc_dev		*dev;
+
+	pr_debug("%s: enter", __func__);
+	if (gadget == NULL) {
+		pr_debug("%s: exit -EINVAL", __func__);
+		return -EINVAL;
+	}
+	dev = container_of(gadget, struct pch_udc_dev, gadget);
+	return pch_udc_get_frame(dev->regs);
+}
+
+/**
+ * pch_udc_pcd_wakeup - This API is invoked to initiate a remote wakeup
+ * @gadget:	Reference to the gadget driver
+ * Returns
+ *	0:		Success
+ *	-EINVAL:	If the gadget passed is NULL
+ */
+static int pch_udc_pcd_wakeup(struct usb_gadget *gadget)
+{
+	struct pch_udc_dev		*dev;
+	unsigned long			flags;
+
+	pr_debug("%s: enter", __func__);
+	if (gadget == NULL) {
+		pr_debug("%s: exit -EINVAL", __func__);
+		return -EINVAL;
+	}
+
+	dev = container_of(gadget, struct pch_udc_dev, gadget);
+
+	pr_debug("%s: initiate remote wakeup", __func__);
+	spin_lock_irqsave(&dev->lock, flags);
+	pch_udc_rmt_wakeup(dev->regs);
+	spin_unlock_irqrestore(&dev->lock, flags);
+	return 0;
+}
+
+/**
+ * pch_udc_pcd_selfpowered - This API is invoked to specify whether the device
+ *				is self powered or not
+ * @gadget:	Reference to the gadget driver
+ * @value:	Specifies self powered or not
+ * Returns
+ *	0:		Success
+ *	-EINVAL:	If the gadget passed is NULL
+ */
+static int pch_udc_pcd_selfpowered(struct usb_gadget *gadget, int value)
+{
+	struct pch_udc_dev		*dev;
+
+	pr_debug("%s: enter", __func__);
+	if (gadget == NULL) {
+		pr_debug("%s: exit -EINVAL", __func__);
+		return -EINVAL;
+	}
+	dev = container_of(gadget, struct pch_udc_dev, gadget);
+	if (value == 0)
+		pch_udc_clear_selfpowered(dev->regs);
+	else
+		pch_udc_set_selfpowered(dev->regs);
+	return 0;
+}
+
+/**
+ * pch_udc_pcd_pullup - This API is invoked to make the device
+ *				visible/invisible to the host
+ * @gadget:	Reference to the gadget driver
+ * @is_on:	Specifies whether the pull up is made active or inactive
+ * Returns
+ *	0:		Success
+ *	-EINVAL:	If the gadget passed is NULL
+ */
+static int pch_udc_pcd_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct pch_udc_dev		*dev;
+
+	pr_debug("%s: enter", __func__);
+	if (gadget == NULL) {
+		pr_debug("%s: exit -EINVAL", __func__);
+		return -EINVAL;
+	}
+	dev = container_of(gadget, struct pch_udc_dev, gadget);
+	if (is_on == 0)
+		pch_udc_set_disconnect(dev->regs);
+	else
+		pch_udc_clear_disconnect(dev->regs);
+	return 0;
+}
+
+/**
+ * pch_udc_pcd_vbus_session - This API is used by a driver for an external
+ *				transceiver (or GPIO) that
+ *				detects a VBUS power session starting/ending
+ * @gadget:	Reference to the gadget driver
+ * @is_active:	specifies whether the session is starting or ending
+ * Returns
+ *	0:		Success
+ *	-EINVAL:	If the gadget passed is NULL
+ */
+static int pch_udc_pcd_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+	struct pch_udc_dev	*dev;
+
+	pr_debug("%s: enter", __func__);
+	if (gadget == NULL) {
+		pr_debug("%s: exit -EINVAL", __func__);
+		return -EINVAL;
+	}
+	dev = container_of(gadget, struct pch_udc_dev, gadget);
+	pch_udc_vbus_session(dev->regs, is_active);
+	return 0;
+}
+
+/**
+ * pch_udc_pcd_vbus_draw - This API is used by gadget drivers during
+ *				SET_CONFIGURATION calls to
+ *				specify how much power the device can consume
+ * @gadget:	Reference to the gadget driver
+ * @mA:		specifies the current limit in 2mA unit
+ * Returns
+ *	-EINVAL:	If the gadget passed is NULL
+ *	-EOPNOTSUPP:
+ */
+static int pch_udc_pcd_vbus_draw(struct usb_gadget *gadget, unsigned int mA)
+{
+	pr_debug("%s: enter", __func__);
+	if ((gadget == NULL) || (mA > 250)) { /* Max is 250 in 2mA unit */
+		pr_debug("%s: exit -EINVAL", __func__);
+		return -EINVAL;
+	}
+	/* Could not find any regs where we can set the limit	*/
+	return -EOPNOTSUPP;
+}
+
+const struct usb_gadget_ops pch_udc_ops = {
+	.get_frame = pch_udc_pcd_get_frame,
+	.wakeup = pch_udc_pcd_wakeup,
+	.set_selfpowered = pch_udc_pcd_selfpowered,
+	.pullup = pch_udc_pcd_pullup,
+	.vbus_session = pch_udc_pcd_vbus_session,
+	.vbus_draw = pch_udc_pcd_vbus_draw,
+};
+
+/**
+ * complete_req - This API is invoked from the driver when processing
+ *			of a request is complete
+ * @ep:		Reference to the endpoint structure
+ * @req:	Reference to the request structure
+ * @status:	Indicates the success/failure of completion
+ */
+static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req,
+								 int status)
+{
+	struct pch_udc_dev	*dev;
+	unsigned halted = ep->halted;
+
+	pr_debug("%s: enter", __func__);
+	list_del_init(&req->queue);
+
+	/* set new status if pending */
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = status;
+	else
+		status = req->req.status;
+
+	dev = ep->dev;
+	if (req->dma_mapped) {
+		if (ep->in) {
+			pci_unmap_single(dev->pdev, req->req.dma,
+					   req->req.length, PCI_DMA_TODEVICE);
+		} else {
+			pci_unmap_single(dev->pdev, req->req.dma,
+					   req->req.length, PCI_DMA_FROMDEVICE);
+		}
+		req->dma_mapped = 0;
+		req->req.dma = DMA_ADDR_INVALID;
+	}
+	ep->halted = 1;
+
+	pr_debug("%s: %s req %p status %d len %u pch-req 0x%08x"
+		  "req->queue 0x%08x", __func__,
+		  ep->ep.name, &req->req, status, req->req.length,
+		  (u32)req, (u32)(&(req->queue)));
+	spin_unlock(&dev->lock);
+	if (!ep->in)
+		pch_udc_ep_clear_rrdy(ep->regs);
+
+	req->req.complete(&ep->ep, &req->req);
+
+	spin_lock(&dev->lock);
+	ep->halted = halted;
+}
+
+/**
+ * empty_req_queue - This API empties the request queue of an endpoint
+ * @ep:		Reference to the endpoint structure
+ */
+void empty_req_queue(struct pch_udc_ep *ep)
+{
+	struct pch_udc_request	*req;
+
+	pr_debug("%s: enter", __func__);
+	ep->halted = 1;
+	while (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct pch_udc_request, queue);
+		pr_debug("%s: complete_req  ep%d%s", __func__, ep->num,
+			  (ep->in ? "in" : "out"));
+		complete_req(ep, req, -ESHUTDOWN);
+	}
+}
+
+/**
+ * pch_udc_free_dma_chain - This function frees the DMA chain created
+ *				for the request
+ * @dev		Reference to the driver structure
+ * @req		Reference to the request to be freed
+ * Return	0: Success
+ */
+static int pch_udc_free_dma_chain(struct pch_udc_dev *dev,
+						 struct pch_udc_request *req)
+{
+	struct pch_udc_data_dma_desc	*td;
+	struct pch_udc_data_dma_desc	*td_last;
+	u32 i;
+
+	pr_debug("%s: enter", __func__);
+	/* do not free first desc., will be done by free for request */
+	td_last = req->td_data;
+	td = phys_to_virt(td_last->next);
+
+	for (i = 1; i < req->chain_len; i++) {
+		pci_pool_free(dev->data_requests, td,
+				(dma_addr_t) td_last->next);
+		td_last = td;
+		td = phys_to_virt(td_last->next);
+	}
+	return 0;
+}
+
+/**
+ * pch_udc_create_dma_chain - This function creates or reinitializes
+ *				a DMA chain
+ * @ep:		Reference to the endpoint structure
+ * @req:	Reference to the request
+ * @buf_len:	The buffer length
+ * @gfp_flags:	Flags to be used while mapping the data buffer
+ * Return
+ *	0:		success,
+ *	-ENOMEM:	pci_pool_alloc invocation fails
+ */
+static int pch_udc_create_dma_chain(struct pch_udc_ep *ep,
+					 struct pch_udc_request *req,
+					 unsigned long buf_len,
+					 gfp_t gfp_flags)
+{
+	unsigned long bytes = req->req.length;
+	unsigned int i;
+	dma_addr_t dma_addr;
+	struct pch_udc_data_dma_desc	*td = NULL;
+	struct pch_udc_data_dma_desc	*last = NULL;
+	unsigned long txbytes;
+	unsigned len;
+
+	pr_debug("%s: enter  bytes = %ld buf_len = %ld", __func__,
+		  bytes, buf_len);
+	/* unset L bit in first desc for OUT */
+	if (!ep->in)
+		req->td_data->status = PCH_UDC_BS_HST_BSY;
+
+	/* alloc only new desc's if not already available */
+	len = req->req.length / buf_len;
+	if (req->req.length % buf_len)
+		len++;
+
+	/* shorter chain already allocated before */
+	if (req->chain_len > 1)
+		pch_udc_free_dma_chain(ep->dev, req);
+
+	req->chain_len = len;
+
+	td = req->td_data;
+	/* gen. required number of descriptors and buffers */
+	for (i = buf_len; i < bytes; i += buf_len) {
+		dma_addr = DMA_ADDR_INVALID;
+		/* create or determine next desc. */
+		td = pci_pool_alloc(ep->dev->data_requests, gfp_flags,
+				      &dma_addr);
+		if (td == NULL)
+			return -ENOMEM;
+
+		td->status = 0;
+		td->dataptr = req->req.dma + i; /* assign buffer */
+
+		if ((bytes - i) >= buf_len) {
+			txbytes = buf_len;
+		} else { /* short packet */
+			txbytes = bytes - i;
+		}
+		/* link td and assign tx bytes */
+		if (i == buf_len) {
+			req->td_data->next = dma_addr;
+			/* set the count bytes */
+			if (ep->in) {
+				req->td_data->status = PCH_UDC_BS_HST_BSY |
+							  buf_len;
+				/* second desc */
+				td->status = PCH_UDC_BS_HST_BSY | txbytes;
+			} else {
+				td->status = PCH_UDC_BS_HST_BSY;
+			}
+		} else {
+			last->next = dma_addr;
+			if (ep->in)
+				td->status = PCH_UDC_BS_HST_BSY | txbytes;
+			else
+				td->status = PCH_UDC_BS_HST_BSY;
+
+		}
+		last = td;
+	}
+	/* set last bit */
+	if (td) {
+		td->status |= PCH_UDC_DMA_LAST;
+		/* last desc. points to itself */
+		req->td_data_last = td;
+		td->next = req->td_data_phys;
+	}
+	return 0;
+}
+
+/**
+ * prepare_dma - This function creates and initializes the DMA chain
+ *			for the request
+ * @ep:		Reference to the endpoint structure
+ * @req:	Reference to the request
+ * @gfp:	Flag to be used while mapping the data buffer
+ * Returns
+ *	0:		Success
+ *	Other 0:	linux error number on failure
+ */
+static int prepare_dma(struct pch_udc_ep *ep, struct pch_udc_request *req,
+			  gfp_t gfp)
+{
+	int	retval = 0;
+
+	pr_debug("%s: enter  req->req.dma=0x%08x", __func__, req->req.dma);
+	/* set buffer pointer */
+	req->td_data->dataptr = req->req.dma;
+	/* set last bit */
+	req->td_data->status |= PCH_UDC_DMA_LAST;
+
+	/* Allocate and create a DMA chain */
+	retval = pch_udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp);
+	if (retval != 0) {
+		if (retval == -ENOMEM)
+			pr_err("%s: Out of DMA memory", __func__);
+		return retval;
+	}
+	if (ep->in) {
+		if (req->req.length <= ep->ep.maxpacket) {
+			/* write tx bytes */
+			req->td_data->status = PCH_UDC_DMA_LAST |
+						  PCH_UDC_BS_HST_BSY |
+						  req->req.length;
+		}
+	}
+
+	if (ep->in) {
+		/* if bytes < max packet then tx bytes must
+		 *be written in packet per buffer mode
+		 */
+		if ((req->req.length < ep->ep.maxpacket) || (ep->num == 0)) {
+			/* write the count */
+			req->td_data->status = (req->td_data->status &
+						   ~PCH_UDC_RXTX_BYTES) |
+						  req->req.length;
+		}
+		/* set HOST BUSY */
+		req->td_data->status = (req->td_data->status &
+					   ~PCH_UDC_BUFF_STS) |
+					  PCH_UDC_BS_HST_BSY;
+	}
+	return retval;
+}
+
+/**
+ * process_zlp - This function process zero length packets
+ *			from the gadget driver
+ * @ep:		Reference to the endpoint structure
+ * @req:	Reference to the request
+ */
+static void process_zlp(struct pch_udc_ep *ep, struct pch_udc_request *req)
+{
+	struct pch_udc_dev	*dev = ep->dev;
+
+	pr_debug("%s: enter  ep%d%s",
+				__func__, ep->num, (ep->in ? "in" : "out"));
+	/* IN zlp's are handled by hardware */
+	complete_req(ep, req, 0);
+
+	/* if set_config or set_intf is waiting for ack by zlp
+	 *then set CSR_DONE
+	 */
+	if (dev->set_cfg_not_acked) {
+		pr_debug("%s: process_zlp: csr done", __func__);
+		pch_udc_set_csr_done(dev->regs);
+		dev->set_cfg_not_acked = 0;
+	}
+	/* setup command is ACK'ed now by zlp */
+	if (!dev->stall) {
+		if (dev->waiting_zlp_ack) {
+			/* clear NAK by writing CNAK in EP0_IN */
+			pch_udc_ep_clear_nak(dev->ep[UDC_EP0IN_IDX].regs);
+			dev->waiting_zlp_ack = 0;
+		}
+	}
+}
+
+/**
+ * pch_udc_start_rxrequest - This function starts the receive requirement.
+ * @ep:		Reference to the endpoint structure
+ * @req:	Reference to the request structure
+ */
+static void pch_udc_start_rxrequest(struct pch_udc_ep *ep,
+					 struct pch_udc_request *req)
+{
+	struct pch_udc_data_dma_desc *td_data;
+
+	pr_debug("%s: enter", __func__);
+	pch_udc_clear_dma(ep->dev->regs, DMA_DIR_RX);
+	td_data = req->td_data;
+	ep->td_data = req->td_data;
+	/* Set the status bits for all descriptors */
+	while (1) {
+		td_data->status = (td_data->status & ~PCH_UDC_BUFF_STS) |
+				    PCH_UDC_BS_HST_RDY;
+		if ((td_data->status & PCH_UDC_DMA_LAST) ==  PCH_UDC_DMA_LAST)
+			break;
+
+		td_data = (struct pch_udc_data_dma_desc *) \
+			   phys_to_virt(td_data->next);
+	}
+	/* Write the descriptor pointer */
+	pch_udc_ep_set_ddptr(ep->regs, req->td_data_phys);
+	req->dma_going = 1;
+	pch_udc_enable_ep_interrupts(ep->dev->regs,
+					 1 << (ep->num + UDC_EPINT_OUT_EP0));
+	pch_udc_set_dma(ep->dev->regs, DMA_DIR_RX);
+	pch_udc_ep_clear_nak(ep->regs);
+	pch_udc_ep_set_rrdy(ep->regs);
+}
+
+/**
+ * pch_udc_pcd_ep_enable - This API enables the endpoint. It is called
+ *				from gadget driver
+ * @usbep:	Reference to the USB endpoint structure
+ * @desc:	Reference to the USB endpoint descriptor structure
+ * Returns
+ *	0:		Success
+ *	-EINVAL:
+ *	-ESHUTDOWN:
+ */
+static int pch_udc_pcd_ep_enable(struct usb_ep *usbep,
+				    const struct usb_endpoint_descriptor *desc)
+{
+	struct pch_udc_ep	*ep;
+	struct pch_udc_dev	*dev;
+	unsigned long		iflags;
+
+	pr_debug("%s: enter", __func__);
+	if ((usbep == NULL) || (usbep->name == ep0_string) || (desc == NULL) ||
+		(desc->bDescriptorType != USB_DT_ENDPOINT) ||
+						 (desc->wMaxPacketSize == 0)) {
+		return -EINVAL;
+	}
+
+	ep = container_of(usbep, struct pch_udc_ep, ep);
+	dev = ep->dev;
+
+	pr_debug("%s: ep %d", __func__, ep->num);
+	if ((dev->driver == NULL) || (dev->gadget.speed == USB_SPEED_UNKNOWN))
+		return -ESHUTDOWN;
+
+
+	spin_lock_irqsave(&dev->lock, iflags);
+	ep->desc = desc;
+	ep->halted = 0;
+	pch_udc_ep_enable(ep->regs, &ep->dev->cfg_data, desc);
+	ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+	pch_udc_enable_ep_interrupts(ep->dev->regs,
+			1 << (ep->in ? ep->num : ep->num + UDC_EPINT_OUT_EP0));
+
+	pr_debug("%s: %s enabled", __func__, usbep->name);
+
+	spin_unlock_irqrestore(&dev->lock, iflags);
+	return 0;
+}
+
+/**
+ * pch_udc_pcd_ep_disable - This API disables endpoint and is called
+ *				from gadget driver
+ * @usbep	Reference to the USB endpoint structure
+ * Returns
+ *	0:		Success
+ *	-EINVAL:
+ */
+static int pch_udc_pcd_ep_disable(struct usb_ep *usbep)
+{
+	struct pch_udc_ep	*ep = NULL;
+	unsigned long	iflags;
+
+	pr_debug("%s: enter", __func__);
+	if (usbep == NULL)
+		return -EINVAL;
+
+	ep = container_of(usbep, struct pch_udc_ep, ep);
+	if ((usbep->name == ep0_string) || (ep->desc == NULL))
+		return -EINVAL;
+
+	pr_debug("%s: ep%d%s", __func__, ep->num,
+						 (ep->in ? "in" : "out"));
+	spin_lock_irqsave(&ep->dev->lock, iflags);
+	empty_req_queue(ep);
+	ep->halted = 1;
+	pch_udc_ep_disable(ep->regs);
+
+	/* disable interrupt */
+	pch_udc_disable_ep_interrupts(ep->dev->regs,
+			1 << (ep->in ? ep->num : ep->num + UDC_EPINT_OUT_EP0));
+	ep->desc = NULL;
+	INIT_LIST_HEAD(&ep->queue);
+	spin_unlock_irqrestore(&ep->dev->lock, iflags);
+	return 0;
+}
+
+/**
+ * pch_udc_alloc_request - This function allocates request structure.
+ *				It iscalled by gadget driver
+ * @usbep:	Reference to the USB endpoint structure
+ * @gfp:	Flag to be used while allocating memory
+ * Returns
+ *	NULL:			Failure
+ *	Allocated address:	Success
+ */
+static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep,
+								 gfp_t gfp)
+{
+	struct pch_udc_request	*req;
+	struct pch_udc_ep		*ep;
+
+	pr_debug("%s: enter", __func__);
+	if (usbep == NULL)
+		return NULL;
+
+	ep = container_of(usbep, struct pch_udc_ep, ep);
+	pr_debug("%s: ep %s", __func__, usbep->name);
+	req = kzalloc(sizeof(struct pch_udc_request), gfp);
+	if (req == NULL) {
+		pr_debug("%s: no memory for request", __func__);
+		return NULL;
+	}
+	memset(req, 0, sizeof(struct pch_udc_request));
+	req->req.dma = DMA_ADDR_INVALID;
+	INIT_LIST_HEAD(&req->queue);
+
+	if (ep->dma != NULL) {
+		struct pch_udc_data_dma_desc	*dma_desc;
+
+		/* ep0 in requests are allocated from data pool here */
+		dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp,
+							 &req->td_data_phys);
+		if (NULL == dma_desc) {
+			kfree(req);
+			return NULL;
+		}
+
+		pr_debug("%s: req = 0x%p dma_desc = 0x%p, "
+			"td_phys = 0x%08lx", __func__,
+			req, dma_desc, (unsigned long)req->td_data_phys);
+
+		/* prevent from using desc. - set HOST BUSY */
+		dma_desc->status |= PCH_UDC_BS_HST_BSY;
+		dma_desc->dataptr = __constant_cpu_to_le32(DMA_ADDR_INVALID);
+		req->td_data = dma_desc;
+		req->td_data_last = dma_desc;
+		req->chain_len = 1;
+	}
+	return &req->req;
+}
+
+/**
+ * pch_udc_free_request - This function frees request structure.
+ *				It is called by gadget driver
+ * @usbep:	Reference to the USB endpoint structure
+ * @usbreq:	Reference to the USB request
+ */
+static void pch_udc_free_request(struct usb_ep *usbep,
+						 struct usb_request *usbreq)
+{
+	struct pch_udc_ep	*ep;
+	struct pch_udc_request	*req;
+
+	pr_debug("%s: enter", __func__);
+	if ((usbep == NULL) || (usbreq == NULL))
+		return;
+
+	ep = container_of(usbep, struct pch_udc_ep, ep);
+	req = container_of(usbreq, struct pch_udc_request, req);
+	pr_debug("%s: %s  req = 0x%p", __func__, usbep->name, req);
+
+	if (!list_empty(&req->queue))
+		pr_err("%s: %s  req = 0x%p  queue not empty", __func__,
+		       usbep->name, req);
+
+	if (req->td_data != NULL) {
+		if (req->chain_len > 1)
+			pch_udc_free_dma_chain(ep->dev, req);
+		else
+			pci_pool_free(ep->dev->data_requests, req->td_data,
+							 req->td_data_phys);
+
+	}
+	kfree(req);
+}
+
+/**
+ * pch_udc_pcd_queue - This function queues a request packet. It is called
+ *			by gadget driver
+ * @usbep:	Reference to the USB endpoint structure
+ * @usbreq:	Reference to the USB request
+ * @gfp:	Flag to be used while mapping the data buffer
+ * Returns
+ *	0:			Success
+ *	linux error number:	Failure
+ */
+static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq,
+								 gfp_t gfp)
+{
+	int retval = 0;
+	struct pch_udc_ep	*ep;
+	struct pch_udc_dev	*dev;
+	struct pch_udc_request	*req;
+	unsigned long	iflags;
+
+	pr_debug("%s: enter", __func__);
+	if ((usbep == NULL) || (usbreq == NULL) || (usbreq->complete == NULL) ||
+						 (usbreq->buf == NULL)) {
+		pr_debug("%s: Invalid end point OR request", __func__);
+		return -EINVAL;
+	}
+
+	ep = container_of(usbep, struct pch_udc_ep, ep);
+	if ((ep->desc == NULL) && (ep->num != 0)) {
+		pr_debug("%s: Trying to queue before before enabling "
+				"the end point %d", __func__, ep->num);
+		/* Don't let non-control ep queue before enable */
+		return -EINVAL;
+	}
+	req = container_of(usbreq, struct pch_udc_request, req);
+	pr_debug("%s: ep%d%s  req = 0x%08x", __func__, ep->num,
+					 (ep->in ? "in" : "out"), (u32)req);
+	if (!list_empty(&req->queue)) {
+		pr_debug("%s: list_empty error: req->queue = 0x%08x"
+				 " pch-req = 0x%08x",
+				__func__, (u32)(&(req->queue)), (u32)req);
+		return -EINVAL;
+	}
+	dev = ep->dev;
+	if ((dev->driver == NULL) || (dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+		pr_debug("%s: Gadget not bound/invalid dev->driver = 0x%p "
+				" speed = 0x%x",
+				__func__, dev->driver, dev->gadget.speed);
+		return -ESHUTDOWN;
+	}
+	spin_lock_irqsave(&ep->dev->lock, iflags);
+	/* map the buffer for dma */
+	if ((usbreq->length != 0) &&
+		((usbreq->dma == DMA_ADDR_INVALID) || (usbreq->dma == 0))) {
+		if (ep->in) {
+			usbreq->dma = pci_map_single(dev->pdev, usbreq->buf,
+					usbreq->length, PCI_DMA_TODEVICE);
+		} else {
+			usbreq->dma = pci_map_single(dev->pdev, usbreq->buf,
+					usbreq->length, PCI_DMA_FROMDEVICE);
+		}
+		req->dma_mapped = 1;
+	}
+
+	if (usbreq->length > 0) { /* setup the descriptors */
+		retval = prepare_dma(ep, req, gfp);
+		if (retval != 0) {
+			/* Need to unmap before returning? ...
+							 req->dma_mapped = 1; */
+			spin_unlock_irqrestore(&dev->lock, iflags);
+			return retval;
+		}
+	}
+
+	usbreq->actual = 0;
+	usbreq->status = -EINPROGRESS;
+	req->dma_done = 0;
+
+	if (list_empty(&ep->queue) && !ep->halted) {
+		/* no pending transfer, so start this req */
+		if ((usbreq->length == 0)) {
+			process_zlp(ep, req);
+			spin_unlock_irqrestore(&dev->lock, iflags);
+			return 0;
+		}
+		if (!ep->in) {
+			pch_udc_start_rxrequest(ep, req);
+		} else {
+			/*
+			* For IN trfr the descriptors will be programmed and
+			* P bit will be set when
+			* we get an IN token
+			*/
+
+			while (pch_udc_read_ep_control(ep->regs) &
+							 (1 << UDC_EPCTL_S))
+				udelay(100);
+
+			pch_udc_ep_clear_nak(ep->regs);
+			pch_udc_enable_ep_interrupts(ep->dev->regs,
+							 (1 << ep->num));
+			/* enable DMA */
+			pch_udc_set_dma(dev->regs, DMA_DIR_TX);
+		}
+	}
+	pr_debug("%s: desc[stat:0x%08x  dptr:0x%08x next:0x%08x]",
+			__func__, req->td_data->status, req->td_data->dataptr,
+							 req->td_data->next);
+	/* Now add this request to the ep's pending requests */
+	if (req != NULL)
+		list_add_tail(&req->queue, &ep->queue);
+
+	spin_unlock_irqrestore(&dev->lock, iflags);
+	return retval;
+}
+
+/**
+ * pch_udc_pcd_dequeue - This function de-queues a request packet.
+ *				It is called by gadget driver
+ * @usbep:	Reference to the USB endpoint structure
+ * @usbreq:	Reference to the USB request
+ * Returns
+ *	0:			Success
+ *	linux error number:	Failure
+ */
+static int pch_udc_pcd_dequeue(struct usb_ep *usbep,
+				struct usb_request *usbreq)
+{
+	struct pch_udc_ep		*ep;
+	struct pch_udc_request	*req;
+	unsigned long			flags;
+
+	pr_debug("%s: enter", __func__);
+	ep = container_of(usbep, struct pch_udc_ep, ep);
+	if ((usbep == NULL) || (usbreq == NULL) ||
+			((ep->desc == NULL) && (ep->num != 0))) {
+		return -EINVAL;
+	}
+	pr_debug("%s: enter  ep%d%s", __func__, ep->num,
+						 (ep->in ? "in" : "out"));
+	req = container_of(usbreq, struct pch_udc_request, req);
+	spin_lock_irqsave(&ep->dev->lock, flags);
+	/* make sure it's still queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == usbreq)
+			break;
+
+	}
+
+	if (&req->req != usbreq) {
+		spin_unlock_irqrestore(&ep->dev->lock, flags);
+		return -EINVAL;
+	}
+	pch_udc_ep_set_nak(ep->regs);
+	if (!list_empty(&req->queue))
+		complete_req(ep, req, -ECONNRESET);
+
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+	return 0;
+}
+
+/**
+ * pch_udc_pcd_set_halt - This function Sets or clear the endpoint halt feature
+ * @usbep:	Reference to the USB endpoint structure
+ * @halt:	Specifies whether to set or clear the feature
+ * Returns
+ *	0:			Success
+ *	linux error number:	Failure
+ */
+static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt)
+{
+	struct pch_udc_ep	*ep;
+	unsigned long iflags;
+
+	if (usbep == NULL)
+		return -EINVAL;
+
+
+	pr_debug("%s: %s: halt=%d", __func__, usbep->name, halt);
+	ep = container_of(usbep, struct pch_udc_ep, ep);
+	if ((ep->desc == NULL) && (ep->num == 0)) {
+		pr_debug("%s: ep->desc = 0x%x: ep->num = 0x%x",
+				__func__, (u32)(ep->desc), ep->num);
+		return -EINVAL;
+	}
+	if ((ep->dev->driver == NULL) || (ep->dev->gadget.speed\
+						 == USB_SPEED_UNKNOWN)) {
+		pr_debug("%s: ep->dev->driver = 0x%x:"
+				" ep->dev->gadget.speed = 0x%x",
+				__func__, (u32)(ep->dev->driver),
+				 ep->dev->gadget.speed);
+		return -ESHUTDOWN;
+	}
+
+	spin_lock_irqsave(&udc_stall_spinlock, iflags);
+
+	if (!list_empty(&ep->queue)) {
+		pr_debug("%s: list not empty", __func__);
+		spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
+		return -EAGAIN;
+	}
+	/* halt or clear halt */
+	if (halt == 0) {
+			pch_udc_ep_clear_stall(ep->regs);
+	} else {
+		if (ep->num == PCH_UDC_EP0)
+			ep->dev->stall = 1;
+
+		pch_udc_ep_set_stall(ep->regs);
+		pch_udc_enable_ep_interrupts(ep->dev->regs,
+			1 << (ep->in ? ep->num : ep->num + UDC_EPINT_OUT_EP0));
+	}
+	spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
+	return 0;
+}
+
+/**
+ * pch_udc_pcd_set_wedge - This function Sets or clear the endpoint
+ *				halt feature
+ * @usbep:	Reference to the USB endpoint structure
+ * @halt:	Specifies whether to set or clear the feature
+ * Returns
+ *	0:			Success
+ *	linux error number:	Failure
+ */
+static int pch_udc_pcd_set_wedge(struct usb_ep *usbep)
+{
+	struct pch_udc_ep	*ep;
+	unsigned long iflags;
+
+	if (usbep == NULL)
+		return -EINVAL;
+
+	pr_debug("%s: %s:", __func__, usbep->name);
+	ep = container_of(usbep, struct pch_udc_ep, ep);
+	if ((ep->desc == NULL) && (ep->num == 0)) {
+		pr_debug("%s: ep->desc = 0x%x: ep->num = 0x%x",
+				__func__, (u32)(ep->desc), ep->num);
+		return -EINVAL;
+	}
+	if ((ep->dev->driver == NULL) || (ep->dev->gadget.speed ==\
+							 USB_SPEED_UNKNOWN)) {
+		pr_debug("%s: ep->dev->driver = 0x%x:"
+				" ep->dev->gadget.speed = 0x%x",
+				__func__, (u32)(ep->dev->driver),
+				 ep->dev->gadget.speed);
+		return -ESHUTDOWN;
+	}
+
+	spin_lock_irqsave(&udc_stall_spinlock, iflags);
+
+	if (!list_empty(&ep->queue)) {
+		pr_debug("%s: list not empty", __func__);
+		spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
+		return -EAGAIN;
+	}
+	/* halt */
+	if (ep->num == PCH_UDC_EP0)
+		ep->dev->stall = 1;
+
+	pch_udc_ep_set_stall(ep->regs);
+	pch_udc_enable_ep_interrupts(ep->dev->regs,
+		1 << (ep->in ? ep->num : ep->num + UDC_EPINT_OUT_EP0));
+
+	ep->dev->prot_stall = 1;
+	spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
+	return 0;
+}
+
+/**
+ * pch_udc_pcd_fifo_flush - This function Flush the FIFO of specified endpoint
+ * @usbep:	Reference to the USB endpoint structure
+ */
+static void pch_udc_pcd_fifo_flush(struct usb_ep *usbep)
+{
+	struct pch_udc_ep	*ep;
+
+	if (usbep == NULL)
+		return;
+
+	pr_debug("%s: %s", __func__, usbep->name);
+	ep = container_of(usbep, struct pch_udc_ep, ep);
+	if ((ep->desc == NULL) && (ep->num != 0))
+		return;
+	pch_udc_ep_fifo_flush(ep->regs, ep->in);
+}
+
+static const struct usb_ep_ops pch_udc_ep_ops = {
+	.enable		= pch_udc_pcd_ep_enable,
+	.disable	= pch_udc_pcd_ep_disable,
+	.alloc_request	= pch_udc_alloc_request,
+	.free_request	= pch_udc_free_request,
+	.queue		= pch_udc_pcd_queue,
+	.dequeue	= pch_udc_pcd_dequeue,
+	.set_halt	= pch_udc_pcd_set_halt,
+	.set_wedge	= pch_udc_pcd_set_wedge,
+	.fifo_status	= NULL,
+	.fifo_flush	= pch_udc_pcd_fifo_flush,
+};
+
+/**
+ * pch_udc_init_setup_buff - This function initializes the SETUP buffer
+ * @td_stp:	Reference to the SETP buffer structure
+ */
+static void pch_udc_init_setup_buff(struct pch_udc_stp_dma_desc *td_stp)
+{
+	static u32	pky_marker;
+
+	pr_debug("%s: enter", __func__);
+	if (td_stp == NULL) {
+		pr_debug("%s: SETUP BUFF == NULL", __func__);
+		return;
+	}
+	td_stp->reserved = ++pky_marker;
+	td_stp->data12 = 0xFFFFFFFF;
+	td_stp->data34 = 0xFFFFFFFF;
+	td_stp->status = PCH_UDC_BS_HST_RDY;
+}
+
+/**
+ * pch_udc_start_next_txrequest - This function starts
+ *					the next transmission requirement
+ * @ep:	Reference to the endpoint structure
+ */
+static void pch_udc_start_next_txrequest(struct pch_udc_ep *ep)
+{
+	struct pch_udc_request *req;
+
+	pr_debug("%s: enter", __func__);
+	if (pch_udc_read_ep_control(ep->regs) & (1 << UDC_EPCTL_P))
+		return;
+
+	if (!list_empty(&ep->queue)) {
+		/* next request */
+		req = list_entry(ep->queue.next, struct pch_udc_request, queue);
+		if (req && !req->dma_going) {
+			pr_debug("%s: Set request: req=%p req->td_data=%p",
+					__func__, req, req->td_data);
+			if (req->td_data) {
+				struct pch_udc_data_dma_desc *td_data;
+
+				while (pch_udc_read_ep_control(ep->regs) &
+							 (1 << UDC_EPCTL_S))
+					udelay(100);
+
+				req->dma_going = 1;
+				/* Clear the descriptor pointer */
+				pch_udc_ep_set_ddptr(ep->regs, 0);
+
+				td_data = req->td_data;
+				while (1) {
+					td_data->status = (td_data->status &
+						 ~PCH_UDC_BUFF_STS) |
+						 PCH_UDC_BS_HST_RDY;
+					if ((td_data->status &
+						 PCH_UDC_DMA_LAST) ==
+						 PCH_UDC_DMA_LAST)
+						break;
+
+					td_data =
+					(struct pch_udc_data_dma_desc *)\
+					phys_to_virt(td_data->next);
+				}
+				/* Write the descriptor pointer */
+				pch_udc_ep_set_ddptr(ep->regs,
+							 req->td_data_phys);
+				pch_udc_set_dma(ep->dev->regs, DMA_DIR_TX);
+				/* Set the poll demand bit */
+				pch_udc_ep_set_pd(ep->regs);
+				pch_udc_enable_ep_interrupts(ep->dev->regs,
+						1 << (ep->in ? ep->num :\
+						 ep->num + UDC_EPINT_OUT_EP0));
+				pch_udc_ep_clear_nak(ep->regs);
+			}
+		}
+	}
+}
+
+/**
+ * pch_udc_complete_transfer - This function completes a transfer
+ * @ep:		Reference to the endpoint structure
+ */
+static void pch_udc_complete_transfer(struct pch_udc_ep	*ep)
+{
+	struct pch_udc_request *req;
+
+	pr_debug("%s: enter", __func__);
+	if (!list_empty(&ep->queue)) {
+		pr_debug("%s: list_entry", __func__);
+		req = list_entry(ep->queue.next, struct pch_udc_request, queue);
+		if (req && ((req->td_data_last->status & PCH_UDC_BUFF_STS) ==
+							 PCH_UDC_BS_DMA_DONE)) {
+#ifdef DMA_PPB_WITH_DESC_UPDATE
+			struct pch_udc_data_dma_desc *td_data = req->td_data;
+			for (i = 0; i < req->chain_len; i++) {
+				if ((td_data->status & PCH_UDC_RXTX_STS) !=
+							 PCH_UDC_RTS_SUCC) {
+					pr_err("Invalid RXTX status (0x%08x)"
+					       " epstatus=0x%08x\n",
+					       (td_data->status &
+						PCH_UDC_RXTX_STS),
+					       (int)(ep->epsts));
+					return;
+				}
+				td_data = (struct pch_udc_data_dma_desc *)
+						 phys_to_virt(td_data->next);
+			}
+#else
+			if ((req->td_data_last->status & PCH_UDC_RXTX_STS) !=
+							 PCH_UDC_RTS_SUCC) {
+				pr_err("Invalid RXTX status (0x%08x)"
+				       " epstatus=0x%08x\n",
+				       (req->td_data_last->status &
+					PCH_UDC_RXTX_STS),
+				       (int)(ep->epsts));
+				return;
+			}
+#endif
+			req->req.actual = req->req.length;
+			req->td_data_last->status = PCH_UDC_BS_HST_BSY |
+							 PCH_UDC_DMA_LAST;
+			req->td_data->status = PCH_UDC_BS_HST_BSY |
+							 PCH_UDC_DMA_LAST;
+			/* complete req */
+			complete_req(ep, req, 0);
+			req->dma_going = 0;
+			if (!list_empty(&ep->queue)) {
+				while (pch_udc_read_ep_control(ep->regs) &
+							 (1 << UDC_EPCTL_S))
+					udelay(100);
+
+				pch_udc_ep_clear_nak(ep->regs);
+				pch_udc_enable_ep_interrupts(ep->dev->regs,
+					1 << (ep->in ? ep->num : ep->num +
+							 UDC_EPINT_OUT_EP0));
+			} else {
+				pch_udc_disable_ep_interrupts(ep->dev->regs,
+					1 << (ep->in ? ep->num : ep->num +
+							 UDC_EPINT_OUT_EP0));
+			}
+		}
+	}
+}
+
+/**
+ * pch_udc_complete_receiver - This function completes a receiver
+ * @ep:		Reference to the endpoint structure
+ */
+static void pch_udc_complete_receiver(struct pch_udc_ep	*ep)
+{
+	struct pch_udc_request *req;
+	unsigned int count;
+
+	pr_debug("%s: enter", __func__);
+	if (!list_empty(&ep->queue)) {
+		/* next request */
+		req = list_entry(ep->queue.next, struct pch_udc_request, queue);
+		if (req && (req->td_data_last->status & PCH_UDC_BUFF_STS) ==
+							PCH_UDC_BS_DMA_DONE) {
+			pr_debug("%s: ep%d%s  DMA Done", __func__,
+					 ep->num, (ep->in ? "in" : "out"));
+			/* Disable DMA */
+			pch_udc_clear_dma(ep->dev->regs, DMA_DIR_RX);
+#ifdef DMA_PPB_WITH_DESC_UPDATE
+{
+			/* Get Rx bytes */
+			struct pch_udc_data_dma_desc *td_data = req->td_data;
+			for (i = 0, count = 0; i < req->chain_len; i++) {
+				if ((td_data->status & PCH_UDC_RXTX_STS) !=
+							 PCH_UDC_RTS_SUCC) {
+					pr_err("Invalid RXTX status (0x%08x)"
+					       " epstatus=0x%08x\n",
+					       (td_data->status &
+						PCH_UDC_RXTX_STS),
+					       (int)(ep->epsts));
+					return;
+				}
+				count += td_data->status & PCH_UDC_RXTX_BYTES;
+				td_data = (struct pch_udc_data_dma_desc *)\
+						 phys_to_virt(td_data->next);
+			}
+}
+#else
+			if ((req->td_data_last->status & PCH_UDC_RXTX_STS) !=
+							 PCH_UDC_RTS_SUCC) {
+				pr_err("Invalid RXTX status (0x%08x)"
+				       " epstatus=0x%08x\n",
+				       (req->td_data_last->status &
+					PCH_UDC_RXTX_STS),
+				       (int)(ep->epsts));
+				return;
+			}
+			count = req->td_data_last->status & PCH_UDC_RXTX_BYTES;
+#endif
+			if ((count == 0) && (req->req.length ==
+						 UDC_DMA_MAXPACKET)) {
+				/* on 64k packets the RXBYTES field is zero */
+				count = UDC_DMA_MAXPACKET;
+			}
+
+			/* Set the descriptor status */
+			req->td_data->status |= PCH_UDC_DMA_LAST;
+			req->td_data_last->status |= PCH_UDC_BS_HST_BSY;
+
+			req->dma_going = 0;
+			/* complete request */
+			req->req.actual = count;
+			complete_req(ep, req, 0);
+
+			/* If there is a new/failed requests try that now */
+			if (!list_empty(&ep->queue)) {
+				req = list_entry(ep->queue.next,
+					 struct pch_udc_request, queue);
+				pch_udc_start_rxrequest(ep, req);
+			}
+		}
+#ifdef DMA_PPB_WITH_DESC_UPDATE
+		else {
+			pr_debug("%s: ep%d%s  DMA not Done",
+				__func__, ep->num, (ep->in ? "in" : "out"));
+			pch_udc_ep_set_rrdy(ep->regs);
+		}
+#endif
+	}
+}
+
+/**
+ * pch_udc_svc_data_in - This function process endpoint interrupts
+ *				for IN endpoints
+ * @dev:	Reference to the device structure
+ * @ep_num:	Endpoint that generated the interrupt
+ */
+static void pch_udc_svc_data_in(struct pch_udc_dev *dev, int ep_num)
+{
+	u32	epsts;
+	struct pch_udc_ep	*ep;
+	ep = &dev->ep[2*ep_num];
+	epsts = ep->epsts;
+	ep->epsts = 0;
+
+	pr_debug("%s: enter  ep%d%s status = 0x%08x", __func__, ep->num,
+					 (ep->in ? "in" : "out"), epsts);
+
+	if ((epsts & ((1 << UDC_EPSTS_IN) | (1 << UDC_EPSTS_BNA)  |
+						 (1 << UDC_EPSTS_HE) |
+			 (1 << UDC_EPSTS_TDC) | (1 << UDC_EPSTS_RCS) |
+						 (1 << UDC_EPSTS_TXEMPTY) |
+			 (1 << UDC_EPSTS_RSS) |
+			 (1 << UDC_EPSTS_XFERDONE))) == 0) {
+		pr_debug("%s: Non interrupt request ep%din status %x",
+				__func__, ep->num, epsts);
+		return;
+	}
+	if ((epsts & (1 << UDC_EPSTS_BNA))) { /* Just log it */
+		pr_debug("%s: BNA on ep%din occured", __func__, ep->num);
+		return;
+	}
+	if (epsts & (1 << UDC_EPSTS_HE)) {
+		pr_debug("%s: Host Error on ep%din occured",
+				__func__, ep->num);
+		return;
+	}
+	if (epsts & (1 << UDC_EPSTS_RSS)) {
+		pr_debug("%s: RSS", __func__);
+		pch_udc_ep_set_stall(ep->regs);
+		pch_udc_enable_ep_interrupts(ep->dev->regs,
+			1 << (ep->in ? ep->num : ep->num + UDC_EPINT_OUT_EP0));
+	}
+	if (epsts & (1 << UDC_EPSTS_RCS)) {
+		pr_debug("%s: RCS  prot_stall = %d",
+				__func__, dev->prot_stall);
+		if (dev->prot_stall == 0) {
+			pch_udc_ep_clear_stall(ep->regs);
+		} else {
+			pch_udc_ep_set_stall(ep->regs);
+			pch_udc_enable_ep_interrupts(ep->dev->regs,
+				1 << (ep->in ? ep->num : ep->num +
+							 UDC_EPINT_OUT_EP0));
+		}
+	}
+	if (epsts & (1 << UDC_EPSTS_TDC)) { /* DMA completed */
+		pch_udc_complete_transfer(ep);
+	}
+	/* On IN interrupt, provide data if we have any */
+	if ((epsts & (1 << UDC_EPSTS_IN)) &&
+		 ((epsts & (1 << UDC_EPSTS_RSS)) == 0) &&
+		 ((epsts & (1 << UDC_EPSTS_TDC)) == 0) &&
+		 ((epsts & (1 << UDC_EPSTS_TXEMPTY)) == 0)) {
+		pch_udc_start_next_txrequest(ep);
+	}
+	pr_debug("%s: ep ctrl = 0x%x", __func__,
+					 ioread32(&ep->regs->epctl));
+}
+
+/**
+ * pch_udc_svc_data_out - Handles interrupts from OUT endpoint
+ * @dev:	Reference to the device structure
+ * @ep_num:	Endpoint that generated the interrupt
+ */
+static void pch_udc_svc_data_out(struct pch_udc_dev *dev, int ep_num)
+{
+	u32			epsts;
+	struct pch_udc_ep		*ep;
+	struct pch_udc_request		*req = NULL;
+
+	ep = &dev->ep[2*ep_num + 1];
+	epsts = ep->epsts;
+	ep->epsts = 0;
+
+	pr_debug("%s: enter  ep%d%s status = 0x%08x", __func__, ep->num,
+					 (ep->in ? "in" : "out"), epsts);
+	if (epsts & (1 << UDC_EPSTS_BNA)) { /* Just log it; only in DMA mode */
+		if (!list_empty(&ep->queue)) {
+			/* next request */
+			req = list_entry(ep->queue.next, struct pch_udc_request,
+									 queue);
+			pr_debug("%s: BNA on ep%dout occured",
+					__func__, ep->num);
+			if ((req->td_data_last->status & PCH_UDC_BUFF_STS) !=
+							 PCH_UDC_BS_DMA_DONE) {
+				if (req->dma_going == 0)
+					pch_udc_start_rxrequest(ep, req);
+
+				return;
+			}
+		}
+	}
+	if (epsts & (1 << UDC_EPSTS_HE)) {  /* Host error - Just log it */
+		pr_debug("%s: Host Error on ep%dout occured",
+				__func__, ep->num);
+		return;
+	}
+	if (epsts & (1 << UDC_EPSTS_RSS)) {
+		pr_debug("%s: RSS", __func__);
+		pch_udc_ep_set_stall(ep->regs);
+		pch_udc_enable_ep_interrupts(ep->dev->regs,
+			1 << (ep->in ? ep->num : ep->num + UDC_EPINT_OUT_EP0));
+	}
+	if (epsts & (1 << UDC_EPSTS_RCS)) {
+		pr_debug("%s: RCS  prot_stall = %d", __func__,
+							 dev->prot_stall);
+		if (dev->prot_stall == 0) {
+			pch_udc_ep_clear_stall(ep->regs);
+		} else {
+			pch_udc_ep_set_stall(ep->regs);
+			pch_udc_enable_ep_interrupts(ep->dev->regs,
+				1 << (ep->in ? ep->num : ep->num +
+							 UDC_EPINT_OUT_EP0));
+		}
+	}
+	if (((epsts & UDC_EPSTS_OUT_MASK) >> UDC_EPSTS_OUT_OFS) ==
+						 UDC_EPSTS_OUT_DATA) {
+		if (ep->dev->prot_stall == 1) {
+			pch_udc_ep_set_stall(ep->regs);
+			pch_udc_enable_ep_interrupts(ep->dev->regs,
+				1 << (ep->in ? ep->num : ep->num +
+							 UDC_EPINT_OUT_EP0));
+		} else {
+			pch_udc_complete_receiver(ep);
+		}
+	}
+
+	if (list_empty(&ep->queue)) {
+		/* enable DMA */
+		pch_udc_set_dma(dev->regs, DMA_DIR_RX);
+	}
+}
+
+/**
+ * pch_udc_svc_control_in - Handle Control IN endpoint interrupts
+ * @dev:	Reference to the device structure
+ */
+static void pch_udc_svc_control_in(struct pch_udc_dev *dev)
+{
+	u32	epsts;
+	struct pch_udc_ep	*ep;
+
+	ep = &dev->ep[UDC_EP0IN_IDX];
+	epsts = ep->epsts;
+	ep->epsts = 0;
+
+	pr_debug("%s: enter  status 0x%x", __func__, epsts);
+	if ((epsts & ((1 << UDC_EPSTS_IN) | (1 << UDC_EPSTS_BNA)  |
+						 (1 << UDC_EPSTS_HE) |
+			 (1 << UDC_EPSTS_TDC) | (1 << UDC_EPSTS_RCS) |
+						 (1 << UDC_EPSTS_TXEMPTY) |
+			 (1 << UDC_EPSTS_XFERDONE))) == 0) {
+		pr_debug("%s: Non interrupt request ep%din status %x",
+					__func__, ep->num, epsts);
+		return;
+	}
+	if ((epsts & (1 << UDC_EPSTS_BNA))) { /* Just log it */
+		pr_debug("%s: BNA on ep%din occured", __func__, ep->num);
+		return;
+	}
+	if (epsts & (1 << UDC_EPSTS_HE)) {
+		pr_debug("%s: Host Error on ep%din occured",
+					__func__, ep->num);
+		return;
+	}
+	if (epsts & (1 << UDC_EPSTS_TXEMPTY)) { /* Tx empty */
+		pr_debug("%s: TXEMPTY", __func__);
+	}
+	if ((epsts & (1 << UDC_EPSTS_TDC)) && (!dev->stall)) {
+		/* DMA completed */
+		pr_debug("%s: TDC on ep%din", __func__, ep->num);
+		pch_udc_complete_transfer(ep);
+	}
+	/* On IN interrupt, provide data if we have any */
+	if ((epsts & (1 << UDC_EPSTS_IN)) &&
+		 ((epsts & (1 << UDC_EPSTS_TDC)) == 0) &&
+		 ((epsts & (1 << UDC_EPSTS_TXEMPTY)) == 0))	{
+		pch_udc_start_next_txrequest(ep);
+	}
+}
+
+/**
+ * pch_udc_svc_control_out - Routine that handle Control
+ *					OUT endpoint interrupts
+ * @dev:	Reference to the device structure
+ */
+static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
+{
+	u32	stat;
+	int setup_supported;
+	struct pch_udc_ep	*ep;
+
+	pr_debug("%s: enter", __func__);
+	ep = &dev->ep[UDC_EP0OUT_IDX];
+	stat = ep->epsts;
+	ep->epsts = 0;
+
+	if (stat & (1 << UDC_EPSTS_BNA)) {
+		pr_debug("%s: EP0: BNA", __func__);
+		/* When we get a request, we will populate the descriptors. */
+		/* Anything else to do? */
+	}
+	/* If setup data */
+	if (((stat & UDC_EPSTS_OUT_MASK) >> UDC_EPSTS_OUT_OFS) ==
+							 UDC_EPSTS_OUT_SETUP) {
+		dev->stall = 0;
+		dev->ep[UDC_EP0IN_IDX].halted = 0;
+		dev->ep[UDC_EP0OUT_IDX].halted = 0;
+		/* In data not ready */
+		pch_udc_ep_set_nak(dev->ep[UDC_EP0IN_IDX].regs);
+		setup_data.data[0] = ep->td_stp->data12;
+		setup_data.data[1] = ep->td_stp->data34;
+		pr_debug("%s: EP0 setup data12: 0x%x data34:0x%x",
+			__func__, ep->td_stp->data12, ep->td_stp->data34);
+		pch_udc_init_setup_buff(ep->td_stp);
+		pch_udc_clear_dma(dev->regs, DMA_DIR_TX);
+		pch_udc_ep_fifo_flush(dev->ep[UDC_EP0IN_IDX].regs,
+						 dev->ep[UDC_EP0IN_IDX].in);
+		if ((setup_data.request.bRequestType & USB_DIR_IN) != 0) {
+			dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IDX].ep;
+		} else { /*	OUT */
+			dev->gadget.ep0 = &ep->ep;
+		}
+		pr_debug("%s: EP0 setup data: 0x%x 0x%x", __func__,
+				setup_data.data[0], setup_data.data[1]);
+		spin_unlock(&dev->lock);
+		/* Mass storage Reset */
+		if ((setup_data.data[0] == 0x0000ff21) && (setup_data.data[1] ==
+								 0x00000000)) {
+			dev->prot_stall = 0;
+			pr_debug("%s: Mass storage reset  prot_stall = %d",
+					__func__, dev->prot_stall);
+		}
+		/* call gadget with setup data received */
+		setup_supported = dev->driver->setup(&dev->gadget,
+							 &setup_data.request);
+		spin_lock(&dev->lock);
+
+		/* ep0 in returns data on IN phase */
+		if (setup_supported >= 0 && setup_supported <
+						 UDC_EP0IN_MAX_PKT_SIZE) {
+			pch_udc_ep_clear_nak(dev->ep[UDC_EP0IN_IDX].regs);
+			/* Gadget would have queued a request when
+							 we called the setup */
+			pch_udc_set_dma(dev->regs, DMA_DIR_RX);
+			pch_udc_ep_clear_nak(ep->regs);
+		} else if (setup_supported < 0) {
+			/* if unsupported request, then stall */
+			pr_debug("EP0 setup unsupported: ep0_set_stall");
+			pch_udc_ep_set_stall(dev->ep[UDC_EP0IN_IDX].regs);
+			pch_udc_enable_ep_interrupts(ep->dev->regs,
+				1 << (ep->in ? ep->num : ep->num +
+							 UDC_EPINT_OUT_EP0));
+			dev->stall = 0;
+			pch_udc_set_dma(dev->regs, DMA_DIR_RX);
+		} else {
+			dev->waiting_zlp_ack = 1;
+		}
+	} else if ((((stat & UDC_EPSTS_OUT_MASK) >> UDC_EPSTS_OUT_OFS) ==
+				 UDC_EPSTS_OUT_DATA) && (dev->stall == 0)) {
+		if (list_empty(&ep->queue)) {
+			pr_err("%s: ZLP", __func__);
+			/* If no requests, reactivate */
+			ep->td_data->status =
+					(ep->td_data->status &
+							 ~PCH_UDC_BUFF_STS) |
+							PCH_UDC_BS_HST_RDY;
+			/* Enable RDE */
+			pch_udc_set_dma(dev->regs, DMA_DIR_RX);
+		} else {
+			/* control write */
+			pch_udc_svc_data_out(dev, UDC_EP0OUT_IDX);
+			/* re-program desc. pointer for possible ZLPs */
+			pch_udc_ep_set_ddptr(ep->regs,
+					ep->td_data_phys);
+			/* Enable RDE */
+			pch_udc_set_dma(dev->regs, DMA_DIR_RX);
+		}
+	}
+	pch_udc_ep_set_rrdy(ep->regs);
+}
+
+
+/**
+ * pch_udc_postsvc_epinters - This function enables end point interrupts
+ *				and clears NAK status
+ * @dev:	Reference to the device structure
+ * @ep_num:	End point number
+ */
+static void pch_udc_postsvc_epinters(struct pch_udc_dev *dev, int ep_num)
+{
+	struct pch_udc_ep	*ep;
+	struct pch_udc_request *req;
+	ep = &dev->ep[2*ep_num];
+
+	if (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct pch_udc_request, queue);
+		pch_udc_enable_ep_interrupts(ep->dev->regs,
+			1 << (ep->in ? ep->num : ep->num + UDC_EPINT_OUT_EP0));
+		pch_udc_ep_clear_nak(ep->regs);
+	}
+}
+
+/**
+ * pch_udc_read_all_epstatus - This function read all endpoint status
+ * @dev:	Reference to the device structure
+ * @ep_intr:	Status of endpoint interrupt
+ */
+static void pch_udc_read_all_epstatus(struct pch_udc_dev *dev, u32 ep_intr)
+{
+	int i;
+	struct pch_udc_ep	*ep;
+
+	for (i = 0; i < PCH_UDC_USED_EP_NUM; i++) {
+		/* IN */
+		if (ep_intr & (0x1 << i)) {
+			ep = &dev->ep[2*i];
+			ep->epsts = pch_udc_read_ep_status(ep->regs);
+			pch_udc_clear_ep_status(ep->regs, ep->epsts);
+		}
+		/* OUT */
+		if (ep_intr & (0x10000 << i)) {
+			ep = &dev->ep[2*i+1];
+			ep->epsts = pch_udc_read_ep_status(ep->regs);
+			pch_udc_clear_ep_status(ep->regs, ep->epsts);
+		}
+	}
+	return;
+}
+
+/**
+ * pch_udc_activate_control_ep - This function enables the control endpoints
+ *					for traffic after a reset
+ * @dev:	Reference to the device structure
+ */
+void pch_udc_activate_control_ep(struct pch_udc_dev *dev)
+{
+	struct pch_udc_ep	*ep;
+	u32 val;
+
+	pr_debug("%s: enter", __func__);
+	/* Setup IN endpoint */
+	ep = &dev->ep[UDC_EP0IN_IDX];
+
+	/* Flush TX fifo */
+	pch_udc_clear_ep_control(ep->regs);
+	pch_udc_ep_fifo_flush(ep->regs, ep->in);
+
+	/* Set buffer size (tx fifo entries) of EP0_IN  */
+	pch_udc_ep_set_bufsz(ep->regs, UDC_EP0IN_BUFF_SIZE, ep->in);
+
+	/* Set max packet size of EP0_IN */
+	pch_udc_ep_set_maxpkt(ep->regs, UDC_EP0IN_MAX_PKT_SIZE);
+
+	/* Initialize the IN EP Descriptor */
+	ep->td_data      = NULL;
+	ep->td_stp       = NULL;
+	ep->td_data_phys = 0;
+	ep->td_stp_phys  = 0;
+
+	/* Setup OUT endpoint */
+	ep = &dev->ep[UDC_EP0OUT_IDX];
+
+	/* Flush RX fifo */
+	pch_udc_clear_ep_control(ep->regs);
+	pch_udc_ep_fifo_flush(ep->regs, ep->in);
+
+	/* Set buffer size (rx fifo entries) of EP0_OUT  */
+	pch_udc_ep_set_bufsz(ep->regs, UDC_EP0OUT_BUFF_SIZE, ep->in);
+
+	/* Set max packet size of EP0_OUT */
+	pch_udc_ep_set_maxpkt(ep->regs, UDC_EP0OUT_MAX_PKT_SIZE);
+
+	/* Set max packet size of EP0 OUT UDC CSR */
+	val = UDC_EP0OUT_MAX_PKT_SIZE << UDC_CSR_NE_MAX_PKT_OFS;
+	pch_udc_write_csr(val, (u32) (&dev->csr->ne[UDC_EP0OUT_IDX]));
+
+	/* Initialize the SETUP buffer */
+	pch_udc_init_setup_buff(ep->td_stp);
+
+	/* Write dma desc address */
+	pch_udc_ep_set_subptr(ep->regs, ep->td_stp_phys);
+
+	/* Write Setup desc address */
+	pch_udc_ep_set_ddptr(ep->regs, ep->td_data_phys);
+
+	/* Initialize dma descriptor */
+	ep->td_data->status  = PCH_UDC_DMA_LAST;
+	ep->td_data->dataptr = dma_addr;
+	ep->td_data->next    = ep->td_data_phys;
+
+	/* Clear NAK */
+	pch_udc_ep_clear_nak(ep->regs);
+}
+
+
+/**
+ * pch_udc_svc_ur_interrupt - This function handles a USB reset interrupt
+ * @dev:	Reference to driver structure
+ */
+void pch_udc_svc_ur_interrupt(struct pch_udc_dev *dev)
+{
+	struct pch_udc_ep	*ep;
+	int i;
+
+	pr_debug("%s: enter", __func__);
+	pch_udc_clear_dma(dev->regs, DMA_DIR_TX);
+	pch_udc_clear_dma(dev->regs, DMA_DIR_RX);
+	/* Mask all endpoint interrupts */
+	pch_udc_disable_ep_interrupts(dev->regs, UDC_EPINT_MSK_DISABLE_ALL);
+	/* clear all endpoint interrupts */
+	pch_udc_write_ep_interrupts(dev->regs, UDC_EPINT_MSK_DISABLE_ALL);
+
+	for (i = 0; i < PCH_UDC_EP_NUM; i++) {
+		ep = &dev->ep[i];
+		pch_udc_clear_ep_status(ep->regs, 0x1F0006F0);
+		pch_udc_clear_ep_control(ep->regs);
+		pch_udc_ep_set_ddptr(ep->regs, 0);
+		pch_udc_write_csr(0x00, (u32) (&dev->csr->ne[i]));
+	}
+
+	dev->stall = 0;
+	dev->prot_stall = 0;
+	dev->waiting_zlp_ack = 0;
+	dev->set_cfg_not_acked = 0;
+
+	/* disable ep to empty req queue. Skip the control EP's */
+	for (i = 0; i < (PCH_UDC_USED_EP_NUM*2); i++) {
+		ep = &dev->ep[i];
+		/* Set NAK */
+		pch_udc_ep_set_nak(ep->regs);
+		/* Flush fifo */
+		pch_udc_ep_fifo_flush(ep->regs , ep->in);
+		/* Complete request queue */
+		empty_req_queue(ep);
+	}
+	if (dev->driver && dev->driver->disconnect)
+		dev->driver->disconnect(&dev->gadget);
+}
+
+/**
+ * pch_udc_svc_enum_interrupt - This function handles a USB speed enumeration
+ *				done interrupt
+ * @dev:	Reference to driver structure
+ */
+void
+pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev)
+{
+	u32 dev_stat, dev_speed;
+	u32 speed = USB_SPEED_FULL;
+
+	pr_debug("%s: enter", __func__);
+	dev_stat = pch_udc_read_device_status(dev->regs);
+	dev_speed = (dev_stat & UDC_DEVSTS_ENUM_SPEED_MASK) >>
+						 UDC_DEVSTS_ENUM_SPEED_OFS;
+
+	pr_debug("%s: dev_speed = 0x%08x", __func__, dev_speed);
+
+	if (dev_speed == UDC_DEVSTS_ENUM_SPEED_HIGH) {
+		pr_debug("HighSpeed");
+		speed = USB_SPEED_HIGH;
+	} else if (dev_speed == UDC_DEVSTS_ENUM_SPEED_FULL) {
+		pr_debug("FullSpeed");
+		speed = USB_SPEED_FULL;
+	} else if (dev_speed == UDC_DEVSTS_ENUM_SPEED_LOW) {
+		pr_debug("LowSpeed?");
+		speed = USB_SPEED_LOW;
+	} else {
+		pr_debug("FullSpeed?");
+	}
+	dev->gadget.speed = speed;
+
+	pch_udc_activate_control_ep(dev);
+
+	/* enable ep0 interrupts */
+	pch_udc_enable_ep_interrupts(dev->regs, 1 << UDC_EPINT_IN_EP0 |
+							1 << UDC_EPINT_OUT_EP0);
+	/* enable DMA */
+	pch_udc_set_dma(dev->regs, DMA_DIR_TX);
+	pch_udc_set_dma(dev->regs, DMA_DIR_RX);
+	pch_udc_ep_set_rrdy(dev->ep[UDC_EP0OUT_IDX].regs);
+
+
+	pr_debug("%s: EP mask set to %x", __func__,
+				 ioread32(&dev->regs->epirqmsk));
+}
+
+/**
+ * pch_udc_svc_intf_interrupt - This function handles a set interface interrupt
+ * @dev:	Reference to driver structure
+ */
+void
+pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
+{
+	u32 reg, dev_stat = 0;
+	int i, ret;
+
+	pr_debug("%s: enter", __func__);
+	dev_stat = pch_udc_read_device_status(dev->regs);
+	dev->cfg_data.cur_intf = (dev_stat & UDC_DEVSTS_INTF_MASK) >>
+							 UDC_DEVSTS_INTF_OFS;
+	dev->cfg_data.cur_alt = (dev_stat & UDC_DEVSTS_ALT_MASK) >>
+							 UDC_DEVSTS_ALT_OFS;
+	pr_debug("DVSTATUS=%08x, cfg=%d, intf=%d, alt=%d", dev_stat,
+			(dev_stat & UDC_CSR_NE_CFG_MASK) >> UDC_CSR_NE_CFG_OFS,
+			dev->cfg_data.cur_intf, dev->cfg_data.cur_alt);
+
+	dev->set_cfg_not_acked = 1;
+
+	/* Construct the usb request for gadget driver and inform it */
+	memset(&setup_data, 0 , sizeof setup_data);
+	setup_data.request.bRequest = USB_REQ_SET_INTERFACE;
+	setup_data.request.bRequestType = USB_RECIP_INTERFACE;
+	setup_data.request.wValue = cpu_to_le16(dev->cfg_data.cur_alt);
+	setup_data.request.wIndex = cpu_to_le16(dev->cfg_data.cur_intf);
+
+	/* programm the Endpoint Cfg registers */
+	for (i = 0; i < PCH_UDC_USED_EP_NUM * 2; i++) {
+		if (i == 1) { /* Only one end point cfg register */
+			reg = pch_udc_read_csr((u32) (&dev->csr->ne[i]));
+			reg = (reg & ~UDC_CSR_NE_INTF_MASK) |
+			 (dev->cfg_data.cur_intf << UDC_CSR_NE_INTF_OFS);
+			reg = (reg & ~UDC_CSR_NE_ALT_MASK) |
+			 (dev->cfg_data.cur_alt << UDC_CSR_NE_ALT_OFS);
+			pch_udc_write_csr(reg, (u32) (&dev->csr->ne[i]));
+		}
+		/* clear stall bits */
+		pch_udc_ep_clear_stall(dev->ep[i].regs);
+		dev->ep[i].halted = 0;
+	}
+	dev->stall = 0;
+	spin_unlock(&dev->lock);
+	ret = dev->driver->setup(&dev->gadget, &setup_data.request);
+	spin_lock(&dev->lock);
+}
+
+/**
+ * pch_udc_svc_cfg_interrupt - This function handles a set configuration
+ *				interrupt
+ * @dev:	Reference to driver structure
+ */
+void
+pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev)
+{
+	int i, ret;
+	u32 reg, dev_stat = 0;
+
+	pr_debug("%s: enter", __func__);
+	dev_stat = pch_udc_read_device_status(dev->regs);
+	pr_debug("DVSTATUS=%08x, cfg=%d, intf=%d, alt=%d", dev_stat,
+		(dev_stat & UDC_DEVSTS_CFG_MASK) >> UDC_DEVSTS_CFG_OFS,
+		(dev_stat & UDC_DEVSTS_INTF_MASK) >> UDC_DEVSTS_INTF_OFS,
+		(dev_stat & UDC_DEVSTS_ALT_MASK) >> UDC_DEVSTS_ALT_OFS);
+
+	dev->set_cfg_not_acked = 1;
+
+	dev->cfg_data.cur_cfg = (dev_stat & UDC_DEVSTS_CFG_MASK) >>
+							 UDC_DEVSTS_CFG_OFS;
+	/* make usb request for gadget driver */
+	memset(&setup_data, 0 , sizeof setup_data);
+	setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION;
+	setup_data.request.wValue = cpu_to_le16(dev->cfg_data.cur_cfg);
+
+	/* program the NE registers */
+	for (i = 0; i < PCH_UDC_USED_EP_NUM * 2; i++) {
+		if (i == 1) {
+			reg = pch_udc_read_csr((u32) (&dev->csr->ne[i]));
+			reg = (reg & ~UDC_CSR_NE_CFG_MASK) |
+				 (dev->cfg_data.cur_cfg << UDC_CSR_NE_CFG_OFS);
+			pch_udc_write_csr(reg, (u32) (&dev->csr->ne[i]));
+		}
+		/* clear stall bits */
+		pch_udc_ep_clear_stall(dev->ep[i].regs);
+		dev->ep[i].halted = 0;
+	}
+	dev->stall = 0;
+
+	/* call gadget zero with setup data received */
+	spin_unlock(&dev->lock);
+	ret = dev->driver->setup(&dev->gadget, &setup_data.request);
+	spin_lock(&dev->lock);
+}
+
+/**
+ * pch_udc_dev_isr - This function services device interrupts
+ *			by invoking appropriate routines.
+ * @dev:	Reference to the device structure
+ * @dev_intr:	The Device interrupt status.
+ */
+void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
+{
+	/* USB Reset Interrupt */
+	if (dev_intr & (1 << UDC_DEVINT_UR))
+		pch_udc_svc_ur_interrupt(dev);
+
+	/* Enumeration Done Interrupt */
+	if (dev_intr & (1 << UDC_DEVINT_ENUM))
+		pch_udc_svc_enum_interrupt(dev);
+
+	/* Set Interface Interrupt */
+	if (dev_intr & (1 << UDC_DEVINT_SI))
+		pch_udc_svc_intf_interrupt(dev);
+
+	/* Set Config Interrupt */
+	if (dev_intr & (1 << UDC_DEVINT_SC))
+		pch_udc_svc_cfg_interrupt(dev);
+
+	/* USB Suspend interrupt */
+	if (dev_intr & (1 << UDC_DEVINT_US))
+		pr_debug("USB_SUSPEND");
+
+	/* Clear the SOF interrupt, if enabled */
+	if (dev_intr & (1 << UDC_DEVINT_SOF))
+		pr_debug("SOF");
+
+	/* ES interrupt, IDLE > 3ms on the USB */
+	if (dev_intr & (1 << UDC_DEVINT_ES))
+		pr_debug("ES");
+
+	/* RWKP interrupt */
+	if (dev_intr & (1 << UDC_DEVINT_RWKP))
+		pr_debug("RWKP");
+
+}
+
+/**
+ * pch_udc_isr - This function handles interrupts from the PCH USB Device
+ * @irq:	Interrupt request number
+ * @dev:	Reference to the device structure
+ */
+irqreturn_t pch_udc_isr(int irq, void *pdev)
+{
+	struct pch_udc_dev *dev;
+	u32 dev_intr, ep_intr;
+	int i;
+
+	pr_debug("%s: enter", __func__);
+	dev = (struct pch_udc_dev *) pdev;
+	dev_intr = pch_udc_read_device_interrupts(dev->regs);
+	ep_intr = pch_udc_read_ep_interrupts(dev->regs);
+
+	if (dev_intr != 0) {
+		/* Clear device interrupts */
+		pch_udc_write_device_interrupts(dev->regs, dev_intr);
+	}
+	if (ep_intr != 0) {
+		/* Clear ep interrupts */
+		pch_udc_write_ep_interrupts(dev->regs, ep_intr);
+	}
+	if ((dev_intr == 0) && (ep_intr == 0)) {
+		pr_debug("%s: exit IRQ_NONE", __func__);
+		return IRQ_NONE;
+	}
+	spin_lock(&dev->lock);
+
+	if (dev_intr != 0) {
+		pr_debug("%s: device intr 0x%x", __func__, dev_intr);
+		pch_udc_dev_isr(dev, dev_intr);
+	}
+
+	if (ep_intr != 0) {
+		pr_debug("%s: ep intr 0x%x", __func__, ep_intr);
+		pch_udc_read_all_epstatus(dev, ep_intr);
+
+		/* Process Control In interrupts, if present */
+		if (ep_intr & (1 << UDC_EPINT_IN_EP0)) {
+			pch_udc_svc_control_in(dev);
+			pch_udc_postsvc_epinters(dev, 0);
+		}
+		/* Process Control Out interrupts, if present */
+		if (ep_intr & (1 << UDC_EPINT_OUT_EP0))
+			pch_udc_svc_control_out(dev);
+
+		/* Process data in end point interrupts */
+		for (i = 1; i < PCH_UDC_USED_EP_NUM; i++) {
+			if (ep_intr & (1 <<  i)) {
+				pch_udc_svc_data_in(dev, i);
+				pch_udc_postsvc_epinters(dev, i);
+			}
+		}
+		/* Process data out end point interrupts */
+		for (i = UDC_EPINT_OUT_EP1; i < (UDC_EPINT_OUT_EP0 +
+						 PCH_UDC_USED_EP_NUM); i++) {
+			if (ep_intr & (1 <<  i))
+				pch_udc_svc_data_out(dev, i -
+							 UDC_EPINT_OUT_EP0);
+		}
+	}
+	spin_unlock(&dev->lock);
+	return IRQ_HANDLED;
+}
+
+/**
+ * pch_udc_setup_ep0 - This function enables control endpoint for traffic
+ * @dev:	Reference to the device structure
+ */
+static void pch_udc_setup_ep0(struct pch_udc_dev *dev)
+{
+	pr_debug("%s: enter", __func__);
+	/* enable ep0 interrupts */
+	pch_udc_enable_ep_interrupts(dev->regs, 1 << UDC_EPINT_IN_EP0 |
+						 1 << UDC_EPINT_OUT_EP0);
+
+	/* enable device interrupts */
+	pch_udc_enable_interrupts(dev->regs, (1 << UDC_DEVINT_UR) |
+			(1 << UDC_DEVINT_US) | (1 << UDC_DEVINT_ES) |
+			(1 << UDC_DEVINT_ENUM) | (1 << UDC_DEVINT_SI) |
+						 (1 << UDC_DEVINT_SC));
+	pr_debug("Dev intr mask set to %x  Ep intr mask set to %x",
+				ioread32(&dev->regs->devirqmsk),
+				ioread32(&dev->regs->epirqmsk));
+}
+
+/**
+ * gadget_release - Free the gadget driver private data
+ * @pdev	reference to struct pci_dev
+ */
+static void gadget_release(struct device *pdev)
+{
+	struct pch_udc_dev *dev = dev_get_drvdata(pdev);
+	kfree(dev);
+}
+
+/**
+ * pch_udc_pcd_reinit - This API initializes the endpoint structures
+ * @dev:	Reference to the driver structure
+ */
+static void pch_udc_pcd_reinit(struct pch_udc_dev *dev)
+{
+	static const char *ep_string[] = {
+		ep0_string, "ep0out", "ep1in", "ep1out",
+		"ep2in", "ep2out", "ep3in", "ep3out",
+		"ep4in", "ep4out", "ep5in", "ep5out",
+		"ep6in", "ep6out", "ep7in", "ep7out",
+		"ep8in", "ep8out", "ep9in", "ep9out",
+		"ep10in", "ep10out", "ep11in", "ep11out",
+		"ep12in", "ep12out", "ep13in", "ep13out",
+		"ep14in", "ep14out", "ep15in", "ep15out",
+	};
+	int i;
+
+	pr_debug("%s: enter", __func__);
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+	INIT_LIST_HEAD(&dev->gadget.ep_list);
+
+	/* Initialize the endpoints structures */
+	for (i = 0; i < PCH_UDC_EP_NUM; i++) {
+		struct pch_udc_ep *ep = &dev->ep[i];
+		memset(ep, 0, sizeof(*ep));
+
+		ep->desc = NULL;
+		ep->dev = dev;
+		ep->halted = 1;
+		ep->num = i / 2;
+		ep->in = ((i & 1) == 0) ? 1 : 0;
+
+		ep->ep.name = ep_string[i];
+		ep->ep.ops = &pch_udc_ep_ops;
+		if (ep->in)
+			ep->regs = (struct pch_udc_ep_regs *)\
+				 ((int)dev->ep_regs + ep->num * UDC_EP_REG_OFS);
+		else
+			ep->regs = (struct pch_udc_ep_regs *)\
+				 ((int)dev->ep_regs + \
+				(UDC_EPINT_OUT_EP0 + ep->num) * UDC_EP_REG_OFS);
+
+		ep->dma = &ep->regs->epctl;
+		/* need to set ep->ep.maxpacket and set Default Configuration?*/
+		ep->ep.maxpacket = UDC_BULK_MAX_PKT_SIZE;
+		list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
+		INIT_LIST_HEAD(&ep->queue);
+	}
+	dev->ep[UDC_EP0IN_IDX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
+	dev->ep[UDC_EP0OUT_IDX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
+
+	dma_addr = pci_map_single(dev->pdev, ep0out_buf,
+						 256, PCI_DMA_FROMDEVICE);
+
+	/* remove ep0 in and out from the list.  They have own pointer */
+	list_del_init(&dev->ep[UDC_EP0IN_IDX].ep.ep_list);
+	list_del_init(&dev->ep[UDC_EP0OUT_IDX].ep.ep_list);
+
+	dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IDX].ep;
+	INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+}
+
+/**
+ * pch_udc_pcd_init - This API initializes the driver structure
+ * @dev:	Reference to the driver structure
+ * Return	0: Success
+ */
+int pch_udc_pcd_init(struct pch_udc_dev *dev)
+{
+	pr_debug("%s: enter", __func__);
+	/* udc csr registers base */
+	dev->csr = dev->virt_addr + UDC_CSR_ADDR;
+	/* dev registers base */
+	dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
+	/* ep registers base */
+	dev->ep_regs = dev->virt_addr + UDC_EPIN_REGS_ADDR;
+
+	/* init registers, interrupts, ... */
+	pch_udc_init(dev->regs);
+
+	pch_udc_pcd_reinit(dev);
+	return 0;
+}
+
+/**
+ * init_dma_pools - create dma pools during initialization
+ * @pdev:	reference to struct pci_dev
+ */
+static int init_dma_pools(struct pch_udc_dev *dev)
+{
+	struct pch_udc_stp_dma_desc	*td_stp;
+	struct pch_udc_data_dma_desc	*td_data;
+
+	pr_debug("%s: enter", __func__);
+	/* DMA setup */
+	dev->data_requests = pci_pool_create("data_requests", dev->pdev,
+		sizeof(struct pch_udc_data_dma_desc), 0, 0);
+	if (dev->data_requests == NULL) {
+		pr_err("%s: can't get request data pool", __func__);
+		return -ENOMEM;
+	}
+
+	/* dma desc for setup data */
+	dev->stp_requests = pci_pool_create("setup requests", dev->pdev,
+		sizeof(struct pch_udc_stp_dma_desc), 0, 0);
+	if (dev->stp_requests == NULL) {
+		pr_err("%s: can't get setup request pool", __func__);
+		return -ENOMEM;
+	}
+	/* setup */
+	td_stp = pci_pool_alloc(dev->stp_requests, GFP_KERNEL,
+				&dev->ep[UDC_EP0OUT_IDX].td_stp_phys);
+	if (td_stp == NULL) {
+		pr_err("%s: can't allocate setup dma descriptor", __func__);
+		return -ENOMEM;
+	}
+	dev->ep[UDC_EP0OUT_IDX].td_stp = td_stp;
+
+	/* data: 0 packets !? */
+	td_data = pci_pool_alloc(dev->data_requests, GFP_KERNEL,
+				&dev->ep[UDC_EP0OUT_IDX].td_data_phys);
+	if (td_data == NULL) {
+		pr_err("%s: can't allocate data dma descriptor", __func__);
+		return -ENOMEM;
+	}
+	dev->ep[UDC_EP0OUT_IDX].td_data = td_data;
+	dev->ep[UDC_EP0IN_IDX].td_stp = NULL;
+	dev->ep[UDC_EP0IN_IDX].td_stp_phys = 0;
+	dev->ep[UDC_EP0IN_IDX].td_data = NULL;
+	dev->ep[UDC_EP0IN_IDX].td_data_phys = 0;
+	return 0;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct pch_udc_dev	*dev = pch_udc;
+	int			retval;
+
+	pr_debug("%s: enter", __func__);
+	if ((driver == NULL) || (driver->speed == USB_SPEED_UNKNOWN) ||
+		(driver->bind == NULL) || (driver->setup == NULL) ||
+		(driver->unbind == NULL) || (driver->disconnect == NULL)) {
+		pr_err("%s: invalid driver parameter", __func__);
+		return -EINVAL;
+	}
+
+	if (dev == NULL)
+		return -ENODEV;
+
+	if (dev->driver != NULL) {
+		pr_err("%s: already bound", __func__);
+		return -EBUSY;
+	}
+	driver->driver.bus = NULL;
+	dev->driver = driver;
+	dev->gadget.dev.driver = &driver->driver;
+
+	/* Invoke the bind routine of the gadget driver */
+	retval = driver->bind(&dev->gadget);
+
+	if (retval != 0) {
+		pr_err("%s: binding to %s returning %d",
+		       __func__, driver->driver.name, retval);
+		dev->driver = NULL;
+		dev->gadget.dev.driver = NULL;
+		return retval;
+	}
+	/* get ready for ep0 traffic */
+	pch_udc_setup_ep0(dev);
+
+	/* clear SD */
+	pch_udc_clear_disconnect(dev->regs);
+
+	dev->connected = 1;
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct pch_udc_dev	*dev = pch_udc;
+
+	pr_debug("%s: enter", __func__);
+	if (dev == NULL)
+		return -ENODEV;
+
+	if ((driver == NULL) || (driver != dev->driver)) {
+		pr_err("%s: invalid driver parameter", __func__);
+		return -EINVAL;
+	}
+
+	pch_udc_disable_interrupts(dev->regs, UDC_DEVINT_MSK);
+
+	/* Assues that there are no pending requets with this driver */
+	driver->unbind(&dev->gadget);
+	dev->gadget.dev.driver = NULL;
+	dev->driver = NULL;
+	dev->connected = 0;
+
+	/* set SD */
+	pch_udc_set_disconnect(dev->regs);
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+void pch_udc_shutdown(struct pci_dev *pdev)
+{
+	struct pch_udc_dev *dev = pci_get_drvdata(pdev);
+
+	dev_dbg(&pdev->dev, "%s: enter", __func__);
+	pch_udc_disable_interrupts(dev->regs, UDC_DEVINT_MSK);
+	pch_udc_disable_ep_interrupts(dev->regs, UDC_EPINT_MSK_DISABLE_ALL);
+
+	/* disable the pullup so the host will think we're gone */
+	pch_udc_set_disconnect(dev->regs);
+}
+
+void pch_udc_remove(struct pci_dev *pdev)
+{
+	struct pch_udc_dev	*dev = pci_get_drvdata(pdev);
+
+	dev_dbg(&pdev->dev, "%s: enter", __func__);
+	/* gadget driver must not be registered */
+	if (dev->driver != NULL)
+		dev_err(&pdev->dev, "%s: gadget driver still bound!!!",
+								__func__);
+	/* dma pool cleanup */
+	if (dev->data_requests != NULL)
+		pci_pool_destroy(dev->data_requests);
+
+	if (dev->stp_requests != NULL) {
+		/* cleanup DMA desc's for ep0in */
+		if (dev->ep[UDC_EP0OUT_IDX].td_stp != NULL) {
+			pci_pool_free(dev->stp_requests,
+				dev->ep[UDC_EP0OUT_IDX].td_stp,
+				dev->ep[UDC_EP0OUT_IDX].td_stp_phys);
+		}
+		if (dev->ep[UDC_EP0OUT_IDX].td_data != NULL) {
+			pci_pool_free(dev->stp_requests,
+				dev->ep[UDC_EP0OUT_IDX].td_data,
+				dev->ep[UDC_EP0OUT_IDX].td_data_phys);
+		}
+		pci_pool_destroy(dev->stp_requests);
+	}
+
+	pch_udc_exit(dev->regs);
+
+	if (dev->irq_registered)
+		free_irq(pdev->irq, dev);
+
+	if (dev->virt_addr != NULL)
+		iounmap(dev->virt_addr);
+
+	if (dev->mem_region)
+		release_mem_region(dev->phys_addr, pci_resource_len(pdev,
+							 PCH_UDC_PCI_BAR));
+	if (dev->active)
+		pci_disable_device(pdev);
+
+	if (dev->registered)
+		device_unregister(&dev->gadget.dev);
+	else
+		kfree(dev);
+
+	pci_set_drvdata(pdev, NULL);
+}
+
+#ifdef CONFIG_PM
+int pch_udc_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct pch_udc_dev *dev = pci_get_drvdata(pdev);
+
+	dev_dbg(&pdev->dev, "%s: enter", __func__);
+	pch_udc_disable_interrupts(dev->regs, UDC_DEVINT_MSK);
+	pch_udc_disable_ep_interrupts(dev->regs, UDC_EPINT_MSK_DISABLE_ALL);
+
+	pci_disable_device(pdev);
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+
+	if (pci_save_state(pdev) != 0) {
+		dev_err(&pdev->dev, "%s: could not save PCI config state",
+								__func__);
+		return -ENOMEM;
+	}
+
+	if (pci_set_power_state(pdev, pci_choose_state(pdev, state)) == -EIO)
+		dev_dbg(&pdev->dev, "%s: does not support PM cpabilities",
+								__func__);
+
+	return 0;
+}
+
+int pch_udc_resume(struct pci_dev *pdev)
+{
+	int ret;
+
+	dev_dbg(&pdev->dev, "%s: enter", __func__);
+	ret = pci_set_power_state(pdev, PCI_D0);
+	if (ret != 0)
+		dev_dbg(&pdev->dev,
+			"%s: does not support PM cpabilities", __func__);
+
+	ret = pci_restore_state(pdev);
+	if (ret != 0) {
+		dev_err(&pdev->dev,
+			"%s: pci_restore_state failed", __func__);
+		return ret;
+	}
+
+	ret = pci_enable_device(pdev);
+
+	if (ret != 0) {
+		dev_err(&pdev->dev, "%s: pci_enable_device failed", __func__);
+		return ret;
+	}
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+
+	return 0;
+}
+#else
+#define pch_udc_suspend	NULL
+#define pch_udc_resume	NULL
+#endif /* CONFIG_PM */
+
+int pch_udc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	unsigned long		resource;
+	unsigned long		len;
+	int					retval = 0;
+	struct pch_udc_dev	*dev;
+
+	dev_dbg(&pdev->dev, "%s: enter", __func__);
+	/* one udc only */
+	if (pch_udc != NULL) {
+		dev_err(&pdev->dev, "%s: already probed", __func__);
+		return -EBUSY;
+	}
+
+	/* init */
+	dev = kzalloc(sizeof(struct pch_udc_dev), GFP_KERNEL);
+	if (dev == NULL) {
+		dev_err(&pdev->dev, "%s: no memory for device structure",
+								__func__);
+		return -ENOMEM;
+	}
+	memset(dev, 0, sizeof(struct pch_udc_dev));
+	/* pci setup */
+	if (pci_enable_device(pdev) < 0) {
+		kfree(dev);
+		dev_err(&pdev->dev, "%s: pci_enable_device failed", __func__);
+		return -ENODEV;
+	}
+	dev->active = 1;
+	pci_set_drvdata(pdev, dev);
+
+	/* PCI resource allocation */
+	resource = pci_resource_start(pdev, 1);
+	len = pci_resource_len(pdev, 1);
+	dev_dbg(&pdev->dev, "%s: resource %lx, len %ld",
+			__func__, resource, len);
+
+	if (request_mem_region(resource, len, KBUILD_MODNAME) == NULL) {
+		dev_err(&pdev->dev, "%s: pci device used already", __func__);
+		retval = -EBUSY;
+		goto finished;
+	}
+	dev->phys_addr = resource;
+	dev->mem_region = 1;
+
+	dev->virt_addr = ioremap_nocache(resource, len);
+	if (dev->virt_addr == NULL) {
+		dev_err(&pdev->dev, "%s: device memory cannot be mapped",
+			__func__);
+		retval = -ENOMEM;
+		goto finished;
+	}
+	dev_dbg(&pdev->dev, "%s: device memory mapped at %x", __func__,
+		(int)dev->virt_addr);
+
+	if (pdev->irq == 0) {
+		dev_err(&pdev->dev, "%s: irq not set", __func__);
+		retval = -ENODEV;
+		goto finished;
+	}
+
+	pch_udc = dev;
+
+	/* initialize the hardware */
+	if (pch_udc_pcd_init(dev) != 0)
+		goto finished;
+
+	if (request_irq(pdev->irq, pch_udc_isr, IRQF_SHARED,
+			KBUILD_MODNAME, dev) != 0) {
+		dev_err(&pdev->dev, "%s: request_irq(%d) fail", __func__,
+			pdev->irq);
+		retval = -ENODEV;
+		goto finished;
+	}
+	dev->irq = pdev->irq;
+	dev->irq_registered = 1;
+
+	pci_set_master(pdev);
+	pci_try_set_mwi(pdev);
+
+	/* device struct setup */
+	spin_lock_init(&dev->lock);
+	dev->pdev = pdev;
+	dev->gadget.ops = &pch_udc_ops;
+
+	retval = init_dma_pools(dev);
+	if (retval != 0)
+		goto finished;
+
+	dev_set_name(&dev->gadget.dev, "gadget");
+	dev->gadget.dev.parent = &pdev->dev;
+	dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+	dev->gadget.dev.release = gadget_release;
+	dev->gadget.name = KBUILD_MODNAME;
+	dev->gadget.is_dualspeed = 1;
+
+	retval = device_register(&dev->gadget.dev);
+	if (retval != 0)
+		goto finished;
+	dev->registered = 1;
+
+	/* Put the device in disconnected state till a driver is bound */
+	pch_udc_set_disconnect(dev->regs);
+	return 0;
+
+finished:
+	pch_udc_remove(pdev);
+	return retval;
+}
+
+static const struct pci_device_id pch_udc_pcidev_id[] = {
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PCH1_UDC),
+		.class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+		.class_mask = 0xffffffff,
+	},
+	{ 0 },
+};
+
+MODULE_DEVICE_TABLE(pci, pch_udc_pcidev_id);
+
+
+static struct pci_driver pch_udc_driver = {
+	.name =	KBUILD_MODNAME,
+	.id_table =	pch_udc_pcidev_id,
+	.probe =	pch_udc_probe,
+	.remove =	pch_udc_remove,
+	.suspend =	pch_udc_suspend,
+	.resume =	pch_udc_resume,
+	.shutdown =	pch_udc_shutdown,
+};
+
+static int __init pch_udc_pci_init(void)
+{
+	return pci_register_driver(&pch_udc_driver);
+}
+module_init(pch_udc_pci_init);
+
+static void __exit pch_udc_pci_exit(void)
+{
+	pci_unregister_driver(&pch_udc_driver);
+}
+module_exit(pch_udc_pci_exit);
diff --git a/drivers/usb/gadget/pch_udc.h b/drivers/usb/gadget/pch_udc.h
new file mode 100755
index 0000000..55c22ef
--- /dev/null
+++ b/drivers/usb/gadget/pch_udc.h
@@ -0,0 +1,495 @@
+/*
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 _PCH_UDC_H_
+#define _PCH_UDC_H_
+
+/* Address offset of Registers */
+#define UDC_EPIN_REGS_ADDR		0x000
+#define UDC_EPOUT_REGS_ADDR		0x200
+#define UDC_EP_REG_OFS			0x20	/* Offset to next EP */
+#define UDC_DEVCFG_ADDR			0x400
+#define PCH_UDC_CSR_BUSY_ADDR		0x4f0
+#define PCH_UDC_SRST_ADDR		0x4fc
+#define UDC_CSR_ADDR			0x500
+
+/* Bit position in UDC CSR Busy status Register */
+#define PCH_UDC_CSR_BUSY		1
+/* Bit position in UDC Soft reset Register */
+#define PCH_UDC_PSRST			1
+#define PCH_UDC_SRST			0
+
+/* DMA */
+#define DMA_DIR_RX		1	/* DMA for data receive */
+#define DMA_DIR_TX		2	/* DMA for data transmit */
+#define UDC_DMA_MAXPACKET	65536	/* maximum packet size for DMA */
+
+#define EP_IS_IN(ep)	(((u32)(ep)) < (pch_udc_base + UDC_EPOUT_REGS_ADDR))
+#define EP_NUM(ep)	((((u32)(ep) - (pch_udc_base +\
+				UDC_EPIN_REGS_ADDR)) / UDC_EP_REG_OFS) & 0xf)
+
+#define PCH_UDC_EP_NUM		32	/* Total number of EPs (16 IN,16 OUT) */
+#define PCH_UDC_USED_EP_NUM	4	/* EP number of EP's really used */
+
+/* Control ep index */
+#define UDC_EP0IN_IDX		0
+#define UDC_EP0OUT_IDX		1
+/* number of EP */
+#define PCH_UDC_EP0		0
+#define PCH_UDC_EP1		1
+#define PCH_UDC_EP2		2
+#define PCH_UDC_EP3		3
+
+/* Rx fifo address and size = 2k */
+#define UDC_RXFIFO_ADDR		0x800	/* Address offset of Rx FIFO */
+#define UDC_RXFIFO_SIZE		0x800	/* Rx FIFO size */
+
+/* Tx fifo address and size = 4k */
+#define UDC_TXFIFO_ADDR		0x1000	/* Address offset of Tx FIFO */
+#define UDC_TXFIFO_SIZE		0x1000	/* Tx FIFO size */
+
+
+/**
+ * pch_udc_csrs - Structure to Endpoint configuration registers
+ */
+struct pch_udc_csrs {
+	u32 ne[PCH_UDC_USED_EP_NUM * 2];
+/* Starting bit position */
+#define UDC_CSR_NE_NUM_OFS			0
+#define UDC_CSR_NE_DIR_OFS			4
+#define UDC_CSR_NE_TYPE_OFS			5
+#define UDC_CSR_NE_CFG_OFS			7
+#define UDC_CSR_NE_INTF_OFS			11
+#define UDC_CSR_NE_ALT_OFS			15
+#define UDC_CSR_NE_MAX_PKT_OFS			19
+/* Mask patern */
+#define UDC_CSR_NE_NUM_MASK			0x0000000f
+#define UDC_CSR_NE_DIR_MASK			0x00000010
+#define UDC_CSR_NE_TYPE_MASK			0x00000060
+#define UDC_CSR_NE_CFG_MASK			0x00000780
+#define UDC_CSR_NE_INTF_MASK			0x00007800
+#define UDC_CSR_NE_ALT_MASK			0x00078000
+#define UDC_CSR_NE_MAX_PKT_MASK			0x3ff80000
+};
+
+/**
+ * pch_udc_regs - Structure holding values of configuration registers
+ *
+ * @devcfg	Device configuration register
+ * @devctl	Device control register
+ * @devsts	Device status register
+ * @devirqsts	Device irq status register
+ * @devirqmsk	Device irq mask register
+ * @epirqsts	Endpoint irq status register
+ * @epirqmsk	Endpoint irq mask register
+ * @devlpm	LPM control / status registe
+ */
+struct pch_udc_regs {
+	u32 devcfg;
+/* Bit position */
+#define UDC_DEVCFG_SET_DESC	18
+#define UDC_DEVCFG_CSR_PRG	17
+#define UDC_DEVCFG_HALT_STATUS	16
+#define UDC_DEVCFG_STATUS1	8
+#define UDC_DEVCFG_STATUS	7
+#define UDC_DEVCFG_DIR		6
+#define UDC_DEVCFG_PI		5
+#define UDC_DEVCFG_SS		4
+#define UDC_DEVCFG_SP		3
+#define UDC_DEVCFG_RWKP		2
+#define UDC_DEVCFG_SPD_OFS	0
+/* Mask patern */
+#define UDC_DEVCFG_SPD_MASK	0x00000003
+/* SPD Valee */
+#define UDC_DEVCFG_SPD_HS	0x0
+#define UDC_DEVCFG_SPD_FS	0x1
+#define UDC_DEVCFG_SPD_LS	0x2
+
+	u32 devctl;
+/* Bit position */
+#define UDC_DEVCTL_THLEN_OFS	24
+#define UDC_DEVCTL_BRLEN_OFS	16
+#define UDC_DEVCTL_CSR_DONE	13
+#define UDC_DEVCTL_DEVNAK	12
+#define UDC_DEVCTL_SD		10
+#define UDC_DEVCTL_MODE		9
+#define UDC_DEVCTL_BREN		8
+#define UDC_DEVCTL_THE		7
+#define UDC_DEVCTL_BF		6
+#define UDC_DEVCTL_BE		5
+#define UDC_DEVCTL_DU		4
+#define UDC_DEVCTL_TDE		3
+#define UDC_DEVCTL_RDE		2
+#define UDC_DEVCTL_RES		0
+/* Mask patern */
+#define UDC_DEVCTL_THLEN_MASK	0xff000000
+#define UDC_DEVCTL_BRLEN_MASK	0x00ff0000
+/* Length Valee */
+#define PCH_UDC_BRLEN		0x0F	/* Burst length */
+#define PCH_UDC_THLEN		0x1F	/* Threshold length */
+
+	u32 devsts;
+/* Bit position */
+#define UDC_DEVSTS_TS_OFS		18
+#define UDC_DEVSTS_RWKPST		17
+#define UDC_DEVSTS_PHY_ERROR		16
+#define UDC_DEVSTS_RXFIFO_EMPTY		15
+#define UDC_DEVSTS_ENUM_SPEED_OFS	13
+#define UDC_DEVSTS_SUSP			12
+#define UDC_DEVSTS_ALT_OFS		8
+#define UDC_DEVSTS_INTF_OFS		4
+#define UDC_DEVSTS_CFG_OFS		0
+/* Mask patern */
+#define UDC_DEVSTS_TS_MASK		0xfffc0000
+#define UDC_DEVSTS_ENUM_SPEED_MASK	0x00006000
+#define UDC_DEVSTS_ALT_MASK		0x00000f00
+#define UDC_DEVSTS_INTF_MASK		0x000000f0
+#define UDC_DEVSTS_CFG_MASK		0x0000000f
+/* value for maximum speed for SPEED field */
+#define UDC_DEVSTS_ENUM_SPEED_FULL	1
+#define UDC_DEVSTS_ENUM_SPEED_HIGH	0
+#define UDC_DEVSTS_ENUM_SPEED_LOW	2
+#define UDC_DEVSTS_ENUM_SPEED_FULLX	3
+
+	u32 devirqsts;
+/* Bit position */
+#define UDC_DEVINT_RWKP			7
+#define UDC_DEVINT_ENUM			6
+#define UDC_DEVINT_SOF			5
+#define UDC_DEVINT_US			4
+#define UDC_DEVINT_UR			3
+#define UDC_DEVINT_ES			2
+#define UDC_DEVINT_SI			1
+#define UDC_DEVINT_SC			0
+
+	u32 devirqmsk;
+/* Mask patern */
+#define UDC_DEVINT_MSK			0x7f
+
+	u32 epirqsts;
+/* Bit position */
+#define UDC_EPINT_IN_OFS		0
+#define UDC_EPINT_OUT_OFS		16
+#define UDC_EPINT_IN_EP0		0
+#define UDC_EPINT_IN_EP1		1
+#define UDC_EPINT_IN_EP2		2
+#define UDC_EPINT_IN_EP3		3
+#define UDC_EPINT_OUT_EP0		16
+#define UDC_EPINT_OUT_EP1		17
+#define UDC_EPINT_OUT_EP2		18
+#define UDC_EPINT_OUT_EP3		19
+/* Mask patern */
+#define UDC_EPINT_OUT_MASK		0xffff0000
+#define UDC_EPINT_IN_MASK		0x0000ffff
+#define UDC_EPINT_EP0_ENABLE_MSK	0x000e000e
+
+	u32 epirqmsk;
+/* Bit position */
+#define UDC_EPINT_OUT_MSK_OFS		16
+#define UDC_EPINT_IN_MSK_OFS		0
+/* Mask patern */
+#define UDC_EPINT_MSK_DISABLE_ALL	0xffffffff
+
+	u32 devlpm;
+};
+
+/**
+ * pch_udc_ep_regs -  Structure holding values of ep configuration registers
+ * @epctl		Endpoint control register
+ * @epsts		Endpoint status register
+ * @bufin_framenum	buffer size in / frame number out
+ * @bufout_maxpkt	buffer size out / maxpkt in
+ * @subptr		setup buffer pointer
+ * @desptr		Data descriptor pointer
+ * @confirm		Write/Read confirmation  for slave mode only
+ */
+struct pch_udc_ep_regs {
+	u32 epctl;
+/* Bit position */
+#define UDC_EPCTL_MRXFLUSH		12
+#define UDC_EPCTL_RRDY			9
+#define UDC_EPCTL_CNAK			8
+#define UDC_EPCTL_SNAK			7
+#define UDC_EPCTL_NAK			6
+#define UDC_EPCTL_ET_OFS		4
+#define UDC_EPCTL_P			3
+#define UDC_EPCTL_SN			2
+#define UDC_EPCTL_F			1
+#define UDC_EPCTL_S			0
+/* Mask patern */
+#define UDC_EPCTL_ET_MASK		0x00000030
+/* Value for ET field */
+#define UDC_EPCTL_ET_CONTROL		0
+#define UDC_EPCTL_ET_ISO		1
+#define UDC_EPCTL_ET_BULK		2
+#define UDC_EPCTL_ET_INTERRUPT		3
+
+	u32 epsts;
+/* Bit position */
+#define UDC_EPSTS_XFERDONE		27
+#define UDC_EPSTS_RSS			26
+#define UDC_EPSTS_RCS			25
+#define UDC_EPSTS_TXEMPTY		24
+#define UDC_EPSTS_ISOINDONE		23
+#define UDC_EPSTS_RX_PKT_SIZE_OFS	11
+#define UDC_EPSTS_TDC			10
+#define UDC_EPSTS_HE			9
+#define UDC_EPSTS_MRXFIFO_EMP		8
+#define UDC_EPSTS_BNA			7
+#define UDC_EPSTS_IN			6
+#define UDC_EPSTS_OUT_OFS		4
+#define UDC_EPSTS_OUT_SETUP		2
+#define UDC_EPSTS_OUT_DATA		1
+/* Mask patern */
+#define UDC_EPSTS_RX_PKT_SIZE_MASK	0x007ff800
+#define UDC_EPSTS_OUT_MASK		0x00000030
+/* Value for OUT field */
+#define UDC_EPSTS_OUT_DATA_CLEAR	0x10
+#define UDC_EPSTS_OUT_SETUP_CLEAR	0x20
+#define UDC_EPSTS_OUT_CLEAR		0x30
+
+	u32 bufin_framenum;
+/* Bit position */
+#define UDC_EPIN_BUFF_SIZE_OFS		0
+#define UDC_EPOUT_FRAME_NUMBER_OFS	0
+/* Mask patern */
+#define UDC_EPIN_BUFF_SIZE_MASK		0x0000ffff
+#define UDC_EPOUT_FRAME_NUMBER_MASK	0x0000ffff
+/* EPIN0 Buffer Size */
+#define UDC_EP0IN_BUFF_SIZE		64
+#define UDC_FS_EPIN0_BUFF_SIZE		32
+#define UDC_EPIN_BUFF_SIZE_MULT		2
+#define UDC_EPIN_BUFF_SIZE		512
+#define UDC_EPIN_SMALLINT_BUFF_SIZE	32
+#define UDC_FS_EPIN_BUFF_SIZE		32
+
+	u32 bufout_maxpkt;
+/* Starting bit position */
+#define UDC_EPOUT_BUFF_SIZE_OFS		16
+#define UDC_EP_MAX_PKT_SIZE_OFS		0
+/* Mask patern */
+#define UDC_EPOUT_BUFF_SIZE_MASK	0xffff0000
+#define UDC_EP_MAX_PKT_SIZE_MASK	0x0000ffff
+/* Value of EP OUT Buffer Size */
+#define UDC_EP0OUT_BUFF_SIZE		64
+#define UDC_EPOUT_BUFF_SIZE		512
+#define UDC_FS_EPOUT_BUFF_SIZE		32
+/* Value of EP0 maximum packet size */
+#define UDC_EP0IN_MAX_PKT_SIZE		64
+#define UDC_EP0OUT_MAX_PKT_SIZE		64
+#define UDC_BULK_MAX_PKT_SIZE		512
+#define UDC_FS_EP0IN_MAX_PKT_SIZE	64
+#define UDC_FS_EP0OUT_MAX_PKT_SIZE	64
+
+	u32 subptr;
+	u32 desptr;
+	u32 confirm;
+};
+
+#define DMA_ADDR_INVALID	(~(dma_addr_t)0)
+
+/**
+ * pch_udc_data_dma_desc - Structure to hold DMA descriptor information
+ *				for data
+ * @status		Status quadlet
+ * @reserved		Reserved
+ * @dataptr		Buffer descriptor
+ * @next		Next descriptor
+*/
+struct pch_udc_data_dma_desc {
+	u32 status;
+	u32 reserved;
+	u32 dataptr;
+	u32 next;
+};
+
+/**
+ * pch_udc_stp_dma_desc - Structure to hold DMA descriptor information
+ *				for control data
+ * @status	Status
+ * @reserved	Reserved
+ * @data12	First setup word
+ * @data34	Second setup word
+
+*/
+struct pch_udc_stp_dma_desc {
+	u32 status;
+	u32 reserved;
+	u32 data12;
+	u32 data34;
+};
+
+/* DMA status definitions */
+/* Buffer status */
+#define PCH_UDC_BUFF_STS	0xC0000000
+#define PCH_UDC_BS_HST_RDY	0x00000000
+#define PCH_UDC_BS_DMA_BSY	0x40000000
+#define PCH_UDC_BS_DMA_DONE	0x80000000
+#define PCH_UDC_BS_HST_BSY	0xC0000000
+/*  Rx/Tx Status */
+#define PCH_UDC_RXTX_STS	0x30000000
+#define PCH_UDC_RTS_SUCC	0x00000000
+#define PCH_UDC_RTS_DESERR	0x10000000
+#define PCH_UDC_RTS_BUFERR	0x30000000
+/* Last Descriptor Indication */
+#define PCH_UDC_DMA_LAST	0x08000000
+/* Number of Rx/Tx Bytes Mask */
+#define PCH_UDC_RXTX_BYTES	0x0000ffff
+
+/**
+ * pch_udc_cfg_data - Structure to hold current configuration
+ *			and interface information
+ * @cur_cfg	current configuration in use
+ * @cur_intf	current interface in use
+ * @cur_alt	current alt interface in use
+ */
+struct pch_udc_cfg_data {
+	u16 cur_cfg;
+	u16 cur_intf;
+	u16 cur_alt;
+};
+
+
+/**
+ * pch_udc_request - Structure holding a PCH USB device request
+ * @req			embedded ep request
+ * @td_data_phys	phys. address
+ * @td_data		first dma desc. of chain
+ * @td_data_last	last dma desc. of chain
+ * @queue		associated queue
+ * @dma_going		DMA in progress for request
+ * @dma_mapped		DMA memory mapped for request
+ * @dma_done		DMA completed for request
+ * @chain_len		chain length
+ */
+struct pch_udc_request /* request packet */
+{
+	struct usb_request		req;
+	dma_addr_t			td_data_phys;
+	struct pch_udc_data_dma_desc	*td_data;
+	struct pch_udc_data_dma_desc	*td_data_last;
+	struct list_head		queue;
+	unsigned			dma_going:1,
+					dma_mapped:1,
+					dma_done:1;
+	unsigned			chain_len;
+};
+
+/**
+ * pch_udc_ep - Structure holding a PCH USB device Endpoint information
+ * @ep			embedded ep request
+ * @td_stp_phys		for setup request
+ * @td_data_phys	for data request
+ * @td_stp		for setup request
+ * @td_data		for data request
+ * @dev			reference to device struct
+ * @regs
+ * @dma			dma enabled or not
+ * @desc		for this ep
+ * @queue		queue for requests
+ * @num			endpoint number
+ * @in			endpoint is IN
+ * @halted		endpoint halted?
+ * @epsts		Endpoint status
+ */
+struct pch_udc_ep {
+	struct usb_ep			ep;
+	dma_addr_t			td_stp_phys;
+	dma_addr_t			td_data_phys;
+	struct pch_udc_stp_dma_desc	*td_stp;
+	struct pch_udc_data_dma_desc	*td_data;
+	struct pch_udc_dev		*dev;
+	struct pch_udc_ep_regs __iomem	*regs;
+	u32 __iomem			*dma;
+	const struct usb_endpoint_descriptor	*desc;
+	struct list_head		queue;
+	unsigned			num:5;
+	unsigned			in:1;
+	unsigned			halted;
+	unsigned long			epsts;
+};
+
+
+/**
+ * pch_udc_dev - Structure holding complete information of the PCH USB device
+ *
+ * @gadget		gadget driver data
+ * @driver;		reference to gadget driver bound
+ * @pdev;		reference to the PCI device
+ * @ep[PCH_UDC_EP_NUM];	array of endpoints
+ * @lock;		protects all state
+ * @active:1,		enabled the PCI device
+ * @stall:1,		stall requested
+ * @prot_stall:1,	protcol stall requested
+ * @irq_registered:1,	irq registered with system
+ * @mem_region:1,	device memory mapped
+ * @registered:1,	driver regsitered with system
+ * @suspended:1,	driver in suspended state
+ * @connected:1,	gadget driver associated
+ * @set_cfg_not_acked:1,	pending acknowledgement 4 setup
+ * @waiting_zlp_ack:1;	pending acknowledgement 4 ZLP
+ * @csr;		address of config & status
+ * @regs;		address of device registers
+ * @*ep_regs;		address of endpoint registers
+ * @data_requests;	DMA pool for data requests
+ * @stp_requests;	DMA pool for setup requests
+ * @phys_addr;		of device memory
+ * @virt_addr;		for mapped device memory
+ * @irq;		IRQ line for the device
+ * @cfg_data;		current cfg, intf, and alt in use
+ */
+
+struct pch_udc_dev {
+	struct usb_gadget		gadget;
+	struct usb_gadget_driver	*driver;
+	struct pci_dev			*pdev;
+	/* all endpoints */
+	struct pch_udc_ep		ep[PCH_UDC_EP_NUM];
+	spinlock_t			lock;
+	unsigned	active:1,
+			stall:1,
+			prot_stall:1,
+			irq_registered:1,
+			mem_region:1,
+			registered:1,
+			suspended:1,
+			connected:1,
+			set_cfg_not_acked:1,
+			waiting_zlp_ack:1;
+	struct pch_udc_csrs __iomem	*csr;
+	struct pch_udc_regs __iomem	*regs;
+	struct pch_udc_ep_regs __iomem	*ep_regs;
+	struct pci_pool			*data_requests;
+	struct pci_pool			*stp_requests;
+	unsigned long			phys_addr;
+	void __iomem			*virt_addr;
+	unsigned			irq;
+	struct pch_udc_cfg_data		cfg_data;
+};
+
+/**
+ * pch_udc_ep - Structure holding setup request data
+ *
+ * @data[2];		8 bytes of setup data
+ * @request;		setup request for gadget driver
+ */
+union pch_udc_setup_data {
+	u32		data[2];
+	struct usb_ctrlrequest	request;
+};
+
+#endif	/* _PCH_UDC_H_ */
-- 
1.6.2.5

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

* Re: [PATCH] USB device driver of Topcliff PCH
  2010-09-07  7:49 [PATCH] USB device driver of Topcliff PCH Masayuki Ohtake
@ 2010-09-07 12:53 ` Maurus Cuelenaere
  2010-09-13  4:23   ` Masayuki Ohtake
  2010-09-08  0:22 ` Greg KH
  2010-09-08  1:58 ` Michał Nazarewicz
  2 siblings, 1 reply; 14+ messages in thread
From: Maurus Cuelenaere @ 2010-09-07 12:53 UTC (permalink / raw)
  To: Masayuki Ohtake
  Cc: Randy Dunlap, Peter Korsgaard, Nicolas Ferre, Michal Nazarewicz,
	linux-usb, Laurent Pinchart, Greg Kroah-Hartman, Fabien Chouteau,
	david Brownell, Christoph Egger, LKML, MeeGo, Wang, Qi, Wang,
	Yong Y, Andrew, Intel OTC, Foster, Margie, Arjan,
	Toshiharu Okada, Takahiro Shimizu, Tomoya Morinaga

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=UTF-8, Size: 29282 bytes --]

2010/9/7 Masayuki Ohtake <masa-korg@dsn.okisemi.com>
>
> This patch adds the USB device driver of Topcliff PCH.
> Topcliff PCH is the platform controller hub that is going to be used in
> Intel's upcoming general embedded platform. All IO peripherals in
> Topcliff PCH are actually devices sitting on AMBA bus.
> Topcliff PCH has USB device I/F. Using this I/F, it is able to access system
> devices connected to USB device.
>
> Signed-off-by: Masayuki Ohtake <masa-korg@dsn.okisemi.com>

No need to mail all these people, just the maintainers and appropriate mailing
lists will do.

> ---
>  drivers/usb/gadget/Kconfig        |   24 +
>  drivers/usb/gadget/Makefile       |    2 +-
>  drivers/usb/gadget/gadget_chips.h |    7 +
>  drivers/usb/gadget/pch_udc.c      | 3153 +++++++++++++++++++++++++++++++++++++
>  drivers/usb/gadget/pch_udc.h      |  495 ++++++
>  5 files changed, 3680 insertions(+), 1 deletions(-)
>  create mode 100755 drivers/usb/gadget/pch_udc.c
>  create mode 100755 drivers/usb/gadget/pch_udc.h
>
[snip]
> diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
> new file mode 100755
> index 0000000..2065c11
> --- /dev/null
> +++ b/drivers/usb/gadget/pch_udc.c
[snip]
> +
> +const char     ep0_string[] = "ep0in";
> +static DEFINE_SPINLOCK(udc_stall_spinlock);    /* stall spin lock */
> +static u32 pch_udc_base;
> +static union pch_udc_setup_data setup_data;    /* received setup data */
> +static unsigned long ep0out_buf[64];
> +static dma_addr_t dma_addr;
> +struct pch_udc_dev *pch_udc;           /* pointer to device object */
> +int speed_fs;

I'd put all these in struct phc_udc_dev or similar, so you could have multiple
controllers.

> +
> +module_param_named(speed_fs, speed_fs, bool, S_IRUGO);
> +MODULE_PARM_DESC(speed_fs, "true for Full speed operation");
> +MODULE_DESCRIPTION("OKISEMI PCH UDC - USB Device Controller");
> +MODULE_LICENSE("GPL");
> +
> +/**
> + * pch_udc_write_csr - Write the command and status registers.
> + * @val:       value to be written to CSR register
> + * @addr:      address of CSR register
> + */
> +inline void pch_udc_write_csr(unsigned long val, unsigned long addr)

Make all these functions static.

> +{
> +       int count = MAX_LOOP;
> +
> +       /* Wait till idle */
> +       while ((count > 0) &&\
> +               (ioread32((u32 *)(PCH_UDC_CSR_BUSY_ADDR + pch_udc_base)) &
> +               PCH_UDC_CSR_BUSY))

Why not define PCH_UDC_* as (void __iomem*) so no casting is necessary.

> +               count--;
> +
> +       if (count < 0)
> +               pr_debug("%s: wait error; count = %x", __func__, count);
> +
> +       iowrite32(val, (u32 *)addr);
> +       /* Wait till idle */
> +       count = MAX_LOOP;
> +       while ((count > 0) &&
> +               (ioread32((u32 *)(PCH_UDC_CSR_BUSY_ADDR + pch_udc_base)) &
> +               PCH_UDC_CSR_BUSY))
> +               count--;
> +
> +       if (count < 0)
> +               pr_debug("%s: wait error; count = %x", __func__, count);
> +
> +}
> +
> +/**
> + * pch_udc_read_csr - Read the command and status registers.
> + * @addr:      address of CSR register
> + * Returns
> + *     content of CSR register
> + */
> +inline u32 pch_udc_read_csr(unsigned long addr)

void __iomem *addr

> +{
> +       int count = MAX_LOOP;
> +
> +       /* Wait till idle */
> +       while ((count > 0) &&
> +               (ioread32((u32 *)(PCH_UDC_CSR_BUSY_ADDR + pch_udc_base)) &
> +               PCH_UDC_CSR_BUSY))
> +               count--;
> +
> +       if (count < 0)
> +               pr_debug("%s: wait error; count = %x", __func__, count);
> +       /* Dummy read */
> +       ioread32((u32 *)addr);
> +       count = MAX_LOOP;
> +       /* Wait till idle */
> +       while ((count > 0) &&
> +               (ioread32((u32 *)(PCH_UDC_CSR_BUSY_ADDR + pch_udc_base)) &
> +               PCH_UDC_CSR_BUSY))
> +               count--;
> +       /* actual read */
> +       if (count < 0)
> +               pr_debug("%s: wait error; count = %x", __func__, count);
> +
> +       return ioread32((u32 *)addr);
> +}
> +
> +/**
> + * pch_udc_rmt_wakeup - Initiate for remote wakeup
> + * @dev:       Reference to pch_udc_regs structure
> + */
> +inline void pch_udc_rmt_wakeup(struct pch_udc_regs *dev)
> +{
> +       PCH_UDC_BIT_SET(&dev->devctl, 1 << UDC_DEVCTL_RES);
> +       mdelay(1);
> +       PCH_UDC_BIT_CLR(&dev->devctl, 1 << UDC_DEVCTL_RES);
> +}
> +
> +/**
> + * pch_udc_get_frame - Get the current frame from device status register
> + * @dev:       Reference to pch_udc_regs structure
> + * Retern      current frame
> + */
> +inline int pch_udc_get_frame(struct pch_udc_regs *dev)
> +{
> +       u32 frame;
> +
> +       frame = ioread32(&dev->devsts);

Why not just get rid of struct pch_udc_regs and do something like:

static inline u32 pch_readl(struct pch_udc_dev *dev, unsigned long reg)
{
	return ioread32(dev->base_addr + reg);
}

(and similar for pch_writel)

> +       return (frame & UDC_DEVSTS_TS_MASK) >> UDC_DEVSTS_TS_OFS;
> +}
[snip]
> +static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep,
> +                                                                gfp_t gfp)
> +{
> +       struct pch_udc_request  *req;
> +       struct pch_udc_ep               *ep;
> +
> +       pr_debug("%s: enter", __func__);
> +       if (usbep == NULL)
> +               return NULL;
> +
> +       ep = container_of(usbep, struct pch_udc_ep, ep);
> +       pr_debug("%s: ep %s", __func__, usbep->name);
> +       req = kzalloc(sizeof(struct pch_udc_request), gfp);
> +       if (req == NULL) {
> +               pr_debug("%s: no memory for request", __func__);
> +               return NULL;
> +       }
> +       memset(req, 0, sizeof(struct pch_udc_request));

kzalloc does this..

> +       req->req.dma = DMA_ADDR_INVALID;
> +       INIT_LIST_HEAD(&req->queue);
> +
> +       if (ep->dma != NULL) {
> +               struct pch_udc_data_dma_desc    *dma_desc;
> +
> +               /* ep0 in requests are allocated from data pool here */
> +               dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp,
> +                                                        &req->td_data_phys);
> +               if (NULL == dma_desc) {
> +                       kfree(req);
> +                       return NULL;
> +               }
> +
> +               pr_debug("%s: req = 0x%p dma_desc = 0x%p, "
> +                       "td_phys = 0x%08lx", __func__,
> +                       req, dma_desc, (unsigned long)req->td_data_phys);
> +
> +               /* prevent from using desc. - set HOST BUSY */
> +               dma_desc->status |= PCH_UDC_BS_HST_BSY;
> +               dma_desc->dataptr = __constant_cpu_to_le32(DMA_ADDR_INVALID);
> +               req->td_data = dma_desc;
> +               req->td_data_last = dma_desc;
> +               req->chain_len = 1;
> +       }
> +       return &req->req;
> +}
[snip]
> +
> +/**
> + * pch_udc_start_next_txrequest - This function starts
> + *                                     the next transmission requirement
> + * @ep:        Reference to the endpoint structure
> + */
> +static void pch_udc_start_next_txrequest(struct pch_udc_ep *ep)
> +{
> +       struct pch_udc_request *req;
> +
> +       pr_debug("%s: enter", __func__);
> +       if (pch_udc_read_ep_control(ep->regs) & (1 << UDC_EPCTL_P))
> +               return;
> +
> +       if (!list_empty(&ep->queue)) {

Convert this into:
if (list_empty(&ep->queue))
	return;

That way you get rid of the unnecessary spacing below

> +               /* next request */
> +               req = list_entry(ep->queue.next, struct pch_udc_request, queue);
> +               if (req && !req->dma_going) {
> +                       pr_debug("%s: Set request: req=%p req->td_data=%p",
> +                                       __func__, req, req->td_data);
> +                       if (req->td_data) {
> +                               struct pch_udc_data_dma_desc *td_data;
> +
> +                               while (pch_udc_read_ep_control(ep->regs) &
> +                                                        (1 << UDC_EPCTL_S))
> +                                       udelay(100);
> +
> +                               req->dma_going = 1;
> +                               /* Clear the descriptor pointer */
> +                               pch_udc_ep_set_ddptr(ep->regs, 0);
> +
> +                               td_data = req->td_data;
> +                               while (1) {
> +                                       td_data->status = (td_data->status &
> +                                                ~PCH_UDC_BUFF_STS) |
> +                                                PCH_UDC_BS_HST_RDY;
> +                                       if ((td_data->status &
> +                                                PCH_UDC_DMA_LAST) ==
> +                                                PCH_UDC_DMA_LAST)
> +                                               break;
> +
> +                                       td_data =
> +                                       (struct pch_udc_data_dma_desc *)\
> +                                       phys_to_virt(td_data->next);
> +                               }
> +                               /* Write the descriptor pointer */
> +                               pch_udc_ep_set_ddptr(ep->regs,
> +                                                        req->td_data_phys);
> +                               pch_udc_set_dma(ep->dev->regs, DMA_DIR_TX);
> +                               /* Set the poll demand bit */
> +                               pch_udc_ep_set_pd(ep->regs);
> +                               pch_udc_enable_ep_interrupts(ep->dev->regs,
> +                                               1 << (ep->in ? ep->num :\
> +                                                ep->num + UDC_EPINT_OUT_EP0));
> +                               pch_udc_ep_clear_nak(ep->regs);
> +                       }
> +               }
> +       }
> +}
> +
> +/**
> + * pch_udc_complete_transfer - This function completes a transfer
> + * @ep:                Reference to the endpoint structure
> + */
> +static void pch_udc_complete_transfer(struct pch_udc_ep        *ep)
> +{
> +       struct pch_udc_request *req;
> +
> +       pr_debug("%s: enter", __func__);
> +       if (!list_empty(&ep->queue)) {

Same here

> +               pr_debug("%s: list_entry", __func__);
> +               req = list_entry(ep->queue.next, struct pch_udc_request, queue);
> +               if (req && ((req->td_data_last->status & PCH_UDC_BUFF_STS) ==
> +                                                        PCH_UDC_BS_DMA_DONE)) {
> +#ifdef DMA_PPB_WITH_DESC_UPDATE
> +                       struct pch_udc_data_dma_desc *td_data = req->td_data;
> +                       for (i = 0; i < req->chain_len; i++) {
> +                               if ((td_data->status & PCH_UDC_RXTX_STS) !=
> +                                                        PCH_UDC_RTS_SUCC) {
> +                                       pr_err("Invalid RXTX status (0x%08x)"
> +                                              " epstatus=0x%08x\n",
> +                                              (td_data->status &
> +                                               PCH_UDC_RXTX_STS),
> +                                              (int)(ep->epsts));
> +                                       return;
> +                               }
> +                               td_data = (struct pch_udc_data_dma_desc *)
> +                                                phys_to_virt(td_data->next);
> +                       }
> +#else
> +                       if ((req->td_data_last->status & PCH_UDC_RXTX_STS) !=
> +                                                        PCH_UDC_RTS_SUCC) {
> +                               pr_err("Invalid RXTX status (0x%08x)"
> +                                      " epstatus=0x%08x\n",
> +                                      (req->td_data_last->status &
> +                                       PCH_UDC_RXTX_STS),
> +                                      (int)(ep->epsts));
> +                               return;
> +                       }
> +#endif
> +                       req->req.actual = req->req.length;
> +                       req->td_data_last->status = PCH_UDC_BS_HST_BSY |
> +                                                        PCH_UDC_DMA_LAST;
> +                       req->td_data->status = PCH_UDC_BS_HST_BSY |
> +                                                        PCH_UDC_DMA_LAST;
> +                       /* complete req */
> +                       complete_req(ep, req, 0);
> +                       req->dma_going = 0;
> +                       if (!list_empty(&ep->queue)) {
> +                               while (pch_udc_read_ep_control(ep->regs) &
> +                                                        (1 << UDC_EPCTL_S))
> +                                       udelay(100);
> +
> +                               pch_udc_ep_clear_nak(ep->regs);
> +                               pch_udc_enable_ep_interrupts(ep->dev->regs,
> +                                       1 << (ep->in ? ep->num : ep->num +
> +                                                        UDC_EPINT_OUT_EP0));
> +                       } else {
> +                               pch_udc_disable_ep_interrupts(ep->dev->regs,
> +                                       1 << (ep->in ? ep->num : ep->num +
> +                                                        UDC_EPINT_OUT_EP0));
> +                       }
> +               }
> +       }
> +}
[snip]
> +
> +/**
> + * pch_udc_svc_enum_interrupt - This function handles a USB speed enumeration
> + *                             done interrupt
> + * @dev:       Reference to driver structure
> + */
> +void
> +pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev)
> +{
> +       u32 dev_stat, dev_speed;
> +       u32 speed = USB_SPEED_FULL;
> +
> +       pr_debug("%s: enter", __func__);
> +       dev_stat = pch_udc_read_device_status(dev->regs);
> +       dev_speed = (dev_stat & UDC_DEVSTS_ENUM_SPEED_MASK) >>
> +                                                UDC_DEVSTS_ENUM_SPEED_OFS;
> +
> +       pr_debug("%s: dev_speed = 0x%08x", __func__, dev_speed);
> +
> +       if (dev_speed == UDC_DEVSTS_ENUM_SPEED_HIGH) {
> +               pr_debug("HighSpeed");
> +               speed = USB_SPEED_HIGH;
> +       } else if (dev_speed == UDC_DEVSTS_ENUM_SPEED_FULL) {
> +               pr_debug("FullSpeed");
> +               speed = USB_SPEED_FULL;
> +       } else if (dev_speed == UDC_DEVSTS_ENUM_SPEED_LOW) {
> +               pr_debug("LowSpeed?");
> +               speed = USB_SPEED_LOW;
> +       } else {
> +               pr_debug("FullSpeed?");

BUG() perhaps? Also, change this into a switch statement

> +       }
> +       dev->gadget.speed = speed;
> +
> +       pch_udc_activate_control_ep(dev);
> +
> +       /* enable ep0 interrupts */
> +       pch_udc_enable_ep_interrupts(dev->regs, 1 << UDC_EPINT_IN_EP0 |
> +                                                       1 << UDC_EPINT_OUT_EP0);
> +       /* enable DMA */
> +       pch_udc_set_dma(dev->regs, DMA_DIR_TX);
> +       pch_udc_set_dma(dev->regs, DMA_DIR_RX);
> +       pch_udc_ep_set_rrdy(dev->ep[UDC_EP0OUT_IDX].regs);
> +
> +
> +       pr_debug("%s: EP mask set to %x", __func__,
> +                                ioread32(&dev->regs->epirqmsk));
> +}
[snip]
> +
> +int pch_udc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> +{
> +       unsigned long           resource;
> +       unsigned long           len;
> +       int                                     retval = 0;
> +       struct pch_udc_dev      *dev;
> +
> +       dev_dbg(&pdev->dev, "%s: enter", __func__);
> +       /* one udc only */
> +       if (pch_udc != NULL) {
> +               dev_err(&pdev->dev, "%s: already probed", __func__);
> +               return -EBUSY;
> +       }
> +
> +       /* init */
> +       dev = kzalloc(sizeof(struct pch_udc_dev), GFP_KERNEL);
> +       if (dev == NULL) {
> +               dev_err(&pdev->dev, "%s: no memory for device structure",
> +                                                               __func__);
> +               return -ENOMEM;
> +       }
> +       memset(dev, 0, sizeof(struct pch_udc_dev));

kzalloc already does this for you

> +       /* pci setup */
> +       if (pci_enable_device(pdev) < 0) {
> +               kfree(dev);
> +               dev_err(&pdev->dev, "%s: pci_enable_device failed", __func__);
> +               return -ENODEV;
> +       }
> +       dev->active = 1;
> +       pci_set_drvdata(pdev, dev);
> +
> +       /* PCI resource allocation */
> +       resource = pci_resource_start(pdev, 1);
> +       len = pci_resource_len(pdev, 1);
> +       dev_dbg(&pdev->dev, "%s: resource %lx, len %ld",
> +                       __func__, resource, len);
> +
> +       if (request_mem_region(resource, len, KBUILD_MODNAME) == NULL) {
> +               dev_err(&pdev->dev, "%s: pci device used already", __func__);
> +               retval = -EBUSY;
> +               goto finished;
> +       }
> +       dev->phys_addr = resource;
> +       dev->mem_region = 1;
> +
> +       dev->virt_addr = ioremap_nocache(resource, len);
> +       if (dev->virt_addr == NULL) {
> +               dev_err(&pdev->dev, "%s: device memory cannot be mapped",
> +                       __func__);
> +               retval = -ENOMEM;
> +               goto finished;
> +       }
> +       dev_dbg(&pdev->dev, "%s: device memory mapped at %x", __func__,
> +               (int)dev->virt_addr);
> +
> +       if (pdev->irq == 0) {
> +               dev_err(&pdev->dev, "%s: irq not set", __func__);
> +               retval = -ENODEV;
> +               goto finished;
> +       }
> +
> +       pch_udc = dev;
> +
> +       /* initialize the hardware */
> +       if (pch_udc_pcd_init(dev) != 0)
> +               goto finished;
> +
> +       if (request_irq(pdev->irq, pch_udc_isr, IRQF_SHARED,
> +                       KBUILD_MODNAME, dev) != 0) {
> +               dev_err(&pdev->dev, "%s: request_irq(%d) fail", __func__,
> +                       pdev->irq);
> +               retval = -ENODEV;
> +               goto finished;
> +       }
> +       dev->irq = pdev->irq;
> +       dev->irq_registered = 1;
> +
> +       pci_set_master(pdev);
> +       pci_try_set_mwi(pdev);
> +
> +       /* device struct setup */
> +       spin_lock_init(&dev->lock);
> +       dev->pdev = pdev;
> +       dev->gadget.ops = &pch_udc_ops;
> +
> +       retval = init_dma_pools(dev);
> +       if (retval != 0)
> +               goto finished;
> +
> +       dev_set_name(&dev->gadget.dev, "gadget");
> +       dev->gadget.dev.parent = &pdev->dev;
> +       dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
> +       dev->gadget.dev.release = gadget_release;
> +       dev->gadget.name = KBUILD_MODNAME;
> +       dev->gadget.is_dualspeed = 1;
> +
> +       retval = device_register(&dev->gadget.dev);
> +       if (retval != 0)
> +               goto finished;
> +       dev->registered = 1;
> +
> +       /* Put the device in disconnected state till a driver is bound */
> +       pch_udc_set_disconnect(dev->regs);
> +       return 0;
> +
> +finished:
> +       pch_udc_remove(pdev);
> +       return retval;
> +}
> +
> +static const struct pci_device_id pch_udc_pcidev_id[] = {
> +       {
> +               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PCH1_UDC),
> +               .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
> +               .class_mask = 0xffffffff,
> +       },
> +       { 0 },
> +};
> +
> +MODULE_DEVICE_TABLE(pci, pch_udc_pcidev_id);
> +
> +
> +static struct pci_driver pch_udc_driver = {
> +       .name = KBUILD_MODNAME,
> +       .id_table =     pch_udc_pcidev_id,
> +       .probe =        pch_udc_probe,
> +       .remove =       pch_udc_remove,
> +       .suspend =      pch_udc_suspend,
> +       .resume =       pch_udc_resume,
> +       .shutdown =     pch_udc_shutdown,

Make all these functions static

> +};
> +
> +static int __init pch_udc_pci_init(void)
> +{
> +       return pci_register_driver(&pch_udc_driver);
> +}
> +module_init(pch_udc_pci_init);
> +
> +static void __exit pch_udc_pci_exit(void)
> +{
> +       pci_unregister_driver(&pch_udc_driver);
> +}
> +module_exit(pch_udc_pci_exit);
> diff --git a/drivers/usb/gadget/pch_udc.h b/drivers/usb/gadget/pch_udc.h
> new file mode 100755
> index 0000000..55c22ef
> --- /dev/null
> +++ b/drivers/usb/gadget/pch_udc.h
> @@ -0,0 +1,495 @@
> +/*
> + * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
> + *
> + * 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; version 2 of the License.
> + *
> + * 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 _PCH_UDC_H_
> +#define _PCH_UDC_H_
> +
> +/* Address offset of Registers */
> +#define UDC_EPIN_REGS_ADDR             0x000
> +#define UDC_EPOUT_REGS_ADDR            0x200
> +#define UDC_EP_REG_OFS                 0x20    /* Offset to next EP */
> +#define UDC_DEVCFG_ADDR                        0x400
> +#define PCH_UDC_CSR_BUSY_ADDR          0x4f0
> +#define PCH_UDC_SRST_ADDR              0x4fc
> +#define UDC_CSR_ADDR                   0x500
> +
> +/* Bit position in UDC CSR Busy status Register */
> +#define PCH_UDC_CSR_BUSY               1
> +/* Bit position in UDC Soft reset Register */
> +#define PCH_UDC_PSRST                  1
> +#define PCH_UDC_SRST                   0
> +
[snip]
> +
> +/**
> + * pch_udc_csrs - Structure to Endpoint configuration registers
> + */
> +struct pch_udc_csrs {
> +       u32 ne[PCH_UDC_USED_EP_NUM * 2];

Why not do away with the structs and do something like:

#define PCH_UDC_CSR(ep)				(UDC_CSR_ADDR + ep*4)

(and similar for the others)

> +/* Starting bit position */
> +#define UDC_CSR_NE_NUM_OFS                     0
> +#define UDC_CSR_NE_DIR_OFS                     4
> +#define UDC_CSR_NE_TYPE_OFS                    5
> +#define UDC_CSR_NE_CFG_OFS                     7
> +#define UDC_CSR_NE_INTF_OFS                    11
> +#define UDC_CSR_NE_ALT_OFS                     15
> +#define UDC_CSR_NE_MAX_PKT_OFS                 19
> +/* Mask patern */
> +#define UDC_CSR_NE_NUM_MASK                    0x0000000f
> +#define UDC_CSR_NE_DIR_MASK                    0x00000010
> +#define UDC_CSR_NE_TYPE_MASK                   0x00000060
> +#define UDC_CSR_NE_CFG_MASK                    0x00000780
> +#define UDC_CSR_NE_INTF_MASK                   0x00007800
> +#define UDC_CSR_NE_ALT_MASK                    0x00078000
> +#define UDC_CSR_NE_MAX_PKT_MASK                        0x3ff80000
> +};
> +
[snip]
> +
> +/**
> + * pch_udc_request - Structure holding a PCH USB device request
> + * @req                        embedded ep request
> + * @td_data_phys       phys. address
> + * @td_data            first dma desc. of chain
> + * @td_data_last       last dma desc. of chain
> + * @queue              associated queue
> + * @dma_going          DMA in progress for request
> + * @dma_mapped         DMA memory mapped for request
> + * @dma_done           DMA completed for request
> + * @chain_len          chain length
> + */
> +struct pch_udc_request /* request packet */
> +{

I don't see any reason to not put this in the main .c file?
(same for struct pch_udc_{ep,request})

> +       struct usb_request              req;
> +       dma_addr_t                      td_data_phys;
> +       struct pch_udc_data_dma_desc    *td_data;
> +       struct pch_udc_data_dma_desc    *td_data_last;
> +       struct list_head                queue;
> +       unsigned                        dma_going:1,
> +                                       dma_mapped:1,
> +                                       dma_done:1;
> +       unsigned                        chain_len;
> +};
> +
[snip]
> +
> +struct pch_udc_dev {
> +       struct usb_gadget               gadget;
> +       struct usb_gadget_driver        *driver;
> +       struct pci_dev                  *pdev;
> +       /* all endpoints */
> +       struct pch_udc_ep               ep[PCH_UDC_EP_NUM];
> +       spinlock_t                      lock;
> +       unsigned        active:1,
> +                       stall:1,
> +                       prot_stall:1,
> +                       irq_registered:1,
> +                       mem_region:1,
> +                       registered:1,
> +                       suspended:1,
> +                       connected:1,
> +                       set_cfg_not_acked:1,
> +                       waiting_zlp_ack:1;
> +       struct pch_udc_csrs __iomem     *csr;
> +       struct pch_udc_regs __iomem     *regs;
> +       struct pch_udc_ep_regs __iomem  *ep_regs;

These pointers just seem unnecessary, especially as you could easily construct
them in-place by adding the appropriate offset to your base address..

> +       struct pci_pool                 *data_requests;
> +       struct pci_pool                 *stp_requests;
> +       unsigned long                   phys_addr;
> +       void __iomem                    *virt_addr;
> +       unsigned                        irq;
> +       struct pch_udc_cfg_data         cfg_data;
> +};
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* Re: [PATCH] USB device driver of Topcliff PCH
  2010-09-07  7:49 [PATCH] USB device driver of Topcliff PCH Masayuki Ohtake
  2010-09-07 12:53 ` Maurus Cuelenaere
@ 2010-09-08  0:22 ` Greg KH
  2010-09-13  4:23   ` Masayuki Ohtake
  2010-09-08  1:58 ` Michał Nazarewicz
  2 siblings, 1 reply; 14+ messages in thread
From: Greg KH @ 2010-09-08  0:22 UTC (permalink / raw)
  To: Masayuki Ohtake
  Cc: Randy Dunlap, Peter Korsgaard, Nicolas Ferre, Michal Nazarewicz,
	Maurus Cuelenaere, linux-usb, Laurent Pinchart, Fabien Chouteau,
	david Brownell, Christoph Egger, LKML, MeeGo, Wang, Qi, Wang,
	Yong Y, Andrew, Intel OTC, Foster, Margie, Arjan,
	Toshiharu Okada, Takahiro Shimizu, Tomoya Morinaga

On Tue, Sep 07, 2010 at 04:49:03PM +0900, Masayuki Ohtake wrote:
> This patch adds the USB device driver of Topcliff PCH.
> 
> Topcliff PCH is the platform controller hub that is going to be used in
> Intel's upcoming general embedded platform. All IO peripherals in
> Topcliff PCH are actually devices sitting on AMBA bus. 
> Topcliff PCH has USB device I/F. Using this I/F, it is able to access system
> devices connected to USB device.
> 
> Signed-off-by: Masayuki Ohtake <masa-korg@dsn.okisemi.com>
> ---
>  drivers/usb/gadget/Kconfig        |   24 +
>  drivers/usb/gadget/Makefile       |    2 +-
>  drivers/usb/gadget/gadget_chips.h |    7 +
>  drivers/usb/gadget/pch_udc.c      | 3153 +++++++++++++++++++++++++++++++++++++
>  drivers/usb/gadget/pch_udc.h      |  495 ++++++
>  5 files changed, 3680 insertions(+), 1 deletions(-)
>  create mode 100755 drivers/usb/gadget/pch_udc.c
>  create mode 100755 drivers/usb/gadget/pch_udc.h

Heh, really?  executable .c and .h files?  I think you need to look at
your development system :)


> 
> diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
> index 591ae9f..3bc839d 100644
> --- a/drivers/usb/gadget/Kconfig
> +++ b/drivers/usb/gadget/Kconfig
> @@ -220,6 +220,30 @@ config USB_OTG
>  
>  	   Select this only if your OMAP board has a Mini-AB connector.
>  
> +config USB_GADGET_PCH
> +	boolean "PCH USB Dev"

Please spell this out a lot more as to what it is.

> +	depends on PCI
> +	select USB_GADGET_DUALSPEED
> +	help
> +	  This is a USB device driver for Topcliff PCH.
> +	  Topcliff PCH is the platform controller hub that is used in Intel's
> +	  general embedded platform.
> +	  Topcliff PCH has USB device interface.
> +	  Using this interface, it is able to access system devices connected
> +	  to USB device.
> +	  This driver enables USB device function.
> +	  USB device is a USB peripheral controller which
> +	  supports both full and high speed USB 2.0 data transfers.
> +	  This driver supports for control transfer, and bulk transfer modes.
> +	  This driver dose not support interrupt transfer, and isochronous
> +	  transfer modes.
> +
> +config PCH_USBDEV
> +	tristate
> +	depends on USB_GADGET_PCH
> +	default USB_GADGET
> +	select USB_GADGET_SELECTED
> +
>  config USB_GADGET_PXA25X
>  	boolean "PXA 25x or IXP 4xx"
>  	depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
> diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
> index 9bcde11..9473430 100644
> --- a/drivers/usb/gadget/Makefile
> +++ b/drivers/usb/gadget/Makefile
> @@ -63,4 +63,4 @@ obj-$(CONFIG_USB_G_HID)		+= g_hid.o
>  obj-$(CONFIG_USB_G_MULTI)	+= g_multi.o
>  obj-$(CONFIG_USB_G_NOKIA)	+= g_nokia.o
>  obj-$(CONFIG_USB_G_WEBCAM)	+= g_webcam.o
> -
> +obj-$(CONFIG_PCH_USBDEV) += pch_udc.o
> diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
> index e511fec..f67dd29 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_GADGET_PCH
> +#define	gadget_is_pch(g)	(!strcmp("pch_udc", (g)->name))
> +#else
> +#define	gadget_is_pch(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_pch(gadget))
> +		return 0x27;
>  	return -ENOENT;
>  }
>  
> diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
> new file mode 100755
> index 0000000..2065c11
> --- /dev/null
> +++ b/drivers/usb/gadget/pch_udc.c
> @@ -0,0 +1,3153 @@
> +/*
> + * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
> + *
> + * 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; version 2 of the License.
> + *
> + * 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.
> + */
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +#include <linux/types.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/kernel.h>
> +#include <linux/delay.h>
> +#include <linux/ioport.h>
> +#include <linux/sched.h>
> +#include <linux/slab.h>
> +#include <linux/smp_lock.h>
> +#include <linux/errno.h>
> +#include <linux/init.h>
> +#include <linux/timer.h>
> +#include <linux/list.h>
> +#include <linux/interrupt.h>
> +#include <linux/ioctl.h>
> +#include <linux/fs.h>
> +#include <linux/dmapool.h>
> +#include <linux/moduleparam.h>
> +#include <linux/device.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +
> +#include <asm/byteorder.h>
> +#include <asm/system.h>
> +#include <asm/unaligned.h>
> +
> +/* gadget stack */
> +#include <linux/usb/ch9.h>
> +#include <linux/usb/gadget.h>
> +#include "pch_udc.h"

Why do you need a .h file?

> +/* macro to set a specified bit(mask) at the specified address */
> +#define PCH_UDC_BIT_SET(reg, bitmask) \
> +		 iowrite32(((ioread32((reg)) | (bitmask))), (reg))
> +/* macro to clear a specified bit(mask) at the specified address */
> +#define PCH_UDC_BIT_CLR(reg, bitMask) \
> +		iowrite32((ioread32((reg)) & (~(bitMask))), (reg))


Why not just use the iowrite32 functions directly?  Or surely there's
another built-in kernel macro for this somewhere, right?

> +#define MAX_LOOP				200
> +#define PCH_UDC_PCI_BAR			1
> +#define PCI_VENDOR_ID_INTEL			0x8086

No need to define this, it's in pci_ids.h already.

> +#define PCI_DEVICE_ID_INTEL_PCH1_UDC	0x8808

I think this is there too.

> +
> +const char	ep0_string[] = "ep0in";
> +static DEFINE_SPINLOCK(udc_stall_spinlock);	/* stall spin lock */
> +static u32 pch_udc_base;
> +static union pch_udc_setup_data setup_data;	/* received setup data */
> +static unsigned long ep0out_buf[64];
> +static dma_addr_t dma_addr;
> +struct pch_udc_dev *pch_udc;		/* pointer to device object */
> +int speed_fs;

Why are 2 of these not static variables?

Have you run this driver through the sparse tool?  It will catch these
errors.  Please do so.

thanks,

greg k-h

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

* Re: [PATCH] USB device driver of Topcliff PCH
  2010-09-07  7:49 [PATCH] USB device driver of Topcliff PCH Masayuki Ohtake
  2010-09-07 12:53 ` Maurus Cuelenaere
  2010-09-08  0:22 ` Greg KH
@ 2010-09-08  1:58 ` Michał Nazarewicz
  2010-09-08 13:57   ` Masayuki Ohtake
  2010-09-13  4:23   ` Masayuki Ohtake
  2 siblings, 2 replies; 14+ messages in thread
From: Michał Nazarewicz @ 2010-09-08  1:58 UTC (permalink / raw)
  To: Randy Dunlap, Peter Korsgaard, Nicolas Ferre, Maurus Cuelenaere,
	linux-usb, Laurent Pinchart, Greg Kroah-Hartman, Fabien Chouteau,
	david Brownell, Christoph Egger, LKML, MeeGo, Masayuki Ohtake
  Cc: Wang, Qi, Wang, Yong Y, Andrew, Intel OTC, Foster, Margie, Arjan,
	Toshiharu Okada, Takahiro Shimizu, Tomoya Morinaga

Not sure why I'm on the "To" list, but here are a few of my comments:

On Tue, 07 Sep 2010 09:49:03 +0200, Masayuki Ohtake <masa-korg@dsn.okisemi.com> wrote:
> +/**
> + * pch_udc_write_csr - Write the command and status registers.

IIRC, the correct way to write kernel doc is:

+ * pch_udc_write_csr() - Write the command and status registers.

Note the "()".  This applies to other functions as well.

> + * @val:	value to be written to CSR register
> + * @addr:	address of CSR register
> + */
> +inline void pch_udc_write_csr(unsigned long val, unsigned long addr)

As it was pointed, unless those functions are extern, make them static and remove
the inline.

> +{
> +	int count = MAX_LOOP;
> +
> +	/* Wait till idle */
> +	while ((count > 0) &&\
> +		(ioread32((u32 *)(PCH_UDC_CSR_BUSY_ADDR + pch_udc_base)) &
> +		PCH_UDC_CSR_BUSY))
> +		count--;

I'd say: "while (ioread(...) && --count);"  Also, I'd make count to be unsigned.

> +
> +	if (count < 0)
> +		pr_debug("%s: wait error; count = %x", __func__, count);

Dead code.  If MAX_LOOP is >= 0 count will never get negative.  Did you mean
if (!count)?

> +
> +	iowrite32(val, (u32 *)addr);
> +	/* Wait till idle */
> +	count = MAX_LOOP;
> +	while ((count > 0) &&
> +		(ioread32((u32 *)(PCH_UDC_CSR_BUSY_ADDR + pch_udc_base)) &
> +		PCH_UDC_CSR_BUSY))
> +		count--;
> +
> +	if (count < 0)
> +		pr_debug("%s: wait error; count = %x", __func__, count);

Dead code.

> +/**
> + * pch_udc_read_csr - Read the command and status registers.
> + * @addr:	address of CSR register
> + * Returns
> + *	content of CSR register
> + */
> +inline u32 pch_udc_read_csr(unsigned long addr)

All comments to the pch_udc_write_csr() function apply here as well.

> +/**
> + * pch_udc_get_speed - Return the speed status
> + * @dev:	Reference to pch_udc_regs structure
> + * Retern	The speed(LOW=1, FULL=2, HIGH=3)
> + */
> +inline int pch_udc_get_speed(struct pch_udc_regs __iomem *dev)
> +{
> +	u32 val;
> +
> +	val = ioread32(&dev->devsts);

It's just me, but why not join the two lines together:

+	u32 val = ioread32(&dev->devsts);

> +	return (val & UDC_DEVSTS_ENUM_SPEED_MASK) >> UDC_DEVSTS_ENUM_SPEED_OFS;
> +}

> +/**
> + * pch_udc_ep_clear_nak - Set the bit 8 (CNAK field)
> + *				of the endpoint control register
> + * @ep:		reference to structure of type pch_udc_ep_regs
> + */
> +void pch_udc_ep_clear_nak(struct pch_udc_ep_regs __iomem *ep)
> +{
> +	unsigned int loopcnt = 0;
> +
> +	if (ioread32(&ep->epctl) & (1 << UDC_EPCTL_NAK)) {

	if (!(ioread32(&ep->epctl) & (1 << UDC_EPCTL_NAK)))
		return;

and then drop one indention level for the rest of the function.
This will help to keep indention level nearer the recommended
limit of 3.

> +		if (!(EP_IS_IN(ep))) {
> +			while ((pch_udc_read_ep_status(ep) &
> +					 (1 << UDC_EPSTS_MRXFIFO_EMP)) == 0) {
> +				if (loopcnt++ > 100000) {
> +					pr_debug("%s: RxFIFO not Empty "
> +						  "loop count = %d",
> +						  __func__, loopcnt);
> +					break;
> +				}
> +				udelay(100);
> +			}
> +		}
> +		while (ioread32(&ep->epctl) & (1 << UDC_EPCTL_NAK)) {
> +			PCH_UDC_BIT_SET(&ep->epctl, 1 << UDC_EPCTL_CNAK);
> +			udelay(5);
> +			if (loopcnt++ >= 25) {
> +				pr_debug("%s: Clear NAK not set for"
> +					  "ep%d%s: counter=%d",
> +					  __func__, EP_NUM(ep),
> +					  (EP_IS_IN(ep) ? "in" : "out"),
> +					  loopcnt);
> +				break;
> +			}
> +		}
> +	}
> +}
> +
> +/**
> + * pch_udc_ep_fifo_flush - Flush the endpoint fifo
> + * @ep:	reference to structure of type pch_udc_ep_regs
> + * @dir:	direction of endpoint
> + *		- dir = 0 endpoint is OUT
> + *		- dir != 0 endpoint is IN
> + */
> +void pch_udc_ep_fifo_flush(struct pch_udc_ep_regs __iomem *ep, int dir)
> +{
> +	unsigned int loopcnt = 0;
> +
> +	pr_debug("%s: ep%d%s", __func__, EP_NUM(ep),
> +						 (EP_IS_IN(ep) ? "in" : "out"));
> +	if (dir) {	/* IN ep */
> +		PCH_UDC_BIT_SET(&ep->epctl, 1 << UDC_EPCTL_F);

I'd add "return;" here and move the else part out of the else dropping
one indention level.

> +	} else {
> +		if ((pch_udc_read_ep_status(ep) &
> +		    (1 << UDC_EPSTS_MRXFIFO_EMP)) == 0) {

	if (pch_udc_read_ep_status(ep) & (1 << UDC_EPSTS_MRXFIFO_EMP)
		return;

and drop indention.

> +			PCH_UDC_BIT_SET(&ep->epctl, 1 << UDC_EPCTL_MRXFLUSH);
> +			/* Wait for RxFIFO Empty */
> +			while ((pch_udc_read_ep_status(ep) &
> +				(1 << UDC_EPSTS_MRXFIFO_EMP)) == 0) {
> +				if (loopcnt++ > 1000000) {
> +					pr_debug("RxFIFO not Empty loop"
> +						  " count = %d", loopcnt);
> +					break;
> +				}
> +				udelay(100);
> +			}
> +			PCH_UDC_BIT_CLR(&ep->epctl, 1 << UDC_EPCTL_MRXFLUSH);
> +		}
> +	}
> +}

> +/**
> + * pch_udc_pcd_pullup - This API is invoked to make the device
> + *				visible/invisible to the host
> + * @gadget:	Reference to the gadget driver
> + * @is_on:	Specifies whether the pull up is made active or inactive
> + * Returns
> + *	0:		Success
> + *	-EINVAL:	If the gadget passed is NULL
> + */
> +static int pch_udc_pcd_pullup(struct usb_gadget *gadget, int is_on)
> +{
> +	struct pch_udc_dev		*dev;
> +
> +	pr_debug("%s: enter", __func__);

It just struck me.  Wouldn't it be feasible to use "dev_*" instead of "pr_*"?

> +	if (gadget == NULL) {
> +		pr_debug("%s: exit -EINVAL", __func__);
> +		return -EINVAL;
> +	}
> +	dev = container_of(gadget, struct pch_udc_dev, gadget);
> +	if (is_on == 0)
> +		pch_udc_set_disconnect(dev->regs);
> +	else
> +		pch_udc_clear_disconnect(dev->regs);

There was function that did exactly that I think.  Wasn't there?

> +	return 0;
> +}

> +/**
> + * pch_udc_start_next_txrequest - This function starts
> + *					the next transmission requirement
> + * @ep:	Reference to the endpoint structure
> + */
> +static void pch_udc_start_next_txrequest(struct pch_udc_ep *ep)
> +{
> +	struct pch_udc_request *req;
> +
> +	pr_debug("%s: enter", __func__);
> +	if (pch_udc_read_ep_control(ep->regs) & (1 << UDC_EPCTL_P))
> +		return;
> +
> +	if (!list_empty(&ep->queue)) {

if (list_empty(...))
	return;

and drop indention.

> +		/* next request */
> +		req = list_entry(ep->queue.next, struct pch_udc_request, queue);
> +		if (req && !req->dma_going) {

Same here.

> +			pr_debug("%s: Set request: req=%p req->td_data=%p",
> +					__func__, req, req->td_data);
> +			if (req->td_data) {

Same eher.

> +				struct pch_udc_data_dma_desc *td_data;
> +
> +				while (pch_udc_read_ep_control(ep->regs) &
> +							 (1 << UDC_EPCTL_S))
> +					udelay(100);
> +
> +				req->dma_going = 1;
> +				/* Clear the descriptor pointer */
> +				pch_udc_ep_set_ddptr(ep->regs, 0);
> +
> +				td_data = req->td_data;
> +				while (1) {
> +					td_data->status = (td_data->status &
> +						 ~PCH_UDC_BUFF_STS) |
> +						 PCH_UDC_BS_HST_RDY;
> +					if ((td_data->status &
> +						 PCH_UDC_DMA_LAST) ==
> +						 PCH_UDC_DMA_LAST)
> +						break;

The line above has 6 levels of indention.  If you drop indentions the way
described above you get back to 3.

> +
> +					td_data =
> +					(struct pch_udc_data_dma_desc *)\
> +					phys_to_virt(td_data->next);
> +				}
> +				/* Write the descriptor pointer */
> +				pch_udc_ep_set_ddptr(ep->regs,
> +							 req->td_data_phys);
> +				pch_udc_set_dma(ep->dev->regs, DMA_DIR_TX);
> +				/* Set the poll demand bit */
> +				pch_udc_ep_set_pd(ep->regs);
> +				pch_udc_enable_ep_interrupts(ep->dev->regs,
> +						1 << (ep->in ? ep->num :\
> +						 ep->num + UDC_EPINT_OUT_EP0));
> +				pch_udc_ep_clear_nak(ep->regs);
> +			}
> +		}
> +	}
> +}
> +
> +/**
> + * pch_udc_complete_transfer - This function completes a transfer
> + * @ep:		Reference to the endpoint structure
> + */
> +static void pch_udc_complete_transfer(struct pch_udc_ep	*ep)

Same as with the function above.

> +/**
> + * pch_udc_complete_receiver - This function completes a receiver
> + * @ep:		Reference to the endpoint structure
> + */
> +static void pch_udc_complete_receiver(struct pch_udc_ep	*ep)

This function would use some indention fixing as well.

> +	if (list_empty(&ep->queue)) {
> +		/* enable DMA */
> +		pch_udc_set_dma(dev->regs, DMA_DIR_RX);
> +	}

Drop the "{" and "}". script/checkpatch.pl will find issues like this one.

> +}

> +static void pch_udc_read_all_epstatus(struct pch_udc_dev *dev, u32 ep_intr)
> +{
> +	int i;
> +	struct pch_udc_ep	*ep;
> +
> +	for (i = 0; i < PCH_UDC_USED_EP_NUM; i++) {
> +		/* IN */
> +		if (ep_intr & (0x1 << i)) {
> +			ep = &dev->ep[2*i];
> +			ep->epsts = pch_udc_read_ep_status(ep->regs);
> +			pch_udc_clear_ep_status(ep->regs, ep->epsts);
> +		}
> +		/* OUT */
> +		if (ep_intr & (0x10000 << i)) {
> +			ep = &dev->ep[2*i+1];
> +			ep->epsts = pch_udc_read_ep_status(ep->regs);
> +			pch_udc_clear_ep_status(ep->regs, ep->epsts);
> +		}
> +	}
> +	return;

Useless return.

> +}

> +/**
> + * pch_udc_svc_enum_interrupt - This function handles a USB speed enumeration
> + *				done interrupt
> + * @dev:	Reference to driver structure
> + */
> +void
> +pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev)

Useless line break.  This applies not only to this function.

> +void
> +pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
> +{
> +	u32 reg, dev_stat = 0;
> +	int i, ret;
> +
> +	pr_debug("%s: enter", __func__);
> +	dev_stat = pch_udc_read_device_status(dev->regs);
> +	dev->cfg_data.cur_intf = (dev_stat & UDC_DEVSTS_INTF_MASK) >>
> +							 UDC_DEVSTS_INTF_OFS;
> +	dev->cfg_data.cur_alt = (dev_stat & UDC_DEVSTS_ALT_MASK) >>
> +							 UDC_DEVSTS_ALT_OFS;
> +	pr_debug("DVSTATUS=%08x, cfg=%d, intf=%d, alt=%d", dev_stat,
> +			(dev_stat & UDC_CSR_NE_CFG_MASK) >> UDC_CSR_NE_CFG_OFS,
> +			dev->cfg_data.cur_intf, dev->cfg_data.cur_alt);
> +
> +	dev->set_cfg_not_acked = 1;
> +
> +	/* Construct the usb request for gadget driver and inform it */
> +	memset(&setup_data, 0 , sizeof setup_data);
> +	setup_data.request.bRequest = USB_REQ_SET_INTERFACE;
> +	setup_data.request.bRequestType = USB_RECIP_INTERFACE;
> +	setup_data.request.wValue = cpu_to_le16(dev->cfg_data.cur_alt);
> +	setup_data.request.wIndex = cpu_to_le16(dev->cfg_data.cur_intf);
> +
> +	/* programm the Endpoint Cfg registers */
> +	for (i = 0; i < PCH_UDC_USED_EP_NUM * 2; i++) {
> +		if (i == 1) { /* Only one end point cfg register */
> +			reg = pch_udc_read_csr((u32) (&dev->csr->ne[i]));
> +			reg = (reg & ~UDC_CSR_NE_INTF_MASK) |
> +			 (dev->cfg_data.cur_intf << UDC_CSR_NE_INTF_OFS);
> +			reg = (reg & ~UDC_CSR_NE_ALT_MASK) |
> +			 (dev->cfg_data.cur_alt << UDC_CSR_NE_ALT_OFS);
> +			pch_udc_write_csr(reg, (u32) (&dev->csr->ne[i]));
> +		}

Could this if be put outside of the loop? This applies not only to this function.

> +		/* clear stall bits */
> +		pch_udc_ep_clear_stall(dev->ep[i].regs);
> +		dev->ep[i].halted = 0;
> +	}
> +	dev->stall = 0;
> +	spin_unlock(&dev->lock);
> +	ret = dev->driver->setup(&dev->gadget, &setup_data.request);
> +	spin_lock(&dev->lock);
> +}

> +irqreturn_t pch_udc_isr(int irq, void *pdev)
> +{
> +	struct pch_udc_dev *dev;
> +	u32 dev_intr, ep_intr;
> +	int i;
> +
> +	pr_debug("%s: enter", __func__);
> +	dev = (struct pch_udc_dev *) pdev;
> +	dev_intr = pch_udc_read_device_interrupts(dev->regs);
> +	ep_intr = pch_udc_read_ep_interrupts(dev->regs);
> +
> +	if (dev_intr != 0) {
> +		/* Clear device interrupts */
> +		pch_udc_write_device_interrupts(dev->regs, dev_intr);
> +	}
> +	if (ep_intr != 0) {
> +		/* Clear ep interrupts */
> +		pch_udc_write_ep_interrupts(dev->regs, ep_intr);
> +	}

Useless "{" and "}" in the two above ifs.

> +	if ((dev_intr == 0) && (ep_intr == 0)) {
> +		pr_debug("%s: exit IRQ_NONE", __func__);
> +		return IRQ_NONE;
> +	}
> +	spin_lock(&dev->lock);
> +
> +	if (dev_intr != 0) {
> +		pr_debug("%s: device intr 0x%x", __func__, dev_intr);
> +		pch_udc_dev_isr(dev, dev_intr);
> +	}
> +
> +	if (ep_intr != 0) {
> +		pr_debug("%s: ep intr 0x%x", __func__, ep_intr);
> +		pch_udc_read_all_epstatus(dev, ep_intr);
> +
> +		/* Process Control In interrupts, if present */
> +		if (ep_intr & (1 << UDC_EPINT_IN_EP0)) {
> +			pch_udc_svc_control_in(dev);
> +			pch_udc_postsvc_epinters(dev, 0);
> +		}
> +		/* Process Control Out interrupts, if present */
> +		if (ep_intr & (1 << UDC_EPINT_OUT_EP0))
> +			pch_udc_svc_control_out(dev);
> +
> +		/* Process data in end point interrupts */
> +		for (i = 1; i < PCH_UDC_USED_EP_NUM; i++) {
> +			if (ep_intr & (1 <<  i)) {
> +				pch_udc_svc_data_in(dev, i);
> +				pch_udc_postsvc_epinters(dev, i);
> +			}
> +		}
> +		/* Process data out end point interrupts */
> +		for (i = UDC_EPINT_OUT_EP1; i < (UDC_EPINT_OUT_EP0 +
> +						 PCH_UDC_USED_EP_NUM); i++) {
> +			if (ep_intr & (1 <<  i))
> +				pch_udc_svc_data_out(dev, i -
> +							 UDC_EPINT_OUT_EP0);
> +		}

Useless "{" and "}" in for.

> +	}
> +	spin_unlock(&dev->lock);
> +	return IRQ_HANDLED;
> +}

> +int pch_udc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> +{
> +	unsigned long		resource;
> +	unsigned long		len;
> +	int					retval = 0;
> +	struct pch_udc_dev	*dev;
> +
> +	dev_dbg(&pdev->dev, "%s: enter", __func__);
> +	/* one udc only */
> +	if (pch_udc != NULL) {
> +		dev_err(&pdev->dev, "%s: already probed", __func__);
> +		return -EBUSY;
> +	}
> +
> +	/* init */
> +	dev = kzalloc(sizeof(struct pch_udc_dev), GFP_KERNEL);

I just noticed it here but it may apply to other places as well.  I recommend:

+	dev = kzalloc(sizeof *dev, GFP_KERNEL);

> +	if (dev == NULL) {
> +		dev_err(&pdev->dev, "%s: no memory for device structure",
> +								__func__);
> +		return -ENOMEM;
> +	}
> +	memset(dev, 0, sizeof(struct pch_udc_dev));

kzalloc() does that.

> +/**
> + * pch_udc_cfg_data - Structure to hold current configuration
> + *			and interface information

This applies to other places as well.  The above should read:

+ * struct pch_udc_cfg_data - ...

> + * @cur_cfg	current configuration in use
> + * @cur_intf	current interface in use
> + * @cur_alt	current alt interface in use

And there should be ":" after member name.

> + */
> +struct pch_udc_cfg_data {
> +	u16 cur_cfg;
> +	u16 cur_intf;
> +	u16 cur_alt;
> +};

> +/**
> + * pch_udc_dev - Structure holding complete information of the PCH USB device
> + *
> + * @gadget		gadget driver data
> + * @driver;		reference to gadget driver bound
> + * @pdev;		reference to the PCI device
> + * @ep[PCH_UDC_EP_NUM];	array of endpoints
> + * @lock;		protects all state
> + * @active:1,		enabled the PCI device
> + * @stall:1,		stall requested
> + * @prot_stall:1,	protcol stall requested
> + * @irq_registered:1,	irq registered with system
> + * @mem_region:1,	device memory mapped
> + * @registered:1,	driver regsitered with system
> + * @suspended:1,	driver in suspended state
> + * @connected:1,	gadget driver associated
> + * @set_cfg_not_acked:1,	pending acknowledgement 4 setup
> + * @waiting_zlp_ack:1;	pending acknowledgement 4 ZLP
> + * @csr;		address of config & status
> + * @regs;		address of device registers
> + * @*ep_regs;		address of endpoint registers
> + * @data_requests;	DMA pool for data requests
> + * @stp_requests;	DMA pool for setup requests
> + * @phys_addr;		of device memory
> + * @virt_addr;		for mapped device memory
> + * @irq;		IRQ line for the device
> + * @cfg_data;		current cfg, intf, and alt in use
> + */

Useless ":1", there should be ":" after member name and not nothing, ";" or ",".

> +

Needless empty line.

> +struct pch_udc_dev {

-- 
Best regards,                                        _     _
| Humble Liege of Serenely Enlightened Majesty of  o' \,=./ `o
| Computer Science,  Michał "mina86" Nazarewicz       (o o)
+----[mina86*mina86.com]---[mina86*jabber.org]----ooO--(_)--Ooo--


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

* Re: [PATCH] USB device driver of Topcliff PCH
  2010-09-08  1:58 ` Michał Nazarewicz
@ 2010-09-08 13:57   ` Masayuki Ohtake
  2010-09-13  4:23   ` Masayuki Ohtake
  1 sibling, 0 replies; 14+ messages in thread
From: Masayuki Ohtake @ 2010-09-08 13:57 UTC (permalink / raw)
  To: Micha? Nazarewicz, Randy Dunlap, Peter Korsgaard, Nicolas Ferre,
	Maurus Cuelenaere, linux-usb, Laurent Pinchart,
	Greg Kroah-Hartman, Fabien Chouteau, david Brownell,
	Christoph Egger, LKML, MeeGo
  Cc: Wang, Qi, Wang, Yong Y, Andrew, Intel OTC, Foster, Margie, Arjan,
	Toshiharu Okada, Takahiro Shimizu, Tomoya Morinaga

Hi Micha?, Greg and Maurus.

Thank you for your comments.
I confirm them.

Thanks, Ohtake
----- Original Message ----- 
From: "Micha? Nazarewicz" <m.nazarewicz@samsung.com>
To: "Randy Dunlap" <randy.dunlap@oracle.com>; "Peter Korsgaard" <peter.korsgaard@barco.com>; "Nicolas Ferre"
<nicolas.ferre@atmel.com>; "Maurus Cuelenaere" <mcuelenaere@gmail.com>; "linux-usb" <linux-usb@vger.kernel.org>;
"Laurent Pinchart" <laurent.pinchart@ideasonboard.com>; "Greg Kroah-Hartman" <gregkh@suse.de>; "Fabien Chouteau"
<fabien.chouteau@barco.com>; "david Brownell" <dbrownell@users.sourceforge.net>; "Christoph Egger"
<siccegge@stud.informatik.uni-erlangen.de>; "LKML" <linux-kernel@vger.kernel.org>; "MeeGo" <meego-dev@meego.com>;
"Masayuki Ohtake" <masa-korg@dsn.okisemi.com>
Cc: "Wang, Qi" <qi.wang@intel.com>; "Wang, Yong Y" <yong.y.wang@intel.com>; "Andrew" <andrew.chih.howe.khor@intel.com>;
"Intel OTC" <joel.clark@intel.com>; "Foster, Margie" <margie.foster@intel.com>; "Arjan" <arjan@linux.intel.com>;
"Toshiharu Okada" <okada533@dsn.okisemi.com>; "Takahiro Shimizu" <shimizu394@dsn.okisemi.com>; "Tomoya Morinaga"
<morinaga526@dsn.okisemi.com>
Sent: Wednesday, September 08, 2010 10:58 AM
Subject: Re: [PATCH] USB device driver of Topcliff PCH


Not sure why I'm on the "To" list, but here are a few of my comments:

On Tue, 07 Sep 2010 09:49:03 +0200, Masayuki Ohtake <masa-korg@dsn.okisemi.com> wrote:
> +/**
> + * pch_udc_write_csr - Write the command and status registers.

IIRC, the correct way to write kernel doc is:

+ * pch_udc_write_csr() - Write the command and status registers.

Note the "()".  This applies to other functions as well.

> + * @val: value to be written to CSR register
> + * @addr: address of CSR register
> + */
> +inline void pch_udc_write_csr(unsigned long val, unsigned long addr)

As it was pointed, unless those functions are extern, make them static and remove
the inline.

> +{
> + int count = MAX_LOOP;
> +
> + /* Wait till idle */
> + while ((count > 0) &&\
> + (ioread32((u32 *)(PCH_UDC_CSR_BUSY_ADDR + pch_udc_base)) &
> + PCH_UDC_CSR_BUSY))
> + count--;

I'd say: "while (ioread(...) && --count);"  Also, I'd make count to be unsigned.

> +
> + if (count < 0)
> + pr_debug("%s: wait error; count = %x", __func__, count);

Dead code.  If MAX_LOOP is >= 0 count will never get negative.  Did you mean
if (!count)?

> +
> + iowrite32(val, (u32 *)addr);
> + /* Wait till idle */
> + count = MAX_LOOP;
> + while ((count > 0) &&
> + (ioread32((u32 *)(PCH_UDC_CSR_BUSY_ADDR + pch_udc_base)) &
> + PCH_UDC_CSR_BUSY))
> + count--;
> +
> + if (count < 0)
> + pr_debug("%s: wait error; count = %x", __func__, count);

Dead code.

> +/**
> + * pch_udc_read_csr - Read the command and status registers.
> + * @addr: address of CSR register
> + * Returns
> + * content of CSR register
> + */
> +inline u32 pch_udc_read_csr(unsigned long addr)

All comments to the pch_udc_write_csr() function apply here as well.

> +/**
> + * pch_udc_get_speed - Return the speed status
> + * @dev: Reference to pch_udc_regs structure
> + * Retern The speed(LOW=1, FULL=2, HIGH=3)
> + */
> +inline int pch_udc_get_speed(struct pch_udc_regs __iomem *dev)
> +{
> + u32 val;
> +
> + val = ioread32(&dev->devsts);

It's just me, but why not join the two lines together:

+ u32 val = ioread32(&dev->devsts);

> + return (val & UDC_DEVSTS_ENUM_SPEED_MASK) >> UDC_DEVSTS_ENUM_SPEED_OFS;
> +}

> +/**
> + * pch_udc_ep_clear_nak - Set the bit 8 (CNAK field)
> + * of the endpoint control register
> + * @ep: reference to structure of type pch_udc_ep_regs
> + */
> +void pch_udc_ep_clear_nak(struct pch_udc_ep_regs __iomem *ep)
> +{
> + unsigned int loopcnt = 0;
> +
> + if (ioread32(&ep->epctl) & (1 << UDC_EPCTL_NAK)) {

if (!(ioread32(&ep->epctl) & (1 << UDC_EPCTL_NAK)))
return;

and then drop one indention level for the rest of the function.
This will help to keep indention level nearer the recommended
limit of 3.

> + if (!(EP_IS_IN(ep))) {
> + while ((pch_udc_read_ep_status(ep) &
> + (1 << UDC_EPSTS_MRXFIFO_EMP)) == 0) {
> + if (loopcnt++ > 100000) {
> + pr_debug("%s: RxFIFO not Empty "
> +   "loop count = %d",
> +   __func__, loopcnt);
> + break;
> + }
> + udelay(100);
> + }
> + }
> + while (ioread32(&ep->epctl) & (1 << UDC_EPCTL_NAK)) {
> + PCH_UDC_BIT_SET(&ep->epctl, 1 << UDC_EPCTL_CNAK);
> + udelay(5);
> + if (loopcnt++ >= 25) {
> + pr_debug("%s: Clear NAK not set for"
> +   "ep%d%s: counter=%d",
> +   __func__, EP_NUM(ep),
> +   (EP_IS_IN(ep) ? "in" : "out"),
> +   loopcnt);
> + break;
> + }
> + }
> + }
> +}
> +
> +/**
> + * pch_udc_ep_fifo_flush - Flush the endpoint fifo
> + * @ep: reference to structure of type pch_udc_ep_regs
> + * @dir: direction of endpoint
> + * - dir = 0 endpoint is OUT
> + * - dir != 0 endpoint is IN
> + */
> +void pch_udc_ep_fifo_flush(struct pch_udc_ep_regs __iomem *ep, int dir)
> +{
> + unsigned int loopcnt = 0;
> +
> + pr_debug("%s: ep%d%s", __func__, EP_NUM(ep),
> + (EP_IS_IN(ep) ? "in" : "out"));
> + if (dir) { /* IN ep */
> + PCH_UDC_BIT_SET(&ep->epctl, 1 << UDC_EPCTL_F);

I'd add "return;" here and move the else part out of the else dropping
one indention level.

> + } else {
> + if ((pch_udc_read_ep_status(ep) &
> +     (1 << UDC_EPSTS_MRXFIFO_EMP)) == 0) {

if (pch_udc_read_ep_status(ep) & (1 << UDC_EPSTS_MRXFIFO_EMP)
return;

and drop indention.

> + PCH_UDC_BIT_SET(&ep->epctl, 1 << UDC_EPCTL_MRXFLUSH);
> + /* Wait for RxFIFO Empty */
> + while ((pch_udc_read_ep_status(ep) &
> + (1 << UDC_EPSTS_MRXFIFO_EMP)) == 0) {
> + if (loopcnt++ > 1000000) {
> + pr_debug("RxFIFO not Empty loop"
> +   " count = %d", loopcnt);
> + break;
> + }
> + udelay(100);
> + }
> + PCH_UDC_BIT_CLR(&ep->epctl, 1 << UDC_EPCTL_MRXFLUSH);
> + }
> + }
> +}

> +/**
> + * pch_udc_pcd_pullup - This API is invoked to make the device
> + * visible/invisible to the host
> + * @gadget: Reference to the gadget driver
> + * @is_on: Specifies whether the pull up is made active or inactive
> + * Returns
> + * 0: Success
> + * -EINVAL: If the gadget passed is NULL
> + */
> +static int pch_udc_pcd_pullup(struct usb_gadget *gadget, int is_on)
> +{
> + struct pch_udc_dev *dev;
> +
> + pr_debug("%s: enter", __func__);

It just struck me.  Wouldn't it be feasible to use "dev_*" instead of "pr_*"?

> + if (gadget == NULL) {
> + pr_debug("%s: exit -EINVAL", __func__);
> + return -EINVAL;
> + }
> + dev = container_of(gadget, struct pch_udc_dev, gadget);
> + if (is_on == 0)
> + pch_udc_set_disconnect(dev->regs);
> + else
> + pch_udc_clear_disconnect(dev->regs);

There was function that did exactly that I think.  Wasn't there?

> + return 0;
> +}

> +/**
> + * pch_udc_start_next_txrequest - This function starts
> + * the next transmission requirement
> + * @ep: Reference to the endpoint structure
> + */
> +static void pch_udc_start_next_txrequest(struct pch_udc_ep *ep)
> +{
> + struct pch_udc_request *req;
> +
> + pr_debug("%s: enter", __func__);
> + if (pch_udc_read_ep_control(ep->regs) & (1 << UDC_EPCTL_P))
> + return;
> +
> + if (!list_empty(&ep->queue)) {

if (list_empty(...))
return;

and drop indention.

> + /* next request */
> + req = list_entry(ep->queue.next, struct pch_udc_request, queue);
> + if (req && !req->dma_going) {

Same here.

> + pr_debug("%s: Set request: req=%p req->td_data=%p",
> + __func__, req, req->td_data);
> + if (req->td_data) {

Same eher.

> + struct pch_udc_data_dma_desc *td_data;
> +
> + while (pch_udc_read_ep_control(ep->regs) &
> + (1 << UDC_EPCTL_S))
> + udelay(100);
> +
> + req->dma_going = 1;
> + /* Clear the descriptor pointer */
> + pch_udc_ep_set_ddptr(ep->regs, 0);
> +
> + td_data = req->td_data;
> + while (1) {
> + td_data->status = (td_data->status &
> + ~PCH_UDC_BUFF_STS) |
> + PCH_UDC_BS_HST_RDY;
> + if ((td_data->status &
> + PCH_UDC_DMA_LAST) ==
> + PCH_UDC_DMA_LAST)
> + break;

The line above has 6 levels of indention.  If you drop indentions the way
described above you get back to 3.

> +
> + td_data =
> + (struct pch_udc_data_dma_desc *)\
> + phys_to_virt(td_data->next);
> + }
> + /* Write the descriptor pointer */
> + pch_udc_ep_set_ddptr(ep->regs,
> + req->td_data_phys);
> + pch_udc_set_dma(ep->dev->regs, DMA_DIR_TX);
> + /* Set the poll demand bit */
> + pch_udc_ep_set_pd(ep->regs);
> + pch_udc_enable_ep_interrupts(ep->dev->regs,
> + 1 << (ep->in ? ep->num :\
> + ep->num + UDC_EPINT_OUT_EP0));
> + pch_udc_ep_clear_nak(ep->regs);
> + }
> + }
> + }
> +}
> +
> +/**
> + * pch_udc_complete_transfer - This function completes a transfer
> + * @ep: Reference to the endpoint structure
> + */
> +static void pch_udc_complete_transfer(struct pch_udc_ep *ep)

Same as with the function above.

> +/**
> + * pch_udc_complete_receiver - This function completes a receiver
> + * @ep: Reference to the endpoint structure
> + */
> +static void pch_udc_complete_receiver(struct pch_udc_ep *ep)

This function would use some indention fixing as well.

> + if (list_empty(&ep->queue)) {
> + /* enable DMA */
> + pch_udc_set_dma(dev->regs, DMA_DIR_RX);
> + }

Drop the "{" and "}". script/checkpatch.pl will find issues like this one.

> +}

> +static void pch_udc_read_all_epstatus(struct pch_udc_dev *dev, u32 ep_intr)
> +{
> + int i;
> + struct pch_udc_ep *ep;
> +
> + for (i = 0; i < PCH_UDC_USED_EP_NUM; i++) {
> + /* IN */
> + if (ep_intr & (0x1 << i)) {
> + ep = &dev->ep[2*i];
> + ep->epsts = pch_udc_read_ep_status(ep->regs);
> + pch_udc_clear_ep_status(ep->regs, ep->epsts);
> + }
> + /* OUT */
> + if (ep_intr & (0x10000 << i)) {
> + ep = &dev->ep[2*i+1];
> + ep->epsts = pch_udc_read_ep_status(ep->regs);
> + pch_udc_clear_ep_status(ep->regs, ep->epsts);
> + }
> + }
> + return;

Useless return.

> +}

> +/**
> + * pch_udc_svc_enum_interrupt - This function handles a USB speed enumeration
> + * done interrupt
> + * @dev: Reference to driver structure
> + */
> +void
> +pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev)

Useless line break.  This applies not only to this function.

> +void
> +pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
> +{
> + u32 reg, dev_stat = 0;
> + int i, ret;
> +
> + pr_debug("%s: enter", __func__);
> + dev_stat = pch_udc_read_device_status(dev->regs);
> + dev->cfg_data.cur_intf = (dev_stat & UDC_DEVSTS_INTF_MASK) >>
> + UDC_DEVSTS_INTF_OFS;
> + dev->cfg_data.cur_alt = (dev_stat & UDC_DEVSTS_ALT_MASK) >>
> + UDC_DEVSTS_ALT_OFS;
> + pr_debug("DVSTATUS=%08x, cfg=%d, intf=%d, alt=%d", dev_stat,
> + (dev_stat & UDC_CSR_NE_CFG_MASK) >> UDC_CSR_NE_CFG_OFS,
> + dev->cfg_data.cur_intf, dev->cfg_data.cur_alt);
> +
> + dev->set_cfg_not_acked = 1;
> +
> + /* Construct the usb request for gadget driver and inform it */
> + memset(&setup_data, 0 , sizeof setup_data);
> + setup_data.request.bRequest = USB_REQ_SET_INTERFACE;
> + setup_data.request.bRequestType = USB_RECIP_INTERFACE;
> + setup_data.request.wValue = cpu_to_le16(dev->cfg_data.cur_alt);
> + setup_data.request.wIndex = cpu_to_le16(dev->cfg_data.cur_intf);
> +
> + /* programm the Endpoint Cfg registers */
> + for (i = 0; i < PCH_UDC_USED_EP_NUM * 2; i++) {
> + if (i == 1) { /* Only one end point cfg register */
> + reg = pch_udc_read_csr((u32) (&dev->csr->ne[i]));
> + reg = (reg & ~UDC_CSR_NE_INTF_MASK) |
> + (dev->cfg_data.cur_intf << UDC_CSR_NE_INTF_OFS);
> + reg = (reg & ~UDC_CSR_NE_ALT_MASK) |
> + (dev->cfg_data.cur_alt << UDC_CSR_NE_ALT_OFS);
> + pch_udc_write_csr(reg, (u32) (&dev->csr->ne[i]));
> + }

Could this if be put outside of the loop? This applies not only to this function.

> + /* clear stall bits */
> + pch_udc_ep_clear_stall(dev->ep[i].regs);
> + dev->ep[i].halted = 0;
> + }
> + dev->stall = 0;
> + spin_unlock(&dev->lock);
> + ret = dev->driver->setup(&dev->gadget, &setup_data.request);
> + spin_lock(&dev->lock);
> +}

> +irqreturn_t pch_udc_isr(int irq, void *pdev)
> +{
> + struct pch_udc_dev *dev;
> + u32 dev_intr, ep_intr;
> + int i;
> +
> + pr_debug("%s: enter", __func__);
> + dev = (struct pch_udc_dev *) pdev;
> + dev_intr = pch_udc_read_device_interrupts(dev->regs);
> + ep_intr = pch_udc_read_ep_interrupts(dev->regs);
> +
> + if (dev_intr != 0) {
> + /* Clear device interrupts */
> + pch_udc_write_device_interrupts(dev->regs, dev_intr);
> + }
> + if (ep_intr != 0) {
> + /* Clear ep interrupts */
> + pch_udc_write_ep_interrupts(dev->regs, ep_intr);
> + }

Useless "{" and "}" in the two above ifs.

> + if ((dev_intr == 0) && (ep_intr == 0)) {
> + pr_debug("%s: exit IRQ_NONE", __func__);
> + return IRQ_NONE;
> + }
> + spin_lock(&dev->lock);
> +
> + if (dev_intr != 0) {
> + pr_debug("%s: device intr 0x%x", __func__, dev_intr);
> + pch_udc_dev_isr(dev, dev_intr);
> + }
> +
> + if (ep_intr != 0) {
> + pr_debug("%s: ep intr 0x%x", __func__, ep_intr);
> + pch_udc_read_all_epstatus(dev, ep_intr);
> +
> + /* Process Control In interrupts, if present */
> + if (ep_intr & (1 << UDC_EPINT_IN_EP0)) {
> + pch_udc_svc_control_in(dev);
> + pch_udc_postsvc_epinters(dev, 0);
> + }
> + /* Process Control Out interrupts, if present */
> + if (ep_intr & (1 << UDC_EPINT_OUT_EP0))
> + pch_udc_svc_control_out(dev);
> +
> + /* Process data in end point interrupts */
> + for (i = 1; i < PCH_UDC_USED_EP_NUM; i++) {
> + if (ep_intr & (1 <<  i)) {
> + pch_udc_svc_data_in(dev, i);
> + pch_udc_postsvc_epinters(dev, i);
> + }
> + }
> + /* Process data out end point interrupts */
> + for (i = UDC_EPINT_OUT_EP1; i < (UDC_EPINT_OUT_EP0 +
> + PCH_UDC_USED_EP_NUM); i++) {
> + if (ep_intr & (1 <<  i))
> + pch_udc_svc_data_out(dev, i -
> + UDC_EPINT_OUT_EP0);
> + }

Useless "{" and "}" in for.

> + }
> + spin_unlock(&dev->lock);
> + return IRQ_HANDLED;
> +}

> +int pch_udc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> +{
> + unsigned long resource;
> + unsigned long len;
> + int retval = 0;
> + struct pch_udc_dev *dev;
> +
> + dev_dbg(&pdev->dev, "%s: enter", __func__);
> + /* one udc only */
> + if (pch_udc != NULL) {
> + dev_err(&pdev->dev, "%s: already probed", __func__);
> + return -EBUSY;
> + }
> +
> + /* init */
> + dev = kzalloc(sizeof(struct pch_udc_dev), GFP_KERNEL);

I just noticed it here but it may apply to other places as well.  I recommend:

+ dev = kzalloc(sizeof *dev, GFP_KERNEL);

> + if (dev == NULL) {
> + dev_err(&pdev->dev, "%s: no memory for device structure",
> + __func__);
> + return -ENOMEM;
> + }
> + memset(dev, 0, sizeof(struct pch_udc_dev));

kzalloc() does that.

> +/**
> + * pch_udc_cfg_data - Structure to hold current configuration
> + * and interface information

This applies to other places as well.  The above should read:

+ * struct pch_udc_cfg_data - ...

> + * @cur_cfg current configuration in use
> + * @cur_intf current interface in use
> + * @cur_alt current alt interface in use

And there should be ":" after member name.

> + */
> +struct pch_udc_cfg_data {
> + u16 cur_cfg;
> + u16 cur_intf;
> + u16 cur_alt;
> +};

> +/**
> + * pch_udc_dev - Structure holding complete information of the PCH USB device
> + *
> + * @gadget gadget driver data
> + * @driver; reference to gadget driver bound
> + * @pdev; reference to the PCI device
> + * @ep[PCH_UDC_EP_NUM]; array of endpoints
> + * @lock; protects all state
> + * @active:1, enabled the PCI device
> + * @stall:1, stall requested
> + * @prot_stall:1, protcol stall requested
> + * @irq_registered:1, irq registered with system
> + * @mem_region:1, device memory mapped
> + * @registered:1, driver regsitered with system
> + * @suspended:1, driver in suspended state
> + * @connected:1, gadget driver associated
> + * @set_cfg_not_acked:1, pending acknowledgement 4 setup
> + * @waiting_zlp_ack:1; pending acknowledgement 4 ZLP
> + * @csr; address of config & status
> + * @regs; address of device registers
> + * @*ep_regs; address of endpoint registers
> + * @data_requests; DMA pool for data requests
> + * @stp_requests; DMA pool for setup requests
> + * @phys_addr; of device memory
> + * @virt_addr; for mapped device memory
> + * @irq; IRQ line for the device
> + * @cfg_data; current cfg, intf, and alt in use
> + */

Useless ":1", there should be ":" after member name and not nothing, ";" or ",".

> +

Needless empty line.

> +struct pch_udc_dev {

-- 
Best regards,                                        _     _
| Humble Liege of Serenely Enlightened Majesty of  o' \,=./ `o
| Computer Science,  Micha? "mina86" Nazarewicz       (o o)
+----[mina86*mina86.com]---[mina86*jabber.org]----ooO--(_)--Ooo--



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

* Re: [PATCH] USB device driver of Topcliff PCH
  2010-09-08  1:58 ` Michał Nazarewicz
  2010-09-08 13:57   ` Masayuki Ohtake
@ 2010-09-13  4:23   ` Masayuki Ohtake
  1 sibling, 0 replies; 14+ messages in thread
From: Masayuki Ohtake @ 2010-09-13  4:23 UTC (permalink / raw)
  To: Micha? Nazarewicz, Randy Dunlap, Peter Korsgaard, Nicolas Ferre,
	Maurus Cuelenaere, linux-usb, Laurent Pinchart,
	Greg Kroah-Hartman, Fabien Chouteau, david Brownell,
	Christoph Egger, LKML, MeeGo
  Cc: Wang, Qi, Wang, Yong Y, Andrew, Intel OTC, Foster, Margie, Arjan,
	Toshiharu Okada, Takahiro Shimizu, Tomoya Morinaga

Hi Michal

My reply comments are included in the following.

Thanks Ohtake

Date: Wed, 08 Sep 2010 03:58:04 +0200
From: "Micha? Nazarewicz" <m.nazarewicz@samsung.com>
>Not sure why I'm on the "To" list, but here are a few of my comments:

[masa]
Your address was got the following scripts as maintainer.
"./scripts/get_maintainer.pl"
Whom should I submit patch to?


>On Tue, 07 Sep 2010 09:49:03 +0200, Masayuki Ohtake <masa-korg@dsn.okisemi.com> wrote:
>> +/**
>> + * pch_udc_write_csr - Write the command and status registers.
>
>IIRC, the correct way to write kernel doc is:
>
>+ * pch_udc_write_csr() - Write the command and status registers.
>
>Note the "()".  This applies to other functions as well.
>

[masa]
This will be modified.


>> + * @val: value to be written to CSR register
>> + * @addr: address of CSR register
>> + */
>> +inline void pch_udc_write_csr(unsigned long val, unsigned long addr)
>
>As it was pointed, unless those functions are extern, make them static and remove
>the inline.

[masa]
This will be modified as
"static void pch_udc_write_csr(unsigned long val, unsigned long addr)"


>> +{
>> + int count = MAX_LOOP;
>> +
>> + /* Wait till idle */
>> + while ((count > 0) &&\
>> + (ioread32((u32 *)(PCH_UDC_CSR_BUSY_ADDR + pch_udc_base)) &
>> + PCH_UDC_CSR_BUSY))
>> + count--;
>
>I'd say: "while (ioread(...) && --count);"  Also, I'd make count to be unsigned.

[masa]
This will be modified.


>> +
>> + if (count < 0)
>> + pr_debug("%s: wait error; count = %x", __func__, count);
>
>Dead code.  If MAX_LOOP is >= 0 count will never get negative.  Did you mean
>if (!count)?

[masa]
This will be modified.

>> +
>> + iowrite32(val, (u32 *)addr);
>> + /* Wait till idle */
>> + count = MAX_LOOP;
>> + while ((count > 0) &&
>> + (ioread32((u32 *)(PCH_UDC_CSR_BUSY_ADDR + pch_udc_base)) &
>> + PCH_UDC_CSR_BUSY))
>> + count--;
>> +
>> + if (count < 0)
>> + pr_debug("%s: wait error; count = %x", __func__, count);
>
>Dead code.

[masa]
This will be modified.

>> +/**
>> + * pch_udc_read_csr - Read the command and status registers.
>> + * @addr: address of CSR register
>> + * Returns
>> + * content of CSR register
>> + */
>> +inline u32 pch_udc_read_csr(unsigned long addr)
>
>All comments to the pch_udc_write_csr() function apply here as well.

[masa]
This will be modified.


>> +/**
>> + * pch_udc_get_speed - Return the speed status
>> + * @dev: Reference to pch_udc_regs structure
>> + * Retern The speed(LOW=1, FULL=2, HIGH=3)
>> + */
>> +inline int pch_udc_get_speed(struct pch_udc_regs __iomem *dev)
>> +{
>> + u32 val;
>> +
>> + val = ioread32(&dev->devsts);
>
>It's just me, but why not join the two lines together:
>
>+ u32 val = ioread32(&dev->devsts);
>
>> + return (val & UDC_DEVSTS_ENUM_SPEED_MASK) >> UDC_DEVSTS_ENUM_SPEED_OFS;
>> +}

[masa]
This will be modified.


>> +/**
>> + * pch_udc_ep_clear_nak - Set the bit 8 (CNAK field)
>> + * of the endpoint control register
>> + * @ep: reference to structure of type pch_udc_ep_regs
>> + */
>> +void pch_udc_ep_clear_nak(struct pch_udc_ep_regs __iomem *ep)
>> +{
>> + unsigned int loopcnt = 0;
>> +
>> + if (ioread32(&ep->epctl) & (1 << UDC_EPCTL_NAK)) {
>
>if (!(ioread32(&ep->epctl) & (1 << UDC_EPCTL_NAK)))
>return;
>
>and then drop one indention level for the rest of the function.
>This will help to keep indention level nearer the recommended
>limit of 3.

[masa]
This will be modified.


>> +void pch_udc_ep_fifo_flush(struct pch_udc_ep_regs __iomem *ep, int dir)
>> +{
>> + unsigned int loopcnt = 0;
>> +
>> + pr_debug("%s: ep%d%s", __func__, EP_NUM(ep),
>> + (EP_IS_IN(ep) ? "in" : "out"));
>> + if (dir) { /* IN ep */
>> + PCH_UDC_BIT_SET(&ep->epctl, 1 << UDC_EPCTL_F);
>
>I'd add "return;" here and move the else part out of the else dropping
>one indention level.

[masa]
This will be modified.

>> + } else {
>> + if ((pch_udc_read_ep_status(ep) &
>> +     (1 << UDC_EPSTS_MRXFIFO_EMP)) == 0) {
>
>if (pch_udc_read_ep_status(ep) & (1 << UDC_EPSTS_MRXFIFO_EMP)
>return;
>
>and drop indention.

[masa]
This will be modified.


>> +/**
>> + * pch_udc_pcd_pullup - This API is invoked to make the device
>> + * visible/invisible to the host
>> + * @gadget: Reference to the gadget driver
>> + * @is_on: Specifies whether the pull up is made active or inactive
>> + * Returns
>> + * 0: Success
>> + * -EINVAL: If the gadget passed is NULL
>> + */
>> +static int pch_udc_pcd_pullup(struct usb_gadget *gadget, int is_on)
>> +{
>> + struct pch_udc_dev *dev;
>> +
>> + pr_debug("%s: enter", __func__);
>
>It just struck me.  Wouldn't it be feasible to use "dev_*" instead of "pr_*"?

[masa]
This will be modified.


>> + if (gadget == NULL) {
>> + pr_debug("%s: exit -EINVAL", __func__);
>> + return -EINVAL;
>> + }
>> + dev = container_of(gadget, struct pch_udc_dev, gadget);
>> + if (is_on == 0)
>> + pch_udc_set_disconnect(dev->regs);
>> + else
>> + pch_udc_clear_disconnect(dev->regs);
>
>There was function that did exactly that I think.  Wasn't there?

[masa] ???

>> +/**
>> + * pch_udc_start_next_txrequest - This function starts
>> + * the next transmission requirement
>> + * @ep: Reference to the endpoint structure
>> + */
>> +static void pch_udc_start_next_txrequest(struct pch_udc_ep *ep)
>> +{
>> + struct pch_udc_request *req;
>> +
>> + pr_debug("%s: enter", __func__);
>> + if (pch_udc_read_ep_control(ep->regs) & (1 << UDC_EPCTL_P))
>> + return;
>> +
>> + if (!list_empty(&ep->queue)) {
>
>if (list_empty(...))
>return;
>
>and drop indention.

[masa]
This will be modified.

>> + /* next request */
>> + req = list_entry(ep->queue.next, struct pch_udc_request, queue);
>> + if (req && !req->dma_going) {
>
>Same here.

[masa]
This will be modified.

>> + pr_debug("%s: Set request: req=%p req->td_data=%p",
>> + __func__, req, req->td_data);
>> + if (req->td_data) {
>
>Same eher.

[masa]
This will be modified.

>> + struct pch_udc_data_dma_desc *td_data;
>> +
>> + while (pch_udc_read_ep_control(ep->regs) &
>> + (1 << UDC_EPCTL_S))
>> + udelay(100);
>> +
>> + req->dma_going = 1;
>> + /* Clear the descriptor pointer */
>> + pch_udc_ep_set_ddptr(ep->regs, 0);
>> +
>> + td_data = req->td_data;
>> + while (1) {
>> + td_data->status = (td_data->status &
>> + ~PCH_UDC_BUFF_STS) |
>> + PCH_UDC_BS_HST_RDY;
>> + if ((td_data->status &
>> + PCH_UDC_DMA_LAST) ==
>> + PCH_UDC_DMA_LAST)
>> + break;
>
>The line above has 6 levels of indention.  If you drop indentions the way
>described above you get back to 3.

[masa]
This will be modified.

>> +static void pch_udc_complete_transfer(struct pch_udc_ep *ep)
>
>Same as with the function above.

[masa]
This will be modified.

>> +/**
>> + * pch_udc_complete_receiver - This function completes a receiver
>> + * @ep: Reference to the endpoint structure
>> + */
>> +static void pch_udc_complete_receiver(struct pch_udc_ep *ep)
>
>This function would use some indention fixing as well.

[masa]
This will be modified.

>> + if (list_empty(&ep->queue)) {
>> + /* enable DMA */
>> + pch_udc_set_dma(dev->regs, DMA_DIR_RX);
>> + }
>
>Drop the "{" and "}". script/checkpatch.pl will find issues like this one.

[masa]
This will be deleted.


>> +static void pch_udc_read_all_epstatus(struct pch_udc_dev *dev, u32 ep_intr)
>> +{
>> + int i;
>> + struct pch_udc_ep *ep;
>> +
>> + for (i = 0; i < PCH_UDC_USED_EP_NUM; i++) {
>> + /* IN */
>> + if (ep_intr & (0x1 << i)) {
>> + ep = &dev->ep[2*i];
>> + ep->epsts = pch_udc_read_ep_status(ep->regs);
>> + pch_udc_clear_ep_status(ep->regs, ep->epsts);
>> + }
>> + /* OUT */
>> + if (ep_intr & (0x10000 << i)) {
>> + ep = &dev->ep[2*i+1];
>> + ep->epsts = pch_udc_read_ep_status(ep->regs);
>> + pch_udc_clear_ep_status(ep->regs, ep->epsts);
>> + }
>> + }
>> + return;
>
>Useless return.

[masa]
This will be deleted.


>> +/**
>> + * pch_udc_svc_enum_interrupt - This function handles a USB speed enumeration
>> + * done interrupt
>> + * @dev: Reference to driver structure
>> + */
>> +void
>> +pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev)
>
>Useless line break.  This applies not only to this function.

[masa]
This will be modified as
"void pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev)"


>> +void
>> +pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
>> +{
>> + u32 reg, dev_stat = 0;
>> + int i, ret;
>> +
>> + pr_debug("%s: enter", __func__);
>> + dev_stat = pch_udc_read_device_status(dev->regs);
>> + dev->cfg_data.cur_intf = (dev_stat & UDC_DEVSTS_INTF_MASK) >>
>> + UDC_DEVSTS_INTF_OFS;
>> + dev->cfg_data.cur_alt = (dev_stat & UDC_DEVSTS_ALT_MASK) >>
>> + UDC_DEVSTS_ALT_OFS;
>> + pr_debug("DVSTATUS=%08x, cfg=%d, intf=%d, alt=%d", dev_stat,
>> + (dev_stat & UDC_CSR_NE_CFG_MASK) >> UDC_CSR_NE_CFG_OFS,
>> + dev->cfg_data.cur_intf, dev->cfg_data.cur_alt);
>> +
>> + dev->set_cfg_not_acked = 1;
>> +
>> + /* Construct the usb request for gadget driver and inform it */
>> + memset(&setup_data, 0 , sizeof setup_data);
>> + setup_data.request.bRequest = USB_REQ_SET_INTERFACE;
>> + setup_data.request.bRequestType = USB_RECIP_INTERFACE;
>> + setup_data.request.wValue = cpu_to_le16(dev->cfg_data.cur_alt);
>> + setup_data.request.wIndex = cpu_to_le16(dev->cfg_data.cur_intf);
>> +
>> + /* programm the Endpoint Cfg registers */
>> + for (i = 0; i < PCH_UDC_USED_EP_NUM * 2; i++) {
>> + if (i == 1) { /* Only one end point cfg register */
>> + reg = pch_udc_read_csr((u32) (&dev->csr->ne[i]));
>> + reg = (reg & ~UDC_CSR_NE_INTF_MASK) |
>> + (dev->cfg_data.cur_intf << UDC_CSR_NE_INTF_OFS);
>> + reg = (reg & ~UDC_CSR_NE_ALT_MASK) |
>> + (dev->cfg_data.cur_alt << UDC_CSR_NE_ALT_OFS);
>> + pch_udc_write_csr(reg, (u32) (&dev->csr->ne[i]));
>> + }
>
>Could this if be put outside of the loop? This applies not only to this function.

[masa]
This will be modified.

>> +irqreturn_t pch_udc_isr(int irq, void *pdev)
>> +{
>> + struct pch_udc_dev *dev;
>> + u32 dev_intr, ep_intr;
>> + int i;
>> +
>> + pr_debug("%s: enter", __func__);
>> + dev = (struct pch_udc_dev *) pdev;
>> + dev_intr = pch_udc_read_device_interrupts(dev->regs);
>> + ep_intr = pch_udc_read_ep_interrupts(dev->regs);
>> +
>> + if (dev_intr != 0) {
>> + /* Clear device interrupts */
>> + pch_udc_write_device_interrupts(dev->regs, dev_intr);
>> + }
>> + if (ep_intr != 0) {
>> + /* Clear ep interrupts */
>> + pch_udc_write_ep_interrupts(dev->regs, ep_intr);
>> + }
>
>Useless "{" and "}" in the two above ifs.

[masa]
This will be deleted.

>> + /* Process data in end point interrupts */
>> + for (i = 1; i < PCH_UDC_USED_EP_NUM; i++) {
>> + if (ep_intr & (1 <<  i)) {
>> + pch_udc_svc_data_in(dev, i);
>> + pch_udc_postsvc_epinters(dev, i);
>> + }
>> + }
>> + /* Process data out end point interrupts */
>> + for (i = UDC_EPINT_OUT_EP1; i < (UDC_EPINT_OUT_EP0 +
>> + PCH_UDC_USED_EP_NUM); i++) {
>> + if (ep_intr & (1 <<  i))
>> + pch_udc_svc_data_out(dev, i -
>> + UDC_EPINT_OUT_EP0);
>> + }
>
>Useless "{" and "}" in for.

[masa]
This will be deleted.

>> +int pch_udc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>> +{
>> + unsigned long resource;
>> + unsigned long len;
>> + int retval = 0;
>> + struct pch_udc_dev *dev;
>> +
>> + dev_dbg(&pdev->dev, "%s: enter", __func__);
>> + /* one udc only */
>> + if (pch_udc != NULL) {
>> + dev_err(&pdev->dev, "%s: already probed", __func__);
>> + return -EBUSY;
>> + }
>> +
>> + /* init */
>> + dev = kzalloc(sizeof(struct pch_udc_dev), GFP_KERNEL);
>
>I just noticed it here but it may apply to other places as well.  I recommend:
>
>+ dev = kzalloc(sizeof *dev, GFP_KERNEL);

[masa]
This will be modeified.

>> + if (dev == NULL) {
>> + dev_err(&pdev->dev, "%s: no memory for device structure",
>> + __func__);
>> + return -ENOMEM;
>> + }
>> + memset(dev, 0, sizeof(struct pch_udc_dev));
>
>kzalloc() does that.

[masa]
This will be deleted.

>> +/**
>> + * pch_udc_cfg_data - Structure to hold current configuration
>> + * and interface information
>
>This applies to other places as well.  The above should read:
>
>+ * struct pch_udc_cfg_data - ...

[masa]
This will be modeified.

>> + * @cur_cfg current configuration in use
>> + * @cur_intf current interface in use
>> + * @cur_alt current alt interface in use
>
>And there should be ":" after member name.

[masa]
This will be modeified.


>> +/**
>> + * pch_udc_dev - Structure holding complete information of the PCH USB device
>> + *
>> + * @gadget gadget driver data
>> + * @driver; reference to gadget driver bound
>> + * @pdev; reference to the PCI device
>> + * @ep[PCH_UDC_EP_NUM]; array of endpoints
>> + * @lock; protects all state
>> + * @active:1, enabled the PCI device
>> + * @stall:1, stall requested
>> + * @prot_stall:1, protcol stall requested
>> + * @irq_registered:1, irq registered with system
>> + * @mem_region:1, device memory mapped
>> + * @registered:1, driver regsitered with system
>> + * @suspended:1, driver in suspended state
>> + * @connected:1, gadget driver associated
>> + * @set_cfg_not_acked:1, pending acknowledgement 4 setup
>> + * @waiting_zlp_ack:1; pending acknowledgement 4 ZLP
>> + * @csr; address of config & status
>> + * @regs; address of device registers
>> + * @*ep_regs; address of endpoint registers
>> + * @data_requests; DMA pool for data requests
>> + * @stp_requests; DMA pool for setup requests
>> + * @phys_addr; of device memory
>> + * @virt_addr; for mapped device memory
>> + * @irq; IRQ line for the device
>> + * @cfg_data; current cfg, intf, and alt in use
>> + */
>
>Useless ":1", there should be ":" after member name and not nothing, ";" or ",".

[masa]
This will be modeified.

>> +
>
>Needless empty line.
>
>> +struct pch_udc_dev {

[masa]
This will be modeified.

-- 
Best regards,                                        _     _
| Humble Liege of Serenely Enlightened Majesty of  o' \,=./ `o
| Computer Science,  Micha? "mina86" Nazarewicz       (o o)
+----[mina86*mina86.com]---[mina86*jabber.org]----ooO--(_)--Ooo--





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

* Re: [PATCH] USB device driver of Topcliff PCH
  2010-09-07 12:53 ` Maurus Cuelenaere
@ 2010-09-13  4:23   ` Masayuki Ohtake
  2010-09-13 10:26     ` Maurus Cuelenaere
  0 siblings, 1 reply; 14+ messages in thread
From: Masayuki Ohtake @ 2010-09-13  4:23 UTC (permalink / raw)
  To: Maurus Cuelenaere
  Cc: Randy Dunlap, Peter Korsgaard, Nicolas Ferre, Michal Nazarewicz,
	linux-usb, Laurent Pinchart, Greg Kroah-Hartman, Fabien Chouteau,
	david Brownell, Christoph Egger, LKML, MeeGo, Wang, Qi, Wang,
	Yong Y, Andrew, Intel OTC, Foster, Margie, Arjan,
	Toshiharu Okada, Takahiro Shimizu, Tomoya Morinaga

Hi Maurus

My reply comments are included in the following.
I will resubmit after modified

Thanks Ohtake

From: Maurus Cuelenaere <mcuelenaere@gmail.com>
Date: Tue, 7 Sep 2010 14:53:05 +0200
> 2010/9/7 Masayuki Ohtake <masa-korg@dsn.okisemi.com>
> >
> > This patch adds the USB device driver of Topcliff PCH.
> > Topcliff PCH is the platform controller hub that is going to be used in
> > Intel's upcoming general embedded platform. All IO peripherals in
> > Topcliff PCH are actually devices sitting on AMBA bus.
> > Topcliff PCH has USB device I/F. Using this I/F, it is able to access system
> > devices connected to USB device.
> >
> > Signed-off-by: Masayuki Ohtake <masa-korg@dsn.okisemi.com>
>
> No need to mail all these people, just the maintainers and appropriate mailing
> lists will do.

[masa]
I have question. Please tell me.
Whom should I submit patch to?
 TO: LKML and maintainers
Is it correct?

The maintainer was got the following scripts.
"./scripts/get_maintainer.pl"


>
> > ---
> > drivers/usb/gadget/Kconfig | 24 +
> > drivers/usb/gadget/Makefile | 2 +-
> > drivers/usb/gadget/gadget_chips.h | 7 +
> > drivers/usb/gadget/pch_udc.c | 3153 +++++++++++++++++++++++++++++++++++++
> > drivers/usb/gadget/pch_udc.h | 495 ++++++
> > 5 files changed, 3680 insertions(+), 1 deletions(-)
> > create mode 100755 drivers/usb/gadget/pch_udc.c
> > create mode 100755 drivers/usb/gadget/pch_udc.h
> >
> [snip]
> > diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
> > new file mode 100755
> > index 0000000..2065c11
> > --- /dev/null
> > +++ b/drivers/usb/gadget/pch_udc.c
> [snip]
> > +
> > +const char ep0_string[] = "ep0in";
> > +static DEFINE_SPINLOCK(udc_stall_spinlock); /* stall spin lock */
> > +static u32 pch_udc_base;
> > +static union pch_udc_setup_data setup_data; /* received setup data */
> > +static unsigned long ep0out_buf[64];
> > +static dma_addr_t dma_addr;
> > +struct pch_udc_dev *pch_udc; /* pointer to device object */
> > +int speed_fs;
>
> I'd put all these in struct phc_udc_dev or similar, so you could have multiple
> controllers.

[masa]
This will be modified.

>
> > +
> > +module_param_named(speed_fs, speed_fs, bool, S_IRUGO);
> > +MODULE_PARM_DESC(speed_fs, "true for Full speed operation");
> > +MODULE_DESCRIPTION("OKISEMI PCH UDC - USB Device Controller");
> > +MODULE_LICENSE("GPL");
> > +
> > +/**
> > + * pch_udc_write_csr - Write the command and status registers.
> > + * @val: value to be written to CSR register
> > + * @addr: address of CSR register
> > + */
> > +inline void pch_udc_write_csr(unsigned long val, unsigned long addr)
>
> Make all these functions static.

[masa]
This will be modified.

>
> > +{
> > + int count = MAX_LOOP;
> > +
> > + /* Wait till idle */
> > + while ((count > 0) &&\
> > + (ioread32((u32 *)(PCH_UDC_CSR_BUSY_ADDR + pch_udc_base)) &
> > + PCH_UDC_CSR_BUSY))
>
> Why not define PCH_UDC_* as (void __iomem*) so no casting is necessary.

[masa]
This will be modified.

>
> > + count--;
> > +
> > + if (count < 0)
> > + pr_debug("%s: wait error; count = %x", __func__, count);
> > +
> > + iowrite32(val, (u32 *)addr);
> > + /* Wait till idle */
> > + count = MAX_LOOP;
> > + while ((count > 0) &&
> > + (ioread32((u32 *)(PCH_UDC_CSR_BUSY_ADDR + pch_udc_base)) &
> > + PCH_UDC_CSR_BUSY))
> > + count--;
> > +
> > + if (count < 0)
> > + pr_debug("%s: wait error; count = %x", __func__, count);
> > +
> > +}
> > +
> > +/**
> > + * pch_udc_read_csr - Read the command and status registers.
> > + * @addr: address of CSR register
> > + * Returns
> > + * content of CSR register
> > + */
> > +inline u32 pch_udc_read_csr(unsigned long addr)
>
> void __iomem *addr

[masa]
This will be modified.

>
> > +{
> > + int count = MAX_LOOP;
> > +
> > + /* Wait till idle */
> > + while ((count > 0) &&
> > + (ioread32((u32 *)(PCH_UDC_CSR_BUSY_ADDR + pch_udc_base)) &
> > + PCH_UDC_CSR_BUSY))
> > + count--;
> > +
> > + if (count < 0)
> > + pr_debug("%s: wait error; count = %x", __func__, count);
> > + /* Dummy read */
> > + ioread32((u32 *)addr);
> > + count = MAX_LOOP;
> > + /* Wait till idle */
> > + while ((count > 0) &&
> > + (ioread32((u32 *)(PCH_UDC_CSR_BUSY_ADDR + pch_udc_base)) &
> > + PCH_UDC_CSR_BUSY))
> > + count--;
> > + /* actual read */
> > + if (count < 0)
> > + pr_debug("%s: wait error; count = %x", __func__, count);
> > +
> > + return ioread32((u32 *)addr);
> > +}
> > +
> > +/**
> > + * pch_udc_rmt_wakeup - Initiate for remote wakeup
> > + * @dev: Reference to pch_udc_regs structure
> > + */
> > +inline void pch_udc_rmt_wakeup(struct pch_udc_regs *dev)
> > +{
> > + PCH_UDC_BIT_SET(&dev->devctl, 1 << UDC_DEVCTL_RES);
> > + mdelay(1);
> > + PCH_UDC_BIT_CLR(&dev->devctl, 1 << UDC_DEVCTL_RES);
> > +}
> > +
> > +/**
> > + * pch_udc_get_frame - Get the current frame from device status register
> > + * @dev: Reference to pch_udc_regs structure
> > + * Retern current frame
> > + */
> > +inline int pch_udc_get_frame(struct pch_udc_regs *dev)
> > +{
> > + u32 frame;
> > +
> > + frame = ioread32(&dev->devsts);
>
> Why not just get rid of struct pch_udc_regs and do something like:
>
> static inline u32 pch_readl(struct pch_udc_dev *dev, unsigned long reg)
> {
> return ioread32(dev->base_addr + reg);
> }
>
> (and similar for pch_writel)

[masa]
This will be modified.

>
> > + return (frame & UDC_DEVSTS_TS_MASK) >> UDC_DEVSTS_TS_OFS;
> > +}
> [snip]
> > +static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep,
> > + gfp_t gfp)
> > +{
> > + struct pch_udc_request *req;
> > + struct pch_udc_ep *ep;
> > +
> > + pr_debug("%s: enter", __func__);
> > + if (usbep == NULL)
> > + return NULL;
> > +
> > + ep = container_of(usbep, struct pch_udc_ep, ep);
> > + pr_debug("%s: ep %s", __func__, usbep->name);
> > + req = kzalloc(sizeof(struct pch_udc_request), gfp);
> > + if (req == NULL) {
> > + pr_debug("%s: no memory for request", __func__);
> > + return NULL;
> > + }
> > + memset(req, 0, sizeof(struct pch_udc_request));
>
> kzalloc does this..

[masa]
memset() is removed

>
> > + req->req.dma = DMA_ADDR_INVALID;
> > + INIT_LIST_HEAD(&req->queue);
> > +
> > + if (ep->dma != NULL) {
> > + struct pch_udc_data_dma_desc *dma_desc;
> > +
> > + /* ep0 in requests are allocated from data pool here */
> > + dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp,
> > + &req->td_data_phys);
> > + if (NULL == dma_desc) {
> > + kfree(req);
> > + return NULL;
> > + }
> > +
> > + pr_debug("%s: req = 0x%p dma_desc = 0x%p, "
> > + "td_phys = 0x%08lx", __func__,
> > + req, dma_desc, (unsigned long)req->td_data_phys);
> > +
> > + /* prevent from using desc. - set HOST BUSY */
> > + dma_desc->status |= PCH_UDC_BS_HST_BSY;
> > + dma_desc->dataptr = __constant_cpu_to_le32(DMA_ADDR_INVALID);
> > + req->td_data = dma_desc;
> > + req->td_data_last = dma_desc;
> > + req->chain_len = 1;
> > + }
> > + return &req->req;
> > +}
> [snip]
> > +
> > +/**
> > + * pch_udc_start_next_txrequest - This function starts
> > + * the next transmission requirement
> > + * @ep: Reference to the endpoint structure
> > + */
> > +static void pch_udc_start_next_txrequest(struct pch_udc_ep *ep)
> > +{
> > + struct pch_udc_request *req;
> > +
> > + pr_debug("%s: enter", __func__);
> > + if (pch_udc_read_ep_control(ep->regs) & (1 << UDC_EPCTL_P))
> > + return;
> > +
> > + if (!list_empty(&ep->queue)) {
>
> Convert this into:
> if (list_empty(&ep->queue))
> return;
>
> That way you get rid of the unnecessary spacing below

[masa]
This will be modified.

>
> > + /* next request */
> > + req = list_entry(ep->queue.next, struct pch_udc_request, queue);
> > + if (req && !req->dma_going) {
> > + pr_debug("%s: Set request: req=%p req->td_data=%p",
> > + __func__, req, req->td_data);
> > + if (req->td_data) {
> > + struct pch_udc_data_dma_desc *td_data;
> > +
> > + while (pch_udc_read_ep_control(ep->regs) &
> > + (1 << UDC_EPCTL_S))
> > + udelay(100);
> > +
> > + req->dma_going = 1;
> > + /* Clear the descriptor pointer */
> > + pch_udc_ep_set_ddptr(ep->regs, 0);
> > +
> > + td_data = req->td_data;
> > + while (1) {
> > + td_data->status = (td_data->status &
> > + ~PCH_UDC_BUFF_STS) |
> > + PCH_UDC_BS_HST_RDY;
> > + if ((td_data->status &
> > + PCH_UDC_DMA_LAST) ==
> > + PCH_UDC_DMA_LAST)
> > + break;
> > +
> > + td_data =
> > + (struct pch_udc_data_dma_desc *)\
> > + phys_to_virt(td_data->next);
> > + }
> > + /* Write the descriptor pointer */
> > + pch_udc_ep_set_ddptr(ep->regs,
> > + req->td_data_phys);
> > + pch_udc_set_dma(ep->dev->regs, DMA_DIR_TX);
> > + /* Set the poll demand bit */
> > + pch_udc_ep_set_pd(ep->regs);
> > + pch_udc_enable_ep_interrupts(ep->dev->regs,
> > + 1 << (ep->in ? ep->num :\
> > + ep->num + UDC_EPINT_OUT_EP0));
> > + pch_udc_ep_clear_nak(ep->regs);
> > + }
> > + }
> > + }
> > +}
> > +
> > +/**
> > + * pch_udc_complete_transfer - This function completes a transfer
> > + * @ep: Reference to the endpoint structure
> > + */
> > +static void pch_udc_complete_transfer(struct pch_udc_ep *ep)
> > +{
> > + struct pch_udc_request *req;
> > +
> > + pr_debug("%s: enter", __func__);
> > + if (!list_empty(&ep->queue)) {
>
> Same here

[masa]
This will be modified.

>
> > + pr_debug("%s: list_entry", __func__);
> > + req = list_entry(ep->queue.next, struct pch_udc_request, queue);
> > + if (req && ((req->td_data_last->status & PCH_UDC_BUFF_STS) ==
> > + PCH_UDC_BS_DMA_DONE)) {
> > +#ifdef DMA_PPB_WITH_DESC_UPDATE
> > + struct pch_udc_data_dma_desc *td_data = req->td_data;
> > + for (i = 0; i < req->chain_len; i++) {
> > + if ((td_data->status & PCH_UDC_RXTX_STS) !=
> > + PCH_UDC_RTS_SUCC) {
> > + pr_err("Invalid RXTX status (0x%08x)"
> > + " epstatus=0x%08x\n",
> > + (td_data->status &
> > + PCH_UDC_RXTX_STS),
> > + (int)(ep->epsts));
> > + return;
> > + }
> > + td_data = (struct pch_udc_data_dma_desc *)
> > + phys_to_virt(td_data->next);
> > + }
> > +#else
> > + if ((req->td_data_last->status & PCH_UDC_RXTX_STS) !=
> > + PCH_UDC_RTS_SUCC) {
> > + pr_err("Invalid RXTX status (0x%08x)"
> > + " epstatus=0x%08x\n",
> > + (req->td_data_last->status &
> > + PCH_UDC_RXTX_STS),
> > + (int)(ep->epsts));
> > + return;
> > + }
> > +#endif
> > + req->req.actual = req->req.length;
> > + req->td_data_last->status = PCH_UDC_BS_HST_BSY |
> > + PCH_UDC_DMA_LAST;
> > + req->td_data->status = PCH_UDC_BS_HST_BSY |
> > + PCH_UDC_DMA_LAST;
> > + /* complete req */
> > + complete_req(ep, req, 0);
> > + req->dma_going = 0;
> > + if (!list_empty(&ep->queue)) {
> > + while (pch_udc_read_ep_control(ep->regs) &
> > + (1 << UDC_EPCTL_S))
> > + udelay(100);
> > +
> > + pch_udc_ep_clear_nak(ep->regs);
> > + pch_udc_enable_ep_interrupts(ep->dev->regs,
> > + 1 << (ep->in ? ep->num : ep->num +
> > + UDC_EPINT_OUT_EP0));
> > + } else {
> > + pch_udc_disable_ep_interrupts(ep->dev->regs,
> > + 1 << (ep->in ? ep->num : ep->num +
> > + UDC_EPINT_OUT_EP0));
> > + }
> > + }
> > + }
> > +}
> [snip]
> > +
> > +/**
> > + * pch_udc_svc_enum_interrupt - This function handles a USB speed enumeration
> > + * done interrupt
> > + * @dev: Reference to driver structure
> > + */
> > +void
> > +pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev)
> > +{
> > + u32 dev_stat, dev_speed;
> > + u32 speed = USB_SPEED_FULL;
> > +
> > + pr_debug("%s: enter", __func__);
> > + dev_stat = pch_udc_read_device_status(dev->regs);
> > + dev_speed = (dev_stat & UDC_DEVSTS_ENUM_SPEED_MASK) >>
> > + UDC_DEVSTS_ENUM_SPEED_OFS;
> > +
> > + pr_debug("%s: dev_speed = 0x%08x", __func__, dev_speed);
> > +
> > + if (dev_speed == UDC_DEVSTS_ENUM_SPEED_HIGH) {
> > + pr_debug("HighSpeed");
> > + speed = USB_SPEED_HIGH;
> > + } else if (dev_speed == UDC_DEVSTS_ENUM_SPEED_FULL) {
> > + pr_debug("FullSpeed");
> > + speed = USB_SPEED_FULL;
> > + } else if (dev_speed == UDC_DEVSTS_ENUM_SPEED_LOW) {
> > + pr_debug("LowSpeed?");
> > + speed = USB_SPEED_LOW;
> > + } else {
> > + pr_debug("FullSpeed?");
>
> BUG() perhaps? Also, change this into a switch statement

[masa]
This will be modified.


>
> > + }
> > + dev->gadget.speed = speed;
> > +
> > + pch_udc_activate_control_ep(dev);
> > +
> > + /* enable ep0 interrupts */
> > + pch_udc_enable_ep_interrupts(dev->regs, 1 << UDC_EPINT_IN_EP0 |
> > + 1 << UDC_EPINT_OUT_EP0);
> > + /* enable DMA */
> > + pch_udc_set_dma(dev->regs, DMA_DIR_TX);
> > + pch_udc_set_dma(dev->regs, DMA_DIR_RX);
> > + pch_udc_ep_set_rrdy(dev->ep[UDC_EP0OUT_IDX].regs);
> > +
> > +
> > + pr_debug("%s: EP mask set to %x", __func__,
> > + ioread32(&dev->regs->epirqmsk));
> > +}
> [snip]
> > +
> > +int pch_udc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> > +{
> > + unsigned long resource;
> > + unsigned long len;
> > + int retval = 0;
> > + struct pch_udc_dev *dev;
> > +
> > + dev_dbg(&pdev->dev, "%s: enter", __func__);
> > + /* one udc only */
> > + if (pch_udc != NULL) {
> > + dev_err(&pdev->dev, "%s: already probed", __func__);
> > + return -EBUSY;
> > + }
> > +
> > + /* init */
> > + dev = kzalloc(sizeof(struct pch_udc_dev), GFP_KERNEL);
> > + if (dev == NULL) {
> > + dev_err(&pdev->dev, "%s: no memory for device structure",
> > + __func__);
> > + return -ENOMEM;
> > + }
> > + memset(dev, 0, sizeof(struct pch_udc_dev));
>
> kzalloc already does this for you

[masa]
memset is removed.

>
> > + /* pci setup */
> > + if (pci_enable_device(pdev) < 0) {
> > + kfree(dev);
> > + dev_err(&pdev->dev, "%s: pci_enable_device failed", __func__);
> > + return -ENODEV;
> > + }
> > + dev->active = 1;
> > + pci_set_drvdata(pdev, dev);
> > +
> > + /* PCI resource allocation */
> > + resource = pci_resource_start(pdev, 1);
> > + len = pci_resource_len(pdev, 1);
> > + dev_dbg(&pdev->dev, "%s: resource %lx, len %ld",
> > + __func__, resource, len);
> > +
> > + if (request_mem_region(resource, len, KBUILD_MODNAME) == NULL) {
> > + dev_err(&pdev->dev, "%s: pci device used already", __func__);
> > + retval = -EBUSY;
> > + goto finished;
> > + }
> > + dev->phys_addr = resource;
> > + dev->mem_region = 1;
> > +
> > + dev->virt_addr = ioremap_nocache(resource, len);
> > + if (dev->virt_addr == NULL) {
> > + dev_err(&pdev->dev, "%s: device memory cannot be mapped",
> > + __func__);
> > + retval = -ENOMEM;
> > + goto finished;
> > + }
> > + dev_dbg(&pdev->dev, "%s: device memory mapped at %x", __func__,
> > + (int)dev->virt_addr);
> > +
> > + if (pdev->irq == 0) {
> > + dev_err(&pdev->dev, "%s: irq not set", __func__);
> > + retval = -ENODEV;
> > + goto finished;
> > + }
> > +
> > + pch_udc = dev;
> > +
> > + /* initialize the hardware */
> > + if (pch_udc_pcd_init(dev) != 0)
> > + goto finished;
> > +
> > + if (request_irq(pdev->irq, pch_udc_isr, IRQF_SHARED,
> > + KBUILD_MODNAME, dev) != 0) {
> > + dev_err(&pdev->dev, "%s: request_irq(%d) fail", __func__,
> > + pdev->irq);
> > + retval = -ENODEV;
> > + goto finished;
> > + }
> > + dev->irq = pdev->irq;
> > + dev->irq_registered = 1;
> > +
> > + pci_set_master(pdev);
> > + pci_try_set_mwi(pdev);
> > +
> > + /* device struct setup */
> > + spin_lock_init(&dev->lock);
> > + dev->pdev = pdev;
> > + dev->gadget.ops = &pch_udc_ops;
> > +
> > + retval = init_dma_pools(dev);
> > + if (retval != 0)
> > + goto finished;
> > +
> > + dev_set_name(&dev->gadget.dev, "gadget");
> > + dev->gadget.dev.parent = &pdev->dev;
> > + dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
> > + dev->gadget.dev.release = gadget_release;
> > + dev->gadget.name = KBUILD_MODNAME;
> > + dev->gadget.is_dualspeed = 1;
> > +
> > + retval = device_register(&dev->gadget.dev);
> > + if (retval != 0)
> > + goto finished;
> > + dev->registered = 1;
> > +
> > + /* Put the device in disconnected state till a driver is bound */
> > + pch_udc_set_disconnect(dev->regs);
> > + return 0;
> > +
> > +finished:
> > + pch_udc_remove(pdev);
> > + return retval;
> > +}
> > +
> > +static const struct pci_device_id pch_udc_pcidev_id[] = {
> > + {
> > + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PCH1_UDC),
> > + .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
> > + .class_mask = 0xffffffff,
> > + },
> > + { 0 },
> > +};
> > +
> > +MODULE_DEVICE_TABLE(pci, pch_udc_pcidev_id);
> > +
> > +
> > +static struct pci_driver pch_udc_driver = {
> > + .name = KBUILD_MODNAME,
> > + .id_table = pch_udc_pcidev_id,
> > + .probe = pch_udc_probe,
> > + .remove = pch_udc_remove,
> > + .suspend = pch_udc_suspend,
> > + .resume = pch_udc_resume,
> > + .shutdown = pch_udc_shutdown,
>
> Make all these functions static

[masa]
This will be modified.

>
> > +};
> > +
> > +static int __init pch_udc_pci_init(void)
> > +{
> > + return pci_register_driver(&pch_udc_driver);
> > +}
> > +module_init(pch_udc_pci_init);
> > +
> > +static void __exit pch_udc_pci_exit(void)
> > +{
> > + pci_unregister_driver(&pch_udc_driver);
> > +}
> > +module_exit(pch_udc_pci_exit);
> > diff --git a/drivers/usb/gadget/pch_udc.h b/drivers/usb/gadget/pch_udc.h
> > new file mode 100755
> > index 0000000..55c22ef
> > --- /dev/null
> > +++ b/drivers/usb/gadget/pch_udc.h
> > @@ -0,0 +1,495 @@
> > +/*
> > + * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
> > + *
> > + * 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; version 2 of the License.
> > + *
> > + * 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 _PCH_UDC_H_
> > +#define _PCH_UDC_H_
> > +
> > +/* Address offset of Registers */
> > +#define UDC_EPIN_REGS_ADDR 0x000
> > +#define UDC_EPOUT_REGS_ADDR 0x200
> > +#define UDC_EP_REG_OFS 0x20 /* Offset to next EP */
> > +#define UDC_DEVCFG_ADDR 0x400
> > +#define PCH_UDC_CSR_BUSY_ADDR 0x4f0
> > +#define PCH_UDC_SRST_ADDR 0x4fc
> > +#define UDC_CSR_ADDR 0x500
> > +
> > +/* Bit position in UDC CSR Busy status Register */
> > +#define PCH_UDC_CSR_BUSY 1
> > +/* Bit position in UDC Soft reset Register */
> > +#define PCH_UDC_PSRST 1
> > +#define PCH_UDC_SRST 0
> > +
> [snip]
> > +
> > +/**
> > + * pch_udc_csrs - Structure to Endpoint configuration registers
> > + */
> > +struct pch_udc_csrs {
> > + u32 ne[PCH_UDC_USED_EP_NUM * 2];
>
> Why not do away with the structs and do something like:
>
> #define PCH_UDC_CSR(ep) (UDC_CSR_ADDR + ep*4)
>
> (and similar for the others)

[masa]
This will be modified.

>
> > +/* Starting bit position */
> > +#define UDC_CSR_NE_NUM_OFS 0
> > +#define UDC_CSR_NE_DIR_OFS 4
> > +#define UDC_CSR_NE_TYPE_OFS 5
> > +#define UDC_CSR_NE_CFG_OFS 7
> > +#define UDC_CSR_NE_INTF_OFS 11
> > +#define UDC_CSR_NE_ALT_OFS 15
> > +#define UDC_CSR_NE_MAX_PKT_OFS 19
> > +/* Mask patern */
> > +#define UDC_CSR_NE_NUM_MASK 0x0000000f
> > +#define UDC_CSR_NE_DIR_MASK 0x00000010
> > +#define UDC_CSR_NE_TYPE_MASK 0x00000060
> > +#define UDC_CSR_NE_CFG_MASK 0x00000780
> > +#define UDC_CSR_NE_INTF_MASK 0x00007800
> > +#define UDC_CSR_NE_ALT_MASK 0x00078000
> > +#define UDC_CSR_NE_MAX_PKT_MASK 0x3ff80000
> > +};
> > +
> [snip]
> > +
> > +/**
> > + * pch_udc_request - Structure holding a PCH USB device request
> > + * @req embedded ep request
> > + * @td_data_phys phys. address
> > + * @td_data first dma desc. of chain
> > + * @td_data_last last dma desc. of chain
> > + * @queue associated queue
> > + * @dma_going DMA in progress for request
> > + * @dma_mapped DMA memory mapped for request
> > + * @dma_done DMA completed for request
> > + * @chain_len chain length
> > + */
> > +struct pch_udc_request /* request packet */
> > +{
>
> I don't see any reason to not put this in the main .c file?
> (same for struct pch_udc_{ep,request})

[masa]
This moves to main.c.

>
> > + struct usb_request req;
> > + dma_addr_t td_data_phys;
> > + struct pch_udc_data_dma_desc *td_data;
> > + struct pch_udc_data_dma_desc *td_data_last;
> > + struct list_head queue;
> > + unsigned dma_going:1,
> > + dma_mapped:1,
> > + dma_done:1;
> > + unsigned chain_len;
> > +};
> > +
> [snip]
> > +
> > +struct pch_udc_dev {
> > + struct usb_gadget gadget;
> > + struct usb_gadget_driver *driver;
> > + struct pci_dev *pdev;
> > + /* all endpoints */
> > + struct pch_udc_ep ep[PCH_UDC_EP_NUM];
> > + spinlock_t lock;
> > + unsigned active:1,
> > + stall:1,
> > + prot_stall:1,
> > + irq_registered:1,
> > + mem_region:1,
> > + registered:1,
> > + suspended:1,
> > + connected:1,
> > + set_cfg_not_acked:1,
> > + waiting_zlp_ack:1;
> > + struct pch_udc_csrs __iomem *csr;
> > + struct pch_udc_regs __iomem *regs;
> > + struct pch_udc_ep_regs __iomem *ep_regs;
>
> These pointers just seem unnecessary, especially as you could easily construct
> them in-place by adding the appropriate offset to your base address..

[masa]
This will be deleted.





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

* Re: [PATCH] USB device driver of Topcliff PCH
  2010-09-08  0:22 ` Greg KH
@ 2010-09-13  4:23   ` Masayuki Ohtake
  2010-09-13 15:29     ` Greg KH
  0 siblings, 1 reply; 14+ messages in thread
From: Masayuki Ohtake @ 2010-09-13  4:23 UTC (permalink / raw)
  To: Greg KH
  Cc: Randy Dunlap, Peter Korsgaard, Nicolas Ferre, Michal Nazarewicz,
	Maurus Cuelenaere, linux-usb, Laurent Pinchart, Fabien Chouteau,
	david Brownell, Christoph Egger, LKML, MeeGo, Wang, Qi, Wang,
	Yong Y, Andrew, Intel OTC, Foster, Margie, Arjan,
	Toshiharu Okada, Takahiro Shimizu, Tomoya Morinaga

Hi Greg

> > +#define PCH_UDC_BIT_CLR(reg, bitMask) \
> > + iowrite32((ioread32((reg)) & (~(bitMask))), (reg))
>
>
> Why not just use the iowrite32 functions directly?  Or surely there's
> another built-in kernel macro for this somewhere, right?

[masa]
Which macro is it?
Do you know?

My reply comments are included in the following.

Thanks Ohtake
---------
Date: Tue, 7 Sep 2010 17:22:29 -0700
From: Greg KH <gregkh@suse.de>
> On Tue, Sep 07, 2010 at 04:49:03PM +0900, Masayuki Ohtake wrote:
> > This patch adds the USB device driver of Topcliff PCH.
> >
> > Topcliff PCH is the platform controller hub that is going to be used in
> > Intel's upcoming general embedded platform. All IO peripherals in
> > Topcliff PCH are actually devices sitting on AMBA bus.
> > Topcliff PCH has USB device I/F. Using this I/F, it is able to access system
> > devices connected to USB device.
> >
> > Signed-off-by: Masayuki Ohtake <masa-korg@dsn.okisemi.com>
> > ---
> >  drivers/usb/gadget/Kconfig        |   24 +
> >  drivers/usb/gadget/Makefile       |    2 +-
> >  drivers/usb/gadget/gadget_chips.h |    7 +
> >  drivers/usb/gadget/pch_udc.c      | 3153 +++++++++++++++++++++++++++++++++++++
> >  drivers/usb/gadget/pch_udc.h      |  495 ++++++
> >  5 files changed, 3680 insertions(+), 1 deletions(-)
> >  create mode 100755 drivers/usb/gadget/pch_udc.c
> >  create mode 100755 drivers/usb/gadget/pch_udc.h
>
> Heh, really?  executable .c and .h files?  I think you need to look at
> your development system :)

[masa]
"pch_udc.h" will be removed
It includes in "pch_udc.c"

>
>
> >
> > diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
> > index 591ae9f..3bc839d 100644
> > --- a/drivers/usb/gadget/Kconfig
> > +++ b/drivers/usb/gadget/Kconfig
> > @@ -220,6 +220,30 @@ config USB_OTG
> >
> >     Select this only if your OMAP board has a Mini-AB connector.
> >
> > +config USB_GADGET_PCH
> > + boolean "PCH USB Dev"
>
> Please spell this out a lot more as to what it is.

[masa]
This will be modified as
"boolean "PCH USB Device controller""


>
> > + depends on PCI
> > + select USB_GADGET_DUALSPEED
> > + help
> > +   This is a USB device driver for Topcliff PCH.
> > +   Topcliff PCH is the platform controller hub that is used in Intel's
> > +   general embedded platform.
> > +   Topcliff PCH has USB device interface.
> > +   Using this interface, it is able to access system devices connected
> > +   to USB device.
> > +   This driver enables USB device function.
> > +   USB device is a USB peripheral controller which
> > +   supports both full and high speed USB 2.0 data transfers.
> > +   This driver supports for control transfer, and bulk transfer modes.
> > +   This driver dose not support interrupt transfer, and isochronous
> > +   transfer modes.
> > +
> > +config PCH_USBDEV
> > + tristate
> > + depends on USB_GADGET_PCH
> > + default USB_GADGET
> > + select USB_GADGET_SELECTED
> > +
> >  config USB_GADGET_PXA25X
> >  boolean "PXA 25x or IXP 4xx"
> >  depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
> > diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
> > index 9bcde11..9473430 100644
> > --- a/drivers/usb/gadget/Makefile
> > +++ b/drivers/usb/gadget/Makefile
> > @@ -63,4 +63,4 @@ obj-$(CONFIG_USB_G_HID) += g_hid.o
> >  obj-$(CONFIG_USB_G_MULTI) += g_multi.o
> >  obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o
> >  obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o
> > -
> > +obj-$(CONFIG_PCH_USBDEV) += pch_udc.o
> > diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
> > index e511fec..f67dd29 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_GADGET_PCH
> > +#define gadget_is_pch(g) (!strcmp("pch_udc", (g)->name))
> > +#else
> > +#define gadget_is_pch(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_pch(gadget))
> > + return 0x27;
> >  return -ENOENT;
> >  }
> >
> > diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
> > new file mode 100755
> > index 0000000..2065c11
> > --- /dev/null
> > +++ b/drivers/usb/gadget/pch_udc.c
> > @@ -0,0 +1,3153 @@
> > +/*
> > + * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
> > + *
> > + * 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; version 2 of the License.
> > + *
> > + * 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.
> > + */
> > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > +#include <linux/types.h>
> > +#include <linux/module.h>
> > +#include <linux/pci.h>
> > +#include <linux/kernel.h>
> > +#include <linux/delay.h>
> > +#include <linux/ioport.h>
> > +#include <linux/sched.h>
> > +#include <linux/slab.h>
> > +#include <linux/smp_lock.h>
> > +#include <linux/errno.h>
> > +#include <linux/init.h>
> > +#include <linux/timer.h>
> > +#include <linux/list.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/ioctl.h>
> > +#include <linux/fs.h>
> > +#include <linux/dmapool.h>
> > +#include <linux/moduleparam.h>
> > +#include <linux/device.h>
> > +#include <linux/io.h>
> > +#include <linux/irq.h>
> > +
> > +#include <asm/byteorder.h>
> > +#include <asm/system.h>
> > +#include <asm/unaligned.h>
> > +
> > +/* gadget stack */
> > +#include <linux/usb/ch9.h>
> > +#include <linux/usb/gadget.h>
> > +#include "pch_udc.h"
>
> Why do you need a .h file?


[masa]
"pch_udc.h" will be removed
It includes in "pch_udc.c"


>
> > +/* macro to set a specified bit(mask) at the specified address */
> > +#define PCH_UDC_BIT_SET(reg, bitmask) \
> > + iowrite32(((ioread32((reg)) | (bitmask))), (reg))
> > +/* macro to clear a specified bit(mask) at the specified address */
> > +#define PCH_UDC_BIT_CLR(reg, bitMask) \
> > + iowrite32((ioread32((reg)) & (~(bitMask))), (reg))
>
>
> Why not just use the iowrite32 functions directly?  Or surely there's
> another built-in kernel macro for this somewhere, right?

[masa]
Which macro is it?
Do you know?

>
> > +#define MAX_LOOP 200
> > +#define PCH_UDC_PCI_BAR 1
> > +#define PCI_VENDOR_ID_INTEL 0x8086
>
> No need to define this, it's in pci_ids.h already.

[masa]
OK.
This will be removed.

>
> > +#define PCI_DEVICE_ID_INTEL_PCH1_UDC 0x8808
>
> I think this is there too.

[masa]
This is not still in pci.h.

>
> > +
> > +const char ep0_string[] = "ep0in";
> > +static DEFINE_SPINLOCK(udc_stall_spinlock); /* stall spin lock */
> > +static u32 pch_udc_base;
> > +static union pch_udc_setup_data setup_data; /* received setup data */
> > +static unsigned long ep0out_buf[64];
> > +static dma_addr_t dma_addr;
> > +struct pch_udc_dev *pch_udc; /* pointer to device object */
> > +int speed_fs;
>
> Why are 2 of these not static variables?

[masa]
This will be modified.

>
> Have you run this driver through the sparse tool?  It will catch these
> errors.  Please do so.
>

[masa]
I will do.




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

* Re: [PATCH] USB device driver of Topcliff PCH
  2010-09-13  4:23   ` Masayuki Ohtake
@ 2010-09-13 10:26     ` Maurus Cuelenaere
  2010-09-13 11:31       ` Michał Nazarewicz
  0 siblings, 1 reply; 14+ messages in thread
From: Maurus Cuelenaere @ 2010-09-13 10:26 UTC (permalink / raw)
  To: Masayuki Ohtake
  Cc: Randy Dunlap, Peter Korsgaard, Nicolas Ferre, Michal Nazarewicz,
	linux-usb, Laurent Pinchart, Greg Kroah-Hartman, Fabien Chouteau,
	david Brownell, Christoph Egger, LKML, MeeGo, Wang, Qi, Wang,
	Yong Y, Andrew, Intel OTC, Foster, Margie, Arjan,
	Toshiharu Okada, Takahiro Shimizu, Tomoya Morinaga

 Op 13-09-10 06:23, Masayuki Ohtake schreef:
> Hi Maurus

Hi Ohtake,

>
> My reply comments are included in the following.
> I will resubmit after modified
>
> Thanks Ohtake
>
> From: Maurus Cuelenaere <mcuelenaere@gmail.com>
> Date: Tue, 7 Sep 2010 14:53:05 +0200
>> 2010/9/7 Masayuki Ohtake <masa-korg@dsn.okisemi.com>
>>> This patch adds the USB device driver of Topcliff PCH.
>>> Topcliff PCH is the platform controller hub that is going to be used in
>>> Intel's upcoming general embedded platform. All IO peripherals in
>>> Topcliff PCH are actually devices sitting on AMBA bus.
>>> Topcliff PCH has USB device I/F. Using this I/F, it is able to access system
>>> devices connected to USB device.
>>>
>>> Signed-off-by: Masayuki Ohtake <masa-korg@dsn.okisemi.com>
>> No need to mail all these people, just the maintainers and appropriate mailing
>> lists will do.
> [masa]
> I have question. Please tell me.
> Whom should I submit patch to?
>  TO: LKML and maintainers
> Is it correct?
>
> The maintainer was got the following scripts.
> "./scripts/get_maintainer.pl"

If you do scripts/get_maintainer.pl --rolestats <patch>, you'll see why
get_maintainer.pl picked these persons. I generally CC anyone that's "above"
commit_signer or that I know has an important relation to the patch (e.g. the
author of a driver you're editing).

If there are any mailing lists listed (linux-usb in this case), be sure to CC
them too (except LKML, I wouldn't CC them unless it's a special case like the
changes are kernel-wide or need to reviewed by a wide variation of audience or
...)

IIRC, these rules are also explained at Documentation/Submit*.

--
Maurus Cuelenaere

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

* Re: [PATCH] USB device driver of Topcliff PCH
  2010-09-13 10:26     ` Maurus Cuelenaere
@ 2010-09-13 11:31       ` Michał Nazarewicz
  2010-09-14  8:35         ` Masayuki Ohtake
  2010-09-14 12:50         ` Maurus Cuelenaere
  0 siblings, 2 replies; 14+ messages in thread
From: Michał Nazarewicz @ 2010-09-13 11:31 UTC (permalink / raw)
  To: Masayuki Ohtake, Maurus Cuelenaere
  Cc: Randy Dunlap, Peter Korsgaard, Nicolas Ferre, linux-usb,
	Laurent Pinchart, Greg Kroah-Hartman, Fabien Chouteau,
	david Brownell, Christoph Egger, LKML, MeeGo, Wang, Qi, Wang,
	Yong Y, Andrew, Intel OTC, Foster, Margie, Arjan,
	Toshiharu Okada, Takahiro Shimizu, Tomoya Morinaga

On Mon, 13 Sep 2010 12:26:30 +0200, Maurus Cuelenaere <mcuelenaere@gmail.com> wrote:
> If there are any mailing lists listed (linux-usb in this case), be sure to CC
> them too (except LKML, I wouldn't CC them unless it's a special case like the
> changes are kernel-wide or need to reviewed by a wide variation of audience or
> ...)

Actually, Documentation/SubmittingPatches says:

	Unless you have a reason NOT to do so, CC
	linux-kernel@vger.kernel.org.

-- 
Best regards,                                        _     _
| Humble Liege of Serenely Enlightened Majesty of  o' \,=./ `o
| Computer Science,  Michał "mina86" Nazarewicz       (o o)
+----[mina86*mina86.com]---[mina86*jabber.org]----ooO--(_)--Ooo--

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

* Re: [PATCH] USB device driver of Topcliff PCH
  2010-09-13  4:23   ` Masayuki Ohtake
@ 2010-09-13 15:29     ` Greg KH
  0 siblings, 0 replies; 14+ messages in thread
From: Greg KH @ 2010-09-13 15:29 UTC (permalink / raw)
  To: Masayuki Ohtake
  Cc: Randy Dunlap, Peter Korsgaard, Nicolas Ferre, Michal Nazarewicz,
	Maurus Cuelenaere, linux-usb, Laurent Pinchart, Fabien Chouteau,
	david Brownell, Christoph Egger, LKML, MeeGo, Wang, Qi, Wang,
	Yong Y, Andrew, Intel OTC, Foster, Margie, Arjan,
	Toshiharu Okada, Takahiro Shimizu, Tomoya Morinaga

On Mon, Sep 13, 2010 at 01:23:40PM +0900, Masayuki Ohtake wrote:
> Hi Greg
> 
> > > +#define PCH_UDC_BIT_CLR(reg, bitMask) \
> > > + iowrite32((ioread32((reg)) & (~(bitMask))), (reg))
> >
> >
> > Why not just use the iowrite32 functions directly?  Or surely there's
> > another built-in kernel macro for this somewhere, right?
> 
> [masa]
> Which macro is it?
> Do you know?

Nope, sorry, try digging around.

good luck,

greg k-h

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

* Re: [PATCH] USB device driver of Topcliff PCH
  2010-09-13 11:31       ` Michał Nazarewicz
@ 2010-09-14  8:35         ` Masayuki Ohtake
  2010-09-14 12:50         ` Maurus Cuelenaere
  1 sibling, 0 replies; 14+ messages in thread
From: Masayuki Ohtake @ 2010-09-14  8:35 UTC (permalink / raw)
  To: Micha? Nazarewicz, Maurus Cuelenaere
  Cc: Randy Dunlap, Peter Korsgaard, Nicolas Ferre, linux-usb,
	Laurent Pinchart, Greg Kroah-Hartman, Fabien Chouteau,
	david Brownell, Christoph Egger, LKML, MeeGo, Wang, Qi, Wang,
	Yong Y, Andrew, Intel OTC, Foster, Margie, Arjan,
	Toshiharu Okada, Takahiro Shimizu, Tomoya Morinaga

Hi Michal and Maurus

Thank you for your reply.
I will resubmit patch so.

Thanks Ohtake
-----
Date: Mon, 13 Sep 2010 13:31:13 +0200
From: "Micha? Nazarewicz" <m.nazarewicz@samsung.com>


On Mon, 13 Sep 2010 12:26:30 +0200, Maurus Cuelenaere <mcuelenaere@gmail.com> wrote:
> If there are any mailing lists listed (linux-usb in this case), be sure to CC
> them too (except LKML, I wouldn't CC them unless it's a special case like the
> changes are kernel-wide or need to reviewed by a wide variation of audience or
> ...)

Actually, Documentation/SubmittingPatches says:

Unless you have a reason NOT to do so, CC
linux-kernel@vger.kernel.org.

-- 
Best regards,                                        _     _
| Humble Liege of Serenely Enlightened Majesty of  o' \,=./ `o
| Computer Science,  Micha? "mina86" Nazarewicz       (o o)
+----[mina86*mina86.com]---[mina86*jabber.org]----ooO--(_)--Ooo--



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

* Re: [PATCH] USB device driver of Topcliff PCH
  2010-09-13 11:31       ` Michał Nazarewicz
  2010-09-14  8:35         ` Masayuki Ohtake
@ 2010-09-14 12:50         ` Maurus Cuelenaere
  2010-09-14 17:33           ` Valdis.Kletnieks
  1 sibling, 1 reply; 14+ messages in thread
From: Maurus Cuelenaere @ 2010-09-14 12:50 UTC (permalink / raw)
  To: Michał Nazarewicz
  Cc: Masayuki Ohtake, Randy Dunlap, Peter Korsgaard, Nicolas Ferre,
	linux-usb, Laurent Pinchart, Greg Kroah-Hartman, Fabien Chouteau,
	david Brownell, Christoph Egger, LKML, MeeGo, Wang, Qi, Wang,
	Yong Y, Andrew, Intel OTC, Foster, Margie, Arjan,
	Toshiharu Okada, Takahiro Shimizu, Tomoya Morinaga

 Op 13-09-10 13:31, Michał Nazarewicz schreef:
> On Mon, 13 Sep 2010 12:26:30 +0200, Maurus Cuelenaere <mcuelenaere@gmail.com> wrote:
>> If there are any mailing lists listed (linux-usb in this case), be sure to CC
>> them too (except LKML, I wouldn't CC them unless it's a special case like the
>> changes are kernel-wide or need to reviewed by a wide variation of audience or
>> ...)
>
> Actually, Documentation/SubmittingPatches says:
>
>     Unless you have a reason NOT to do so, CC
>     linux-kernel@vger.kernel.org.
>

Ah, well IMHO it's better not to spam LKML with subsystem-related stuff..

--
Maurus Cuelenaere

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

* Re: [PATCH] USB device driver of Topcliff PCH
  2010-09-14 12:50         ` Maurus Cuelenaere
@ 2010-09-14 17:33           ` Valdis.Kletnieks
  0 siblings, 0 replies; 14+ messages in thread
From: Valdis.Kletnieks @ 2010-09-14 17:33 UTC (permalink / raw)
  To: Maurus Cuelenaere
  Cc: Michał Nazarewicz, Masayuki Ohtake, Randy Dunlap,
	Peter Korsgaard, Nicolas Ferre, linux-usb, Laurent Pinchart,
	Greg Kroah-Hartman, Fabien Chouteau, david Brownell,
	Christoph Egger, LKML, MeeGo, Wang, Qi, Wang, Yong Y, Andrew,
	Intel OTC, Foster, Margie, Arjan, Toshiharu Okada,
	Takahiro Shimizu, Tomoya Morinaga

[-- Attachment #1: Type: text/plain, Size: 757 bytes --]

On Tue, 14 Sep 2010 14:50:45 +0200, Maurus Cuelenaere said:

> Ah, well IMHO it's better not to spam LKML with subsystem-related stuff..

On the flip side, posting to LKML as well means that it's a bit harder for a
patch series to go totally down a rathole, because people outside the subsystem
then have a chance to look at the code and point out where it's going in the
wrong direction. My last code comment was regarding hardware I didn't have, and
happened because I asked myself "What would happen if that code tried to run on
my laptop?".  Similarly, we see lots of stuff posted that looks good to those
of us on 1-4 core systems, only to have somebody from SGI point out that it
will add 45 hours to boot time on one of their big boxes.  And so on.


[-- Attachment #2: Type: application/pgp-signature, Size: 227 bytes --]

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

end of thread, other threads:[~2010-09-14 17:35 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-09-07  7:49 [PATCH] USB device driver of Topcliff PCH Masayuki Ohtake
2010-09-07 12:53 ` Maurus Cuelenaere
2010-09-13  4:23   ` Masayuki Ohtake
2010-09-13 10:26     ` Maurus Cuelenaere
2010-09-13 11:31       ` Michał Nazarewicz
2010-09-14  8:35         ` Masayuki Ohtake
2010-09-14 12:50         ` Maurus Cuelenaere
2010-09-14 17:33           ` Valdis.Kletnieks
2010-09-08  0:22 ` Greg KH
2010-09-13  4:23   ` Masayuki Ohtake
2010-09-13 15:29     ` Greg KH
2010-09-08  1:58 ` Michał Nazarewicz
2010-09-08 13:57   ` Masayuki Ohtake
2010-09-13  4:23   ` Masayuki Ohtake

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.