[PATCH v3] [RFC] USB: ISP1763 driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds support for STE-ISP1763 USB host and device controller
The host-side is based largely on isp1760-hcd and STE pehci driver
The device-side and platform parsing code is written mostly from scratch.

Co-authored-by: Florian Voegel <fvoegel@xxxxxxxxxxxx>

V3:

- checkpatch cleanups are applied.
- EXPORT_SYMBOL to EXPORT_SYMBOL_GPL
- (hdc cleanup) comments from Sebastian are applied.
- (udelay) changed to mdelay where applicable.
- unused #include<asm/*> removed
- isp_debug removed
- PCI probe assumes OTG role as host
- isp1763_common_init: use res_len for ioremap
- fix compiler error about dev.driver_data
- stubbed out debug dump code with #ifdef ISP1763_UDC_DEBUG_DUMP
- fix misc compiler warning about mixed code and declaration

TODO: (that I know of, not comprehensive)
- [udc]  Sebastian's comments on functional changes to udc
         (not using the wheel, etc)
- [base] Cleanup code on device remove/module unload
- [pci]  Update PCI to be inline with isp1763-base enhancements.
---
Greetings,

After cleanups listed above, I figured it is time to post an updated
baseline for all who are interested. The patch is not mainline-ready
but is a good starting point.

[Florian]: 
I got rid of the compile warnings for udc for
using dev.device_data (replaced with [set|get]_gadget__data)

still have one remaining for:
drivers/usb/isp1763/isp1763_udc.c:1646: warning: 
ignoring return value of 'device_register', 
declared with attribute warn_unused_result

[Sebastian]: 
Most of the checkpatch stuff is gone, what is left maybe 
false-positive (I used checkpatch.pl-testing)
The udc cleanups you mentioned will need more work.

[David]
Sorry if I miss any 2.6.24 specific stuff, you might have an easier time
if you patch the 2.6.24 specific stuff on top of this one, that way you
can git-rebase your patch to this one whenever there is a new one posted.

[Wenkai & ST-Ericsson]:
Thanks for joining in the discussion. I am thrilled that there is 
interest for this driver from the vendor. Do you guys mind being 
the integration point? (and maintaining future git patches?) 
my scope of testing for the hdc is PPC centric and my platform
is not udc capable, so I'm flying blind there. Would really appreaciate 
the help in testing & polishing the work to make it mainline-worthy.

 drivers/usb/Kconfig                |    1 +
 drivers/usb/Makefile               |    2 +-
 drivers/usb/isp1763/Kconfig        |   63 +
 drivers/usb/isp1763/Makefile       |    3 +
 drivers/usb/isp1763/isp1763.h      |  309 +++++
 drivers/usb/isp1763/isp1763_base.c |  992 +++++++++++++++
 drivers/usb/isp1763/isp1763_hcd.c  | 2378 ++++++++++++++++++++++++++++++++++++
 drivers/usb/isp1763/isp1763_hcd.h  |  322 +++++
 drivers/usb/isp1763/isp1763_udc.c  | 1692 +++++++++++++++++++++++++
 drivers/usb/isp1763/isp1763_udc.h  |  113 ++
 include/linux/usb/isp1763.h        |   12 +-
 11 files changed, 5880 insertions(+), 7 deletions(-)
 create mode 100644 drivers/usb/isp1763/Kconfig
 create mode 100644 drivers/usb/isp1763/Makefile
 create mode 100644 drivers/usb/isp1763/isp1763.h
 create mode 100644 drivers/usb/isp1763/isp1763_base.c
 create mode 100644 drivers/usb/isp1763/isp1763_hcd.c
 create mode 100644 drivers/usb/isp1763/isp1763_hcd.h
 create mode 100644 drivers/usb/isp1763/isp1763_udc.c
 create mode 100644 drivers/usb/isp1763/isp1763_udc.h

diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 2407508..7d9b9cc 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -157,4 +157,5 @@ source "drivers/usb/gadget/Kconfig"
 
 source "drivers/usb/otg/Kconfig"
 
+source "drivers/usb/isp1763/Kconfig"
 endif # USB_SUPPORT
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index c3ac247..e9f3e56 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -21,7 +21,7 @@ obj-$(CONFIG_USB_U132_HCD)	+= host/
 obj-$(CONFIG_USB_R8A66597_HCD)	+= host/
 obj-$(CONFIG_USB_HWA_HCD)	+= host/
 obj-$(CONFIG_USB_ISP1760_HCD)	+= host/
-obj-$(CONFIG_USB_ISP1763_HCD)	+= host/
+obj-$(CONFIG_USB_ISP1763)	+= isp1763/
 
 obj-$(CONFIG_USB_C67X00_HCD)	+= c67x00/
 
diff --git a/drivers/usb/isp1763/Kconfig b/drivers/usb/isp1763/Kconfig
new file mode 100644
index 0000000..7f4b0b4
--- /dev/null
+++ b/drivers/usb/isp1763/Kconfig
@@ -0,0 +1,63 @@
+#
+#
+
+comment "Enable Host or Gadget support to see ISP1763 options"
+	depends on !USB && USB_GADGET=n
+
+menuconfig USB_ISP1763
+	tristate "ISP 1763A highspeed dual role controller support"
+	depends on (USB || USB_GADGET)
+	---help---
+	  Support for ST Ericsson ISP1763A USB OTG Controller.
+	  Allows for host only, peripheral ony and limited OTG support.
+
+
+if USB_ISP1763
+
+config USB_ISP1763_UDC
+	tristate
+
+config USB_ISP1763_HCD
+	tristate
+
+choice
+	prompt "ISP1763 controller drivers"
+	depends on USB_ISP1763
+	---help---
+	  Marker for multiple choices for the driver operational mode:
+	  host+periperhal or [periperhal|host]-only modes.
+
+config USB_ISP1763_OTG
+	depends on USB_ISP1763
+	tristate 'ISP1763 OTG (host+device auto-select) support'
+	select USB_ISP1763_UDC
+	select USB_ISP1763_HCD
+	---help---
+	  Limited OTG support for ISP1763; enables detection of ID signal and
+	  automatic switching between host and device controller mode. Does
+	  not include HRP and SRP support.
+
+	  This option will build the drivers for both host and peripheral
+	  controller.
+
+config USB_ISP1763_UDC_SELECT
+	depends on USB_ISP1763
+	depends on USB_GADGET
+	select USB_ISP1763_FUNCTION_SELECTED
+	select USB_ISP1763_UDC
+	tristate 'ISP1763 UDC peripheral-only support'
+	---help---
+	   This flag turns on only the Support for peripheral controller
+	   functionality of the ISP1763
+
+config USB_ISP1763_HCD_SELECT
+	depends on USB_ISP1763
+	select USB_ISP1763_HCD
+	tristate 'ISP1763 HCD host-only support'
+	---help---
+	   This flag turns on only the Support for host controller
+	   functionality of the ISP1763
+
+endchoice
+
+endif
diff --git a/drivers/usb/isp1763/Makefile b/drivers/usb/isp1763/Makefile
new file mode 100644
index 0000000..f2cfbd7
--- /dev/null
+++ b/drivers/usb/isp1763/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_USB_ISP1763) += isp1763_base.o
+obj-$(CONFIG_USB_ISP1763_UDC) += isp1763_udc.o
+obj-$(CONFIG_USB_ISP1763_HCD) += isp1763_hcd.o
diff --git a/drivers/usb/isp1763/isp1763.h b/drivers/usb/isp1763/isp1763.h
new file mode 100644
index 0000000..0e7c4bc
--- /dev/null
+++ b/drivers/usb/isp1763/isp1763.h
@@ -0,0 +1,309 @@
+#ifndef __ISP1763_H__
+#define __ISP1763_H__
+
+/*
+* Device flags that can vary from board to board.  All of these
+* indicate the most "atypical" case, so that a devflags of 0 is
+* a sane default configuration.
+*/
+#define ISP1763_FLAG_BUS_WIDTH_8	0x00000002 /* 8-bit data bus width */
+#define ISP1763_FLAG_PORT1_ROLE_HOST	0x00000004 /* Static host */
+#define ISP1763_FLAG_PORT1_ROLE_GADGET	0x00000008 /* Static gadget */
+#define ISP1763_FLAG_PORT1_ROLE_OTG	0x0000000C /* Port 1 supports OTG */
+#define ISP1763_FLAG_DACK_POL_HIGH	0x00000010 /* DACK active high */
+#define ISP1763_FLAG_DREQ_POL_HIGH	0x00000020 /* DREQ active high */
+#define ISP1763_FLAG_INTR_POL_HIGH	0x00000080 /* Active high Interrupt */
+#define ISP1763_FLAG_INTR_EDGE_TRIG	0x00000100 /* Edge trigger Interrupt */
+#define ISP1763_FLAG_DMA_ENABLED	0x00001000
+#define ISP1763_FLAG_DMA_EXTERNAL	0x00002000 /* 1:ext DMA; 0: Internal */
+
+/* memory map of ISP1763A USB dual role/OTG controller */
+struct isp1763_regs {
+
+	/* DC registers (mostly) */
+	u16 address;		/* 0x00 device address */
+	u16 reserved001;
+	u16 ep_maxpktsize;	/* 0x04 EP maxpacketsize */
+	u16 reserved002;
+	u16 ep_type;		/* 0x08 EP type */
+	u16 reserved003;
+	u16 mode;		/* 0x0C mode register */
+	u16 reserved004;
+	u16 icr;		/* 0x10 Interrupt control register */
+	u16 debug;		/* 0x12 debug register - useless */
+	u32 dc_int_enable;	/* 0x14 DC interrupt enable */
+	u32 dc_interrupt;	/* 0x18 DC interrupt */
+	u16 buflen;		/* 0x1C EP buffer length */
+	u16 dcbufstatus;	/* 0x1E EP buffer status */
+	u16 data_port;		/* 0x20 DC data port */
+	u16 reserved006[3];
+	u16 ctrlfn;		/* 0x28 DC control function */
+	u16 reserved007;
+	u16 ep_index;		/* 0x2C PIO EP index */
+	u16 reserved008;
+	u16 dma_cmd;		/* 0x30 DMA command */
+	u16 reserved009;
+	u32 dma_xfer_cnt;	/* 0x34 DMA transfer count */
+	u16 dcdmaconf;		/* 0x38 DC DMA config */
+	u16 reserved010;
+	u16 dmahw;		/* 0x3C DMA hardware parameters */
+	u8 reserved011[18];
+	u16 dma_ireason;	/* 0x50 DMA interrupt reason */
+	u16 reserved012;
+	u16 dma_ienable;	/* 0x54 DMA interrupt enable */
+	u16 reserved013;
+	u16 dma_ep;		/* 0x58 DMA EP index */
+	u8 reserved014[6];
+	u16 dma_data;		/* 0x60 DMA data register */
+	u16 reserved015;
+	u16 dma_burst_cnt;	/* 0x64 DMA burst count */
+	u16 reserved016[4];
+	u32 chip_id;		/* 0x70 chip ID */
+	u16 frameno;		/* 0x74 current frame number */
+	u16 reserved017;
+	u16 scratch;		/* 0x78 scratch register */
+	u16 reserved018;
+	u16 unlock;		/* 0x7C unlock register */
+	u16 reserved019;
+	u16 int_pulse_width;	/* 0x80 interrupt pulse width */
+	u16 reserved020;
+	u16 testmode;		/* 0x84 testmode */
+	u16 reserved021[3];
+
+	/* HC registers */
+	u32 usbcmd;		/* 0x8C USB command register */
+	u32 usbsts;		/* 0x90 USB status register */
+	u32 reserved022;
+	u32 frindex;		/* 0x98 frame index */
+	u32 configflag;		/* 0x9C config valid flag */
+	u32 portsc1;		/* 0xA0 Port 1 status register */
+	u16 iso_pt_done_map;	/* 0xA4 ISO transfer done map */
+	u16 iso_pt_skip_map;	/* 0xA6 ISO transfer skip map */
+	u16 iso_pt_last_ptd;	/* 0xA8 ISO transfer last  */
+	u16 int_pt_done_map;	/* 0xAA INT transfer done map */
+	u16 int_pt_skip_map;	/* 0xAC INT transfer skip map */
+	u16 int_pt_last_ptd;	/* 0xAE INT transfer last */
+	u16 atl_pt_done_map;	/* 0xB0 ATL transfer done map */
+	u16 atl_pt_skip_map;	/* 0xB2 ATL transfer skip map */
+	u16 atl_pt_last_ptd;	/* 0xB4 ATL transfer last map */
+	u16 hwmodectrl;		/* 0xB6 Hardware mode control */
+	u16 swreset;		/* 0xB8 software reset */
+	u16 hcbufferstatus;	/* 0xBA Host controller buffer status */
+	u32 hcdmaconfig;	/* 0xBC Host controller DMA config */
+	u32 atl_done_timeout;	/* 0xC0 ATL done timeout */
+	u16 memory;		/* 0xC2 HC memory pointer register */
+	u16 data;		/* 0xC6 HC data register */
+	u32 edge_int_count;	/* 0xC8 Edge interrupt configuration */
+	u16 dma_start_addr;	/* 0xCC DMA start address */
+	u16 reserved023;
+	u32 power_down_ctrl;	/* 0xD0 power down control */
+	u16 hc_interrupt;	/* 0xD4 HC interrupt status */
+	u16 hc_interrupt_enable;	/* 0xD6 HC interrupt enable */
+	u16 iso_irq_mask_or;	/* 0xD8 ISO IRQ mask OR */
+	u16 int_irq_mask_or;	/* 0xDA INT IRQ mask OR */
+	u16 atl_irq_mask_or;	/* 0xDC ATL IRQ mask OR */
+	u16 reserved024;
+
+	/* OTG registers */
+	u32 reserved025;
+	u32 otg_ctrl;            /* 0xE4 OTG control set & clear */
+	u16 otg_status;          /* 0xE8 OTG status set & clear */
+	u16 reserved026;
+	u32 otg_int_latch;       /* 0xEC OTG interrupt latch set & clear */
+	u32 otg_int_enable_fall; /* 0xF0 OTG interrupt falling set & clr */
+	u32 otg_int_enable_rise; /* 0xF4 OTG interrupt rising set & clr */
+	u32 otg_timer_lw;	 /* 0xF8 OTG timer configuration low word */
+	u32 otg_timer_hw;	 /* 0xFC OTG timer configuration high word */
+} __attribute__ ((aligned(1)));
+
+/** struct isp1763_controller - common struct for interface and private data
+*/
+struct isp1763_controller {
+	int active;
+	struct device *device;
+	struct isp1763_regs *regs;
+	int (*do_irq) (struct isp1763_controller *ctrl, u32 flags);
+	int (*suspend) (struct isp1763_controller *ctrl);
+	int (*resume) (struct isp1763_controller *ctrl);
+	int (*probe) (struct isp1763_controller *ctrl);
+	int (*remove) (struct isp1763_controller *ctrl);
+
+	void *priv;
+};
+
+typedef void (*otgtimer_callback_t) (void *data);
+
+/**
+* struct isp1763_dev - main driver structure
+* @irq: interrupt number
+* @current_role: currently active role
+* @ctrl: array of controllers, role is index
+* @regs: pointer to memory mapped chip registers
+* @otgtimer_cb: registered OTG timer callback
+* @otgtimer_data: registered OTG timer callback context data
+* @devflags: saved hardware configuration flags
+* @dev: pointer to parent device structure
+*/
+struct isp1763_dev {
+	int irq;
+	int current_role;
+	struct isp1763_controller *ctrl[2];
+	struct isp1763_regs *regs;
+	otgtimer_callback_t otgtimer_cb;
+	void *otgtimer_data;
+	unsigned long devflags;
+	struct device *dev;
+};
+
+#define ISP_CHIP_ID	0x00176320ul
+
+#define MASK_OTGINTEN_DP2_SRP		(1 << 11)
+#define MASK_OTGINTEN_P2_A_SESS_VALID	(1 << 10)
+#define MASK_OTGINTEN_TMR_TIMEOUT	(1 <<  9)
+#define MASK_OTGINTEN_B_SE0_SRP		(1 <<  8)
+#define MASK_OTGINTEN_B_SESS_END	(1 <<  7)
+#define MASK_OTGINTEN_BDIS_ACON		(1 <<  6)
+#define MASK_OTGINTEN_RMT_CONN		(1 <<  4)
+#define MASK_OTGINTEN_ID		(1 <<  3)
+#define MASK_OTGINTEN_DP_SRP		(1 <<  2)
+#define MASK_OTGINTEN_SESS_VALID	(1 <<  1)
+#define MASK_OTGINTEN_VBUS_VALID	(1 <<  0)
+
+#define MASK_HCINT_OTG		(1 << 10)
+#define MASK_HCINT_ISO		(1 <<  9)
+#define MASK_HCINT_ATL		(1 <<  8)
+#define MASK_HCINT_INT		(1 <<  7)
+#define MASK_HCINT_CLK_READY	(1 <<  6)
+#define MASK_HCINT_HCSUSP	(1 <<  5)
+#define MASK_HCINT_OPR_REG	(1 <<  4)
+#define MASK_HCINT_DMAEOT_INT	(1 <<  3)
+#define MASK_HCINT_SOFINT	(1 <<  1)
+#define MASK_HCINT_MSOFINT	(1 <<  0)
+
+#define MASK_OTGSTATUS_ID	0x0008
+
+#define MASK_INTCONFIG_INTLVL	0x02
+#define MASK_INTCONFIG_INTPOL	0x01
+
+#define USE_LEVEL	1
+#define USE_PULSE	0
+#define TRIG_HIGH	1
+#define TRIG_LOW	0
+
+#define MASK_HWMODECTRL_ID_PU_DISABLE		(1 << 12)
+#define MASK_HWMODECTRL_DEV_DMA			(1 << 11)
+#define MASK_HWMODECTRL_COMN_INT		(1 << 10)
+#define MASK_HWMODECTRL_COMN_DMA		(1 <<  9)
+#define MASK_HWMODECTRL_DACK_POL		(1 <<  6)
+#define MASK_HWMODECTRL_DREQ_POL		(1 <<  5)
+#define MASK_HWMODECTRL_DATA_BUS_WIDTH		(1 <<  4)
+#define MASK_HWMODECTRL_INTF_LOCK		(1 <<  3)
+#define MASK_HWMODECTRL_INTR_POLARITY		(1 <<  2)
+#define MASK_HWMODECTRL_INTR_EDGE		(1 <<  1)
+#define MASK_HWMODECTRL_GLOBAL_INT_ENABLE	(1 <<  0)
+
+#define MASK_OTGCTRL_HC2DIS		(1 << 15)
+#define MASK_OTGCTRL_TMR_SEL		(1 << 13)
+#define MASK_OTGCTRL_DISABLE		(1 << 10)
+#define MASK_OTGCTRL_SE0_EN		(1 <<  9)
+#define MASK_OTGCTRL_BDIS_ACON_EN	(1 <<  8)
+#define MASK_OTGCTRL_SW_SEL_HC_DC	(1 <<  7)
+#define MASK_OTGCTRL_VBUS_CHRG		(1 <<  6)
+#define MASK_OTGCTRL_VBUS_DISCHRG	(1 <<  5)
+#define MASK_OTGCTRL_VBUS_DRV		(1 <<  4)
+#define MASK_OTGCTRL_DM_PULLDOWN	(1 <<  2)
+#define MASK_OTGCTRL_DP_PULLDOWN	(1 <<  1)
+#define MASK_OTGCTRL_DP_PULLUP		(1 <<  0)
+
+#define MASK_MODE_DMACLOCK_ON	(1 << 9)
+#define MASK_MODE_VBUSSTAT	(1 << 8)
+#define MASK_MODE_CLKAON	(1 << 7)
+#define MASK_MODE_SNDRSU	(1 << 6)
+#define MASK_MODE_GOSUSP	(1 << 5)
+#define MASK_MODE_SFRESET	(1 << 4)
+#define MASK_MODE_GLINTENA	(1 << 3)
+#define MASK_MODE_WKUPCS	(1 << 2)
+
+#define MASK_DCINT_BRESET	(1 <<  0)
+#define MASK_DCINT_SOF		(1 <<  1)
+#define MASK_DCINT_PSOF		(1 <<  2)
+#define MASK_DCINT_SUSP		(1 <<  3)
+#define MASK_DCINT_RESUME	(1 <<  4)
+#define MASK_DCINT_HS_STAT	(1 <<  5)
+#define MASK_DCINT_DMA		(1 <<  6)
+#define MASK_DCINT_VBUS		(1 <<  7)
+#define MASK_DCINT_EP0SETUP	(1 <<  8)
+#define MASK_DCINT_EP0RX	(1 << 10)
+#define MASK_DCINT_EP0TX	(1 << 11)
+#define MASK_DCINT_EP1RX	(1 << 12)
+#define MASK_DCINT_EP1TX	(1 << 13)
+#define MASK_DCINT_EP2RX	(1 << 14)
+#define MASK_DCINT_EP2TX	(1 << 15)
+#define MASK_DCINT_EP3RX	(1 << 16)
+#define MASK_DCINT_EP3TX	(1 << 17)
+#define MASK_DCINT_EP4RX	(1 << 18)
+#define MASK_DCINT_EP4TX	(1 << 19)
+#define MASK_DCINT_EP5RX	(1 << 20)
+#define MASK_DCINT_EP5TX	(1 << 21)
+#define MASK_DCINT_EP6RX	(1 << 22)
+#define MASK_DCINT_EP6TX	(1 << 23)
+#define MASK_DCINT_EP7RX	(1 << 24)
+#define MASK_DCINT_EP7TX	(1 << 25)
+
+#define MASK_DCINT_EP_EVENT		(0x03FFF000)
+#define MASK_DCINTENABLE_RELEVANT	0x00000DF9
+#define UNLOCK_CODE			0xAA37
+
+#define MASK_CTRL_STALL		(1 << 0)
+#define MASK_CTRL_STATUS	(1 << 1)
+#define MASK_CTRL_DSEN		(1 << 2)
+#define MASK_CTRL_VENDP		(1 << 3)
+#define MASK_CTRL_CLBUF		(1 << 4)
+
+#define TOTAL_FIFO_SIZE	4096
+
+#define IDX_EP0_SETUP	(1 << 5)
+#define DIR_TX	1
+#define DIR_RX	0
+
+#define SW_RESET_RESET_ATX	(1 << 3)
+#define SW_RESET_RESET_HC	(1 << 1)
+#define SW_RESET_RESET_ALL	(1 << 0)
+
+#define isp1763_readl(val)		readl(val)
+#define isp1763_writel(val, regs)	writel(val, regs)
+#define isp1763_readw(regs)		readw(regs)
+#define isp1763_writew(val, regs)	writew(val, regs)
+
+#define get_id_pin(dev) (!!(isp1763_readw(&dev->regs->otg_status) \
+				& MASK_OTGSTATUS_ID))
+
+enum id_status {
+	ID_PIN_HOST = 0,
+	ID_PIN_DEVICE,
+};
+
+enum role {
+	ROLE_HOST = 0,
+	ROLE_DEVICE,
+};
+
+#define queue_printk(args...)	/* printk(args) */
+#define info_printk(args...)	/* printk(args) */
+#define warn_printk(args...)	/* printk(args) */
+#define error_printk(args...)	/* printk(args) */
+#define debug_printk(args...)	/* printk(args) */
+
+int isp1763_otg_timer_start(otgtimer_callback_t cb, unsigned long timeout,
+			    void *data);
+void isp1763_otg_timer_cancel(void);
+int isp1763_register_ctrl(struct isp1763_controller *ctrl, int role);
+void isp1763_unregister_ctrl(int role);
+
+#define static_role(x) ((x & ISP1763_FLAG_PORT1_ROLE_OTG) \
+			!= ISP1763_FLAG_PORT1_ROLE_OTG)
+
+#define static_role_host(x) ((x & ISP1763_FLAG_PORT1_ROLE_OTG) \
+			== ISP1763_FLAG_PORT1_ROLE_HOST)
+
+#endif /* ! __ISP1763_H__ */
diff --git a/drivers/usb/isp1763/isp1763_base.c b/drivers/usb/isp1763/isp1763_base.c
new file mode 100644
index 0000000..6496b45
--- /dev/null
+++ b/drivers/usb/isp1763/isp1763_base.c
@@ -0,0 +1,992 @@
+/*
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Description:
+ *
+ * ISP1763 BASE driver - common initialization and OTG support
+ *
+ * Originally being written for a simple bus powered device, this
+ * driver does not support or implement HRP or SRP.
+ *
+ * (c) 2010 F.A. Voegel, Carangul.Tech
+ * (c) 2010 I+ME ACTIA GmbH
+ */
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/io.h>
+#include <linux/workqueue.h>
+#include <linux/gpio.h>
+
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include "../core/hcd.h" /* NOTE: new kernel: #include <linux/usb/hcd.h> */
+#include <linux/sched.h>
+#include <linux/kthread.h>
+
+#ifdef CONFIG_PPC_OF
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#endif
+
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif
+
+#include <linux/usb/isp1763.h>
+#include <linux/platform_device.h>
+
+/* FIXME: Cleanup if it is not breaking anything, comment out now just in case
+* #include <asm/byteorder.h>
+* #include <asm/dma.h>
+* #include <asm/system.h>
+*/
+
+#include "isp1763.h"
+#include "isp1763_udc.h"
+#include "isp1763_hcd.h"
+
+static struct isp1763_dev *ispdev;
+
+
+#define DRIVER_NAME "isp1763"
+static const char driver_name[] = DRIVER_NAME;
+static const char driver_desc[] = "ISP 1763A device controller driver";
+static struct task_struct *otgtask;
+static char *role[] = { "HOST", "PERIPHERAL" };
+
+/**
+ * otg_set_role - set/switch role between host and device
+ * @dev: isp1763_dev structure
+ * @role: role to switch to
+*/
+static void otg_set_role(struct isp1763_dev *dev, int role)
+{
+	unsigned long flags;
+	local_irq_save(flags);
+	if (role == ROLE_HOST) {
+		printk(KERN_ERR "%s() switching to HOST role\n", __func__);
+		isp1763_writel(0xFFFF << 16, &dev->regs->otg_ctrl);
+		isp1763_writel(MASK_OTGCTRL_VBUS_DRV |
+			       MASK_OTGCTRL_VBUS_CHRG |
+			       MASK_OTGCTRL_DM_PULLDOWN |
+			       MASK_OTGCTRL_DP_PULLDOWN,
+			       &dev->regs->otg_ctrl);
+	}
+
+	else {
+		printk(KERN_ERR "%s() switching to PERIPHERAL role\n",
+			__func__);
+		isp1763_writel(0xFFFF << 16, &dev->regs->otg_ctrl);
+		isp1763_writel(MASK_OTGCTRL_SW_SEL_HC_DC |
+			       MASK_OTGCTRL_DP_PULLUP,
+			       &dev->regs->otg_ctrl);
+	}
+	dev->current_role = role;
+	local_irq_restore(flags);
+}
+
+static int isp1763_init_device(struct isp1763_dev *dev);
+
+/**
+* otg_role_switcher - role switch handling task
+* @data: pointer to struct isp1763_dev
+*/
+int otg_role_switcher(void *data)
+{
+	struct isp1763_dev *dev = data;
+	int prev_role = dev->current_role;
+	int id_pin;
+
+	set_current_state(TASK_RUNNING);
+	printk(KERN_ERR "%s starting up...\n", __func__);
+
+	do {
+
+		if (kthread_should_stop()) {
+			set_current_state(TASK_RUNNING);
+			break;
+		}
+
+		schedule_timeout_interruptible(1);
+
+		id_pin = get_id_pin(dev);
+		if (id_pin == dev->current_role)
+			continue;
+
+		printk(KERN_ERR "%s: init role change %s => %s\n", __func__,
+		       role[dev->current_role], role[id_pin]);
+
+
+		if (dev->ctrl[dev->current_role]) {
+			if (dev->ctrl[dev->current_role]->suspend)
+				printk(KERN_ERR "=> SUSPEND %s\n",
+				       role[dev->current_role]);
+				dev->ctrl[dev->current_role]->
+					suspend(dev->ctrl[dev->current_role]);
+		}
+
+		isp1763_init_device(dev);
+		otg_set_role(dev, id_pin);
+
+		if (dev->ctrl[dev->current_role]) {
+			if (dev->ctrl[dev->current_role]->resume) {
+				printk(KERN_ERR "=> RESUME %s\n",
+				       role[dev->current_role]);
+				dev->ctrl[dev->current_role]->
+					resume(dev->ctrl[dev->current_role]);
+				dev->ctrl[dev->current_role]->
+					do_irq(dev->ctrl[dev->current_role],
+					       MASK_DCINT_VBUS);
+			}
+		}
+		prev_role = dev->current_role;
+
+	} while (1);
+	return 0;
+}
+
+/**
+ * otg_do_interrupt - Handle OTG interrupt
+ * @dev: pointer to isp1763_dev struct
+*/
+static void otg_do_interrupt(struct isp1763_dev *dev, u32 latch)
+{
+
+	if ((latch & MASK_OTGSTATUS_ID)
+	    && !static_role(dev->devflags)) {
+		wake_up_process(otgtask);
+	} else if (latch & MASK_OTGSTATUS_ID) {
+		printk(KERN_EMERG "Ignoring OTG event\n");
+	}
+	if (latch & MASK_OTGINTEN_TMR_TIMEOUT) {
+		if (dev->otgtimer_cb)
+			dev->otgtimer_cb(dev->otgtimer_data);
+	}
+}
+
+/**
+ * isp1763 - main IRQ handler
+ * @data: pointer to struct isp1763_dev
+ */
+static irqreturn_t isp1763_irq(int irq, void *data)
+{
+	struct isp1763_dev *dev = (struct isp1763_dev *) data;
+	u32 flags_hc;
+	u32 flags_dc;
+	u32 flags_otg;
+
+	isp1763_writew(UNLOCK_CODE, &dev->regs->unlock);
+
+	flags_dc  = isp1763_readl(&dev->regs->dc_interrupt);
+	isp1763_writel(flags_dc, &dev->regs->dc_interrupt);
+	flags_hc  = isp1763_readw(&dev->regs->hc_interrupt);
+	isp1763_writew(flags_hc, &dev->regs->hc_interrupt);
+	flags_otg = isp1763_readl(&dev->regs->otg_int_latch);
+	isp1763_writel(0xFFFF0000, &dev->regs->otg_int_latch);
+
+	/* printk(KERN_DEBUG "%.8lx %.4x %.8lx\n",
+	 * flags_dc, flags_hc, flags_otg);
+	 */
+
+	if (flags_otg)
+		otg_do_interrupt(dev, flags_otg);
+	if (dev->current_role == ROLE_HOST) {
+		if (flags_hc && dev->ctrl[ROLE_HOST]
+				/*&& dev->ctrl[ROLE_HOST]->do_irq*/)
+			dev->ctrl[ROLE_HOST]->
+				do_irq(dev->ctrl[ROLE_HOST], flags_hc);
+	} else {
+		if (flags_dc && dev->ctrl[ROLE_DEVICE]
+				/*&& dev->ctrl[ROLE_DEVICE]->do_irq*/)
+			dev->ctrl[ROLE_DEVICE]->
+				do_irq(dev->ctrl[ROLE_DEVICE], flags_dc);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static char *bustypes[] = {
+	"NAND", "Generic", "NOR", "SRAM"
+};
+
+/**
+ * isp1763_init_device - reset & initialize controller hardware
+ * @dev: pointer to struct isp1763_dev
+*/
+static int isp1763_init_device(struct isp1763_dev *dev)
+{
+	int i;
+	int ret = 0;
+	u16 hwmode =
+		MASK_HWMODECTRL_COMN_INT | MASK_HWMODECTRL_GLOBAL_INT_ENABLE;
+
+	mdelay(10);
+	/* Dummy reads to "stabilize host controller access" */
+	isp1763_readw(&dev->regs->chip_id);
+	isp1763_readw(&dev->regs->chip_id);
+	isp1763_readw(&dev->regs->chip_id);
+	mdelay(20);
+
+	if (dev->devflags & ISP1763_FLAG_BUS_WIDTH_8) {
+		hwmode |= MASK_HWMODECTRL_DATA_BUS_WIDTH;
+		printk(KERN_NOTICE "hwmode 8bit\n");
+	}
+	if (dev->devflags & ISP1763_FLAG_DACK_POL_HIGH) {
+		hwmode |= MASK_HWMODECTRL_DACK_POL;
+		printk(KERN_NOTICE "hwmode dack polarity high\n");
+	}
+	if (dev->devflags & ISP1763_FLAG_DREQ_POL_HIGH) {
+		hwmode |= MASK_HWMODECTRL_DREQ_POL;
+		printk(KERN_NOTICE "hwmode dreq polarity hight\n");
+	}
+	if (dev->devflags & ISP1763_FLAG_INTR_POL_HIGH) {
+		hwmode |= MASK_HWMODECTRL_INTR_POLARITY;
+		printk(KERN_NOTICE "hwmode int polarity high\n");
+	}
+	if (dev->devflags & ISP1763_FLAG_INTR_EDGE_TRIG) {
+		hwmode |= MASK_HWMODECTRL_INTR_EDGE;
+		printk(KERN_NOTICE "hwmode int edge triggered\n");
+	}
+	if (static_role(dev->devflags)) {
+		hwmode |= MASK_HWMODECTRL_ID_PU_DISABLE;
+		printk(KERN_NOTICE "hwmode pullup disable\n");
+	}
+
+	hwmode &= ~MASK_HWMODECTRL_INTR_POLARITY;
+	hwmode &= ~MASK_HWMODECTRL_INTR_EDGE;
+	isp1763_writew(hwmode, &dev->regs->hwmodectrl);
+	isp1763_writew(hwmode, &dev->regs->hwmodectrl);
+
+	if (isp1763_readl(&dev->regs->chip_id) != ISP_CHIP_ID) {
+		printk(KERN_ERR
+		       "Error: ISP1763 chip ID wrong! (%.8x, expected %.8lx)\n",
+		       isp1763_readl(&dev->regs->chip_id), ISP_CHIP_ID);
+		ret = -EIO;
+		goto out;
+	}
+
+	printk(KERN_NOTICE "%s: %s mode, %i bit bus width\n", DRIVER_NAME,
+	       bustypes[(isp1763_readw(&dev->regs->swreset) >> 6) & 0x3],
+	       isp1763_readw(&dev->regs->hwmodectrl) &
+				MASK_HWMODECTRL_DATA_BUS_WIDTH ? 8 : 16);
+
+	isp1763_writew(UNLOCK_CODE, &dev->regs->unlock);
+
+	printk(KERN_NOTICE "Resetting ISP1763...\n");
+	isp1763_writew(isp1763_readw(&dev->regs->swreset) | SW_RESET_RESET_ATX
+						| SW_RESET_RESET_ALL,
+						&dev->regs->swreset);
+	isp1763_writew(isp1763_readw(&dev->regs->mode) | MASK_MODE_SFRESET,
+		       &dev->regs->mode);
+	udelay(50);
+	isp1763_writew(isp1763_readw(&dev->regs->mode) &
+		       ~MASK_MODE_SFRESET, &dev->regs->mode);
+	mdelay(1);
+
+	isp1763_writew(UNLOCK_CODE, &dev->regs->unlock);
+
+	if (isp1763_readl(&dev->regs->chip_id) != ISP_CHIP_ID) {
+		printk(KERN_ERR
+		       "Error: ISP1763 chip ID wrong after reset! "
+		       "(%.8x, expected %.8lx)\n",
+		       isp1763_readl(&dev->regs->chip_id), ISP_CHIP_ID);
+		ret = -EIO;
+		goto out;
+	}
+	printk(KERN_NOTICE "Reset done\n");
+
+	isp1763_writew(hwmode, &dev->regs->hwmodectrl);
+	isp1763_writew(MASK_HCINT_OTG, &dev->regs->hc_interrupt_enable);
+
+	/*
+	  You'd think there was one single way to configure the interrupt for
+	  this chip, but no. You have to independently configure both
+	  peripheral and host controller IRQs despite the settings obviously
+	  having to be the same...
+	*/
+	isp1763_writew(0xFC |
+		       ((ispdev->devflags & ISP1763_FLAG_INTR_EDGE_TRIG) >> 1)
+		       | (ispdev->devflags & ISP1763_FLAG_INTR_POL_HIGH),
+		       &dev->regs->icr);
+
+	/* data line test */
+	for (i = 0; i < 0x10000; i++) {
+		u16 readback = 0;
+		isp1763_writew(i, &dev->regs->scratch);
+		readback = isp1763_readw(&dev->regs->scratch);
+		if (readback != i) {
+			printk(KERN_ERR
+			       "ERROR: Scratch register write test failed: scratch=%.4x != i=%.4x!\n",
+			       readback, i);
+			ret = -EIO;
+			/*
+			* Don't break here, let us see the other errors too,
+			* helps with diagnosis
+			*/
+		}
+	}
+
+	isp1763_writew(1, &dev->regs->int_pulse_width);
+
+out:
+	return ret;
+}
+
+
+/** otg_setup - initialize ISP1763 OTG component
+  * @dev: isp1763_dev struture
+*/
+static int otg_setup(struct isp1763_dev *dev)
+{
+	int role = ROLE_DEVICE;
+
+	if (static_role_host(dev->devflags))
+		role = ROLE_HOST;
+	else
+		role = get_id_pin(dev);
+
+	printk(KERN_NOTICE "ISP1783 using %s mode\n",
+				static_role(dev->devflags) ?
+					(static_role_host(dev->devflags) ?
+						"host" : "device") : "otg");
+
+	otg_set_role(dev, role);
+
+	enable_glint(dev);
+	isp1763_writel(0xFFFF0000, &dev->regs->otg_int_enable_fall);
+	isp1763_writel(0xFFFF0000, &dev->regs->otg_int_enable_rise);
+	isp1763_writel(0xFFFFFFFF, &dev->regs->otg_int_latch);
+
+	isp1763_writel(MASK_OTGINTEN_ID | MASK_OTGINTEN_SESS_VALID |
+		       MASK_OTGINTEN_VBUS_VALID |
+		       MASK_OTGINTEN_TMR_TIMEOUT,
+		       &dev->regs->otg_int_enable_fall);
+
+	isp1763_writel(MASK_OTGINTEN_ID | MASK_OTGINTEN_SESS_VALID |
+		       MASK_OTGINTEN_VBUS_VALID |
+		       MASK_OTGINTEN_TMR_TIMEOUT,
+		       &dev->regs->otg_int_enable_rise);
+
+	ispdev->current_role = role;
+
+	return role;
+}
+
+/**
+* isp1763_otg_timer_start - start OTG timer in ISP1763
+* @cb: callback function
+* @timeout: timeout in multiples of 10 microseconds
+* @data: callback context data
+*/
+int isp1763_otg_timer_start(otgtimer_callback_t cb,
+				unsigned long timeout,
+				void *data)
+{
+	if (isp1763_readl(&ispdev->regs->otg_timer_hw) & 0x8000)
+		return -EBUSY;
+
+	ispdev->otgtimer_cb = cb;
+	ispdev->otgtimer_data = data;
+
+	isp1763_writel(0xFFFF0000, &ispdev->regs->otg_timer_lw);
+	isp1763_writel(0xFFFF0000, &ispdev->regs->otg_timer_hw);
+
+	isp1763_writel(timeout & 0xFFFF, &ispdev->regs->otg_timer_lw);
+	isp1763_writel(((timeout >> 16) & 0x7FFF) | 0x8000,
+			       &ispdev->regs->otg_timer_hw);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(isp1763_otg_timer_start);
+
+/**
+* isp1763_otg_timer_cancel - cancel running OTG timer
+*
+* No harm done if timer isn't actually running
+*/
+void isp1763_otg_timer_cancel(void)
+{
+	isp1763_writel(isp1763_readl(&ispdev->regs->otg_timer_hw) & 0x7FFF,
+		       &ispdev->regs->otg_timer_hw);
+	ispdev->otgtimer_cb = NULL;
+	ispdev->otgtimer_data = NULL;
+}
+EXPORT_SYMBOL_GPL(isp1763_otg_timer_cancel);
+
+/**
+* isp1763_register_ctrl - register a host or device controller driver
+* @ctrl: controller structure to register
+* @role: role for which to register driver
+*
+* Register a driver for a host or peripheral controller driver. After
+* registering, the driver's probe function will be called, and if OTG is
+* enabled and the current role matches the driver, it's resume function
+* will be called as well.
+*/
+int isp1763_register_ctrl(struct isp1763_controller *ctrl, int role)
+{
+	if (!ispdev)
+		return -ENODEV;
+
+	if (ispdev->ctrl[role]) {
+		printk(KERN_ERR
+		       "Trying to register driver for role %s which already has driver registered\n",
+		       role == ROLE_HOST ? "host" : "device");
+		return -EBUSY;
+	}
+	ispdev->ctrl[role] = ctrl;
+
+	ctrl->device = ispdev->dev;
+	ctrl->regs = ispdev->regs;
+
+	if (!ctrl->probe(ctrl) < 0)
+		return -ENODEV;
+
+	/* driver for the current role? resume right now. */
+	if (role == ispdev->current_role) {
+		printk(KERN_ERR "Registered %s as active driver\n",
+		       role == ROLE_HOST ? "host" : "device");
+		ctrl->resume(ctrl);
+	} else
+		printk(KERN_ERR "Registered %s as suspended driver\n",
+		       role == ROLE_HOST ? "host" : "device");
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(isp1763_register_ctrl);
+
+/**
+ * isp1763_unregister_ctrl - unregister a previously registered controller
+ * @role: role the controller filled
+ */
+void isp1763_unregister_ctrl(int _role)
+{
+	if (!ispdev->ctrl[_role]) {
+		printk(KERN_ERR "Failed to unregister driver for '%s'"
+				"controller\n", role[_role]);
+		return;
+	}
+
+	ispdev->ctrl[_role]->suspend(ispdev->ctrl[_role]);
+
+	if (ispdev->ctrl[_role]->remove)
+		ispdev->ctrl[_role]->remove(ispdev->ctrl[_role]);
+
+	ispdev->ctrl[_role] = NULL;
+}
+EXPORT_SYMBOL_GPL(isp1763_unregister_ctrl);
+
+/*******************************************/
+/* module init / exit / probe related code */
+/*******************************************/
+
+
+/**
+* isp1763_common_init - common module init
+* @dev: struct device pointer passed from probe function
+* @devflags: hardware flags as determined by calling probe function
+* @irq: IRQ number to use
+* @res: ISP1763 register memory resource pointer
+* @res_len: length of resources
+*
+* Called by all probe functions to initialize the hardware and setup data
+* structures.
+*/
+static int isp1763_common_init(struct device *dev,
+				unsigned long devflags,
+				int irq,
+				struct resource *res,
+				resource_size_t res_len)
+{
+	int ret = 0;
+
+	ispdev = kzalloc(sizeof(struct isp1763_dev), GFP_KERNEL);
+	if (!ispdev) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	printk(KERN_ERR "devflags passed by probe: 0x%.8lx\n", devflags);
+
+	ispdev->irq = irq;
+	ispdev->devflags = devflags;
+	ispdev->regs = ioremap(res->start, res_len);
+
+	if (request_irq(ispdev->irq, isp1763_irq, IRQF_SHARED, "ISP1763 IRQ",
+							(void *) ispdev)) {
+		ret = -EIO;
+		goto error_free;
+	}
+
+	isp1763_init_device(ispdev);
+	otg_setup(ispdev);
+
+	/* Only start role switch thread if we're doing OTG */
+	if (!static_role(ispdev->devflags)) {
+		otgtask = kthread_create(otg_role_switcher, ispdev,
+							"isp1763otg");
+		if (otgtask)
+			wake_up_process(otgtask);
+	}
+
+	ispdev->dev = dev;
+
+	printk(KERN_INFO "%s initialization successfully\n", DRIVER_NAME);
+
+	return 0;
+error_free:
+	kfree(ispdev);
+error:
+	return ret;
+}
+
+#ifdef CONFIG_PPC_OF
+static int __devinit isp1763_of_probe(struct of_device *dev,
+					const struct of_device_id *match)
+{
+	struct device_node *np = dev->node;
+	const u32 *prop;
+	int ret = 0;
+	unsigned long devflags = 0;
+	struct resource *res;
+	struct resource memory;
+	int irq;
+	resource_size_t res_len;
+	const char *port1_role = NULL;
+
+	prop = of_get_property(np, "bus-width", NULL);
+	if (prop && be32_to_cpu(*prop) == 8)
+		devflags |= ISP1763_FLAG_BUS_WIDTH_8;
+
+	port1_role = of_get_property(np, "port1-role", NULL);
+	if (port1_role) {
+		printk(KERN_ERR "PORT1 OTG setting: %s\n", port1_role);
+		if (strcmp(port1_role, "otg") == 0)
+			devflags |= ISP1763_FLAG_PORT1_ROLE_OTG;
+		else if (strcmp(port1_role, "host") == 0)
+			devflags |= ISP1763_FLAG_PORT1_ROLE_HOST;
+		else
+			devflags |= ISP1763_FLAG_PORT1_ROLE_GADGET;
+	} else
+		devflags |= ISP1763_FLAG_PORT1_ROLE_GADGET;
+
+	if (of_get_property(np, "dack-polarity-high", NULL) != NULL)
+		devflags |= ISP1763_FLAG_DACK_POL_HIGH;
+
+	if (of_get_property(np, "dreq-polarity-high", NULL) != NULL)
+		devflags |= ISP1763_FLAG_DREQ_POL_HIGH;
+
+	if (of_get_property(np, "intr-polarity-high", NULL) != NULL)
+		devflags |= ISP1763_FLAG_INTR_POL_HIGH;
+
+	if (of_get_property(np, "intr-edge-trig", NULL) != NULL)
+		devflags |= ISP1763_FLAG_INTR_EDGE_TRIG;
+
+	irq = irq_of_parse_and_map(np, 0);
+
+	if (irq == NO_IRQ) {
+		pr_warning("of_isp1763: no interrupt!\n");
+		ret = -EIO;
+		goto error_out;
+	}
+
+	ret = of_address_to_resource(np, 0, &memory);
+	if (ret) {
+		pr_warning("of_isp1763: Memory resource not available\n");
+		goto error_out;
+	}
+
+	res_len = resource_size(&memory);
+
+	res = request_mem_region(memory.start, res_len, dev_name(&dev->dev));
+	if (!res) {
+		pr_warning
+		    ("of_isp1763: Cannot reserve the memory resource\n");
+		return -EBUSY;
+	}
+
+	return isp1763_common_init(&dev->dev, devflags, irq, res, res_len);
+
+error_out:
+	return ret;
+}
+
+static int __devexit isp1763_of_remove(struct of_device *ofdev)
+{
+
+	/* HCD specific removal */
+	struct usb_hcd *hcd = dev_get_drvdata(&ofdev->dev);
+
+	dev_set_drvdata(&ofdev->dev, NULL);
+
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+
+	/* TODO: Any UDC specific removal? */
+
+	/* Common operation for all */
+	free_irq(ispdev->irq, ispdev);
+	kfree(ispdev);
+	return 0;
+}
+
+
+static struct of_device_id __devinitdata isp1763_match[] = {
+	{
+	 .compatible = "st,usb-isp1763",
+	 .compatible = "nxp,usb-isp1763",
+	 },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, isp1763_match);
+
+static struct of_platform_driver isp1763_driver = {
+	.name = driver_name,
+	.match_table = isp1763_match,
+	.probe = isp1763_of_probe,
+	.remove = __devexit_p(isp1763_of_remove),
+};
+
+#endif /* CONFIG_PPC_OF */
+
+
+/******************************************************************/
+/* PCI PROBE                                                      */
+/******************************************************************/
+
+#ifdef CONFIG_PCI
+static int __devinit isp1763_pci_probe(struct pci_dev *dev,
+				       const struct pci_device_id *id)
+{
+	u8 latency, limit;
+	__u32 reg_data;
+	int retry_count;
+	unsigned int devflags = 0;
+	int ret_status = 0;
+
+	resource_size_t pci_mem_phy0;
+	resource_size_t memlength;
+
+	u8 __iomem *chip_addr;
+	u8 __iomem *iobase;
+	resource_size_t nxp_pci_io_base;
+	resource_size_t iolength;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	if (pci_enable_device(dev) < 0)
+		return -ENODEV;
+
+	if (!dev->irq)
+		return -ENODEV;
+
+	/* Grab the PLX PCI mem maped port start address we need  */
+	nxp_pci_io_base = pci_resource_start(dev, 0);
+	iolength = pci_resource_len(dev, 0);
+
+	if (!request_mem_region
+	    (nxp_pci_io_base, iolength, "ISP1763 IO MEM")) {
+		printk(KERN_ERR "request region #1\n");
+		return -EBUSY;
+	}
+
+	iobase = ioremap(nxp_pci_io_base, iolength);
+	if (!iobase) {
+		printk(KERN_ERR "ioremap #1\n");
+		ret_status = -ENOMEM;
+		goto cleanup1;
+	}
+	/* Grab the PLX PCI shared memory of the ISP 1763 we need  */
+	pci_mem_phy0 = pci_resource_start(dev, 3);
+	memlength = pci_resource_len(dev, 3);
+	if (memlength < 0xffff) {
+		printk(KERN_ERR
+		       "memory length for this resource is wrong\n");
+		ret_status = -ENOMEM;
+		goto cleanup2;
+	}
+
+	if (!request_mem_region(pci_mem_phy0, memlength, "ISP-PCI")) {
+		printk(KERN_ERR "host controller already in use\n");
+		ret_status = -EBUSY;
+		goto cleanup2;
+	}
+
+	/* map available memory */
+	chip_addr = ioremap_nocache(pci_mem_phy0, memlength);
+	if (!chip_addr) {
+		printk(KERN_ERR "Error ioremap failed\n");
+		ret_status = -ENOMEM;
+		goto cleanup3;
+	}
+
+	/* bad pci latencies can contribute to overruns */
+	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
+	if (latency) {
+		pci_read_config_byte(dev, PCI_MAX_LAT, &limit);
+		if (limit && limit < latency)
+			pci_write_config_byte(dev, PCI_LATENCY_TIMER,
+					      limit);
+	}
+
+	/* Try to check whether we can access Scratch Register of
+	 * Host Controller or not. The initial PCI access is retried until
+	 * local init for the PCI bridge is completed
+	 */
+	retry_count = 20;
+	reg_data = 0;
+	while ((reg_data != 0xFACE) && retry_count) {
+		/*by default host is in 16bit mode, so
+		 * io operations at this stage must be 16 bit
+		 * */
+		writel(0xface, chip_addr + HC_SCRATCH_REG);
+		udelay(100);
+		reg_data = readl(chip_addr + HC_SCRATCH_REG) & 0x0000ffff;
+		retry_count--;
+	}
+
+	iounmap(chip_addr);
+
+	/* Host Controller presence is detected by writing to scratch register
+	 * and reading back and checking the contents are same or not
+	 */
+	if (reg_data != 0xFACE) {
+		dev_err(&dev->dev, "scratch register mismatch %x\n",
+			reg_data);
+		ret_status = -ENOMEM;
+		goto cleanup3;
+	}
+
+	pci_set_master(dev);
+
+	/* configure PLX PCI chip to pass interrupts */
+#define PLX_INT_CSR_REG 0x68
+	reg_data = readl(iobase + PLX_INT_CSR_REG);
+	reg_data |= 0x900;
+	writel(reg_data, iobase + PLX_INT_CSR_REG);
+
+	dev->dev.dma_mask = NULL;
+
+	/* FIXME: Is there a better way than assuming this? */
+	devflags |= ISP1763_FLAG_PORT1_ROLE_HOST;
+
+	if (isp1763_common_init(&dev->dev, devflags, dev->irq,
+				(void *) pci_mem_phy0, memlength) < 0)
+		goto cleanup3;
+
+	/* done with PLX IO access */
+	iounmap(iobase);
+	release_mem_region(nxp_pci_io_base, iolength);
+
+	return 0;
+
+cleanup3:
+	release_mem_region(pci_mem_phy0, memlength);
+cleanup2:
+	iounmap(iobase);
+cleanup1:
+	release_mem_region(nxp_pci_io_base, iolength);
+	return ret_status;
+}
+
+static void isp1763_pci_remove(struct pci_dev *dev)
+{
+	struct usb_hcd *hcd;
+
+	hcd = pci_get_drvdata(dev);
+	pci_disable_device(dev);
+}
+
+static void isp1763_pci_shutdown(struct pci_dev *dev)
+{
+	printk(KERN_ERR "ips1763_pci_shutdown\n");
+}
+
+static const struct pci_device_id isp1763_plx[] = {
+	{
+	 .class = PCI_CLASS_BRIDGE_OTHER << 8,
+	 .class_mask = ~0,
+	 .vendor = PCI_VENDOR_ID_PLX,
+	 .device = 0x5406,
+	 .subvendor = PCI_VENDOR_ID_PLX,
+	 .subdevice = 0x9054,
+	 },
+	{}
+};
+
+MODULE_DEVICE_TABLE(pci, isp1763_plx);
+
+static struct pci_driver isp1763_pci_driver = {
+	.name = "isp1763",
+	.id_table = isp1763_plx,
+	.probe = isp1763_pci_probe,
+	.remove = isp1763_pci_remove,
+	.shutdown = isp1763_pci_shutdown,
+};
+#endif /* CONFIG_PCI */
+
+
+/******************************************************************/
+/* PLATFORM DEVICE PROBE                                          */
+/******************************************************************/
+
+static int __devexit isp1763_plat_remove(struct platform_device *pdev)
+{
+	struct resource *mem_res;
+	resource_size_t mem_size;
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	mem_size = resource_size(mem_res);
+	release_mem_region(mem_res->start, mem_size);
+
+	return 0;
+}
+
+static int __devinit isp1763_plat_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct resource *mem_res;
+	struct resource *irq_res;
+	resource_size_t mem_size;
+	struct isp1763_platform_data *priv = pdev->dev.platform_data;
+	unsigned int devflags = 0;
+	unsigned long irqflags = IRQF_SHARED | IRQF_DISABLED;
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem_res) {
+		pr_warning("isp1763: Memory resource not available\n");
+		ret = -ENODEV;
+		goto out;
+	}
+	mem_size = resource_size(mem_res);
+	if (!request_mem_region(mem_res->start, mem_size, "isp1763")) {
+		pr_warning
+		    ("isp1763: Cannot reserve the memory resource\n");
+		ret = -EBUSY;
+		goto out;
+	}
+
+	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!irq_res) {
+		pr_warning("isp1763: IRQ resource not available\n");
+		return -ENODEV;
+	}
+	irqflags |= irq_res->flags & IRQF_TRIGGER_MASK;
+
+	if (priv) {
+		if (priv->bus_width_8)
+			devflags |= ISP1763_FLAG_BUS_WIDTH_8;
+		if (priv->port1_otg)
+			devflags |= ISP1763_FLAG_PORT1_ROLE_OTG;
+		else
+			/* TODO: add pure PERIPHERAL support */
+			devflags |= ISP1763_FLAG_PORT1_ROLE_HOST;
+		if (priv->dack_polarity_high)
+			devflags |= ISP1763_FLAG_DACK_POL_HIGH;
+		if (priv->dreq_polarity_high)
+			devflags |= ISP1763_FLAG_DREQ_POL_HIGH;
+		if (priv->intr_polarity_high)
+			devflags |= ISP1763_FLAG_INTR_POL_HIGH;
+		if (priv->intr_edge_trigger)
+			devflags |= ISP1763_FLAG_INTR_EDGE_TRIG;
+	}
+
+	if (isp1763_common_init(&pdev->dev, devflags, irq_res->start,
+						mem_res, mem_size) < 0)
+		goto cleanup;
+
+	pr_info("ISP1763 USB device initialised\n");
+	return ret;
+
+cleanup:
+	release_mem_region(mem_res->start, mem_size);
+out:
+	return ret;
+}
+
+static struct platform_driver isp1763_plat_driver = {
+	.probe = isp1763_plat_probe,
+	.remove = __devexit_p(isp1763_plat_remove),
+	.driver = {
+		.name = "isp1763",
+	},
+};
+
+static int __init isp1763_init(void)
+{
+	int ret = 0;
+	int any_ret = -ENODEV;
+
+
+	ret = platform_driver_register(&isp1763_plat_driver);
+	if (!ret)
+		any_ret = 0;
+
+#ifdef CONFIG_PPC_OF
+	ret = of_register_platform_driver(&isp1763_driver);
+	if (!ret)
+		any_ret = 0;
+#endif
+
+#ifdef CONFIG_PCI
+	ret = pci_register_driver(&isp1763_pci_driver);
+	if (!ret)
+		any_ret = 0;
+#endif
+
+	return any_ret;
+}
+
+static void __exit isp1763_exit(void)
+{
+#ifdef CONFIG_PPC_OF
+	of_unregister_platform_driver(&isp1763_driver);
+#endif
+
+#ifdef CONFIG_PCI
+	pci_unregister_driver(&isp1763_pci_driver);
+#endif
+
+	platform_driver_unregister(&isp1763_plat_driver);
+}
+
+module_init(isp1763_init);
+module_exit(isp1763_exit);
+
+MODULE_DESCRIPTION(DRIVER_NAME);
+MODULE_AUTHOR("F.A. Voegel, Carangul.Tech");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/isp1763/isp1763_hcd.c b/drivers/usb/isp1763/isp1763_hcd.c
new file mode 100644
index 0000000..f0a0d7a
--- /dev/null
+++ b/drivers/usb/isp1763/isp1763_hcd.c
@@ -0,0 +1,2378 @@
+/*
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Description:
+ *
+ * isp1763 Host Controller Driver
+ *
+ * Based on isp1760 driver by Sebastian Siewior <bigeasy@xxxxxxxxxxxxx> and
+ * pehci hcd from ST-Ericsson wired support <wired.support@xxxxxxxxxxxxxx>
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <asm/unaligned.h>
+#include <asm/cacheflush.h>
+
+#include "../core/hcd.h"
+#include "../core/hub.h"
+#include "isp1763.h"
+#include "isp1763_hcd.h"
+
+
+static struct kmem_cache *qtd_cachep;
+static struct kmem_cache *qh_cachep;
+
+static inline struct isp1763_hcd *hcd_to_priv(struct usb_hcd *hcd)
+{
+	return (struct isp1763_hcd *) (hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *priv_to_hcd(struct isp1763_hcd *priv)
+{
+	return container_of((void *) priv, struct usb_hcd, hcd_priv);
+}
+
+/**
+ * isp1763_read_mem - read HC descriptor+payload memory
+ * @hcd: the usb_hcd handle (needed to know the device base address)
+ * @srcaddr: the source (start) address where the data reside on the hcd device
+ * @dstpt: the destination where we want to store the data
+ * @len: the length of the data
+ */
+static void isp1763_read_mem(struct usb_hcd *hcd,
+			     u16 srcaddr, u16 *dstptr, u32 len)
+{
+	if (!hcd || !dstptr || len <= 0) {
+		printk(KERN_ERR "ERROR: hcd: %p dstptr: %p len: %d\n",
+		       hcd, dstptr, len);
+		return;
+	}
+
+	/* Write the starting device address to the hcd memory register */
+	isp1763_writew(srcaddr, hcd->regs + HC_MEMORY_REG);
+
+	/* As long there are at least 16-bit to read ... */
+	while (len >= 2) {
+		*dstptr = __raw_readw(hcd->regs + HC_DATA_REG);
+		len -= 2;	/* Adjust len */
+		dstptr++;	/* Set dest data pointer to its next address */
+	}
+
+	/* If there are no more bytes to read, return */
+	if (len <= 0)
+		return;
+
+	*((u8 *) dstptr) = (u8) (readw(hcd->regs + HC_DATA_REG) & 0xFF);
+}
+
+/**
+ * isp1763_write_mem - write HC descriptor+payload memory
+ * @hcd: the usb_hcd handle (needed to know the device base address)
+ * @dataptr: the source of the data we want to write
+ * @dstaddr: the desitnation (start) address where data is to be written
+ * @len: the length of the data
+ */
+static void isp1763_write_mem(struct usb_hcd *hcd,
+			      u16 *dataptr, u16 dstaddr, u32 len)
+{
+	if (!hcd || !dataptr || len <= 0) {
+		printk(KERN_ERR "ERROR: hcd: %p dataptr: %p len: %d\n",
+		       hcd, dataptr, len);
+		return;
+	}
+
+	isp1763_writew(dstaddr, hcd->regs + HC_MEMORY_REG);
+	while (len >= 2) {
+		__raw_writew(*dataptr, hcd->regs + HC_DATA_REG);
+		dataptr++;
+		len -= 2;
+	}
+
+	if (len <= 0)
+		return;
+
+	writew(*((u8 *) dataptr), hcd->regs + HC_DATA_REG);
+}
+
+/**
+ * init_memory - initialize HC memory management
+ * @priv: HC private data
+ *
+ * memory management of the 20kb payload on the chip from 0x1000 to 0x5fff
+ */
+static void init_memory(struct isp1763_hcd *priv)
+{
+	int i;
+	u32 payload;
+
+	payload = 0x1000;
+	for (i = 0; i < BLOCK_1_NUM; i++) {
+		priv->memory_pool[i].start = payload;
+		priv->memory_pool[i].size = BLOCK_1_SIZE;
+		priv->memory_pool[i].free = 1;
+		payload += priv->memory_pool[i].size;
+	}
+
+
+	for (i = BLOCK_1_NUM; i < BLOCK_1_NUM + BLOCK_2_NUM; i++) {
+		priv->memory_pool[i].start = payload;
+		priv->memory_pool[i].size = BLOCK_2_SIZE;
+		priv->memory_pool[i].free = 1;
+		payload += priv->memory_pool[i].size;
+	}
+
+
+	for (i = BLOCK_1_NUM + BLOCK_2_NUM; i < BLOCKS; i++) {
+		priv->memory_pool[i].start = payload;
+		priv->memory_pool[i].size = BLOCK_3_SIZE;
+		priv->memory_pool[i].free = 1;
+		payload += priv->memory_pool[i].size;
+	}
+
+	BUG_ON(payload - priv->memory_pool[i - 1].size > PAYLOAD_SIZE);
+}
+
+/**
+ * alloc_mem - allocate HC-internal memory for payload data
+ * @priv: HC private data
+ * @size: size of memory chunk to allocate
+ *
+ * memory management of the 20kb payload on the chip from 0x1000 to 0x5fff
+ */
+static u32 alloc_mem(struct isp1763_hcd *priv, u32 size)
+{
+	int i;
+
+	if (!size)
+		return ISP1763_NULL_POINTER;
+
+	for (i = 0; i < BLOCKS; i++) {
+		if (priv->memory_pool[i].size >= size &&
+		    priv->memory_pool[i].free) {
+
+			priv->memory_pool[i].free = 0;
+			return priv->memory_pool[i].start;
+		}
+	}
+
+	printk(KERN_ERR
+	       "ISP1763 MEM: can not allocate %d bytes of memory\n",
+	       size);
+	printk(KERN_ERR "Current memory map:\n");
+	for (i = 0; i < BLOCKS; i++) {
+		printk(KERN_ERR "Pool %2d size %4d status: %d\n",
+		       i,
+		       priv->memory_pool[i].size,
+		       priv->memory_pool[i].free);
+	}
+	/* XXX maybe -ENOMEM could be possible */
+	BUG();
+	return 0;
+}
+
+/**
+ * free_mem - free previously allocated HC-internal memory
+ * @priv: HC private data
+ * @mem: offset of memory block to free
+ */
+static void free_mem(struct isp1763_hcd *priv, u32 mem)
+{
+	int i;
+
+	if (mem == ISP1763_NULL_POINTER)
+		return;
+
+	for (i = 0; i < BLOCKS; i++) {
+		if (priv->memory_pool[i].start == mem) {
+
+			BUG_ON(priv->memory_pool[i].free);
+
+			priv->memory_pool[i].free = 1;
+			return;
+		}
+	}
+
+	printk(KERN_ERR "Trying to free not-here-allocated memory :%08x\n",
+	       mem);
+	BUG();
+}
+
+/**
+ * isp1763_init_regs - initialize registers
+ * @hcd: the usb_hcd handle
+ */
+static void isp1763_init_regs(struct usb_hcd *hcd)
+{
+	isp1763_writew(0, hcd->regs + HC_BUFFER_STATUS_REG);
+
+	isp1763_writew(NO_TRANSFER_ACTIVE,
+		       hcd->regs + HC_ATL_PTD_SKIPMAP_REG);
+	isp1763_writew(NO_TRANSFER_ACTIVE,
+		       hcd->regs + HC_INT_PTD_SKIPMAP_REG);
+	isp1763_writew(NO_TRANSFER_ACTIVE,
+		       hcd->regs + HC_ISO_PTD_SKIPMAP_REG);
+
+	isp1763_writew((u16) (~NO_TRANSFER_ACTIVE),
+		       hcd->regs + HC_ATL_PTD_DONEMAP_REG);
+	isp1763_writew((u16) (~NO_TRANSFER_ACTIVE),
+		       hcd->regs + HC_INT_PTD_DONEMAP_REG);
+	isp1763_writew((u16) (~NO_TRANSFER_ACTIVE),
+		       hcd->regs + HC_ISO_PTD_DONEMAP_REG);
+}
+
+/**
+ * handshake - wait for bitmask to be set in register
+ * @priv: hc private data
+ * @ptr: pointer to memory-mapped register to read
+ * @mask: mask to apply to register (bitwise AND)
+ * @done: expected result of masked register contents
+ * @usec: timeout in microseconds
+ *
+ * WARNING!
+ * This handshake() function should only be used for 32-bit registers
+ * All the accesses so far seems okay for isp1763, since they only access the
+ * standard EHCI regs, which are all 32-bit.
+ */
+static int handshake(struct isp1763_hcd *priv, void __iomem * ptr,
+		     u32 mask, u32 done, int usec)
+{
+	u32 result;
+
+	do {
+		result = isp1763_readl(ptr);
+		if (result == ~0)
+			return -ENODEV;
+		result &= mask;
+		if (result == done)
+			return 0;
+		udelay(1);
+		usec--;
+	} while (usec > 0);
+
+	return -ETIMEDOUT;
+}
+
+/**
+ * ehci_reset - reset EHCI registers
+ * @priv: HC private data
+ *
+ * reset a non-running (STS_HALT == 1) controller
+*/
+static int ehci_reset(struct isp1763_hcd *priv)
+{
+	int retval;
+	struct usb_hcd *hcd = priv_to_hcd(priv);
+	u32 command = isp1763_readl(hcd->regs + HC_USBCMD);
+
+	command |= CMD_RESET;
+	isp1763_writel(command, hcd->regs + HC_USBCMD);
+	hcd->state = HC_STATE_HALT;
+	priv->next_statechange = jiffies;
+	retval = handshake(priv, hcd->regs + HC_USBCMD,
+			   CMD_RESET, 0, 250 * 1000);
+	return retval;
+}
+
+static void qh_destroy(struct isp1763_qh *qh)
+{
+	BUG_ON(!list_empty(&qh->qtd_list));
+	kmem_cache_free(qh_cachep, qh);
+}
+
+static struct isp1763_qh *isp1763_qh_alloc(struct isp1763_hcd *priv,
+							gfp_t flags)
+{
+	struct isp1763_qh *qh;
+
+	qh = kmem_cache_zalloc(qh_cachep, flags);
+	if (!qh)
+		return qh;
+
+	INIT_LIST_HEAD(&qh->qtd_list);
+	qh->priv = priv;
+	return qh;
+}
+
+/**
+ * priv_init - one-time init, only for memory state
+ * @hcd: HC structure
+ */
+static int priv_init(struct usb_hcd *hcd)
+{
+	struct isp1763_hcd *priv = hcd_to_priv(hcd);
+	u32 hcc_params = HCC_HARDCODE;	/* Use hardcoded value */
+
+	spin_lock_init(&priv->lock);
+
+	/*
+	 * hw default: 1K periodic list heads, one per frame.
+	 * periodic_size can shrink by USBCMD update if hcc_params allows.
+	 */
+	priv->periodic_size = DEFAULT_I_TDPS;
+
+	/* full frame cache */
+	if (HCC_ISOC_CACHE(hcc_params))
+		priv->i_thresh = 8;
+	else			/* N microframes cached */
+		priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
+
+	return 0;
+}
+
+/**
+ * isp1763_hc_setup - setup host controller
+ * @hcd: host controller structure
+ *
+ * Fill registers with initial values and reset EHCI controller, enable IRQs
+ */
+static int isp1763_hc_setup(struct usb_hcd *hcd)
+{
+	struct isp1763_hcd *priv = hcd_to_priv(hcd);
+	int result;
+
+	isp1763_init_regs(hcd);
+
+	isp1763_writew(isp1763_readw(hcd->regs + HC_RESET_REG) |
+						SW_RESET_RESET_HC,
+		       hcd->regs + HC_RESET_REG);
+	result = ehci_reset(priv);
+	if (result)
+		return result;
+
+	isp1763_info(priv, "bus width: %d\n",
+		     (priv->devflags & ISP1763_FLAG_BUS_WIDTH_8) ? 8 : 16);
+
+	isp1763_dbg(priv, "hwmode: 0x%04X\n",
+		    isp1763_readw(hcd->regs + HC_HW_MODE_CTRL));
+
+	isp1763_writew(INTERRUPT_ENABLE_MASK,
+		       hcd->regs + HC_INTERRUPT_REG);
+	isp1763_writew(INTERRUPT_ENABLE_MASK,
+		       hcd->regs + HC_INTERRUPT_ENABLE);
+
+	/* This chip does not have HCSPARAMS register, use a hardcoded value. */
+	priv->hcs_params = HCS_HARDCODE;
+
+	return priv_init(hcd);
+}
+
+static void isp1763_init_maps(struct usb_hcd *hcd)
+{
+	/* Set last maps, for iso its only 1, else 16 tds bitmap */
+	isp1763_writew(0x8000, hcd->regs + HC_ATL_PTD_LASTPTD_REG);
+	isp1763_writew(0x8000, hcd->regs + HC_INT_PTD_LASTPTD_REG);
+	isp1763_writew(0x0001, hcd->regs + HC_ISO_PTD_LASTPTD_REG);
+}
+
+static void isp1763_enable_interrupts(struct usb_hcd *hcd)
+{
+	isp1763_writew(0x0000, hcd->regs + HC_ATL_IRQ_MASK_AND_REG);
+	isp1763_writew(0x0000, hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+	isp1763_writew(0x0000, hcd->regs + HC_INT_IRQ_MASK_AND_REG);
+	isp1763_writew(0x0000, hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+	isp1763_writew(0x0000, hcd->regs + HC_ISO_IRQ_MASK_AND_REG);
+	isp1763_writew(0xffff, hcd->regs + HC_ISO_IRQ_MASK_OR_REG);
+}
+
+static int isp1763_run(struct usb_hcd *hcd)
+{
+	struct isp1763_hcd *priv = hcd_to_priv(hcd);
+	int retval;
+	u16 temp;
+	u32 command;
+	u32 chipid;
+
+
+	hcd->uses_new_polling = 1;
+	hcd->poll_rh = 0;
+	hcd->state = HC_STATE_RUNNING;
+
+	isp1763_enable_interrupts(hcd);
+	temp = isp1763_readw(hcd->regs + HC_HW_MODE_CTRL);
+	isp1763_writew(temp | HW_GLOBAL_INTR_EN,
+		       hcd->regs + HC_HW_MODE_CTRL);
+
+	command = isp1763_readl(hcd->regs + HC_USBCMD);
+	command &= ~(CMD_LRESET | CMD_RESET);
+	command |= CMD_RUN;
+	isp1763_writel(command, hcd->regs + HC_USBCMD);
+
+	retval = handshake(priv, hcd->regs + HC_USBCMD, CMD_RUN, CMD_RUN,
+			   250 * 1000);
+	if (retval)
+		return retval;
+
+	down_write(&ehci_cf_port_reset_rwsem);
+	isp1763_writel(FLAG_CF, hcd->regs + HC_CONFIGFLAG);
+
+	retval = handshake(priv, hcd->regs + HC_CONFIGFLAG, FLAG_CF, FLAG_CF,
+								250 * 1000);
+	up_write(&ehci_cf_port_reset_rwsem);
+	if (retval)
+		return retval;
+
+	chipid = isp1763_readl(hcd->regs + HC_CHIP_ID_REG);
+	isp1763_info(priv, "USB ISP %04x HW rev. %d started\n",
+		     ((chipid & 0x00ffff00) >> 8), (chipid & 0x000000ff));
+
+	/* PTD Register Init Part 2, Step 28 */
+	/* enable INTs */
+	isp1763_init_maps(hcd);
+
+	return 0;
+}
+
+static inline u32 base_to_chip(u32 base)
+{
+	u32 chipaddr = ((base - 0x400) >> 3);
+	return chipaddr;
+}
+
+static void transform_into_atl(struct isp1763_hcd *priv,
+			       struct isp1763_qh *qh,
+			       struct isp1763_qtd *qtd, struct urb *urb,
+			       u32 payload, struct ptd *ptd)
+{
+	u32 dw0;
+	u32 dw1;
+	u32 dw2;
+	u32 dw3;
+	u32 maxpacket;
+	u32 multi;
+	u32 pid_code;
+	u32 rl = RL_COUNTER;
+	u32 nak = NAK_COUNTER;
+
+	/* according to 3.6.2, max packet len can not be > 0x400 */
+	maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	multi = 1 + ((maxpacket >> 11) & 0x3);
+	maxpacket &= 0x7ff;
+
+	dw0 = PTD_VALID;
+	dw0 |= PTD_LENGTH(qtd->length);
+	dw0 |= PTD_MAXPACKET(maxpacket);
+	dw0 |= PTD_ENDPOINT(usb_pipeendpoint(urb->pipe));
+	dw1 = usb_pipeendpoint(urb->pipe) >> 1;
+
+	dw1 |= PTD_DEVICE_ADDR(usb_pipedevice(urb->pipe));
+
+	pid_code = qtd->packet_type;
+	dw1 |= PTD_PID_TOKEN(pid_code);
+
+	if (usb_pipebulk(urb->pipe))
+		dw1 |= PTD_TRANS_BULK;
+	else if (usb_pipeint(urb->pipe))
+		dw1 |= PTD_TRANS_INT;
+
+	if (urb->dev->speed != USB_SPEED_HIGH) {
+		/* split transaction */
+
+		dw1 |= PTD_TRANS_SPLIT;
+		if (urb->dev->speed == USB_SPEED_LOW)
+			dw1 |= PTD_SE_USB_LOSPEED;
+
+		dw1 |= PTD_PORT_NUM(urb->dev->ttport);
+		dw1 |= PTD_HUB_NUM(urb->dev->tt->hub->devnum);
+
+		/* SE bit for Split INT transfers */
+		if (usb_pipeint(urb->pipe) &&
+		    (urb->dev->speed == USB_SPEED_LOW))
+			dw1 |= 2 << 16;
+
+		dw3 = 0;
+		rl = 0;
+		nak = 0;
+	} else {
+		dw0 |= PTD_MULTI(multi);
+		if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe))
+			dw3 = qh->ping;
+		else
+			dw3 = 0;
+	}
+
+	dw2 = 0;
+	dw2 |= PTD_DATA_START_ADDR(base_to_chip(payload));
+	dw2 |= PTD_RL_CNT(rl);
+	dw3 |= PTD_NAC_CNT(nak);
+
+	if (usb_pipecontrol(urb->pipe))
+		dw3 |= PTD_DATA_TOGGLE(qtd->toggle);
+	else
+		dw3 |= qh->toggle;
+
+
+	dw3 |= PTD_ACTIVE;
+	dw3 |= PTD_CERR(ERR_COUNTER);
+
+	memset((void *)ptd + (4 * sizeof(u32)), 0, (4 * sizeof(u32)));
+
+	ptd->dw0 = cpu_to_le32(dw0);
+	ptd->dw1 = cpu_to_le32(dw1);
+	ptd->dw2 = cpu_to_le32(dw2);
+	ptd->dw3 = cpu_to_le32(dw3);
+}
+
+static void transform_add_int(struct isp1763_hcd *priv,
+			      struct isp1763_qh *qh,
+			      struct isp1763_qtd *qtd, struct urb *urb,
+			      u32 payload, struct ptd *ptd)
+{
+	u32 maxpacket;
+	u32 multi;
+	u32 numberofusofs;
+	u32 i;
+	u32 usofmask, usof;
+	u32 period;
+
+	maxpacket =
+	    usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	multi = 1 + ((maxpacket >> 11) & 0x3);
+	maxpacket &= 0x7ff;
+	/* length of the data per uframe */
+	maxpacket = multi * maxpacket;
+
+	numberofusofs = urb->transfer_buffer_length / maxpacket;
+	if (urb->transfer_buffer_length % maxpacket)
+		numberofusofs += 1;
+
+	usofmask = 1;
+	usof = 0;
+	for (i = 0; i < numberofusofs; i++) {
+		usof |= usofmask;
+		usofmask <<= 1;
+	}
+
+	/* FIXME: Vendor code checks for:
+	 * if (urb->dev->speed != USB_SPEED_HIGH && usb_pipeint(urb->pipe))
+	 */
+	if (urb->dev->speed != USB_SPEED_HIGH) {
+		/* split */
+		ptd->dw5 = cpu_to_le32(0x1c);
+
+		if (qh->period >= 32)
+			period = qh->period / 2;
+		else
+			period = qh->period;
+
+	} else {
+
+		if (qh->period >= 8)
+			period = qh->period / 8;
+		else
+			period = qh->period;
+
+		if (period >= 32)
+			period = 16;
+
+		if (qh->period >= 8) {
+			/* millisecond period */
+			period = (period << 3);
+		} else {
+			/* usof based transfers */
+			/* minimum 4 usofs */
+			usof = 0x11;
+		}
+	}
+
+	ptd->dw2 |= cpu_to_le32(period);
+	ptd->dw4 = cpu_to_le32(usof);
+}
+
+static void transform_into_int(struct isp1763_hcd *priv,
+			       struct isp1763_qh *qh,
+			       struct isp1763_qtd *qtd, struct urb *urb,
+			       u32 payload, struct ptd *ptd)
+{
+	transform_into_atl(priv, qh, qtd, urb, payload, ptd);
+	transform_add_int(priv, qh, qtd, urb, payload, ptd);
+}
+
+static int qtd_fill(struct isp1763_qtd *qtd, void *databuffer, size_t len,
+		    u32 token)
+{
+	int count;
+
+	qtd->data_buffer = databuffer;
+	qtd->packet_type = GET_QTD_TOKEN_TYPE(token);
+	qtd->toggle = GET_DATA_TOGGLE(token);
+
+	if (len > HC_ATL_PL_SIZE)
+		count = HC_ATL_PL_SIZE;
+	else
+		count = len;
+
+	qtd->length = count;
+	return count;
+}
+
+static int check_error(struct ptd *ptd)
+{
+	int error = 0;
+	u32 dw3;
+
+	dw3 = le32_to_cpu(ptd->dw3);
+	if (dw3 & DW3_HALT_BIT) {
+		error = -EPIPE;
+
+		if (dw3 & DW3_ERROR_BIT)
+			pr_err("error bit is set in DW3\n");
+	}
+
+	if (dw3 & DW3_QTD_ACTIVE) {
+		printk(KERN_ERR "transfer active bit is set DW3\n");
+		printk(KERN_ERR "nak counter: %d, rl: %d\n",
+		       (dw3 >> 19) & 0xf,
+		       (le32_to_cpu(ptd->dw2) >> 25) & 0xf);
+	}
+
+	return error;
+}
+
+static void check_int_err_status(u32 dw4)
+{
+	u32 i;
+
+	dw4 >>= 8;
+
+	for (i = 0; i < 8; i++) {
+		switch (dw4 & 0x7) {
+		case INT_UNDERRUN:
+			printk(KERN_ERR "ERROR: under run , %d\n", i);
+			break;
+
+		case INT_EXACT:
+			printk(KERN_ERR "ERROR: transaction error, %d\n",
+			       i);
+			break;
+
+		case INT_BABBLE:
+			printk(KERN_ERR "ERROR: babble error, %d\n", i);
+			break;
+		}
+		dw4 >>= 3;
+	}
+}
+
+static void enqueue_one_qtd(struct isp1763_qtd *qtd,
+			    struct isp1763_hcd *priv, u32 payload)
+{
+	u32 token;
+	struct usb_hcd *hcd = priv_to_hcd(priv);
+
+	token = qtd->packet_type;
+
+	if (qtd->length && (qtd->length <= HC_ATL_PL_SIZE)) {
+		switch (token) {
+		case IN_PID:
+			break;
+		case OUT_PID:
+		case SETUP_PID:
+			isp1763_write_mem(hcd, (u16 *) qtd->data_buffer,
+					  (u16) payload, qtd->length);
+		}
+	}
+}
+
+static void enqueue_one_atl_qtd(u32 atl_regs, u32 payload,
+				struct isp1763_hcd *priv,
+				struct isp1763_qh *qh, struct urb *urb,
+				u32 slot, struct isp1763_qtd *qtd)
+{
+	struct ptd ptd;
+	struct usb_hcd *hcd = priv_to_hcd(priv);
+
+
+	transform_into_atl(priv, qh, qtd, urb, payload, &ptd);
+	isp1763_write_mem(hcd, (u16 *) &ptd, atl_regs, sizeof(ptd));
+	enqueue_one_qtd(qtd, priv, payload);
+
+	priv->atl_ints[slot].urb = urb;
+	priv->atl_ints[slot].qh = qh;
+	priv->atl_ints[slot].qtd = qtd;
+	priv->atl_ints[slot].data_buffer = qtd->data_buffer;
+	priv->atl_ints[slot].payload = payload;
+	qtd->status |= URB_ENQUEUED | URB_TYPE_ATL;
+	qtd->status |= slot << 16;
+}
+
+static void enqueue_one_int_qtd(u32 int_regs, u32 payload,
+				struct isp1763_hcd *priv,
+				struct isp1763_qh *qh, struct urb *urb,
+				u32 slot, struct isp1763_qtd *qtd)
+{
+	struct ptd ptd;
+	struct usb_hcd *hcd = priv_to_hcd(priv);
+
+
+	transform_into_int(priv, qh, qtd, urb, payload, &ptd);
+	isp1763_write_mem(hcd, (u16 *) &ptd, int_regs, sizeof(ptd));
+	enqueue_one_qtd(qtd, priv, payload);
+
+	priv->int_ints[slot].urb = urb;
+	priv->int_ints[slot].qh = qh;
+	priv->int_ints[slot].qtd = qtd;
+	priv->int_ints[slot].data_buffer = qtd->data_buffer;
+	priv->int_ints[slot].payload = payload;
+	qtd->status |= URB_ENQUEUED | URB_TYPE_INT;
+	qtd->status |= slot << 16;
+}
+
+static void enqueue_an_ATL_packet(struct usb_hcd *hcd,
+				  struct isp1763_qh *qh,
+				  struct isp1763_qtd *qtd)
+{
+	struct isp1763_hcd *priv = hcd_to_priv(hcd);
+	u16 skip_map, or_map;
+	u16 queue_entry;
+	u32 slot;
+	u32 atl_regs, payload;
+	u16 buffstatus;
+
+	/*
+	 * When this function is called from the interrupt handler to enqueue
+	 * a follow-up packet, the SKIP register gets written and read back
+	 * almost immediately. With ISP1763, this register requires a delay of
+	 * 100ns between a write and subsequent read (see section 15.1.2).
+	 */
+	ndelay(100);
+
+	skip_map = isp1763_readw(hcd->regs + HC_ATL_PTD_SKIPMAP_REG);
+	BUG_ON(!skip_map);
+
+	/* 32-bit to 16-bit adjustment */
+	slot = __ffs((u32) skip_map);
+	BUG_ON(slot > 16);	/* skip_map is only 16 bit */
+
+	queue_entry = 1 << slot;
+
+	atl_regs = ATL_REGS_OFFSET + slot * sizeof(struct ptd);
+
+	payload = alloc_mem(priv, qtd->length);
+
+	enqueue_one_atl_qtd(atl_regs, payload, priv, qh, qtd->urb, slot,
+			    qtd);
+
+	or_map = isp1763_readw(hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+	or_map |= queue_entry;
+	isp1763_writew(or_map, hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+
+	skip_map &= ~queue_entry;
+	isp1763_writew(skip_map, hcd->regs + HC_ATL_PTD_SKIPMAP_REG);
+
+	buffstatus = isp1763_readw(hcd->regs + HC_BUFFER_STATUS_REG);
+	buffstatus |= ATL_BUFFER;
+	isp1763_writew(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG);
+}
+
+static void enqueue_an_INT_packet(struct usb_hcd *hcd,
+				  struct isp1763_qh *qh,
+				  struct isp1763_qtd *qtd)
+{
+	struct isp1763_hcd *priv = hcd_to_priv(hcd);
+	u16 skip_map, or_map;
+	u16 queue_entry;
+	u32 slot;
+	u32 int_regs, payload;
+	u16 buffstatus;
+
+	/*
+	 * When this function is called from the interrupt handler to enqueue
+	 * a follow-up packet, the SKIP register gets written and read back
+	 * almost immediately. With ISP1763, this register requires a delay of
+	 * 100ns between a write and subsequent read (see section 15.1.2).
+	 */
+	ndelay(100);
+
+	skip_map = isp1763_readw(hcd->regs + HC_INT_PTD_SKIPMAP_REG);
+	BUG_ON(!skip_map);
+
+	/* 32-bit to 16-bit adjustment */
+	slot = __ffs((u32) skip_map);
+	BUG_ON(slot > 16);	/* skip_map is only 16 bit */
+
+	queue_entry = 1 << slot;
+
+	int_regs = INT_REGS_OFFSET + slot * sizeof(struct ptd);
+
+	payload = alloc_mem(priv, qtd->length);
+
+	enqueue_one_int_qtd(int_regs, payload, priv, qh, qtd->urb, slot,
+			    qtd);
+
+	or_map = isp1763_readw(hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+	or_map |= queue_entry;
+	isp1763_writew(or_map, hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+
+	skip_map &= ~queue_entry;
+	isp1763_writew(skip_map, hcd->regs + HC_INT_PTD_SKIPMAP_REG);
+
+	buffstatus = isp1763_readw(hcd->regs + HC_BUFFER_STATUS_REG);
+	buffstatus |= INT_BUFFER;
+	isp1763_writew(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG);
+}
+
+static void isp1763_urb_done(struct isp1763_hcd *priv, struct urb *urb,
+			     int status)
+__releases(priv->lock)
+__acquires(priv->lock)
+{
+	if (!urb->unlinked) {
+		if (status == -EINPROGRESS)
+			status = 0;
+	}
+
+	if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) != PIPE_CONTROL) {
+		void *ptr;
+		for (ptr = urb->transfer_buffer;
+		     ptr < urb->transfer_buffer + urb->transfer_buffer_length;
+		     ptr += PAGE_SIZE)
+			flush_dcache_page(virt_to_page(ptr));
+	}
+
+	/* complete() can reenter this HCD */
+	usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb);
+	spin_unlock(&priv->lock);
+	usb_hcd_giveback_urb(priv_to_hcd(priv), urb, status);
+	spin_lock(&priv->lock);
+}
+
+static void isp1763_qtd_free(struct isp1763_qtd *qtd)
+{
+	kmem_cache_free(qtd_cachep, qtd);
+}
+
+static struct isp1763_qtd *clean_this_qtd(struct isp1763_qtd *qtd)
+{
+	struct isp1763_qtd *tmp_qtd;
+
+	tmp_qtd = qtd->hw_next;
+	list_del(&qtd->qtd_list);
+	isp1763_qtd_free(qtd);
+	return tmp_qtd;
+}
+
+/*
+ * Remove this QTD from the QH list and free its memory. If this QTD
+ * isn't the last one than remove also his successor(s).
+ * Returns the QTD which is part of an new URB and should be enqueued.
+ */
+static struct isp1763_qtd *clean_up_qtdlist(struct isp1763_qtd *qtd)
+{
+	struct isp1763_qtd *tmp_qtd;
+	int last_one;
+
+	do {
+		tmp_qtd = qtd->hw_next;
+		last_one = qtd->status & URB_COMPLETE_NOTIFY;
+		list_del(&qtd->qtd_list);
+		isp1763_qtd_free(qtd);
+		qtd = tmp_qtd;
+	} while (!last_one && qtd);
+
+	return qtd;
+}
+
+/* NOTE:
+ * It seems that setting up two memory banks in the isp1760's code
+ * is merely for convenience's sake; right now trying with:
+ *
+ * 1. Setup up the memory register for the PTD
+ * 2. Copy PTD from device to the driver's PTD copy
+ * 3. Process the PTD data
+ * (later on)
+ * 4. Setup the memory register for the payload
+ * 5. Copy payload from device to the driver's payload space
+ *
+ * There may be a gotcha here if the isp1760 is taking advantage of the ISP_BANK
+ * ability to automatically increment the address per bank on consecutive access
+ * to the same bank; It does not seem so because atl_regs & payload are
+ * reassigned at every while(done_map) iteration.
+ */
+static void do_atl_int(struct usb_hcd *usb_hcd)
+{
+	struct isp1763_hcd *priv = hcd_to_priv(usb_hcd);
+	u16 done_map, skip_map;
+	struct ptd ptd;
+	struct urb *urb = NULL;
+	u32 atl_regs_base;
+	u32 atl_regs;
+	u32 queue_entry;
+	u32 payload;
+	u32 length;
+	u16 or_map;
+	u32 status = -EINVAL;
+	int error;
+	struct isp1763_qtd *qtd;
+	struct isp1763_qh *qh;
+	u32 rl;
+	u32 nakcount;
+	u16 buffstatus;
+
+	done_map = isp1763_readw(usb_hcd->regs + HC_ATL_PTD_DONEMAP_REG);
+
+	/* NOTE: Move inside while (done_map) at the beginning and remove the
+	 * skip_map read at the end of the loop?
+	 */
+	skip_map = isp1763_readw(usb_hcd->regs + HC_ATL_PTD_SKIPMAP_REG);
+
+	or_map = isp1763_readw(usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+	or_map &= ~done_map;
+	isp1763_writew(or_map, usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+
+	atl_regs_base = ATL_REGS_OFFSET;
+
+	while (done_map) {
+		u32 dw1;
+		u32 dw2;
+		u32 dw3;
+
+		status = 0;
+
+		/* 32-bit to 16-bit done_map adjustment */
+		queue_entry = __ffs((u32) done_map);
+		BUG_ON(queue_entry > 16);
+
+		done_map &= ~(1 << queue_entry);
+		skip_map |= 1 << queue_entry;
+
+		atl_regs =
+		    atl_regs_base + (queue_entry * sizeof(struct ptd));
+
+		urb = priv->atl_ints[queue_entry].urb;
+		qtd = priv->atl_ints[queue_entry].qtd;
+		qh = priv->atl_ints[queue_entry].qh;
+		payload = priv->atl_ints[queue_entry].payload;
+
+		if (!qh) {
+			printk(KERN_ERR "qh is 0\n");
+			continue;
+		}
+
+		memset(&ptd, 0, sizeof(ptd));
+		isp1763_read_mem(usb_hcd, (u16) atl_regs, (u16 *) &ptd,
+				 sizeof(u32)*4/*sizeof(ptd)*/);
+
+		dw1 = le32_to_cpu(ptd.dw1);
+		dw2 = le32_to_cpu(ptd.dw2);
+		dw3 = le32_to_cpu(ptd.dw3);
+		rl = (dw2 >> 25) & 0x0f;
+		nakcount = (dw3 >> 19) & 0xf;
+
+		/* Transfer Error, *but* active and no HALT -> reload */
+		if (unlikely((dw3 & DW3_ERROR_BIT) && (dw3 & DW3_QTD_ACTIVE) &&
+		    !(dw3 & DW3_HALT_BIT))) {
+
+			/* according to priv code, we have to
+			 * reload this one if trasfered bytes != requested bytes
+			 * else act like everything went smooth..
+			 * XXX This just doesn't feel right and hasn't
+			 * triggered so far.
+			 */
+
+			length = PTD_XFERRED_LENGTH(dw3);
+			printk(KERN_ERR
+			       "Should reload now.... transfered %d "
+			       "of %zu\n", length, qtd->length);
+			BUG();
+		}
+
+		if (unlikely(!nakcount && (dw3 & DW3_QTD_ACTIVE))) {
+			printk(KERN_NOTICE
+			       "Reloading ptd %p/%p... qh %p read: "
+			       "%d of %zu done: %08x cur: %08x\n", qtd,
+			       urb, qh, PTD_XFERRED_LENGTH(dw3),
+			       qtd->length, done_map, (1 << queue_entry));
+
+			/* RL counter = ERR counter */
+			dw3 &= ~(0xf << 19);
+			dw3 |= rl << 19;
+			dw3 &= ~(3 << (55 - 32));
+			dw3 |= ERR_COUNTER << (55 - 32);
+
+			/*
+			 * It is not needed to write skip map back because it
+			 * is unchanged. Just make sure that this entry is
+			 * unskipped once it gets written to the HW.
+			 */
+			skip_map &= ~(1 << queue_entry);
+			or_map = isp1763_readw(usb_hcd->regs +
+					       HC_ATL_IRQ_MASK_OR_REG);
+			or_map |= 1 << queue_entry;
+			isp1763_writew(or_map, usb_hcd->regs +
+				       HC_ATL_IRQ_MASK_OR_REG);
+
+			/* FIXME: Why isp1760 need 2 write_mem back-to-back? */
+			ptd.dw3 = cpu_to_le32(dw3);
+			isp1763_write_mem(usb_hcd, (u16 *) &ptd, atl_regs,
+					  sizeof(ptd));
+
+			ptd.dw0 |= cpu_to_le32(PTD_VALID);
+			isp1763_write_mem(usb_hcd, (u16 *) &ptd, atl_regs,
+					  sizeof(u32)/*sizeof(ptd)*/);
+
+			buffstatus = isp1763_readw(usb_hcd->regs +
+						   HC_BUFFER_STATUS_REG);
+			buffstatus |= ATL_BUFFER;
+			isp1763_writew(buffstatus, usb_hcd->regs +
+				       HC_BUFFER_STATUS_REG);
+			continue;
+		}
+
+		error = check_error(&ptd);
+		if (unlikely(error)) {
+			status = error;
+			priv->atl_ints[queue_entry].qh->toggle = 0;
+			priv->atl_ints[queue_entry].qh->ping = 0;
+			urb->status = -EPIPE;
+		} else {
+			if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+				priv->atl_ints[queue_entry].qh->toggle =
+				    dw3 & (1 << 25);
+				priv->atl_ints[queue_entry].qh->ping =
+				    dw3 & (1 << 26);
+			}
+		}
+
+		length = PTD_XFERRED_LENGTH(dw3);
+		if (length) {
+			switch (DW1_GET_PID(dw1)) {
+			case IN_PID:
+				isp1763_read_mem(usb_hcd, (u16) payload,
+						 priv->
+						 atl_ints[queue_entry].
+						 data_buffer, length);
+			case OUT_PID:
+				urb->actual_length += length;
+			case SETUP_PID:
+				break;
+			}
+		}
+
+		priv->atl_ints[queue_entry].data_buffer = NULL;
+		priv->atl_ints[queue_entry].urb = NULL;
+		priv->atl_ints[queue_entry].qtd = NULL;
+		priv->atl_ints[queue_entry].qh = NULL;
+
+		free_mem(priv, payload);
+
+		isp1763_writew(skip_map, usb_hcd->regs +
+			       HC_ATL_PTD_SKIPMAP_REG);
+
+		if (unlikely(urb->status == -EPIPE)) {
+			/* HALT was received */
+
+			qtd = clean_up_qtdlist(qtd);
+			isp1763_urb_done(priv, urb, urb->status);
+		} else if (usb_pipebulk(urb->pipe)
+			   && (length < qtd->length)) {
+			/* short BULK received */
+
+			if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+				urb->status = -EREMOTEIO;
+				isp1763_dbg(priv,
+					    "short bulk, %d instead %zu "
+					    "with URB_SHORT_NOT_OK flag.\n",
+					    length, qtd->length);
+			}
+
+			if (urb->status == -EINPROGRESS)
+				urb->status = 0;
+			qtd = clean_up_qtdlist(qtd);
+			isp1763_urb_done(priv, urb, urb->status);
+
+		} else if (qtd->status & URB_COMPLETE_NOTIFY) {
+			/* that was the last qtd of that URB */
+
+			if (urb->status == -EINPROGRESS)
+				urb->status = 0;
+
+			qtd = clean_this_qtd(qtd);
+			isp1763_urb_done(priv, urb, urb->status);
+
+		} else {
+			/* next QTD of this URB */
+
+			qtd = clean_this_qtd(qtd);
+			BUG_ON(!qtd);
+		}
+
+		if (qtd)
+			enqueue_an_ATL_packet(usb_hcd, qh, qtd);
+
+		/* NOTE: Move to the beginning of while (done_map) loop? */
+		skip_map = isp1763_readw(usb_hcd->regs +
+					 HC_ATL_PTD_SKIPMAP_REG);
+	}
+}
+
+
+/* NOTE:
+ * It seems that setting up two memory banks in the isp1760's code
+ * is merely for convenience's sake; right now trying with:
+ *
+ * 1. Setup up the memory register for the PTD
+ * 2. Copy PTD from device to the driver's PTD copy
+ * 3. Process the PTD data
+ * (later on)
+ * 4. Setup the memory register for the payload
+ * 5. Copy payload from device to the driver's payload space
+ *
+ * There may be a gotcha here if the isp1760 is taking advantage of the ISP_BANK
+ * ability to automatically increment the address per bank on consecutive access
+ * to the same bank; It does not seem so because atl_regs & payload are
+ * reassigned at every while(done_map) iteration.
+ */
+static void do_intl_int(struct usb_hcd *usb_hcd)
+{
+	struct isp1763_hcd *priv = hcd_to_priv(usb_hcd);
+	u16 done_map, skip_map;
+	struct ptd ptd;
+	struct urb *urb = NULL;
+	u32 int_regs;
+	u32 int_regs_base;
+	u32 payload;
+	u32 length;
+	u16 or_map;
+	int error;
+	u32 queue_entry;
+	struct isp1763_qtd *qtd;
+	struct isp1763_qh *qh;
+
+	done_map = isp1763_readw(usb_hcd->regs + HC_INT_PTD_DONEMAP_REG);
+
+	/* NOTE: Move inside while (done_map) at the beginning and remove the
+	 * skip_map read at the end of the loop?
+	 */
+	skip_map = isp1763_readw(usb_hcd->regs + HC_INT_PTD_SKIPMAP_REG);
+
+	or_map = isp1763_readw(usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+	or_map &= ~done_map;
+	isp1763_writew(or_map, usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+
+	int_regs_base = INT_REGS_OFFSET;
+
+	while (done_map) {
+		u32 dw1;
+		u32 dw3;
+
+		/* 32-bit to 16-bit done_map adjustment */
+		queue_entry = __ffs((u32) done_map);
+		BUG_ON(queue_entry > 16);
+
+		done_map &= ~(1 << queue_entry);
+		skip_map |= 1 << queue_entry;
+
+		int_regs =
+		    int_regs_base + (queue_entry * sizeof(struct ptd));
+		urb = priv->int_ints[queue_entry].urb;
+		qtd = priv->int_ints[queue_entry].qtd;
+		qh = priv->int_ints[queue_entry].qh;
+		payload = priv->int_ints[queue_entry].payload;
+
+		if (!qh) {
+			printk(KERN_ERR "(INT) qh is 0\n");
+			continue;
+		}
+		isp1763_read_mem(usb_hcd, (u16) int_regs, (u16 *) &ptd,
+				 sizeof(ptd));
+
+		dw1 = le32_to_cpu(ptd.dw1);
+		dw3 = le32_to_cpu(ptd.dw3);
+		check_int_err_status(le32_to_cpu(ptd.dw4));
+
+		error = check_error(&ptd);
+		if (error) {
+#if 0
+			printk(KERN_ERR "Error in %s().\n", __func__);
+			printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x "
+			       "dw3: %08x dw4: %08x dw5: %08x dw6: "
+			       "%08x dw7: %08x\n",
+			       ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3,
+			       ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7);
+#endif
+			urb->status = -EPIPE;
+			priv->int_ints[queue_entry].qh->toggle = 0;
+			priv->int_ints[queue_entry].qh->ping = 0;
+
+		} else {
+			priv->int_ints[queue_entry].qh->toggle =
+			    dw3 & (1 << 25);
+			priv->int_ints[queue_entry].qh->ping =
+			    dw3 & (1 << 26);
+		}
+
+		if (urb->dev->speed != USB_SPEED_HIGH)
+			length = PTD_XFERRED_LENGTH_LO(dw3);
+		else
+			length = PTD_XFERRED_LENGTH(dw3);
+
+		if (length) {
+			switch (DW1_GET_PID(dw1)) {
+			case IN_PID:
+
+				isp1763_read_mem(usb_hcd, (u16) payload,
+						 priv->
+						 int_ints[queue_entry].
+						 data_buffer, length);
+			case OUT_PID:
+
+				urb->actual_length += length;
+
+			case SETUP_PID:
+				break;
+			}
+		}
+
+		priv->int_ints[queue_entry].data_buffer = NULL;
+		priv->int_ints[queue_entry].urb = NULL;
+		priv->int_ints[queue_entry].qtd = NULL;
+		priv->int_ints[queue_entry].qh = NULL;
+
+		isp1763_writew(skip_map, usb_hcd->regs +
+			       HC_INT_PTD_SKIPMAP_REG);
+		free_mem(priv, payload);
+
+		if (urb->status == -EPIPE) {
+			/* HALT received */
+
+			qtd = clean_up_qtdlist(qtd);
+			isp1763_urb_done(priv, urb, urb->status);
+
+		} else if (qtd->status & URB_COMPLETE_NOTIFY) {
+
+			if (urb->status == -EINPROGRESS)
+				urb->status = 0;
+
+			qtd = clean_this_qtd(qtd);
+			isp1763_urb_done(priv, urb, urb->status);
+
+		} else {
+			/* next QTD of this URB */
+
+			qtd = clean_this_qtd(qtd);
+			BUG_ON(!qtd);
+		}
+
+		if (qtd)
+			enqueue_an_INT_packet(usb_hcd, qh, qtd);
+
+		/* NOTE: Move to the beginning of while (done_map) loop? */
+		skip_map = isp1763_readw(usb_hcd->regs +
+					 HC_INT_PTD_SKIPMAP_REG);
+	}
+}
+
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
+
+/*
+ * GIT COMMIT: 1b9a38bfa6e664ff02511314f5586d711c83cc91 adapted
+ * "USB: EHCI: fix handling of unusual interrupt intervals"
+ */
+static struct isp1763_qh *qh_make(struct isp1763_hcd *priv,
+				  struct urb *urb, gfp_t flags)
+{
+	struct isp1763_qh *qh;
+	int is_input, type;
+
+	qh = isp1763_qh_alloc(priv, flags);
+	if (!qh)
+		return qh;
+
+	/*
+	 * init endpoint/device data for this QH
+	 */
+	is_input = usb_pipein(urb->pipe);
+	type = usb_pipetype(urb->pipe);
+
+	if (type == PIPE_INTERRUPT) {
+
+		if (urb->dev->speed == USB_SPEED_HIGH) {
+
+			qh->period = urb->interval >> 3;
+			if (qh->period == 0 && urb->interval != 1) {
+				/* NOTE interval 2 or 4 uframes could work.
+				 * But interval 1 scheduling is simpler, and
+				 * includes high bandwidth.
+				 */
+				urb->interval = 1;
+			} else if (qh->period > priv->periodic_size) {
+				qh->period = priv->periodic_size;
+				urb->interval = qh->period << 3;
+			}
+		} else {
+			qh->period = urb->interval;
+			if (qh->period > priv->periodic_size) {
+				qh->period = priv->periodic_size;
+				urb->interval = qh->period;
+			}
+		}
+	}
+
+	/* support for tt scheduling, and access to toggles */
+	qh->dev = urb->dev;
+
+	if (!usb_pipecontrol(urb->pipe))
+		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			      !is_input, 1);
+	return qh;
+}
+
+/*
+ * For control/bulk/interrupt, return QH with these TDs appended.
+ * Allocates and initializes the QH if necessary.
+ * Returns null if it can't allocate a QH it needs to.
+ * If the QH has TDs (urbs) already, that's great.
+ */
+static struct isp1763_qh *qh_append_tds(struct isp1763_hcd *priv,
+					struct urb *urb,
+					struct list_head *qtd_list,
+					int epnum, void **ptr)
+{
+	struct isp1763_qh *qh;
+	struct isp1763_qtd *qtd;
+	struct isp1763_qtd *prev_qtd;
+
+	qh = (struct isp1763_qh *) *ptr;
+	if (!qh) {
+		/* can't sleep here, we have priv->lock... */
+		qh = qh_make(priv, urb, GFP_ATOMIC);
+		if (!qh)
+			return qh;
+		*ptr = qh;
+	}
+
+	qtd = list_entry(qtd_list->next, struct isp1763_qtd, qtd_list);
+	if (!list_empty(&qh->qtd_list))
+		prev_qtd = list_entry(qh->qtd_list.prev,
+				      struct isp1763_qtd, qtd_list);
+	else
+		prev_qtd = NULL;
+
+	list_splice(qtd_list, qh->qtd_list.prev);
+	if (prev_qtd) {
+		BUG_ON(prev_qtd->hw_next);
+		prev_qtd->hw_next = qtd;
+	}
+
+	urb->hcpriv = qh;
+	return qh;
+}
+
+static void qtd_list_free(struct isp1763_hcd *priv, struct urb *urb,
+			  struct list_head *qtd_list)
+{
+	struct list_head *entry, *temp;
+
+	list_for_each_safe(entry, temp, qtd_list) {
+		struct isp1763_qtd *qtd;
+
+		qtd = list_entry(entry, struct isp1763_qtd, qtd_list);
+		list_del(&qtd->qtd_list);
+		isp1763_qtd_free(qtd);
+	}
+}
+
+static int isp1763_prepare_enqueue(struct isp1763_hcd *priv,
+				   struct urb *urb,
+				   struct list_head *qtd_list,
+				   gfp_t mem_flags, packet_enqueue *p)
+{
+	struct isp1763_qtd *qtd;
+	int epnum;
+	unsigned long flags;
+	struct isp1763_qh *qh = NULL;
+	int rc;
+	int qh_busy;
+
+	qtd = list_entry(qtd_list->next, struct isp1763_qtd, qtd_list);
+	epnum = urb->ep->desc.bEndpointAddress;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &priv_to_hcd(priv)->flags)) {
+		rc = -ESHUTDOWN;
+		goto done;
+	}
+	rc = usb_hcd_link_urb_to_ep(priv_to_hcd(priv), urb);
+	if (rc)
+		goto done;
+
+	qh = urb->ep->hcpriv;
+	if (qh)
+		qh_busy = !list_empty(&qh->qtd_list);
+	else
+		qh_busy = 0;
+
+	qh = qh_append_tds(priv, urb, qtd_list, epnum, &urb->ep->hcpriv);
+	if (!qh) {
+		usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb);
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	if (!qh_busy)
+		p(priv_to_hcd(priv), qh, qtd);
+
+done:
+	spin_unlock_irqrestore(&priv->lock, flags);
+	if (!qh)
+		qtd_list_free(priv, urb, qtd_list);
+	return rc;
+}
+
+static struct isp1763_qtd *isp1763_qtd_alloc(struct isp1763_hcd *priv,
+					     gfp_t flags)
+{
+	struct isp1763_qtd *qtd;
+
+	qtd = kmem_cache_zalloc(qtd_cachep, flags);
+	if (qtd)
+		INIT_LIST_HEAD(&qtd->qtd_list);
+
+	return qtd;
+}
+
+/*
+ * create a list of filled qtds for this URB; won't link into qh.
+ */
+static struct list_head *qh_urb_transaction(struct isp1763_hcd *priv,
+					    struct urb *urb,
+					    struct list_head *head,
+					    gfp_t flags)
+{
+	struct isp1763_qtd *qtd, *qtd_prev;
+	void *buf;
+	int len, maxpacket;
+	int is_input;
+	u32 token;
+
+	/*
+	 * URBs map to sequences of QTDs:  one logical transaction
+	 */
+	qtd = isp1763_qtd_alloc(priv, flags);
+	if (!qtd)
+		return NULL;
+
+	list_add_tail(&qtd->qtd_list, head);
+	qtd->urb = urb;
+	urb->status = -EINPROGRESS;
+
+	token = 0;
+	/* for split transactions, SplitXState initialized to zero */
+
+	len = urb->transfer_buffer_length;
+	is_input = usb_pipein(urb->pipe);
+	if (usb_pipecontrol(urb->pipe)) {
+		/* SETUP pid */
+		qtd_fill(qtd, urb->setup_packet,
+			 sizeof(struct usb_ctrlrequest),
+			 token | SETUP_PID);
+
+		/* ... and always at least one more pid */
+		token ^= DATA_TOGGLE;
+		qtd_prev = qtd;
+		qtd = isp1763_qtd_alloc(priv, flags);
+		if (!qtd)
+			goto cleanup;
+		qtd->urb = urb;
+		qtd_prev->hw_next = qtd;
+		list_add_tail(&qtd->qtd_list, head);
+
+		/* for zero length DATA stages, STATUS is always IN */
+		if (len == 0)
+			token |= IN_PID;
+	}
+
+	/*
+	 * data transfer stage:  buffer setup
+	 */
+	buf = urb->transfer_buffer;
+
+	if (is_input)
+		token |= IN_PID;
+	else
+		token |= OUT_PID;
+
+	maxpacket =
+	    max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));
+
+	/*
+	 * buffer gets wrapped in one or more qtds;
+	 * last one may be "short" (including zero len)
+	 * and may serve as a control status ack
+	 */
+	for (;;) {
+		int this_qtd_len;
+
+		if (!buf && len) {
+			/* XXX This looks like usb storage / SCSI bug */
+			printk(KERN_ERR
+			       "buf is null, dma is %08lx len is %d\n",
+			       (long unsigned) urb->transfer_dma, len);
+			WARN_ON(1);
+		}
+
+		this_qtd_len = qtd_fill(qtd, buf, len, token);
+		len -= this_qtd_len;
+		buf += this_qtd_len;
+
+		/* qh makes control packets use qtd toggle; maybe switch it */
+		if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
+			token ^= DATA_TOGGLE;
+
+		if (len <= 0)
+			break;
+
+		qtd_prev = qtd;
+		qtd = isp1763_qtd_alloc(priv, flags);
+		if (!qtd)
+			goto cleanup;
+		qtd->urb = urb;
+		qtd_prev->hw_next = qtd;
+		list_add_tail(&qtd->qtd_list, head);
+	}
+
+	/*
+	 * control requests may need a terminating data "status" ack;
+	 * bulk ones may need a terminating short packet (zero length).
+	 */
+	if (urb->transfer_buffer_length != 0) {
+		int one_more = 0;
+
+		if (usb_pipecontrol(urb->pipe)) {
+			one_more = 1;
+			/* "in" <--> "out"  */
+			token ^= IN_PID;
+			/* force DATA1 */
+			token |= DATA_TOGGLE;
+		} else if (usb_pipebulk(urb->pipe)
+			   && (urb->transfer_flags & URB_ZERO_PACKET)
+			   && !(urb->transfer_buffer_length % maxpacket)) {
+			one_more = 1;
+		}
+		if (one_more) {
+			qtd_prev = qtd;
+			qtd = isp1763_qtd_alloc(priv, flags);
+			if (!qtd)
+				goto cleanup;
+			qtd->urb = urb;
+			qtd_prev->hw_next = qtd;
+			list_add_tail(&qtd->qtd_list, head);
+
+			/* never any data in such packets */
+			qtd_fill(qtd, NULL, 0, token);
+		}
+	}
+
+	qtd->status = URB_COMPLETE_NOTIFY;
+	return head;
+
+cleanup:
+	qtd_list_free(priv, urb, head);
+	return NULL;
+}
+
+static int isp1763_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+			       gfp_t mem_flags)
+{
+	struct isp1763_hcd *priv = hcd_to_priv(hcd);
+	struct list_head qtd_list;
+	packet_enqueue *pe;
+
+	INIT_LIST_HEAD(&qtd_list);
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+
+		if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags))
+			return -ENOMEM;
+		pe = enqueue_an_ATL_packet;
+		break;
+
+	case PIPE_INTERRUPT:
+		if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags))
+			return -ENOMEM;
+		pe = enqueue_an_INT_packet;
+		break;
+
+	case PIPE_ISOCHRONOUS:
+		printk(KERN_ERR "PIPE_ISOCHRONOUS ain't supported\n");
+	default:
+		return -EPIPE;
+	}
+
+	return isp1763_prepare_enqueue(priv, urb, &qtd_list, mem_flags,
+				       pe);
+}
+
+static int isp1763_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+			       int status)
+{
+	struct isp1763_hcd *priv = hcd_to_priv(hcd);
+	struct inter_packet_info *ints;
+	u32 i;
+	u32 reg_base, or_reg, skip_reg;
+	unsigned long flags;
+	struct ptd ptd;
+	packet_enqueue *pe;
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_ISOCHRONOUS:
+		return -EPIPE;
+		break;
+
+	case PIPE_INTERRUPT:
+		ints = priv->int_ints;
+		reg_base = INT_REGS_OFFSET;
+		or_reg = HC_INT_IRQ_MASK_OR_REG;
+		skip_reg = HC_INT_PTD_SKIPMAP_REG;
+		pe = enqueue_an_INT_packet;
+		break;
+
+	default:
+		ints = priv->atl_ints;
+		reg_base = ATL_REGS_OFFSET;
+		or_reg = HC_ATL_IRQ_MASK_OR_REG;
+		skip_reg = HC_ATL_PTD_SKIPMAP_REG;
+		pe = enqueue_an_ATL_packet;
+		break;
+	}
+
+	memset(&ptd, 0, sizeof(ptd));
+	spin_lock_irqsave(&priv->lock, flags);
+
+	/* NOTE: isp1763 only have 16 PTDs */
+	for (i = 0; i < NUM_OF_PTD; i++) {
+		if (ints->urb == urb) {
+			u16 skip_map;
+			u16 or_map;
+			struct isp1763_qtd *qtd;
+			struct isp1763_qh *qh = ints->qh;
+
+			skip_map = isp1763_readw(hcd->regs + skip_reg);
+			skip_map |= 1 << (u16) i;
+			isp1763_writew(skip_map, hcd->regs + skip_reg);
+
+			or_map = isp1763_readw(hcd->regs + or_reg);
+			or_map &= ~(1 << (u16) i);
+			isp1763_writew(or_map, hcd->regs + or_reg);
+
+			isp1763_write_mem(hcd, (u16 *) &ptd,
+					  reg_base + i * sizeof(ptd),
+					  sizeof(ptd));
+
+			qtd = ints->qtd;
+			qtd = clean_up_qtdlist(qtd);
+
+			free_mem(priv, ints->payload);
+
+			ints->urb = NULL;
+			ints->qh = NULL;
+			ints->qtd = NULL;
+			ints->data_buffer = NULL;
+			ints->payload = 0;
+
+			isp1763_urb_done(priv, urb, status);
+			if (qtd)
+				pe(hcd, qh, qtd);
+			break;
+
+		} else if (ints->qtd) {
+			struct isp1763_qtd *qtd, *prev_qtd = ints->qtd;
+
+			for (qtd = ints->qtd->hw_next; qtd;
+			     qtd = qtd->hw_next) {
+				if (qtd->urb == urb) {
+					prev_qtd->hw_next =
+					    clean_up_qtdlist(qtd);
+					isp1763_urb_done(priv, urb,
+							 status);
+					break;
+				}
+				prev_qtd = qtd;
+			}
+			/* we found the urb before the end of the list */
+			if (qtd)
+				break;
+		}
+		ints++;
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return 0;
+}
+
+/**
+ * isp1763_irq - host controller interrupt routine
+ * @ctrl: controller structure
+ *
+ * Called by main IRQ handler in isp1763_base.c and not registered via
+ * usb_hcd structure.
+ */
+static int isp1763_irq(struct isp1763_controller *ctrl, u32 flags)
+{
+	struct usb_hcd *usb_hcd = ctrl->priv;
+	struct isp1763_hcd *priv = hcd_to_priv(usb_hcd);
+	u16 imask;
+	irqreturn_t irqret = IRQ_NONE;
+
+	spin_lock(&priv->lock);
+
+	if (!(usb_hcd->state & HC_STATE_RUNNING))
+		goto leave;
+
+	imask = flags;
+	if (unlikely(!imask))
+		goto leave;
+
+	if (imask & HC_ATL_INT)
+		do_atl_int(usb_hcd);
+
+	if (imask & HC_INTL_INT)
+		do_intl_int(usb_hcd);
+
+	irqret = IRQ_HANDLED;
+leave:
+	spin_unlock(&priv->lock);
+	return irqret;
+}
+
+static int isp1763_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+	struct isp1763_hcd *priv = hcd_to_priv(hcd);
+	u32 temp, status = 0;
+	u32 mask;
+	int retval = 1;
+	unsigned long flags;
+
+	/* if !USB_SUSPEND, root hub timers won't get shut down ... */
+	if (!HC_IS_RUNNING(hcd->state))
+		return 0;
+
+	/* init status to no-changes */
+	buf[0] = 0;
+	mask = PORT_CSC;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	temp = isp1763_readl(hcd->regs + HC_PORTSC1);
+
+	if (temp & PORT_OWNER) {
+		if (temp & PORT_CSC) {
+			temp &= ~PORT_CSC;
+			isp1763_writel(temp, hcd->regs + HC_PORTSC1);
+			goto done;
+		}
+	}
+
+	/*
+	 * Return status information even for ports with OWNER set.
+	 * Otherwise khubd wouldn't see the disconnect event when a
+	 * high-speed device is switched over to the companion
+	 * controller by the user.
+	 */
+
+	if ((temp & mask) != 0
+	    || ((temp & PORT_RESUME) != 0
+		&& time_after_eq(jiffies, priv->reset_done))) {
+		buf[0] |= 1 << (0 + 1);
+		status = STS_PCD;
+	}
+	/* FIXME autosuspend idle root hubs */
+done:
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return status ? retval : 0;
+}
+
+/* ref: isp1763: pehci.c:pehci_hub_descriptor() */
+static void isp1763_hub_descriptor(struct isp1763_hcd *priv,
+				   struct usb_hub_descriptor *desc)
+{
+	int ports = HCS_N_PORTS(priv->hcs_params);
+	u16 temp;
+
+	desc->bDescriptorType = 0x29;
+	/* priv 1.0, 2.3.9 says 20ms max */
+	desc->bPwrOn2PwrGood = 10;
+	desc->bHubContrCurrent = 0;
+
+	desc->bNbrPorts = ports;
+	temp = 1 + (ports / 8);
+	desc->bDescLength = 7 + 2 * temp;
+
+	/* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+	memset(&desc->bitmap[0], 0, temp);
+	memset(&desc->bitmap[temp], 0xff, temp);
+
+	/* per-port overcurrent reporting; no power switching */
+	temp = 0x0008;
+
+	if (HCS_PPC(priv->hcs_params))
+		temp |= 0x0001;	/* per-port power control */
+	else
+		temp |= 0x0002;	/* no power switching */
+
+	desc->wHubCharacteristics = cpu_to_le16(temp);
+}
+
+#define	PORT_WAKE_BITS	(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
+
+static int check_reset_complete(struct isp1763_hcd *priv, int index,
+				u32 __iomem *status_reg, int port_status)
+{
+	if (!(port_status & PORT_CONNECT))
+		return port_status;
+
+	/* if reset finished and it's still not enabled -- handoff */
+	if (!(port_status & PORT_PE)) {
+
+		printk(KERN_ERR "port %d full speed --> companion\n",
+		       index + 1);
+
+		port_status |= PORT_OWNER;
+		port_status &= ~PORT_RWC_BITS;
+		isp1763_writel(port_status, status_reg);
+
+	} else
+		printk(KERN_ERR "port %d high speed\n", index + 1);
+
+	return port_status;
+}
+
+static int isp1763_hub_control(struct usb_hcd *hcd, u16 typeReq,
+			       u16 wValue, u16 wIndex, char *buf,
+			       u16 wLength)
+{
+	struct isp1763_hcd *priv = hcd_to_priv(hcd);
+	int ports = HCS_N_PORTS(priv->hcs_params);
+	u32 __iomem *status_reg = hcd->regs + HC_PORTSC1;
+	u32 temp, status;
+	unsigned long flags;
+	int retval = 0;
+	unsigned selector;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	switch (typeReq) {
+	case ClearHubFeature:
+		switch (wValue) {
+		case C_HUB_LOCAL_POWER:
+		case C_HUB_OVER_CURRENT:
+			/* no hub-wide feature/status flags */
+			break;
+		default:
+			goto error;
+		}
+		break;
+
+	case ClearPortFeature:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		temp = isp1763_readl(status_reg);
+
+		switch (wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			isp1763_writel(temp & ~PORT_PE, status_reg);
+			break;
+		case USB_PORT_FEAT_C_ENABLE:
+			/* XXX error? */
+			break;
+		case USB_PORT_FEAT_SUSPEND:
+			if (temp & PORT_RESET)
+				goto error;
+
+			if (temp & PORT_SUSPEND) {
+				if ((temp & PORT_PE) == 0)
+					goto error;
+				/* resume signaling for 20 msec */
+				temp &= ~(PORT_RWC_BITS);
+				isp1763_writel(temp | PORT_RESUME, status_reg);
+				priv->reset_done = jiffies +
+				    msecs_to_jiffies(20);
+			}
+			break;
+		case USB_PORT_FEAT_C_SUSPEND:
+			/* we auto-clear this feature */
+			break;
+		case USB_PORT_FEAT_POWER:
+			if (HCS_PPC(priv->hcs_params))
+				isp1763_writel(temp & ~PORT_POWER, status_reg);
+			break;
+		case USB_PORT_FEAT_C_CONNECTION:
+			isp1763_writel(temp | PORT_CSC, status_reg);
+			break;
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+			/* XXX error ? */
+			break;
+		case USB_PORT_FEAT_C_RESET:
+			/* GetPortStatus clears reset */
+			break;
+		default:
+			goto error;
+		}
+		isp1763_readl(hcd->regs + HC_USBCMD);
+		break;
+
+	case GetHubDescriptor:
+		isp1763_hub_descriptor(priv, (struct usb_hub_descriptor *)buf);
+		break;
+
+	case GetHubStatus:
+		/* no hub-wide feature/status flags */
+		memset(buf, 0, 4);
+		break;
+
+	case GetPortStatus:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		status = 0;
+		temp = isp1763_readl(status_reg);
+
+		/* wPortChange bits */
+		if (temp & PORT_CSC)
+			status |= 1 << USB_PORT_FEAT_C_CONNECTION;
+
+		/* whoever resumes must GetPortStatus to complete it!! */
+		if (temp & PORT_RESUME) {
+			printk(KERN_ERR
+			       "Port resume should be skipped.\n");
+
+			/* Remote Wakeup received? */
+			if (!priv->reset_done) {
+				/* resume signaling for 20 msec */
+				priv->reset_done = jiffies
+				    + msecs_to_jiffies(20);
+				/* check the port again */
+				mod_timer(&priv_to_hcd(priv)->rh_timer,
+					  priv->reset_done);
+			}
+
+			/* resume completed? */
+			else if (time_after_eq(jiffies, priv->reset_done)) {
+				status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+				priv->reset_done = 0;
+
+				/* stop resume signaling */
+				temp = isp1763_readl(status_reg);
+				isp1763_writel(temp &
+					       ~(PORT_RWC_BITS |
+						 PORT_RESUME), status_reg);
+				retval =
+				    handshake(priv, status_reg,
+					      PORT_RESUME, 0, 2000); /* 2msec */
+				if (retval != 0) {
+					isp1763_err(priv,
+						    "port %d resume error %d\n",
+						    wIndex + 1, retval);
+					goto error;
+				}
+				temp &= ~(PORT_SUSPEND|PORT_RESUME|(3 << 10));
+			}
+		}
+
+		/* whoever resets must GetPortStatus to complete it!! */
+		if ((temp & PORT_RESET)
+		    && time_after_eq(jiffies, priv->reset_done)) {
+			status |= 1 << USB_PORT_FEAT_C_RESET;
+			priv->reset_done = 0;
+
+			/* force reset to complete */
+			isp1763_writel(temp & ~PORT_RESET, status_reg);
+			/* REVISIT:  some hardware needs 550+ usec to clear
+			 * this bit; seems too long to spin routinely...
+			 */
+			retval = handshake(priv, status_reg,
+					   PORT_RESET, 0, 750);
+			if (retval != 0) {
+				isp1763_err(priv,
+					    "port %d reset error %d\n",
+					    wIndex + 1, retval);
+				goto error;
+			}
+
+			/* see what we found out */
+			temp =
+			    check_reset_complete(priv, wIndex, status_reg,
+						 isp1763_readl(status_reg));
+		}
+		/*
+		 * Even if OWNER is set, there's no harm letting khubd
+		 * see the wPortStatus values (they should all be 0 except
+		 * for PORT_POWER anyway).
+		 */
+
+		if (temp & PORT_OWNER)
+			printk(KERN_ERR "Warning: PORT_OWNER is set\n");
+
+		if (temp & PORT_CONNECT) {
+			status |= 1 << USB_PORT_FEAT_CONNECTION;
+			/* status may be from integrated TT */
+			status |= ehci_port_speed(priv, temp);
+		}
+		if (temp & PORT_PE)
+			status |= 1 << USB_PORT_FEAT_ENABLE;
+		if (temp & (PORT_SUSPEND | PORT_RESUME))
+			status |= 1 << USB_PORT_FEAT_SUSPEND;
+		if (temp & PORT_RESET)
+			status |= 1 << USB_PORT_FEAT_RESET;
+		if (temp & PORT_POWER)
+			status |= 1 << USB_PORT_FEAT_POWER;
+
+		put_unaligned(cpu_to_le32(status), (__le32 *) buf);
+		break;
+
+	case SetHubFeature:
+		switch (wValue) {
+		case C_HUB_LOCAL_POWER:
+		case C_HUB_OVER_CURRENT:
+			/* no hub-wide feature/status flags */
+			break;
+		default:
+			goto error;
+		}
+		break;
+
+	case SetPortFeature:
+		selector = wIndex >> 8;
+		wIndex &= 0xff;
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		temp = isp1763_readl(status_reg);
+		if (temp & PORT_OWNER)
+			break;
+
+		switch (wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			isp1763_writel(temp | PORT_PE, status_reg);
+			break;
+
+		case USB_PORT_FEAT_SUSPEND:
+			if ((temp & PORT_PE) == 0
+			    || (temp & PORT_RESET) != 0)
+				goto error;
+
+			isp1763_writel(temp | PORT_SUSPEND, status_reg);
+			break;
+		case USB_PORT_FEAT_POWER:
+			if (HCS_PPC(priv->hcs_params))
+				isp1763_writel(temp | PORT_POWER,
+					       status_reg);
+			break;
+		case USB_PORT_FEAT_RESET:
+			if (temp & PORT_RESUME)
+				goto error;
+
+			if ((temp & (PORT_PE | PORT_CONNECT)) ==
+			    PORT_CONNECT && PORT_USB11(temp)) {
+				temp |= PORT_OWNER;
+			} else {
+				if ((temp & PORT_CONNECT) == 0) {
+					printk(KERN_ERR
+					       "ERROR: Port not connected\n");
+					goto error;
+				}
+				if ((temp & PORT_POWER) == 0) {
+					printk(KERN_ERR
+					       "ERROR: Port power not enabled!\n");
+					goto error;
+				}
+
+				temp |= PORT_RESET;
+				temp &= ~PORT_PE;
+
+				isp1763_writel(temp, status_reg);
+				/*
+				 * caller must wait, then call GetPortStatus
+				 * usb 2.0 spec says 50 ms resets on root
+				 */
+				priv->reset_done = jiffies +
+				    msecs_to_jiffies(50);
+				mdelay(50);
+
+				temp &= ~PORT_RESET;
+				isp1763_writel(temp, status_reg);
+
+				while (isp1763_readl(status_reg) & PORT_RESET)
+					continue; /* do nothing */
+
+				temp |= PORT_PE;
+				isp1763_writel(temp, status_reg);
+			}
+			break;
+		default:
+			goto error;
+		}
+		isp1763_readl(hcd->regs + HC_USBCMD);
+		break;
+
+	default:
+error:
+		/* "stall" on error */
+		retval = -EPIPE;
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return retval;
+}
+
+static void isp1763_endpoint_disable(struct usb_hcd *usb_hcd,
+				     struct usb_host_endpoint *ep)
+{
+	struct isp1763_hcd *priv = hcd_to_priv(usb_hcd);
+	struct isp1763_qh *qh;
+	struct isp1763_qtd *qtd;
+	unsigned long flags;
+	struct urb *urb;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	qh = ep->hcpriv;
+	if (!qh)
+		goto out;
+
+	ep->hcpriv = NULL;
+	do {
+		/* more than entry might get removed */
+		if (list_empty(&qh->qtd_list))
+			break;
+
+		qtd = list_first_entry(&qh->qtd_list, struct isp1763_qtd,
+				       qtd_list);
+
+		if (qtd->status & URB_ENQUEUED) {
+
+			spin_unlock_irqrestore(&priv->lock, flags);
+			isp1763_urb_dequeue(usb_hcd, qtd->urb,
+					    -ECONNRESET);
+			spin_lock_irqsave(&priv->lock, flags);
+		} else {
+			urb = qtd->urb;
+			clean_up_qtdlist(qtd);
+			isp1763_urb_done(priv, urb, -ECONNRESET);
+		}
+	} while (1);
+
+	qh_destroy(qh);
+	/* remove requests and leak them.
+	 * ATL are pretty fast done, INT could take a while...
+	 * The latter shoule be removed
+	 */
+out:
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int isp1763_get_frame(struct usb_hcd *hcd)
+{
+	struct isp1763_hcd *priv = hcd_to_priv(hcd);
+	u32 fr;
+
+	fr = isp1763_readl(hcd->regs + HC_FRINDEX);
+	return (fr >> 3) % priv->periodic_size;
+}
+
+static void isp1763_stop(struct usb_hcd *hcd)
+{
+	struct isp1763_hcd *priv = hcd_to_priv(hcd);
+	u32 command;
+
+	isp1763_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1,
+			    NULL, 0);
+	mdelay(20);
+
+	spin_lock_irq(&priv->lock);
+	/* FIXME: is this really needed? */
+	ehci_reset(priv);
+
+	/* Stop host controller */
+	command = isp1763_readl(hcd->regs + HC_USBCMD);
+	command &= ~CMD_RUN;
+	isp1763_writel(command, hcd->regs + HC_USBCMD);
+
+	spin_unlock_irq(&priv->lock);
+
+	isp1763_writel(0, hcd->regs + HC_CONFIGFLAG);
+}
+
+static void isp1763_shutdown(struct usb_hcd *hcd)
+{
+	u16 temp;
+	u32 command;
+
+	isp1763_stop(hcd);
+	temp = isp1763_readw(hcd->regs + HC_HW_MODE_CTRL);
+	isp1763_writew(temp &=
+		       ~HW_GLOBAL_INTR_EN, hcd->regs + HC_HW_MODE_CTRL);
+
+	command = isp1763_readl(hcd->regs + HC_USBCMD);
+	command &= ~CMD_RUN;
+	isp1763_writel(command, hcd->regs + HC_USBCMD);
+}
+
+static const struct hc_driver isp1763_hc_driver = {
+	.description = "isp1763-hcd",
+	.product_desc = "ST-Ericsson ISP1763 USB Host Controller",
+	.hcd_priv_size = sizeof(struct isp1763_hcd),
+	.flags = HCD_MEMORY | HCD_USB2,
+	.reset = isp1763_hc_setup,
+	.start = isp1763_run,
+	.stop = isp1763_stop,
+	.shutdown = isp1763_shutdown,
+	.urb_enqueue = isp1763_urb_enqueue,
+	.urb_dequeue = isp1763_urb_dequeue,
+	.endpoint_disable = isp1763_endpoint_disable,
+	.get_frame_number = isp1763_get_frame,
+	.hub_status_data = isp1763_hub_status_data,
+	.hub_control = isp1763_hub_control,
+};
+
+int __init init_kmem_once(void)
+{
+	qtd_cachep = kmem_cache_create("isp1763_qtd",
+				       sizeof(struct isp1763_qtd), 0,
+				       SLAB_TEMPORARY | SLAB_MEM_SPREAD,
+				       NULL);
+
+	if (!qtd_cachep)
+		return -ENOMEM;
+
+	qh_cachep =
+	    kmem_cache_create("isp1763_qh", sizeof(struct isp1763_qh), 0,
+			      SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL);
+
+	if (!qh_cachep) {
+		kmem_cache_destroy(qtd_cachep);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void deinit_kmem_cache(void)
+{
+	kmem_cache_destroy(qtd_cachep);
+	kmem_cache_destroy(qh_cachep);
+}
+
+/**
+ * isp1763_hcd_resume - resume host
+ * @ctrl: controller
+ *
+ * Register and start up host controller, called by OTG code either during
+ * init or after a role change
+ */
+static int isp1763_hcd_resume(struct isp1763_controller *ctrl)
+{
+	struct usb_hcd *hcd = ctrl->priv;
+
+
+	usb_add_hcd(hcd, 0, 0);
+
+	ctrl->active = 1;
+	return 1;
+}
+
+/**
+ * isp1763_hcd_suspend - suspend host
+ * @ctrl: controller
+ *
+ * Stop and deregister host controller, called by OTG code after a role
+ * change.
+ */
+static int isp1763_hcd_suspend(struct isp1763_controller *ctrl)
+{
+	struct usb_hcd *hcd = ctrl->priv;
+
+
+	if (hcd->state == HC_STATE_RUNNING)
+		usb_remove_hcd(hcd);
+
+	ctrl->active = 0;
+	return 0;
+}
+
+/**
+ * isp1763_hcd_probe - initialize USB host controller structures
+ * @ctrl: controller
+ */
+static int isp1763_hcd_probe(struct isp1763_controller *ctrl)
+{
+	struct usb_hcd *hcd;
+	struct isp1763_hcd *priv;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	if (!ctrl->device)
+		return -ENODEV;
+
+	hcd = usb_create_hcd(&isp1763_hc_driver, ctrl->device,
+					dev_name(ctrl->device));
+	if (!hcd)
+		return -ENOMEM;
+
+	priv = hcd_to_priv(hcd);
+	priv->devflags = 0;
+	init_memory(priv);
+
+	ctrl->active = 0;
+	ctrl->priv = hcd;
+
+	hcd->regs = ctrl->regs;
+	if (hcd->regs)
+		return 0;
+
+	usb_put_hcd(hcd);
+	return -EIO;
+}
+
+static struct isp1763_controller isp1763_hc_controller = {
+	.active = 0,
+	.do_irq = isp1763_irq,
+	.suspend = isp1763_hcd_suspend,
+	.resume = isp1763_hcd_resume,
+	.probe = isp1763_hcd_probe,
+};
+
+static int __init isp1763_hc_init(void)
+{
+	isp1763_register_ctrl(&isp1763_hc_controller, ROLE_HOST);
+	init_kmem_once();
+
+	printk(KERN_ERR "isp1763 host controller driver loaded\n");
+	return 0;
+}
+
+static void __exit isp1763_hc_exit(void)
+{
+	isp1763_unregister_ctrl(ROLE_HOST);
+	if (isp1763_hc_controller.priv)
+		usb_put_hcd(isp1763_hc_controller.priv);
+	return;
+}
+
+module_init(isp1763_hc_init);
+module_exit(isp1763_hc_exit);
+
+
+MODULE_DESCRIPTION("ISP1763 USB host controller driver");
+MODULE_AUTHOR("Richard Retanubun <richardretanubun@xxxxxxxxxxxxx>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/isp1763/isp1763_hcd.h b/drivers/usb/isp1763/isp1763_hcd.h
new file mode 100644
index 0000000..cb3f782
--- /dev/null
+++ b/drivers/usb/isp1763/isp1763_hcd.h
@@ -0,0 +1,322 @@
+#ifndef _ISP1763_HCD_H_
+#define _ISP1763_HCD_H_
+
+/* exports for isp1763-if */
+struct usb_hcd *isp1763_register(phys_addr_t res_start,
+				 resource_size_t res_len,
+				 int irq,
+				 unsigned long irqflags,
+				 struct device *dev,
+				 const char *busname, unsigned int devflags);
+int init_kmem_once(void);
+void deinit_kmem_cache(void);
+
+/* EHCI capability registers;
+ * Vendor claims that HCCPARAMS and HCSPARAMS does not exist for isp1763,
+ * Any access to these registers need to return some hardcoded value.
+ */
+#define HC_CAPLENGTH		0x00
+#define HC_HCSPARAMS		0x04
+#define HC_HCCPARAMS		0x08
+
+/* EHCI operational registers */
+#define HC_USBCMD		0x8C
+#define HC_USBSTS		0x90
+#define HC_FRINDEX		0x98
+#define HC_CONFIGFLAG		0x9C
+#define HC_PORTSC1		0xA0
+#define HC_ISO_PTD_DONEMAP_REG	0xA4
+#define HC_ISO_PTD_SKIPMAP_REG	0xA6
+#define HC_ISO_PTD_LASTPTD_REG	0xA8
+#define HC_INT_PTD_DONEMAP_REG	0xAA
+#define HC_INT_PTD_SKIPMAP_REG	0xAC
+#define HC_INT_PTD_LASTPTD_REG	0xAE
+#define HC_ATL_PTD_DONEMAP_REG	0xB0
+#define HC_ATL_PTD_SKIPMAP_REG	0xB2
+#define HC_ATL_PTD_LASTPTD_REG	0xB4
+
+/* Configuration Register */
+#define HC_HW_MODE_CTRL		0xB6
+#define HW_ID_PULLUP		(1 << 12)
+#define HW_DEV_DMA_EN		(1 << 11)
+#define HW_COMN_INT_EN		(1 << 10)
+#define HW_COMN_DMA_EN		(1 << 9)
+#define HW_DACK_POL_HIGH	(1 << 6)
+#define HW_DREQ_POL_HIGH	(1 << 5)
+#define HW_DATA_BUS_8BIT	(1 << 4)
+#define HW_INTF_LOCK		(1 << 3)
+#define HW_INTR_HIGH_ACT	(1 << 2)
+#define HW_INTR_EDGE_TRIG	(1 << 1)
+#define HW_GLOBAL_INTR_EN	(1 << 0)
+
+#define HC_CHIP_ID_REG		0x70
+#define HC_SCRATCH_REG		0x78
+#define HC_RESET_REG		0xB8
+#define HC_PORT1_SC		0xA0
+
+/* INTF_MODE[1:0] is SW_RESET[7:6] */
+#define SW_INTF_MODE_MASK	0xC0
+/* The various operation mode the chip supports */
+#define SW_INTF_MODE_NAND	0x00
+#define SW_INTF_MODE_GNRC	0x40
+#define SW_INTF_MODE_NOR	0x80
+#define SW_INTF_MODE_SRAM	0xC0
+
+#define SW_RESET_RESET_ATX	(1 << 3)
+#define SW_RESET_RESET_HC	(1 << 1)
+#define SW_RESET_RESET_ALL	(1 << 0)
+
+#define HC_BUFFER_STATUS_REG	0xBA
+#define ATL_BUFFER		0x1
+#define INT_BUFFER		0x2
+#define ISO_BUFFER		0x4
+#define BUFFER_MAP		0x7
+
+#define HC_MEMORY_REG		0xC4
+
+#define HC_DATA_REG		0xC6
+
+#define HW_OTG_CTRL_SET		0xE4
+#define HW_OTG_CTRL_CLR		0xE6
+#define HW_OTG_CTRL_HC_2_DIS		(1 << 15)
+#define HW_OTG_CTRL_OTG_DIS		(1 << 10)
+#define HW_OTG_CTRL_SW_SEL_HC_DC	(1 << 7)
+
+/* Interrupt Register */
+#define HC_INTERRUPT_REG	0xD4
+
+#define HC_INTERRUPT_ENABLE	0xD6
+#define INTERRUPT_ENABLE_MASK	(HC_INTL_INT | HC_ATL_INT | HC_EOT_INT \
+					| HC_OPR_REG_INT | HC_OTG_INT)
+#define HC_OTG_INT		(1 << 10)
+#define HC_ISO_INT		(1 << 9)
+#define HC_ATL_INT		(1 << 8)
+#define HC_INTL_INT		(1 << 7)
+#define HC_CLK_READY_INT	(1 << 6)
+#define HC_HCSUSP_INT		(1 << 5)
+#define HC_OPR_REG_INT		(1 << 4)
+#define HC_EOT_INT		(1 << 3)
+#define HC_SOF_INT		(1 << 1) /* renamed from HC_SOT_INT */
+#define HC_USOF_INT		(1 << 0) /* micro SOF interrupt */
+
+#define HC_ISO_IRQ_MASK_OR_REG	0xD8
+#define HC_INT_IRQ_MASK_OR_REG	0xDA
+#define HC_ATL_IRQ_MASK_OR_REG	0xDC
+#define HC_ISO_IRQ_MASK_AND_REG	0xDE
+#define HC_INT_IRQ_MASK_AND_REG	0xE0
+#define HC_ATL_IRQ_MASK_AND_REG	0xE2
+
+/* Register sets */
+#define HC_BEGIN_OF_ATL		0x0c00
+#define HC_BEGIN_OF_INT		0x0800
+#define HC_BEGIN_OF_ISO		0x0400
+#define HC_BEGIN_OF_PAYLOAD	0x1000 /* size 20KB */
+
+/* urb state*/
+#define DELETE_URB		(0x0008)
+#define NO_TRANSFER_ACTIVE	(0xffff)
+
+#define ATL_REGS_OFFSET		(0x0c00)
+#define INT_REGS_OFFSET		(0x0800)
+
+/* Philips/Proprietary Transfer Descriptor (PTD) */
+struct ptd {
+	__le32 dw0;
+	__le32 dw1;
+	__le32 dw2;
+	__le32 dw3;
+	__le32 dw4;
+	__le32 dw5;
+	__le32 dw6;
+	__le32 dw7;
+};
+
+struct inter_packet_info {
+	void *data_buffer;
+	u32 payload;
+#define PTD_FIRE_NEXT           (1 << 0)
+#define PTD_URB_FINISHED        (1 << 1)
+	struct urb *urb;
+	struct isp1763_qh *qh;
+	struct isp1763_qtd *qtd;
+};
+
+typedef void (packet_enqueue) (struct usb_hcd *hcd,
+			       struct isp1763_qh *qh,
+			       struct isp1763_qtd *qtd);
+
+#define isp1763_dbg(priv, fmt, args...) \
+	dev_dbg(priv_to_hcd(priv)->self.controller, fmt, ##args)
+
+#define isp1763_info(priv, fmt, args...) \
+	dev_info(priv_to_hcd(priv)->self.controller, fmt, ##args)
+
+#define isp1763_err(priv, fmt, args...) \
+	dev_err(priv_to_hcd(priv)->self.controller, fmt, ##args)
+
+/* chip memory management */
+struct memory_chunk {
+	unsigned int start;
+	unsigned int size;
+	unsigned int free;
+};
+
+/*
+ * 20kb divided in: (per pehci.h from ST-Ericsson pehci driver)
+ * -  8 blocks @ 256  bytes =  2KB (10%)
+ * -  6 blocks @ 1024 bytes =  6KB (30%)
+ * -  3 blocks @ 4096 bytes = 12KB (60%)
+ */
+#define BLOCK_1_NUM 8
+#define BLOCK_2_NUM 6
+#define BLOCK_3_NUM 3
+
+#define BLOCK_1_SIZE 256
+#define BLOCK_2_SIZE 1024
+#define BLOCK_3_SIZE 4096
+#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
+#define PAYLOAD_SIZE 0x5000	/* 20 KB */
+
+/* I saw if some reloads if the pointer was negative */
+#define ISP1763_NULL_POINTER	(0x400)
+
+/* ATL */
+/* DW0 */
+#define PTD_VALID			1
+#define PTD_LENGTH(x)			(((u32) x) << 3)
+#define PTD_MAXPACKET(x)		(((u32) x) << 18)
+#define PTD_MULTI(x)			(((u32) x) << 29)
+#define PTD_ENDPOINT(x)			(((u32) x) << 31)
+/* DW1 */
+#define PTD_DEVICE_ADDR(x)		(((u32) x) << 3)
+#define PTD_PID_TOKEN(x)		(((u32) x) << 10)
+#define PTD_TRANS_BULK			((u32) 2 << 12)
+#define PTD_TRANS_INT			((u32) 3 << 12)
+#define PTD_TRANS_SPLIT			((u32) 1 << 14)
+#define PTD_SE_USB_LOSPEED		((u32) 2 << 16)
+#define PTD_PORT_NUM(x)			(((u32) x) << 18)
+#define PTD_HUB_NUM(x)			(((u32) x) << 25)
+#define PTD_PING(x)			(((u32) x) << 26)
+/* DW2 */
+#define PTD_RL_CNT(x)			(((u32) x) << 25)
+#define PTD_DATA_START_ADDR(x)		(((u32) x) << 8)
+#define BASE_ADDR			0x1000
+/* DW3 */
+#define PTD_CERR(x)			(((u32) x) << 23)
+#define PTD_NAC_CNT(x)			(((u32) x) << 19)
+#define PTD_ACTIVE			((u32) 1 << 31)
+#define PTD_DATA_TOGGLE(x)		(((u32) x) << 25)
+
+#define DW3_HALT_BIT			(1 << 30)
+#define DW3_ERROR_BIT			(1 << 28)
+#define DW3_QTD_ACTIVE			(1 << 31)
+
+#define INT_UNDERRUN			(1 << 2)
+#define INT_BABBLE			(1 << 1)
+#define INT_EXACT			(1 << 0)
+
+#define DW1_GET_PID(x)			(((x) >> 10) & 0x3)
+#define PTD_XFERRED_LENGTH(x)		((x) & 0x7fff)
+#define PTD_XFERRED_LENGTH_LO(x)	((x) & 0x7ff)
+
+#define SETUP_PID	(2)
+#define IN_PID		(1)
+#define OUT_PID		(0)
+#define GET_QTD_TOKEN_TYPE(x)	((x) & 0x3)
+
+#define DATA_TOGGLE		(1 << 31)
+#define GET_DATA_TOGGLE(x)	((x) >> 31)
+
+/* FIXME!: Does this apply to isp1763? ST-Ericsson believes no */
+/* Set these to HW defaults of ZERO? */
+/* Errata 1 */
+#define RL_COUNTER	(0) /* isp1760 (0) */
+#define NAK_COUNTER	(0) /* isp1760 (0) */
+#define ERR_COUNTER	(0) /* isp1760 (2) */
+
+#define HC_ATL_PL_SIZE        (4096)	/* isp1760 sets this to (8192) */
+
+/* Section 2.2 Host Controller Capability Registers */
+#define HC_LENGTH(p)		(((p)>>00)&0x00ff)	/* bits 7:0 */
+#define HC_VERSION(p)		(((p)>>16)&0xffff)	/* bits 31:16 */
+#define HCS_INDICATOR(p)	((p)&(1 << 16))	/* true: has port indicators */
+#define HCS_PPC(p)		((p)&(1 << 4))	/* true: port power control */
+#define HCS_N_PORTS(p)		(((p)>>0)&0xf)	/* bits 3:0, ports on HC */
+#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))	/* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)	/* bits 6:4, uframes cached */
+
+/* Section 2.3 Host Controller Operational Registers */
+#define CMD_LRESET	(1<<7)	/* partial reset (no ports, etc) */
+#define CMD_RESET	(1<<1)	/* reset HC not bus */
+#define CMD_RUN		(1<<0)	/* start/stop HC */
+#define STS_PCD		(1<<2)	/* port change detect */
+#define FLAG_CF		(1<<0)	/* true: we'll support "high speed" */
+
+#define PORT_OWNER	(1<<13)	/* true: companion hc owns this port */
+#define PORT_POWER	(1<<12)	/* true: has power (see PPC) */
+#define PORT_USB11(x)	(((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */
+#define PORT_RESET	(1<<8)	/* reset port */
+#define PORT_SUSPEND	(1<<7)	/* suspend port */
+#define PORT_RESUME	(1<<6)	/* resume it */
+#define PORT_PE		(1<<2)	/* port enable */
+#define PORT_CSC	(1<<1)	/* connect status change */
+#define PORT_CONNECT	(1<<0)	/* device connected */
+#define PORT_RWC_BITS   (PORT_CSC)
+
+/* isp1763 does not have HCCPARAMS and HCSPARAMS, use hardcoded values here */
+#define HCS_HARDCODE	(1 | (1 << 4))	/* Port Power Control */
+#define HCC_HARDCODE	(1 << 1)	/* Programmable Frame List */
+
+#define NUM_OF_PTD	16	/* isp1760 have 32 max PTDs; isp1763 have 16 */
+
+struct isp1763_hcd {
+	u32 hcs_params;
+	spinlock_t lock;
+	struct inter_packet_info atl_ints[NUM_OF_PTD];
+	struct inter_packet_info int_ints[NUM_OF_PTD];
+	struct memory_chunk memory_pool[BLOCKS];
+
+	/* periodic schedule support */
+#define	DEFAULT_I_TDPS		1024
+	unsigned periodic_size;
+	unsigned i_thresh;
+	unsigned long reset_done;
+	unsigned long next_statechange;
+	unsigned int devflags;
+};
+
+struct isp1763_qtd {
+	struct isp1763_qtd *hw_next;
+	u8 packet_type;
+	u8 toggle;
+
+	void *data_buffer;
+	/* the rest is HCD-private */
+	struct list_head qtd_list;
+	struct urb *urb;
+	size_t length;
+
+	/* isp special */
+	u32 status;
+#define URB_COMPLETE_NOTIFY	(1 << 0)
+#define URB_ENQUEUED		(1 << 1)
+#define URB_TYPE_ATL		(1 << 2)
+#define URB_TYPE_INT		(1 << 3)
+};
+
+struct isp1763_qh {
+	/* first part defined by EHCI spec */
+	struct list_head qtd_list;
+	struct isp1763_hcd *priv;
+
+	/* periodic schedule info */
+	unsigned short period;	/* polling interval */
+	struct usb_device *dev;
+
+	u32 toggle;
+	u32 ping;
+};
+
+#define ehci_port_speed(priv, portsc) (1 << USB_PORT_FEAT_HIGHSPEED)
+
+#endif
diff --git a/drivers/usb/isp1763/isp1763_udc.c b/drivers/usb/isp1763/isp1763_udc.c
new file mode 100644
index 0000000..8f135a5
--- /dev/null
+++ b/drivers/usb/isp1763/isp1763_udc.c
@@ -0,0 +1,1692 @@
+/*
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Description:
+ *
+ * ISP1763A UDC driver
+ *
+ * TODO:
+ * - check locking for completeness
+ * - use double buffering
+ *
+ * (c) 2010 F. Voegel, Carangul.Tech
+ * (c) 2010 I+ME ACTIA Informatik und Mikroelektronik GmbH
+ *
+ */
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/cdc.h>
+
+/* FIXME: Cleanup if this is not needed, comment out for now, just in case
+* #include <asm/byteorder.h>
+* #include <asm/dma.h>
+* #include <asm/system.h>
+*/
+
+#include "isp1763.h"
+#include "isp1763_udc.h"
+
+#define DRIVER_NAME "isp1763_udc"
+static const char driver_name[] = DRIVER_NAME;
+static const char driver_desc[] = "ISP 1763A udc";
+
+static struct isp1763_udc udc_dev;
+static struct isp_ep isp_eps[USB_MAX_ENDPOINTS];
+
+static int isp1763_udc_do_irq(struct isp1763_controller *ctrl, u32 flags);
+#define USE_DOUBLE_BUFFERING
+
+/* Use this #define to activate dump debug functions and add it where you need
+ * to dump in the code */
+#undef ISP1763_UDC_DUMP_DEBUG
+
+static u32 irq_bits = MASK_DCINTENABLE_RELEVANT;
+
+/* Ladies and gentlemen, I give you... THE WHEEL */
+
+/**
+* queue_add - add item to queue
+* @head: queue head
+* @elem: element for which to create entry
+*/
+static void queue_add(struct queue **head, void *elem)
+{
+	struct queue *p = NULL;
+	struct queue *new = kmalloc(sizeof(struct queue), GFP_ATOMIC);
+
+	new->next = NULL;
+	new->elem = elem;
+
+	queue_printk(KERN_ERR "Adding queue entry %p with elem %p\n", new,
+		     new->elem);
+
+	if (*head) {
+		for (p = *head; p->next != NULL;)
+			p = p->next;
+		p->next = new;
+	} else
+		*head = new;
+}
+
+/**
+* queue_get - get item from top of queue
+* @head: queue head
+*/
+static void *queue_get(struct queue **head)
+{
+	if (head) {
+		if (*head) {
+			queue_printk(KERN_ERR
+				     "Retrieving queue entry %p with elem %p\n",
+				     *head, (*head)->elem);
+			return (*head)->elem;
+		}
+	}
+	return NULL;
+}
+
+/**
+* queue_topkill - remove first entry from queue
+* @head: queue head
+*/
+static void queue_topkill(struct queue **head)
+{
+	struct queue *old = *head;
+
+	queue_printk(KERN_ERR "Killing queue entry %p with elem %p\n",
+		     *head, (*head)->elem);
+
+	if (*head == NULL)
+		return;
+
+	if ((*head)->next)
+		*head = (*head)->next;
+	else
+		*head = NULL;
+
+	kfree(old);
+}
+
+/**
+* queue_empty - is queue empty?
+* @head: queue head
+*/
+static int queue_empty(struct queue **head)
+{
+	return *head == NULL;
+}
+
+/**
+* queue_count - return number of entries in queue
+* @head: queue head
+*/
+static int queue_count(struct queue **head)
+{
+	int cnt = 0;
+	struct queue *p = *head;
+
+	for (; p != NULL; p = p->next) {
+		struct usb_request *r = p->elem;
+		if (!r)
+			continue;
+		if (r->buf == NULL)
+			queue_printk(KERN_ERR
+				     "queued request %i (%p) has NULL buffer and %i size (actual=%i)\n",
+				     cnt, r, r->length, r->actual);
+		cnt++;
+	}
+
+	return cnt;
+}
+
+static void queue_flush(struct queue **head)
+{
+	while (!queue_empty(head))
+		queue_topkill(head);
+}
+
+/* Use this #define to activate dump debug functions and add it where you need
+ * to dump in the code */
+#ifdef ISP1763_UDC_DUMP_DEBUG
+/**
+* dump_ctrlrequest - debug - dump control request
+* @req: pointer to request structure
+*/
+static void dump_ctrlrequest(struct usb_ctrlrequest *req)
+{
+	char reqname[64] = "???";
+	char typename[64] = "???";
+	switch (req->bRequestType & USB_TYPE_MASK) {
+	case USB_TYPE_STANDARD:
+		sprintf(typename, "STD");
+		switch (req->bRequest) {
+		case USB_REQ_GET_STATUS:
+			sprintf(reqname, "USB_REQ_GET_STATUS");
+			break;
+		case USB_REQ_CLEAR_FEATURE:
+			sprintf(reqname, "USB_REQ_CLEAR_FEATURE");
+			break;
+		case USB_REQ_SET_FEATURE:
+			sprintf(reqname, "USB_REQ_SET_FEATURE");
+			break;
+		case USB_REQ_SET_ADDRESS:
+			sprintf(reqname, "USB_REQ_SET_ADDRESS(%i)",
+				le16_to_cpu(req->wValue));
+			break;
+		case USB_REQ_GET_DESCRIPTOR:
+			sprintf(reqname, "USB_REQ_GET_DESCRIPTOR");
+			break;
+		case USB_REQ_SET_DESCRIPTOR:
+			sprintf(reqname, "USB_REQ_SET_DESCRIPTOR");
+			break;
+		case USB_REQ_GET_CONFIGURATION:
+			sprintf(reqname, "USB_REQ_GET_CONFIGURATION");
+			break;
+		case USB_REQ_SET_CONFIGURATION:
+			sprintf(reqname, "USB_REQ_SET_CONFIGURATION");
+			break;
+		case USB_REQ_GET_INTERFACE:
+			sprintf(reqname, "USB_REQ_GET_INTERFACE");
+			break;
+		case USB_REQ_SET_INTERFACE:
+			sprintf(reqname, "USB_REQ_SET_INTERFACE");
+			break;
+		case USB_REQ_SYNCH_FRAME:
+			sprintf(reqname, "USB_REQ_SYNCH_FRAME");
+			break;
+		}
+		break;
+	case USB_TYPE_CLASS:
+		sprintf(typename, "CLASS");
+		switch (req->bRequest) {
+		case USB_CDC_SEND_ENCAPSULATED_COMMAND:
+			sprintf(reqname,
+				"USB_CDC_SEND_ENCAPSULATED_COMMAND");
+			break;
+		case USB_CDC_GET_ENCAPSULATED_RESPONSE:
+			sprintf(reqname,
+				"USB_CDC_GET_ENCAPSULATED_RESPONSE");
+			break;
+		case USB_CDC_REQ_SET_LINE_CODING:
+			sprintf(reqname, "USB_CDC_REQ_SET_LINE_CODING");
+			break;
+		case USB_CDC_REQ_GET_LINE_CODING:
+			sprintf(reqname, "USB_CDC_REQ_GET_LINE_CODING");
+			break;
+		case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
+			sprintf(reqname,
+				"USB_CDC_REQ_SET_CONTROL_LINE_STATE");
+			break;
+		case USB_CDC_REQ_SEND_BREAK:
+			sprintf(reqname, "USB_CDC_REQ_SEND_BREAK");
+			break;
+		case USB_CDC_SET_ETHERNET_MULTICAST_FILTERS:
+			sprintf(reqname,
+				"USB_CDC_SET_ETHERNET_MULTICAST_FILTERS");
+			break;
+		case USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER:
+			sprintf(reqname,
+				"USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER");
+			break;
+		case USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER:
+			sprintf(reqname,
+				"USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER");
+			break;
+		case USB_CDC_SET_ETHERNET_PACKET_FILTER:
+			sprintf(reqname,
+				"USB_CDC_SET_ETHERNET_PACKET_FILTER");
+			break;
+		case USB_CDC_GET_ETHERNET_STATISTIC:
+			sprintf(reqname, "USB_CDC_GET_ETHERNET_STATISTIC");
+			break;
+		}
+
+		break;
+	case USB_TYPE_VENDOR:
+		sprintf(typename, "VENDOR");
+		sprintf(reqname, "%.2x", req->bRequest);
+		break;
+	}
+
+	printk(KERN_INFO "bRequestType: 0x%.2x (%s)\n",
+		    req->bRequestType, typename);
+	printk(KERN_INFO "bRequest:     0x%.2x (%s)\n", req->bRequest,
+		    reqname);
+	printk(KERN_INFO "wValue:       0x%.4x\n", req->wValue);
+	printk(KERN_INFO "wIndex:       0x%.4x\n", req->wIndex);
+	printk(KERN_INFO "wLength:      0x%.4x\n", req->wLength);
+}
+
+/**
+* dump_usb_request - debug - dump USB request
+* @ep: pointer to EP struct
+* @req: pointer to request
+*/
+static void dump_usb_request(struct usb_ep *ep, struct usb_request *req)
+{
+	int i;
+
+#define MAXDUMPLEN 64
+	info_printk("\n%s on %s: ", __func__, ep->name);
+	for (i = 0;
+	     i < (req->length > MAXDUMPLEN ? MAXDUMPLEN : req->length);
+	     i++) {
+		info_printk("%.2x ", ((char *) req->buf)[i]);
+	}
+	info_printk("\n");
+}
+#endif /* ISP1763_UDC_DUMP_DEBUG */
+
+/**
+* get_ep_index - get endpoint index
+* @ep: endpoint pointer
+*/
+static int get_ep_index(struct usb_ep *ep)
+{
+	int i;
+	for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
+		if (&isp_eps[i].ep == ep)
+			return i;
+	}
+	return -1;
+}
+
+/**
+* ep_set_index - set PIO endpoint index
+* @dev: UDC device pointer
+* @index: new EP index
+*/
+static void ep_set_index(struct isp1763_udc *dev, unsigned char index)
+{
+	isp1763_writew(index, &dev->regs->ep_index);
+	isp1763_writew(~index, &dev->regs->dma_ep);
+	ndelay(200);
+}
+
+/**
+* ep_stall - stall endpoint
+* @dev: UDC device pointer
+* @idx: index of ep to stall
+* @do_stall: 1=stall, 0=unstall
+*/
+static void ep_stall(struct isp1763_udc *dev, int idx, int do_stall)
+{
+	warn_printk(KERN_ERR "%sSTALLING EP INDEX %i\n",
+		    do_stall ? "" : "UN", idx);
+	ep_set_index(dev, idx);
+
+	if (do_stall)
+		set_stall_flag(dev);
+	else
+		clr_stall_flag(dev);
+}
+
+#define REAL_EP_NUM(x) (((x & 0x0F) << 1) | x >> 7)
+
+/**
+* ep_feature - handle EP feature request
+* @dev: UDC device pointer
+* @req: pointer to request
+*/
+static void
+ep_feature(struct isp1763_udc *dev, struct usb_ctrlrequest *req)
+{
+	if (le16_to_cpu(req->wValue) == USB_ENDPOINT_HALT) {
+		ep_stall(dev, REAL_EP_NUM(le16_to_cpu(req->wIndex)),
+			 req->bRequest == USB_REQ_SET_FEATURE ? 1 : 0);
+	} else {
+		set_status_flag(dev);
+	}
+}
+
+/**
+* write_ep - write data to endpoint
+* @dev: UDC device pointer
+* @buf: buffer to send
+* @buflen: buffer length
+*/
+static int
+write_ep(struct isp1763_udc *dev, unsigned short *buf, int buflen)
+{
+	int i = 0;
+
+	if (!buf && buflen > 0) {
+		warn_printk(KERN_ERR
+			    "%s: NULL buffer submitted with len %i!\n",
+			    __func__, buflen);
+		return 0;
+	}
+
+	isp1763_writew(buflen, &dev->regs->buflen);
+	disable_glint__(dev);
+
+	for (i = 0; i < (buflen / 2); i++)
+		__raw_writew(buf[i], &dev->regs->data_port);
+
+	if (buflen % 2) {
+		char *bufc = (char *) buf;
+		__raw_writew((unsigned short)
+				(bufc[buflen - 1] | (bufc[buflen - 1] << 8)),
+				&dev->regs->data_port);
+	}
+
+	enable_glint(dev);
+
+	return i * 2 - (buflen % 2);
+}
+
+/**
+* read_ep0 - read request from endpoint 0
+* @dev: UDC device pointer
+* @req: pointer to request to fill
+*/
+int read_ep0(struct isp_ep *ep, struct usb_request *req)
+{
+	struct isp1763_udc *dev = ep->udc;
+	unsigned short *buf;
+	int i;
+	int reqreadlen;
+	int buflen = 0;
+
+	if (!req)
+		return -EINVAL;
+
+	reqreadlen = req->length - req->actual;
+
+	disable_glint(dev);
+
+	buf = (unsigned short *) ((char *) req->buf + req->actual);
+	buflen = reqreadlen > 64 ? 64 : reqreadlen;
+
+	for (i = 0; i < (buflen / 2); i++)
+		buf[i] = __raw_readw(&dev->regs->data_port);
+
+	if (buflen % 2) {
+		char *bufc = (char *) buf;
+		bufc[buflen - 1] =
+		    (char) (__raw_readw(&dev->regs->data_port) & 0xff);
+	}
+
+	req->actual += buflen;
+
+	/*
+	 * Complete if buf filled to capacity or buflen < wMaxPacketSize
+	 * (short packet)
+	*/
+	if (req->actual == req->length || buflen < ep->maxpacketsize) {
+		req->status = 0;
+		set_status_flag(dev);
+		enable_glint(dev);
+		return 1;
+	}
+
+	enable_glint(dev);
+	return 0;
+}
+
+/**
+* read_ep - read data from endpoint
+* @ep: endpoint
+* @req: request
+*/
+int read_ep(struct isp_ep *ep, struct usb_request *req)
+{
+	struct isp1763_udc *dev = ep->udc;
+	int buflen = -1;
+	unsigned short *buf;
+	int i;
+	int reqreadlen = req->length - req->actual;
+
+	/*
+	 * At first I believed this to be a source of errors, but actually
+	 * a RX interrupt without any data is caused by a icr setting where
+	 * an int is generated on the first NAK after previously having an ACK.
+	 * This is it. Nothing to it, so just leave and do naught.
+	 */
+	if (isp1763_readw(&dev->regs->dcbufstatus) == 0)
+		return -1;
+
+	if (req->buf == NULL) {
+		error_printk(KERN_ERR
+			     "%s(): ERROR! req->buf == NULL! (len=%i) %p\n",
+			     __func__, req->length, req);
+		req->actual = 0;
+		req->status = -EINVAL;
+		if (!req->no_interrupt)
+			if (req->complete) {
+				debug_printk(KERN_ERR
+					     "Completing request %p\n",
+					     req);
+				req->complete(&ep->ep, req);
+			}
+		return -1;
+	}
+
+	buflen = isp1763_readw(&dev->regs->buflen);
+
+	/*
+	 * Seems inevitable, but what would happen to the rest of the buffer?
+	 * Does this even happen?
+	*/
+	if (reqreadlen < buflen)
+		buflen = reqreadlen;
+
+	buf = (unsigned short *) ((char *) req->buf + req->actual);
+
+	disable_glint(dev);
+
+	for (i = 0; i < (buflen / 2); i++)
+		buf[i] = __raw_readw(&dev->regs->data_port);
+
+	if (buflen % 2) {
+		char *bufc = (char *) buf;
+		bufc[buflen - 1] =
+		    (char) (readw(&dev->regs->data_port) & 0xFF);
+	}
+
+	req->actual += buflen;
+
+	enable_glint(dev);
+
+	/*
+	 * Complete if buf filled to capacity or buflen < wMaxPacketSize
+	 * (short packet)
+	*/
+	if (req->actual == req->length || buflen < ep->maxpacketsize) {
+		req->status = 0;
+		isp1763_writew(0, &dev->regs->dcbufstatus);
+		set_clbuf_flag(dev);
+		if (!req->no_interrupt)
+			if (req->complete) {
+				debug_printk(KERN_ERR
+					     "Completing OUT request %p (%i bytes)\n",
+					     req, req->actual);
+				req->complete(&ep->ep, req);
+			}
+		return 1;
+	}
+
+	return 0;
+}
+
+/* EP0 FUNCTIONS */
+
+/**
+* configure_ep0 - configure control endpoint
+* @dev: UDC device pointer
+*/
+static int configure_ep0(struct isp1763_udc *dev)
+{
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		ep_set_index(dev, EP_INDEX(0, DIR_RX));
+		isp1763_writew(64, &dev->regs->ep_maxpktsize);
+		isp1763_writew(EP_TYPE_UNUSED | (i << 3),
+			       &dev->regs->ep_type);
+
+		ep_set_index(dev, EP_INDEX(0, DIR_TX));
+		isp1763_writew(64, &dev->regs->ep_maxpktsize);
+		isp1763_writew(EP_TYPE_UNUSED | (i << 3),
+			       &dev->regs->ep_type);
+
+		ep_set_index(dev, IDX_EP0_SETUP);
+		isp1763_writew(64, &dev->regs->ep_maxpktsize);
+		isp1763_writew(EP_TYPE_UNUSED | (i << 3),
+			       &dev->regs->ep_type);
+
+		udelay(5);
+	}
+
+	return 0;
+}
+
+/**
+* read_ep0_setup - read control endpoint setup request
+* @dev: UDC device pointer
+* @buf: buffer
+* @buflen: length of buffer
+*/
+static int
+read_ep0_setup(struct isp1763_udc *dev, unsigned short *buf, int buflen)
+{
+	int readlen = 0;
+	int i;
+
+	ep_set_index(dev, IDX_EP0_SETUP);
+
+	readlen = isp1763_readw(&dev->regs->buflen);
+
+	if (buflen < readlen)
+		return -ENOMEM;
+
+	disable_glint(dev);
+
+	for (i = 0; i < ((readlen / 2) + (readlen % 2)); i++)
+		buf[i] = __raw_readw(&dev->regs->data_port);
+
+	if (buflen % 2) {
+		char *bufc = (char *) buf;
+		bufc[buflen - 1] =
+		    (char) (__raw_readw(&dev->regs->data_port) & 0xff);
+	}
+
+	enable_glint(dev);
+
+	return readlen;
+}
+
+/**
+* handle_ep0_setup - handle control endpoint setup IRQ
+*/
+static void handle_ep0_setup(struct isp1763_udc *dev)
+{
+	char buffer[8];
+	struct usb_ctrlrequest *setup_request;
+	int readlen = 0;
+	int ret = 0;
+
+	memset(buffer, 0, sizeof(buffer));
+	readlen = read_ep0_setup(dev, (unsigned short *) buffer,
+						sizeof(buffer));
+
+	if (readlen < sizeof(struct usb_ctrlrequest)) {
+		warn_printk(KERN_ERR "short setup packet!\n");
+		return;
+	}
+	setup_request = (struct usb_ctrlrequest *) buffer;
+
+	if ((setup_request->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
+		goto non_standard;
+
+	/* STANDARD REQUEST */
+	dev->ep0->state = DIR_TX;
+
+	switch (setup_request->bRequest) {
+	case USB_REQ_SET_ADDRESS:
+		isp1763_writew(le16_to_cpu(setup_request->wValue) |
+					0x80, &dev->regs->address);
+		set_status_flag(dev);
+		break;
+	case USB_REQ_SET_FEATURE:
+	case USB_REQ_CLEAR_FEATURE:
+		ep_feature(dev, setup_request);
+		break;
+	default:
+		/*
+		 * TODO: Check if setup() left any data for us to process,
+		 * if not, ZiLP EP
+		*/
+
+		if (!dev->driver)
+			return;
+
+		ret = dev->driver->setup(dev->gadget, setup_request);
+		if (ret < 0) {
+			error_printk(KERN_ERR
+					"###### ERROR : ->setup() returned with %i\n",
+					ret);
+			ep_stall(dev, 0, 1);
+		}
+		if (setup_request->bRequest & USB_DIR_IN) {
+			if (queue_empty(&dev->ep0->queue) &&
+					(setup_request->bRequest & 0x80)) {
+				ep_set_index(dev, EP_INDEX(0, DIR_TX));
+				set_dsen_flag(dev);
+				write_ep(dev, NULL, 0);
+				set_vendp_flag(dev);
+			}
+		} else if (setup_request->bRequest ==
+				USB_REQ_SET_CONFIGURATION) {
+			ep_set_index(dev, EP_INDEX(0, DIR_TX));
+			write_ep(dev, NULL, 0);
+			set_status_flag(dev);
+		}
+	}
+	return;
+
+	/* CLASS / VENDOR REQUEST */
+non_standard:
+	debug_printk(KERN_ERR
+			"Processing EP0 class/vendor request\n");
+
+	if (setup_request->bRequestType & USB_DIR_IN) {
+		info_printk(KERN_ERR "CLASS IN REQUEST\n");
+		dev->ep0->state = DIR_TX;
+	} else {
+		int timeout = 0;
+		ep_set_index(&udc_dev, EP_INDEX(0, DIR_RX));
+		clr_dsen_flag(&udc_dev);
+		set_dsen_flag(&udc_dev);
+#if 1
+		while (!isp1763_readw(&dev->regs->buflen)) {
+			udelay(10);
+			if (++timeout > 1000) {
+				printk(KERN_EMERG "TIMEOUT!\n");
+				break;
+			ep_set_index(&udc_dev, EP_INDEX(0, DIR_RX));
+
+			}
+		}
+#endif
+		info_printk(KERN_ERR "CLASS OUT REQUEST\n");
+		if (0) {
+			int i;
+
+			printk(KERN_ERR "DATA IN BUFFER FOR EP %i RIGHT NOW: ",
+			       isp1763_readw(&dev->regs->ep_index));
+
+			for (i = 0; i < 16; i++)
+				printk("%.4x ",
+				       isp1763_readw(&dev->regs->data_port));
+			printk(KERN_ERR "\n");
+		}
+
+		debug_printk(KERN_ERR "dcBufferStatus: %.4x buflen: %i\n",
+				isp1763_readw(&dev->regs->dcbufstatus),
+				isp1763_readw(&dev->regs->buflen));
+		dev->ep0->state = DIR_RX;
+	}
+
+	/* Probably a class request */
+	ret = dev->driver->setup(dev->gadget, setup_request);
+	if (ret < 0) {
+		printk(KERN_ERR "dev->driver->setup() returned %i!"
+			"stalling ep0...\n", ret);
+		ep_stall(dev, 0, 1);
+		return;
+	}
+
+	if (setup_request->bRequestType & USB_DIR_IN) {
+		/* ??? */
+	} else {
+		ep_set_index(dev, EP_INDEX(0, DIR_RX));
+		set_dsen_flag(dev);
+		/* printk(KERN_ERR "%s:%i %s()\n",
+		 * __FILE__,__LINE__,__func__);
+		 */
+		set_status_flag(dev);
+	}
+}
+
+/* DEVICE ENABLE / DISABLE */
+
+/**
+* isp1763_udc_disable - disable controller activity
+* @dev: UDC device pointer
+*/
+static void isp1763_udc_disable(struct isp1763_udc *dev)
+{
+	isp1763_writew(0, &dev->regs->address);
+}
+
+/**
+* isp1763_udc_enable - enable controller activity
+* @dev: UDC device pointer
+*/
+static void isp1763_udc_enable(struct isp1763_udc *dev)
+{
+	isp1763_writew(MASK_MODE_CLKAON | MASK_MODE_GLINTENA |
+		       MASK_MODE_WKUPCS, &dev->regs->mode);
+	isp1763_writel(0xFFFFFFFF, &dev->regs->dc_interrupt);
+	isp1763_writel(irq_bits,
+		       &dev->regs->dc_int_enable);
+	isp1763_writew(0x80, &dev->regs->address);
+}
+
+/* ENDPOINT OPS */
+
+static int ep_fifo_space_available = TOTAL_FIFO_SIZE - (3 * 64);
+
+/**
+* isp1763_udc_ep_enable - enable EP (EP API)
+* @ep: USB endpoint to enable
+* @desc: configuration descriptor
+*/
+static int isp1763_udc_ep_enable(struct usb_ep *ep,
+				const struct usb_endpoint_descriptor *desc)
+{
+	struct isp1763_udc *dev = &udc_dev;
+	struct isp_ep *ispep = ep->driver_data;
+	int ep_index = 0;
+	int fifo_size = 0;
+	unsigned long flags = 0;
+
+	info_printk(KERN_ERR "%s:%i: %s(%s)\n", __FILE__, __LINE__,
+		    __func__, ep->name);
+
+	fifo_size = le16_to_cpu(desc->wMaxPacketSize) & 0x7FF;
+	if (ep_fifo_space_available < fifo_size) {
+		error_printk(KERN_ERR
+			     "%s: no FIFO space available for %s, requested %i bytes, have %i\n",
+			     __func__, ep->name, fifo_size,
+			     ep_fifo_space_available);
+		return -ENOMEM;
+	}
+
+	local_irq_save(flags);
+
+	ep_index = get_ep_index(ep);
+	if (ep_index < 0) {
+		error_printk(KERN_ERR
+			     "%s:%i: %s INVALID ENDPOINT INDEX %i\n",
+			     __FILE__, __LINE__, __func__, ep_index);
+		local_irq_restore(flags);
+		return -EINVAL;
+	}
+
+	ispep = &isp_eps[ep_index];
+	dev = ispep->udc;
+
+	ep_set_index(dev, ispep->index);
+
+	info_printk(KERN_ERR "%s:%i: %s(%s=type %i;maxsize=%i)\n",
+		    __FILE__, __LINE__, __func__, ep->name,
+		    desc->bmAttributes & 0x03,
+		    le16_to_cpu(desc->wMaxPacketSize));
+
+	isp1763_writew(desc->bmAttributes & 0x03, &dev->regs->ep_type);
+	isp1763_writew(fifo_size, &dev->regs->ep_maxpktsize);
+
+	isp1763_writew((desc->
+			bmAttributes & 0x03) | EP_TYPE_ENABLE |
+		       EP_TYPE_DBLBUF, &dev->regs->ep_type);
+
+	/* clear buffers, twice for double buffering */
+	set_clbuf_flag(dev);
+	clr_clbuf_flag(dev);
+	set_clbuf_flag(dev);
+	clr_clbuf_flag(dev);
+
+	ispep->maxpacketsize = fifo_size;
+	ispep->ep_type = desc->bmAttributes & 0x03;
+
+	ep_fifo_space_available -= fifo_size * 2;
+
+	memcpy(&ispep->desc, desc, sizeof(struct usb_endpoint_descriptor));
+
+	irq_bits |= 1 << (ep_index + 12);
+	isp1763_writew(irq_bits, &dev->regs->dc_int_enable);
+	/* printk(KERN_ERR "Enabling bit %.8lx in irq_bits\n",
+	 *      1 << (ep_index + 10));
+	 */
+	local_irq_restore(flags);
+	return 0;
+}
+
+/**
+* isp1763_udc_ep_disable - disable EP (EP API)
+* @ep: USB endpoint to disable
+*/
+static int isp1763_udc_ep_disable(struct usb_ep *ep)
+{
+	struct isp1763_udc *dev = &udc_dev;
+	struct isp_ep *ispep;
+	int ep_index = 0;
+	unsigned long flags;
+
+	info_printk(KERN_ERR "%s:%i: %s(%s)\n", __FILE__, __LINE__,
+		    __func__, ep->name);
+
+	local_irq_save(flags);
+
+	ep_index = get_ep_index(ep);
+	if (ep_index < 0) {
+		error_printk(KERN_ERR
+			     "%s:%i: %s INVALID ENDPOINT INDEX %i\n",
+			     __FILE__, __LINE__, __func__, ep_index);
+		local_irq_restore(flags);
+		return -EINVAL;
+	}
+
+
+	irq_bits &= ~(1 << (ep_index + 12));
+	isp1763_writew(irq_bits, &dev->regs->dc_int_enable);
+	/* printk(KERN_ERR "Disabling bit %.8lx in irq_bits\n",
+	 * 1 << (ep_index + 10));
+	 */
+
+	ispep = &isp_eps[ep_index];
+	dev = ispep->udc;
+
+	ep_fifo_space_available += ispep->maxpacketsize;
+
+	ispep->maxpacketsize = 0;
+
+	ep_set_index(dev, ispep->index);
+	isp1763_writew(0, &dev->regs->ep_type);
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+/**
+* isp1763_udc_ep_alloc_request - allocate usb_request structure (EP API)
+* @ep: USB endpoint
+* @gfp_flags: unused
+*/
+static struct usb_request *isp1763_udc_ep_alloc_request(struct usb_ep *ep,
+							gfp_t gfp_flags)
+{
+	struct usb_request *req =
+	    kmalloc(sizeof(struct usb_request), GFP_ATOMIC);
+	info_printk(KERN_ERR "%s:%i: %s(%s) = %p\n", __FILE__, __LINE__,
+		    __func__, ep->name, req);
+
+	memset(req, 0, sizeof(*req));
+	return req;
+}
+
+/**
+* isp1763_udc_ep_free_request - free USB request (EP API)
+* @ep: USB endpoint
+* @req: request to free
+*/
+static void
+isp1763_udc_ep_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+	info_printk(KERN_ERR "%s:%i: %s(%s)\n", __FILE__, __LINE__,
+		    __func__, ep->name);
+	kfree(req);
+}
+
+/**
+* isp1763_udc_ep_queue - queue request on endpoint queue (EP API)
+* @ep: USB endpoint
+* @req: request to queue
+* @gfp_flags: unused
+*/
+static int
+isp1763_udc_ep_queue(struct usb_ep *ep, struct usb_request *req,
+		     gfp_t gfp_flags)
+{
+
+	unsigned long flags = 0;
+	struct isp1763_udc *dev = &udc_dev;
+	local_irq_save(flags);
+
+	disable_glint(dev);
+
+	debug_printk(KERN_ERR "%s:%i: %s(%s) %i bytes %p\n", __FILE__,
+		     __LINE__, __func__, ep->name, req->length, req);
+
+	if (req->buf == NULL && req->length > 0) {
+		error_printk(KERN_ERR "%s: INVALID REQUEST\n",
+			     __func__);
+		req->status = -EINVAL;
+		local_irq_restore(flags);
+		enable_glint(dev);
+		return req->status;
+	}
+
+	req->status = -EINPROGRESS;
+	req->actual = 0;
+
+	if (ep == udc_dev.gadget->ep0) {
+		queue_add(&udc_dev.ep0->queue, req);
+
+		if (udc_dev.ep0->state == DIR_TX) {
+			debug_printk(KERN_ERR "QUEUE EP0 TX PACKET\n");
+
+			ep_set_index(&udc_dev, EP_INDEX(0, DIR_TX));
+			set_dsen_flag(&udc_dev);
+
+			req->actual =
+				write_ep(&udc_dev,
+					(unsigned short *) req->buf,
+					req->length <= 64 ? req->length : 64);
+			if (req->actual < 64)
+				set_vendp_flag(&udc_dev);
+		}
+
+		else {
+			int i;
+			int ret = 0;
+
+			mdelay(1);
+			memset((char *) req->buf, 0, req->length);
+			#if 0
+			ep_set_index(&udc_dev, EP_INDEX(0, DIR_RX));
+			set_dsen_flag(&udc_dev);
+			#endif
+
+more:
+			for (i = 0; i < 150; i++) {
+				ep_set_index(&udc_dev, EP_INDEX(0, DIR_RX));
+				if (isp1763_readw(&dev->regs->buflen))
+					break;
+			}
+			if (!isp1763_readw(&dev->regs->buflen)) {
+				printk(KERN_ERR
+				       "%s ERROR: buflen == 0, bufstatus=%.4x\n",
+				       __func__,
+				       isp1763_readw(&dev->regs->dcbufstatus));
+				local_irq_restore(flags);
+				enable_glint(&udc_dev);
+				return -EAGAIN;
+			}
+
+			ret = read_ep0(udc_dev.ep0, req);
+			if (ret == 1) {
+				if ((!req->no_interrupt) && (req->complete)) {
+					debug_printk(KERN_ERR "Completing OUT "
+						"request %p (%i bytes) "
+						"p=%p ep=%p\n",
+						req, req->actual,
+						req->complete, ep);
+						req->complete(ep, req);
+				}
+			} else if (ret == 0)
+				goto more;
+
+		}
+	}
+	/* normal data transfer */
+	else {
+		struct isp_ep *ispep;
+		int ep_index = get_ep_index(ep);
+
+		if (ep_index < 0) {
+			error_printk(KERN_ERR
+				     "ERROR: INVALID EP POINTER %p\n", ep);
+			local_irq_restore(flags);
+			enable_glint(dev);
+			return -EINVAL;
+		}
+
+		ispep = &isp_eps[ep_index];
+		queue_add(&ispep->queue, req);
+
+		/* IN transfer */
+		if (GET_EP_DIR(ep_index) == DIR_TX)
+			/* && ispep->ep_type != EP_TYPE_INTERRUPT */ {
+			if (isp1763_readw(&dev->regs->buflen) == 0
+				    && queue_count(&ispep->queue) == 1) {
+				ep_set_index(&udc_dev, ispep->index);
+				req->actual +=
+				    write_ep(&udc_dev,
+					     (unsigned short *) req->buf,
+					     req->length <=
+					     ispep->maxpacketsize ? req->length
+					     : ispep->maxpacketsize);
+				if (req->actual == req->length)
+					set_vendp_flag(&udc_dev);
+			}
+		}
+	}
+
+	local_irq_restore(flags);
+	enable_glint(dev);
+	return 0;
+}
+
+/**
+* isp1763_udc_ep_dequeue - dequeue endpoint request
+* @ep: endpoint
+* @req: request
+*
+* NOTE: currently unimplemented
+*/
+static int
+isp1763_udc_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+	info_printk(KERN_ERR "%s:%i: %s(%s)\n", __FILE__, __LINE__,
+		    __func__, ep->name);
+	return 0;
+}
+
+static int isp1763_udc_ep_set_halt(struct usb_ep *ep, int value)
+{
+	info_printk(KERN_ERR "%s:%i: %s(%s)\n", __FILE__, __LINE__,
+		    __func__, ep->name);
+	return 0;
+}
+
+static int isp1763_udc_ep_set_wedge(struct usb_ep *ep)
+{
+	info_printk(KERN_ERR "%s:%i: %s(%s)\n", __FILE__, __LINE__,
+		    __func__, ep->name);
+	return 0;
+}
+
+static int isp1763_udc_ep_fifo_status(struct usb_ep *ep)
+{
+	info_printk(KERN_ERR "%s:%i: %s(%s)\n", __FILE__, __LINE__,
+		    __func__, ep->name);
+	return 0;
+}
+
+static void isp1763_udc_ep_fifo_flush(struct usb_ep *ep)
+{
+	info_printk(KERN_ERR "%s:%i: %s(%s)\n", __FILE__, __LINE__,
+		    __func__, ep->name);
+}
+
+static struct usb_ep_ops isp1763_ep_ops = {
+	.enable = isp1763_udc_ep_enable,
+	.disable = isp1763_udc_ep_disable,
+	.alloc_request = isp1763_udc_ep_alloc_request,
+	.free_request = isp1763_udc_ep_free_request,
+	.queue = isp1763_udc_ep_queue,
+	.dequeue = isp1763_udc_ep_dequeue,
+	.set_halt = isp1763_udc_ep_set_halt,
+	.set_wedge = isp1763_udc_ep_set_wedge,
+	.fifo_status = isp1763_udc_ep_fifo_status,
+	.fifo_flush = isp1763_udc_ep_fifo_flush,
+};
+
+/* GADGET OPS */
+
+/**
+* isp_get_frame - return frame number
+* @gadget: gadget pointer
+*/
+static int isp_get_frame(struct usb_gadget *gadget)
+{
+	/* FIXE: replaced with get_gadget_data
+	 * struct isp1763_dev *dev = gadget->dev.driver_data;
+	 */
+	struct isp1763_dev *dev = get_gadget_data(gadget);
+	unsigned long flags;
+	int ret = 0;
+
+	local_irq_save(flags);
+	ret = isp1763_readw(&dev->regs->frameno);
+	local_irq_restore(flags);
+
+	return ret;
+}
+
+/**
+* isp_pullup - enable or disable pullup
+* @gadget: gadget pointer
+* @is_on: on/off
+*
+* Enable or disable pullup on D+
+* I'm not actually sure it's a good idea to implement this, nor do
+* I know a gadget driver that uses it...
+*/
+static int isp_pullup(struct usb_gadget *gadget, int is_on)
+{
+	/* FIXME: replaced with get_gadget_data
+	 * struct isp1763_dev *dev = gadget->dev.driver_data;
+	 */
+	struct isp1763_dev *dev = get_gadget_data(gadget);
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (is_on)
+		isp1763_writel(MASK_OTGCTRL_DP_PULLUP,
+			       &dev->regs->otg_ctrl);
+	else
+		isp1763_writel(MASK_OTGCTRL_DP_PULLUP << 16,
+			       &dev->regs->otg_ctrl);
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+static int isp_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+	return -ENOTSUPP;
+}
+
+static int isp_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+	return -ENOTSUPP;
+}
+
+static int isp_wakeup(struct usb_gadget *gadget)
+{
+	return -ENOTSUPP;
+}
+
+static struct usb_gadget_ops isp1763_gadget_ops = {
+	.get_frame = isp_get_frame,
+	.wakeup = isp_wakeup,
+	.vbus_session = isp_vbus_session,
+	.vbus_draw = isp_vbus_draw,
+	.pullup = isp_pullup,
+
+};
+
+/* GADGET DEVICE FUNCTIONS */
+
+/**
+* usb_gadget_register_driver - register gadget driver
+* @driver: gadget driver to register
+*/
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	if (!driver ||
+	    !driver->bind ||
+	    !driver->unbind ||
+	    !driver->setup || driver->speed != USB_SPEED_HIGH) {
+		return -EINVAL;
+	}
+
+	info_printk(KERN_ERR "%s: registering gadget function '%s'\n",
+		    __FILE__, driver->function);
+
+	udc_dev.driver = driver;
+
+	udc_dev.driver->bind(udc_dev.gadget);
+
+	if (udc_dev.ctrl.active) {
+		configure_ep0(&udc_dev);
+		isp1763_udc_enable(&udc_dev);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_register_driver);
+
+/**
+* usb_gadget_unregister_driver - unregister gadget driver
+* @driver: gadget driver to unregister
+*/
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	if (udc_dev.ctrl.active)
+		isp1763_udc_disable(&udc_dev);
+
+	/* FIXME: Need to do some more here? */
+	udc_dev.driver->unbind(udc_dev.gadget);
+
+	udc_dev.driver = NULL;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver);
+
+static struct usb_ep ep0 = {
+	.name = "ep0",
+	.ops = &isp1763_ep_ops,
+	.maxpacket = 64,
+};
+
+static struct usb_gadget isp1763_gadget = {
+	.ops = &isp1763_gadget_ops,
+	.ep0 = &ep0,
+	.name = "isp1763_udc",
+	.speed = USB_SPEED_HIGH,
+	.is_otg = 1,
+	.b_hnp_enable = 0,
+	.a_hnp_support = 0,
+	.a_alt_hnp_support = 0,
+};
+
+/**
+* setup_ep_struct - setup endpoint structures
+* @dev: UDC device
+*/
+static void setup_ep_struct(struct isp1763_udc *dev)
+{
+	int i = 0;
+
+	dev->ep0 = kmalloc(sizeof(struct isp_ep), GFP_ATOMIC);
+	memset(dev->ep0, 0, sizeof(struct isp_ep));
+
+	INIT_LIST_HEAD(&dev->gadget->ep_list);
+	dev->ep0->queue = NULL;
+	dev->ep0->udc = &udc_dev;
+	dev->ep0->gadget = dev->gadget;
+	dev->ep0->state = 0;
+	dev->ep0->ep_type = EP_TYPE_UNUSED;
+	snprintf(dev->ep0->name, 8, "ep0");
+	dev->ep0->index = 0;
+
+
+	for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
+		isp_eps[i].queue = NULL;
+		isp_eps[i].ep.driver_data = NULL;
+		isp_eps[i].ep.ops = &isp1763_ep_ops;
+		isp_eps[i].ep.ep_list = dev->gadget->ep_list;
+		isp_eps[i].ep.maxpacket = 4096;
+		isp_eps[i].udc = dev;
+		isp_eps[i].gadget = dev->gadget;
+		isp_eps[i].state = 0;
+		isp_eps[i].ep_type = EP_TYPE_UNUSED;
+		snprintf(isp_eps[i].name, 8, "ep%i%s",
+			 GET_EP_NUM_CANONICAL(i) + 1,
+			 GET_EP_DIR(i) == DIR_TX ? "in" : "out");
+		isp_eps[i].ep.name = kstrdup(isp_eps[i].name, GFP_KERNEL);
+		isp_eps[i].index = i + 2;
+		list_add_tail(&isp_eps[i].ep.ep_list,
+			      &dev->gadget->ep_list);
+
+	}
+}
+
+static void destroy_ep_struct(struct isp1763_udc *dev)
+{
+	int i = 0;
+
+	for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
+		queue_flush(&isp_eps[i].queue);
+		kfree(isp_eps[i].ep.name);
+	}
+
+	queue_flush(&dev->ep0->queue);
+	kfree(dev->ep0);
+}
+
+/* IF FUNCTIONS */
+/**
+* handle_ep_irq - handle endpoint interrupts
+* @dev: UDC device
+* @bit: interrupt bit
+*/
+static void handle_ep_irq(struct isp1763_udc *dev, int bit)
+{
+	struct usb_request *req;
+	int ep_index = bit + 2;
+	struct isp_ep *ispep = NULL;
+
+	ispep = &dev->eps[bit];
+
+	debug_printk(KERN_ERR "Interrupt for EP %s (Bit %i, epindex %i)\n",
+			ispep->name, bit, ep_index);
+
+	if (queue_empty(&ispep->queue)) {
+		queue_printk(KERN_ERR "%s/%s queue empty!\n",
+				ispep->name,
+				ispep->ep.name);
+		goto done;
+	}
+
+	ep_set_index(dev, ep_index);
+	req = queue_get(&ispep->queue);
+
+	if (GET_EP_DIR(ep_index) == DIR_RX) {
+		if (read_ep(ispep, req) > 0)
+			queue_topkill(&ispep->queue);
+	} else {
+		int already_sent_data = 0;
+		/*
+			* check if there's more data to write for
+			* previous packet, otherwise send completion
+		*/
+		if (req->actual == req->length) {
+			if (req->actual > 0
+				&& req->actual % 512 == 0) {
+				/*
+				* insert ZLP to terminate transaction where
+				* length is a multiple of 512
+				*/
+				write_ep(&udc_dev, NULL, 0);
+				set_vendp_flag(&udc_dev);
+			}
+			req->status = 0;
+
+			if (req->complete) {
+				debug_printk
+					(KERN_ERR
+					"Completing IN request %p (%i bytes)\n",
+					req, req->actual);
+				req->complete(&ispep->ep, req);
+			}
+			queue_topkill(&ispep->queue);
+		} else {
+			int written;
+
+			already_sent_data = 1;
+			written = write_ep(&udc_dev,
+					(unsigned short	*) ((char *)
+						req->buf + req->actual),
+					(req->length - req->actual) <=
+						ispep->maxpacketsize
+						? (req->length - req->actual) :
+						ispep->maxpacketsize);
+			if (written < ispep->maxpacketsize)
+				set_vendp_flag(&udc_dev);
+
+			req->actual += written;
+		}
+
+		/*
+		 * if no data was submitted from previous paket, get next from
+		 * list and submit that
+		 */
+		if (!already_sent_data) {
+			if (!queue_empty
+				(&ispep->queue)) {
+
+				req = queue_get(&ispep->queue);
+				req->actual = write_ep(&udc_dev,
+					(unsigned short *)req->buf,
+					req->length <= ispep->maxpacketsize
+					? req->length :	ispep->maxpacketsize);
+				if (req->actual < ispep->maxpacketsize)
+					set_vendp_flag(&udc_dev);
+			}
+		}
+	}
+done:
+	return;
+}
+
+/**
+* isp1763_udc_do_irq - UDC interrupt handler
+* @ctrl: controller pointer
+*/
+static int isp1763_udc_do_irq(struct isp1763_controller *ctrl, u32 flags)
+{
+	struct isp1763_udc *dev = ctrl->priv;
+	u32 interrupts = 0;
+	int bit = 0;
+	int i;
+
+	isp1763_writew(UNLOCK_CODE, &dev->regs->unlock);
+	disable_glint(dev);
+
+	isp1763_writel(irq_bits,
+		       &dev->regs->dc_int_enable);
+	interrupts = flags & irq_bits;
+
+	isp1763_otg_timer_cancel();
+	isp1763_otg_timer_start((otgtimer_callback_t) isp1763_udc_do_irq,
+				100, ctrl);
+	for (i = 1; i < USB_MAX_ENDPOINTS; i += 2) {
+		struct isp_ep *ispep = &udc_dev.eps[i];
+		if (queue_count(&ispep->queue) > 0) {
+			ep_set_index(dev, ispep->index);
+			if (isp1763_readw(&dev->regs->dcbufstatus)
+				== 0) {
+				interrupts |= 1 << (i + 12);
+			}
+		}
+	}
+
+	if (!interrupts)
+		return 0;
+
+#if 0
+	printk(KERN_ERR "dev->regs->dc_int_enable: %.8lx\n",
+		isp1763_readl(&dev->regs->dc_int_enable));
+	printk(KERN_ERR "%s() flags = %.8lx irqbits = %.8lx\n",
+		__func__, flags, irq_bits);
+#endif
+	/* VBUS event */
+	if (interrupts & MASK_DCINT_VBUS) {
+		u16 mode = isp1763_readw(&dev->regs->mode);
+
+		/* Double negation (!!) used to make bitmask into boolean */
+		debug_printk(KERN_ERR "VBUS interrupt (Vbus = %i)\n",
+			     !!(mode & MASK_MODE_VBUSSTAT));
+		if (mode & MASK_MODE_VBUSSTAT) {
+			isp1763_writel(MASK_OTGCTRL_DP_PULLUP |
+				       MASK_OTGCTRL_SW_SEL_HC_DC,
+				       &dev->regs->otg_ctrl);
+		} else
+			isp1763_writel(MASK_OTGCTRL_SW_SEL_HC_DC,
+				       &dev->regs->otg_ctrl);
+	}
+
+	/* Control endpoint setup event */
+	if (interrupts & MASK_DCINT_EP0SETUP) {
+		debug_printk(KERN_ERR "EP0 SETUP event\n");
+		handle_ep0_setup(dev);
+	}
+
+	/* EP0 TX */
+	if (interrupts & MASK_DCINT_EP0TX) {
+		struct usb_request *req;
+		int written = 0;
+
+		debug_printk(KERN_ERR "EP0 TX\n");
+
+		if (dev->ep0->state == DIR_RX)
+			goto done;
+
+		if (queue_empty(&dev->ep0->queue)) {
+			warn_printk(KERN_ERR "EP0TX queue empty!\n");
+			goto done;
+		}
+
+		req = queue_get(&dev->ep0->queue);
+
+		queue_printk(KERN_ERR "EP0 request len=%i, written=%i\n",
+			     req->length, req->actual);
+		ep_set_index(dev, EP_INDEX(0, DIR_TX));
+
+		if (req->actual < req->length) {
+			queue_printk(KERN_ERR
+				     "EP0 request need to write more data\n");
+			written += write_ep(dev,
+				     (unsigned short *) ((char *) req->buf +
+				     req->actual),
+				     (req->length - req->actual) <=
+				     64 ? (req->length - req->actual) : 64);
+			if (written < 64)
+				set_vendp_flag(dev);
+
+			req->actual += written;
+		}
+		/* complete? */
+		if (req->actual == req->length) {
+			debug_printk(KERN_ERR "EP0 TX request complete\n");
+			ep_set_index(dev, EP_INDEX(0, DIR_RX));
+			/* printk(KERN_ERR "%s:%i %s()\n",
+			 * __FILE__,__LINE__,__func__);
+			 */
+			set_status_flag(dev);
+			req->status = 0;
+			if (!req->no_interrupt)
+				if (req->complete)
+					req->complete(dev->gadget->ep0,
+						      req);
+			queue_topkill(&dev->ep0->queue);
+		}
+
+		debug_printk(KERN_ERR "EP0 TX event\n");
+	}
+
+	/* EP0 RX */
+	if (interrupts & MASK_DCINT_EP0RX) {
+		struct usb_request *req;
+
+		ep_set_index(dev, EP_INDEX(0, DIR_RX));
+		if (isp1763_readw(&dev->regs->buflen) == 0) {
+			set_status_flag(dev);
+			goto done;
+		}
+
+		if (queue_empty(&dev->ep0->queue)) {
+			debug_printk(KERN_ERR "EP0RX queue empty!\n");
+			goto done;
+		}
+
+		req = queue_get(&dev->ep0->queue);
+
+		queue_printk(KERN_ERR "EP0 request len=%i, written=%i\n",
+			     req->length, req->actual);
+
+		read_ep(dev->ep0, req);
+		set_status_flag(dev);
+		queue_topkill(&dev->ep0->queue);
+
+		debug_printk(KERN_ERR "EP0 RX event\n");
+	}
+
+	/* BUS reset */
+	if (interrupts & MASK_DCINT_BRESET) {
+		int i;
+#if 1
+		debug_printk(KERN_ERR "BUS reset detected\n");
+		dev->gadget->speed = USB_SPEED_FULL;
+		for (i = 0; i < 14; i++)
+			isp1763_udc_ep_disable(&dev->eps[i].ep);
+#endif
+	}
+
+	/* Highspeed status change */
+	if (interrupts & MASK_DCINT_HS_STAT) {
+		debug_printk(KERN_ERR "Speed change detected\n");
+		dev->gadget->speed = USB_SPEED_HIGH;
+	}
+
+	/* EP interrupts */
+	if (interrupts & MASK_DCINT_EP_EVENT) {
+		for (bit = 0; bit < 14; bit++) {
+			if ((interrupts & (1 << (12 + bit))) == 0)
+				continue;
+			handle_ep_irq(dev, bit);
+		}
+	}
+
+done:
+	enable_glint(dev);
+	return 0;
+}
+
+/**
+* isp1763_udc_suspend - suspend gadget device
+* @ctrl: controller pointer
+*
+* Suspend device controller, usually in order to then activate the
+* host controller
+*/
+static int isp1763_udc_suspend(struct isp1763_controller *ctrl)
+{
+	struct isp1763_udc *dev = ctrl->priv;
+	info_printk(KERN_ERR "udc suspend called\n");
+
+	ctrl->active = 0;
+	isp1763_udc_disable(dev);
+
+	return 0;
+}
+
+/**
+* isp1763_udc_resume - resume gadget device
+* @ctrl: controller pointer
+*
+* Resume/Init device controller
+*/
+static int isp1763_udc_resume(struct isp1763_controller *ctrl)
+{
+	struct isp1763_udc *dev = ctrl->priv;
+	info_printk(KERN_ERR "udc resume called\n");
+
+	ctrl->active = 1;
+
+	configure_ep0(dev);
+	isp1763_udc_enable(dev);
+
+	return 0;
+}
+
+static void isp1763_dc_release(struct device *dev);
+
+/**
+* isp1763_udc_probe - device controller 'probe' function
+* @ctrl: controller pointer
+*
+* Initialize driver, but don't start controller yet
+*/
+static int isp1763_udc_probe(struct isp1763_controller *ctrl)
+{
+	struct isp1763_udc *dev = ctrl->priv;
+	int i;
+
+	printk(KERN_EMERG "%s:%i %s()\n", __FILE__, __LINE__,
+	       __func__);
+	dev->regs = ctrl->regs;
+	if (!dev->regs) {
+		error_printk(KERN_ERR "%s: error retrieving memory mapping "
+				"from base driver!\n", __FILE__);
+		return -ENODEV;
+	}
+	ep0.driver_data = dev;
+
+	dev->gadget = &isp1763_gadget;
+	/* FIXME: replaced with set_gadget_data
+	 * dev->gadget->dev.driver_data = (void *) &udc_dev;
+	 */
+	set_gadget_data(dev->gadget, &udc_dev);
+	setup_ep_struct(dev);
+
+	dev_set_name(&udc_dev.gadget->dev, "gadget");
+	udc_dev.gadget->dev.release = isp1763_dc_release;
+	device_register(&udc_dev.gadget->dev);
+
+	udc_dev.eps = isp_eps;
+
+	for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
+		warn_printk(KERN_ERR "EP %i (%s/%s)\n", i,
+			    udc_dev.eps[i].name, udc_dev.eps[i].ep.name);
+	}
+	return 1;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void isp1763_dc_release(struct device *dev)
+{
+	printk(KERN_EMERG "%s:%i %s()\n", __FILE__, __LINE__,
+	       __func__);
+}
+
+static int __init isp1763_dc_init(void)
+{
+	printk(KERN_EMERG "%s:%i %s()\n", __FILE__, __LINE__,
+	       __func__);
+	udc_dev.ctrl.active = 0;
+	udc_dev.ctrl.probe = isp1763_udc_probe;
+	udc_dev.ctrl.do_irq = isp1763_udc_do_irq;
+	udc_dev.ctrl.suspend = isp1763_udc_suspend;
+	udc_dev.ctrl.resume = isp1763_udc_resume;
+	udc_dev.ctrl.priv = &udc_dev;
+	isp1763_register_ctrl(&udc_dev.ctrl, ROLE_DEVICE);
+
+	return 0;
+}
+
+static void __exit isp1763_dc_exit(void)
+{
+	isp1763_unregister_ctrl(ROLE_DEVICE);	destroy_ep_struct(&udc_dev);
+
+	return;
+}
+
+module_init(isp1763_dc_init);
+module_exit(isp1763_dc_exit);
+
+MODULE_DESCRIPTION(DRIVER_NAME);
+MODULE_AUTHOR("F. Voegel, Carangul.Tech");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/isp1763/isp1763_udc.h b/drivers/usb/isp1763/isp1763_udc.h
new file mode 100644
index 0000000..d105bd3
--- /dev/null
+++ b/drivers/usb/isp1763/isp1763_udc.h
@@ -0,0 +1,113 @@
+#ifndef __ISP1763_UDC_H__
+#define __ISP1763_UDC_H__
+
+enum ep_types {
+	EP_TYPE_UNUSED = 0,
+	EP_TYPE_ISOCHRONOUS,
+	EP_TYPE_BULK,
+	EP_TYPE_INTERRUPT,
+};
+
+#define EP_TYPE_ENABLE  (1 << 3)
+#define EP_TYPE_DBLBUF  (1 << 2)
+#define EP_TYPE_NOEMPKT (1 << 4)
+#define EP_MAXPKTSIZE_NTRANS_SHIFT 11
+
+#define USB_MAX_ENDPOINTS 14
+
+/**
+* struct queue - queue structure
+* @next: next pointer
+* @elem: data pointer
+*/
+struct queue {
+	struct queue *next;
+	void *elem;
+};
+
+/**
+* struct isp1763_udc - UDC device
+* @isp_ep: endpoints
+* @ep0: endpoint 0
+* @gadget: gadget interface
+* @gadget_driver: pointer to gadget driver
+* @isp1763_regs: pointer to memory mapped registers
+* @isp1763_controller: pointer to controller structure
+*/
+struct isp1763_udc {
+	struct isp_ep *eps;
+	struct isp_ep *ep0;
+	struct usb_gadget *gadget;
+	struct usb_gadget_driver *driver;
+	struct isp1763_regs *regs;
+
+	struct isp1763_controller ctrl;
+};
+
+/**
+* struct isp_ep - endpoint structure
+* @ep: embedded usb_ep structure
+* @queue: pointer to EP queue
+* @udc: pointer to parent UDC device struct
+* @gadget: pointer to gadget interface
+* @state: current state
+* @index: EP index
+* @name: EP name (eg ep0-in)
+* @maxpacketsize: maximum packet size
+* @ep_type: type of endpoint
+* @desc: copy of EP descriptor
+*/
+struct isp_ep {
+	struct usb_ep ep;
+	struct queue *queue;
+	struct isp1763_udc *udc;
+	struct usb_gadget *gadget;
+	u8 state;
+	int index;
+	char name[8];
+	int maxpacketsize;
+	int ep_type;
+	struct usb_endpoint_descriptor desc;
+};
+
+#define GET_EP_DIR(idx) ((idx) & 1 ? DIR_TX : DIR_RX)
+#define GET_EP_NUM_CANONICAL(epn) ((epn) >> 1)
+
+#define EP_INDEX(epnum, is_out) (((epnum) << 1) | !!is_out)
+#define set_clbuf_flag(dev)  isp1763_writew(isp1763_readw(&(dev)->regs->ctrlfn)\
+				| MASK_CTRL_CLBUF, &(dev)->regs->ctrlfn)
+#define set_dsen_flag(dev)   isp1763_writew(isp1763_readw(&(dev)->regs->ctrlfn)\
+				| MASK_CTRL_DSEN, &(dev)->regs->ctrlfn)
+#define set_status_flag(dev) isp1763_writew(isp1763_readw(&(dev)->regs->ctrlfn)\
+				| MASK_CTRL_STATUS, &(dev)->regs->ctrlfn)
+#define set_stall_flag(dev)  isp1763_writew(isp1763_readw(&(dev)->regs->ctrlfn)\
+				| MASK_CTRL_STALL, &(dev)->regs->ctrlfn)
+#define set_vendp_flag(dev)  isp1763_writew(isp1763_readw(&(dev)->regs->ctrlfn)\
+				| MASK_CTRL_VENDP, &(dev)->regs->ctrlfn)
+
+#define clr_clbuf_flag(dev)  isp1763_writew(isp1763_readw(&(dev)->regs->ctrlfn)\
+				& ~MASK_CTRL_CLBUF, &(dev)->regs->ctrlfn)
+#define clr_dsen_flag(dev)   isp1763_writew(isp1763_readw(&(dev)->regs->ctrlfn)\
+				& ~MASK_CTRL_DSEN, &(dev)->regs->ctrlfn)
+#define clr_status_flag(dev) isp1763_writew(isp1763_readw(&(dev)->regs->ctrlfn)\
+				& ~MASK_CTRL_STATUS, &(dev)->regs->ctrlfn)
+#define clr_stall_flag(dev)  isp1763_writew(isp1763_readw(&(dev)->regs->ctrlfn)\
+				& ~MASK_CTRL_STALL, &(dev)->regs->ctrlfn)
+#define clr_vendp_flag(dev)  isp1763_writew(isp1763_readw(&(dev)->regs->ctrlfn)\
+				& ~MASK_CTRL_VENDP, &(dev)->regs->ctrlfn)
+
+#if 0
+#define disable_glint(dev)   isp1763_writew(isp1763_readw(&(dev)->regs->mode) \
+				& ~MASK_MODE_GLINTENA, &(dev)->regs->mode);
+#else
+#define disable_glint(dev)
+#endif
+#define enable_glint(dev) isp1763_writew(isp1763_readw(&(dev)->regs->mode) \
+				| MASK_MODE_GLINTENA,  &(dev)->regs->mode);
+#define ep_idx_to_addr(x) (x+2)
+
+
+#define disable_glint__(dev) isp1763_writew(isp1763_readw(&(dev)->regs->mode) \
+				& ~MASK_MODE_GLINTENA, &(dev)->regs->mode);
+
+#endif
diff --git a/include/linux/usb/isp1763.h b/include/linux/usb/isp1763.h
index 662077f..888880d 100644
--- a/include/linux/usb/isp1763.h
+++ b/include/linux/usb/isp1763.h
@@ -26,12 +26,12 @@
 #define __LINUX_USB_ISP1763_H
 
 struct isp1763_platform_data {
-	unsigned bus_width_8:1;			/* 8/16-bit data bus width */
-	unsigned port1_otg:1;			/* Port 1 supports OTG */
-	unsigned dack_polarity_high:1;		/* DACK active high */
-	unsigned dreq_polarity_high:1;		/* DREQ active high */
-	unsigned intr_polarity_high:1;		/* INTR active high */
-	unsigned intr_edge_trigger:1;		/* INTR edge trigger */
+	unsigned bus_width_8:1;		/* 8/16-bit data bus width */
+	unsigned port1_otg:1;		/* Port 1 supports OTG */
+	unsigned dack_polarity_high:1;	/* DACK active high */
+	unsigned dreq_polarity_high:1;	/* DREQ active high */
+	unsigned intr_polarity_high:1;	/* INTR active high */
+	unsigned intr_edge_trigger:1;	/* INTR edge trigger */
 };
 
 #endif /* __LINUX_USB_ISP1763_H */
-- 
1.7.2.3

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux