aboutsummaryrefslogtreecommitdiffstats
path: root/usb
diff options
authorGreg Kroah-Hartman <gregkh@suse.de>2009-07-16 16:39:39 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2009-07-16 16:39:39 -0700
commitc5c368ca56835336674e621f30277a574d596654 (patch)
tree46c94e971452cb1e5168f10d6e34cf571de5dc8d /usb
parent416838ff55d0ecbf421e0ede91a6c151beec8921 (diff)
downloadpatches-c5c368ca56835336674e621f30277a574d596654.tar.gz
more staging and usb patches
Diffstat (limited to 'usb')
-rw-r--r--usb/usb-ehci-add-intel-moorestown-ehci-controller-hostpcx-extensions-and-support-phy-low-power-mode.patch204
-rw-r--r--usb/usb-ehci-add-need_io_watchdog-flag-to-ehci_hcd.patch70
-rw-r--r--usb/usb-ehci-split-ehci_qh-into-hw-and-sw-parts.patch673
-rw-r--r--usb/usb-isp1760-allow-platform-devices-to-customize-devflags.patch125
4 files changed, 1072 insertions, 0 deletions
diff --git a/usb/usb-ehci-add-intel-moorestown-ehci-controller-hostpcx-extensions-and-support-phy-low-power-mode.patch b/usb/usb-ehci-add-intel-moorestown-ehci-controller-hostpcx-extensions-and-support-phy-low-power-mode.patch
new file mode 100644
index 00000000000000..3ea8b62775a3b4
--- /dev/null
+++ b/usb/usb-ehci-add-intel-moorestown-ehci-controller-hostpcx-extensions-and-support-phy-low-power-mode.patch
@@ -0,0 +1,204 @@
+From alek.du@intel.com Thu Jul 16 16:18:37 2009
+From: Alek Du <alek.du@intel.com>
+Date: Mon, 13 Jul 2009 12:41:20 +0800
+Subject: USB: EHCI: Add Intel Moorestown EHCI controller HOSTPCx extensions and support phy low power mode
+To: Greg KH <greg@kroah.com>
+Cc: David Brownell <david-b@pacbell.net>, Alan Stern <stern@rowland.harvard.edu>
+Message-ID: <20090713124120.4db64c95@dxy.sh.intel.com>
+
+
+From: Alek Du <alek.du@intel.com>
+
+The Intel Moorestown EHCI controller supports non-standard HOSTPCx register
+extension. This register controls the LPM behaviour and controls the behaviour
+of each USB port.
+
+Signed-off-by: Jacob Pan <jacob.jun.pan@intel.com>
+Signed-off-by: Alek Du <alek.du@intel.com>
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+Cc: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/usb/host/ehci-hcd.c | 6 ++++
+ drivers/usb/host/ehci-hub.c | 62 +++++++++++++++++++++++++++++++++++++++----
+ drivers/usb/host/ehci.h | 3 +-
+ include/linux/usb/ehci_def.h | 13 +++++++++
+ 4 files changed, 78 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -136,6 +136,7 @@ struct ehci_hcd { /* one per controlle
+ #define OHCI_HCCTRL_OFFSET 0x4
+ #define OHCI_HCCTRL_LEN 0x4
+ __hc32 *ohci_hcctrl_reg;
++ unsigned has_hostpc:1;
+
+ u8 sbrn; /* packed release number */
+
+@@ -548,7 +549,7 @@ static inline unsigned int
+ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
+ {
+ if (ehci_is_TDI(ehci)) {
+- switch ((portsc>>26)&3) {
++ switch ((portsc >> (ehci->has_hostpc ? 25 : 26)) & 3) {
+ case 0:
+ return 0;
+ case 1:
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -249,6 +249,12 @@ static int ehci_reset (struct ehci_hcd *
+ retval = handshake (ehci, &ehci->regs->command,
+ CMD_RESET, 0, 250 * 1000);
+
++ if (ehci->has_hostpc) {
++ ehci_writel(ehci, USBMODE_EX_HC | USBMODE_EX_VBPS,
++ (u32 __iomem *)(((u8 *)ehci->regs) + USBMODE_EX));
++ ehci_writel(ehci, TXFIFO_DEFAULT,
++ (u32 __iomem *)(((u8 *)ehci->regs) + TXFILLTUNING));
++ }
+ if (retval)
+ return retval;
+
+--- a/drivers/usb/host/ehci-hub.c
++++ b/drivers/usb/host/ehci-hub.c
+@@ -111,6 +111,7 @@ static int ehci_bus_suspend (struct usb_
+ struct ehci_hcd *ehci = hcd_to_ehci (hcd);
+ int port;
+ int mask;
++ u32 __iomem *hostpc_reg = NULL;
+
+ ehci_dbg(ehci, "suspend root hub\n");
+
+@@ -142,6 +143,9 @@ static int ehci_bus_suspend (struct usb_
+ u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
+ u32 t2 = t1;
+
++ if (ehci->has_hostpc)
++ hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
++ + HOSTPC0 + 4 * (port & 0xff));
+ /* keep track of which ports we suspend */
+ if (t1 & PORT_OWNER)
+ set_bit(port, &ehci->owned_ports);
+@@ -151,15 +155,37 @@ static int ehci_bus_suspend (struct usb_
+ }
+
+ /* enable remote wakeup on all ports */
+- if (hcd->self.root_hub->do_remote_wakeup)
+- t2 |= PORT_WAKE_BITS;
+- else
++ if (hcd->self.root_hub->do_remote_wakeup) {
++ /* only enable appropriate wake bits, otherwise the
++ * hardware can not go phy low power mode. If a race
++ * condition happens here(connection change during bits
++ * set), the port change detection will finally fix it.
++ */
++ if (t1 & PORT_CONNECT) {
++ t2 |= PORT_WKOC_E | PORT_WKDISC_E;
++ t2 &= ~PORT_WKCONN_E;
++ } else {
++ t2 |= PORT_WKOC_E | PORT_WKCONN_E;
++ t2 &= ~PORT_WKDISC_E;
++ }
++ } else
+ t2 &= ~PORT_WAKE_BITS;
+
+ if (t1 != t2) {
+ ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
+ port + 1, t1, t2);
+ ehci_writel(ehci, t2, reg);
++ if (hostpc_reg) {
++ u32 t3;
++
++ msleep(5);/* 5ms for HCD enter low pwr mode */
++ t3 = ehci_readl(ehci, hostpc_reg);
++ ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
++ t3 = ehci_readl(ehci, hostpc_reg);
++ ehci_dbg(ehci, "Port%d phy low pwr mode %s\n",
++ port, (t3 & HOSTPC_PHCD) ?
++ "succeeded" : "failed");
++ }
+ }
+ }
+
+@@ -563,7 +589,8 @@ static int ehci_hub_control (
+ int ports = HCS_N_PORTS (ehci->hcs_params);
+ u32 __iomem *status_reg = &ehci->regs->port_status[
+ (wIndex & 0xff) - 1];
+- u32 temp, status;
++ u32 __iomem *hostpc_reg = NULL;
++ u32 temp, temp1, status;
+ unsigned long flags;
+ int retval = 0;
+ unsigned selector;
+@@ -575,6 +602,9 @@ static int ehci_hub_control (
+ * power, "this is the one", etc. EHCI spec supports this.
+ */
+
++ if (ehci->has_hostpc)
++ hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
++ + HOSTPC0 + 4 * ((wIndex & 0xff) - 1));
+ spin_lock_irqsave (&ehci->lock, flags);
+ switch (typeReq) {
+ case ClearHubFeature:
+@@ -773,7 +803,11 @@ static int ehci_hub_control (
+ if (temp & PORT_CONNECT) {
+ status |= 1 << USB_PORT_FEAT_CONNECTION;
+ // status may be from integrated TT
+- status |= ehci_port_speed(ehci, temp);
++ if (ehci->has_hostpc) {
++ temp1 = ehci_readl(ehci, hostpc_reg);
++ status |= ehci_port_speed(ehci, temp1);
++ } else
++ status |= ehci_port_speed(ehci, temp);
+ }
+ if (temp & PORT_PE)
+ status |= 1 << USB_PORT_FEAT_ENABLE;
+@@ -832,6 +866,24 @@ static int ehci_hub_control (
+ || (temp & PORT_RESET) != 0)
+ goto error;
+ ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
++ /* After above check the port must be connected.
++ * Set appropriate bit thus could put phy into low power
++ * mode if we have hostpc feature
++ */
++ if (hostpc_reg) {
++ temp &= ~PORT_WKCONN_E;
++ temp |= (PORT_WKDISC_E | PORT_WKOC_E);
++ ehci_writel(ehci, temp | PORT_SUSPEND,
++ status_reg);
++ msleep(5);/* 5ms for HCD enter low pwr mode */
++ temp1 = ehci_readl(ehci, hostpc_reg);
++ ehci_writel(ehci, temp1 | HOSTPC_PHCD,
++ hostpc_reg);
++ temp1 = ehci_readl(ehci, hostpc_reg);
++ ehci_dbg(ehci, "Port%d phy low pwr mode %s\n",
++ wIndex, (temp1 & HOSTPC_PHCD) ?
++ "succeeded" : "failed");
++ }
+ set_bit(wIndex, &ehci->suspended_ports);
+ break;
+ case USB_PORT_FEAT_POWER:
+--- a/include/linux/usb/ehci_def.h
++++ b/include/linux/usb/ehci_def.h
+@@ -132,6 +132,19 @@ struct ehci_regs {
+ #define USBMODE_CM_HC (3<<0) /* host controller mode */
+ #define USBMODE_CM_IDLE (0<<0) /* idle state */
+
++/* Moorestown has some non-standard registers, partially due to the fact that
++ * its EHCI controller has both TT and LPM support. HOSTPCx are extentions to
++ * PORTSCx
++ */
++#define HOSTPC0 0x84 /* HOSTPC extension */
++#define HOSTPC_PHCD (1<<22) /* Phy clock disable */
++#define HOSTPC_PSPD (3<<25) /* Port speed detection */
++#define USBMODE_EX 0xc8 /* USB Device mode extension */
++#define USBMODE_EX_VBPS (1<<5) /* VBus Power Select On */
++#define USBMODE_EX_HC (3<<0) /* host controller mode */
++#define TXFILLTUNING 0x24 /* TX FIFO Tuning register */
++#define TXFIFO_DEFAULT (8<<16) /* FIFO burst threshold 8 */
++
+ /* Appendix C, Debug port ... intended for use with special "debug devices"
+ * that can help if there's no serial console. (nonstandard enumeration.)
+ */
diff --git a/usb/usb-ehci-add-need_io_watchdog-flag-to-ehci_hcd.patch b/usb/usb-ehci-add-need_io_watchdog-flag-to-ehci_hcd.patch
new file mode 100644
index 00000000000000..8cf147aa965cea
--- /dev/null
+++ b/usb/usb-ehci-add-need_io_watchdog-flag-to-ehci_hcd.patch
@@ -0,0 +1,70 @@
+From alek.du@intel.com Thu Jul 16 16:15:33 2009
+From: Alek Du <alek.du@intel.com>
+Date: Mon, 13 Jul 2009 17:30:41 +0800
+Subject: USB: EHCI: add need_io_watchdog flag to ehci_hcd
+To: Sergei Shtylyov <sshtylyov@ru.mvista.com>
+Cc: Greg KH <greg@kroah.com>, David Brownell <david-b@pacbell.net>, "Alan Stern" <stern@rowland.harvard.edu>
+Message-ID: <20090713173041.6c2c3d1e@dxy.sh.intel.com>
+
+
+From: Alek Du <alek.du@intel.com>
+
+Basically the io watchdog is only useful for those quirk HCDs. For most
+good ones, it only brings unnecessary wakeups. At least, I know the
+Intel EHCI HCDs should turn off the flag.
+
+Signed-off-by: Alek Du <alek.du@intel.com>
+Cc: David Brownell <dbrownell@users.sourceforge.net>
+Cc: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/ehci-hcd.c | 6 ++++++
+ drivers/usb/host/ehci-pci.c | 3 +++
+ drivers/usb/host/ehci.h | 1 +
+ 3 files changed, 10 insertions(+)
+
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -126,6 +126,7 @@ struct ehci_hcd { /* one per controlle
+ unsigned big_endian_mmio:1;
+ unsigned big_endian_desc:1;
+ unsigned has_amcc_usb23:1;
++ unsigned need_io_watchdog:1;
+
+ /* required for usb32 quirk */
+ #define OHCI_CTRL_HCFS (3 << 6)
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -127,6 +127,8 @@ timer_action(struct ehci_hcd *ehci, enum
+
+ switch (action) {
+ case TIMER_IO_WATCHDOG:
++ if (!ehci->need_io_watchdog)
++ return;
+ t = EHCI_IO_JIFFIES;
+ break;
+ case TIMER_ASYNC_OFF:
+@@ -508,6 +510,10 @@ static int ehci_init(struct usb_hcd *hcd
+
+ spin_lock_init(&ehci->lock);
+
++ /*
++ * keep io watchdog by default, those good HCDs could turn off it later
++ */
++ ehci->need_io_watchdog = 1;
+ init_timer(&ehci->watchdog);
+ ehci->watchdog.function = ehci_watchdog;
+ ehci->watchdog.data = (unsigned long) ehci;
+--- a/drivers/usb/host/ehci-pci.c
++++ b/drivers/usb/host/ehci-pci.c
+@@ -129,6 +129,9 @@ static int ehci_pci_setup(struct usb_hcd
+ return retval;
+
+ switch (pdev->vendor) {
++ case PCI_VENDOR_ID_INTEL:
++ ehci->need_io_watchdog = 0;
++ break;
+ case PCI_VENDOR_ID_TDI:
+ if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
+ hcd->has_tt = 1;
diff --git a/usb/usb-ehci-split-ehci_qh-into-hw-and-sw-parts.patch b/usb/usb-ehci-split-ehci_qh-into-hw-and-sw-parts.patch
new file mode 100644
index 00000000000000..7824533cd48938
--- /dev/null
+++ b/usb/usb-ehci-split-ehci_qh-into-hw-and-sw-parts.patch
@@ -0,0 +1,673 @@
+From alek.du@intel.com Thu Jul 16 16:16:55 2009
+From: Alek Du <alek.du@intel.com>
+Date: Tue, 14 Jul 2009 07:23:29 +0800
+Subject: USB: EHCI: split ehci_qh into hw and sw parts
+To: Greg KH <greg@kroah.com>
+Cc: David Brownell <david-b@pacbell.net>, Alan Stern <stern@rowland.harvard.edu>
+Message-ID: <20090714072329.000067e7@unknown>
+
+
+From: Alek Du <alek.du@intel.com>
+
+The ehci_qh structure merged hw and sw together which is not good:
+1. More and more items are being added into ehci_qh, the ehci_qh software
+ part are unnecessary to be allocated in DMA qh_pool.
+2. If HCD has local SRAM, the sw part will consume it too, and it won't
+ bring any benefit.
+3. For non-cache-coherence system, the entire ehci_qh is uncachable, actually
+ we only need the hw part to be uncacheable. Spliting them will let the sw
+ part to be cacheable.
+
+Signed-off-by: Alek Du <alek.du@intel.com>
+Cc: David Brownell <dbrownell@users.sourceforge.net>
+CC: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/ehci-dbg.c | 43 +++++++++++++++------------
+ drivers/usb/host/ehci-hcd.c | 14 +++++---
+ drivers/usb/host/ehci-mem.c | 26 ++++++++++------
+ drivers/usb/host/ehci-q.c | 50 +++++++++++++++++--------------
+ drivers/usb/host/ehci-sched.c | 66 ++++++++++++++++++++++++++++--------------
+ drivers/usb/host/ehci.h | 9 +++--
+ 6 files changed, 127 insertions(+), 81 deletions(-)
+
+--- a/drivers/usb/host/ehci-dbg.c
++++ b/drivers/usb/host/ehci-dbg.c
+@@ -134,10 +134,11 @@ dbg_qtd (const char *label, struct ehci_
+ static void __maybe_unused
+ dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
+ {
++ struct ehci_qh_hw *hw = qh->hw;
++
+ ehci_dbg (ehci, "%s qh %p n%08x info %x %x qtd %x\n", label,
+- qh, qh->hw_next, qh->hw_info1, qh->hw_info2,
+- qh->hw_current);
+- dbg_qtd ("overlay", ehci, (struct ehci_qtd *) &qh->hw_qtd_next);
++ qh, hw->hw_next, hw->hw_info1, hw->hw_info2, hw->hw_current);
++ dbg_qtd("overlay", ehci, (struct ehci_qtd *) &hw->hw_qtd_next);
+ }
+
+ static void __maybe_unused
+@@ -400,31 +401,32 @@ static void qh_lines (
+ char *next = *nextp;
+ char mark;
+ __le32 list_end = EHCI_LIST_END(ehci);
++ struct ehci_qh_hw *hw = qh->hw;
+
+- if (qh->hw_qtd_next == list_end) /* NEC does this */
++ if (hw->hw_qtd_next == list_end) /* NEC does this */
+ mark = '@';
+ else
+- mark = token_mark(ehci, qh->hw_token);
++ mark = token_mark(ehci, hw->hw_token);
+ if (mark == '/') { /* qh_alt_next controls qh advance? */
+- if ((qh->hw_alt_next & QTD_MASK(ehci))
+- == ehci->async->hw_alt_next)
++ if ((hw->hw_alt_next & QTD_MASK(ehci))
++ == ehci->async->hw->hw_alt_next)
+ mark = '#'; /* blocked */
+- else if (qh->hw_alt_next == list_end)
++ else if (hw->hw_alt_next == list_end)
+ mark = '.'; /* use hw_qtd_next */
+ /* else alt_next points to some other qtd */
+ }
+- scratch = hc32_to_cpup(ehci, &qh->hw_info1);
+- hw_curr = (mark == '*') ? hc32_to_cpup(ehci, &qh->hw_current) : 0;
++ scratch = hc32_to_cpup(ehci, &hw->hw_info1);
++ hw_curr = (mark == '*') ? hc32_to_cpup(ehci, &hw->hw_current) : 0;
+ temp = scnprintf (next, size,
+ "qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)",
+ qh, scratch & 0x007f,
+ speed_char (scratch),
+ (scratch >> 8) & 0x000f,
+- scratch, hc32_to_cpup(ehci, &qh->hw_info2),
+- hc32_to_cpup(ehci, &qh->hw_token), mark,
+- (cpu_to_hc32(ehci, QTD_TOGGLE) & qh->hw_token)
++ scratch, hc32_to_cpup(ehci, &hw->hw_info2),
++ hc32_to_cpup(ehci, &hw->hw_token), mark,
++ (cpu_to_hc32(ehci, QTD_TOGGLE) & hw->hw_token)
+ ? "data1" : "data0",
+- (hc32_to_cpup(ehci, &qh->hw_alt_next) >> 1) & 0x0f);
++ (hc32_to_cpup(ehci, &hw->hw_alt_next) >> 1) & 0x0f);
+ size -= temp;
+ next += temp;
+
+@@ -435,10 +437,10 @@ static void qh_lines (
+ mark = ' ';
+ if (hw_curr == td->qtd_dma)
+ mark = '*';
+- else if (qh->hw_qtd_next == cpu_to_hc32(ehci, td->qtd_dma))
++ else if (hw->hw_qtd_next == cpu_to_hc32(ehci, td->qtd_dma))
+ mark = '+';
+ else if (QTD_LENGTH (scratch)) {
+- if (td->hw_alt_next == ehci->async->hw_alt_next)
++ if (td->hw_alt_next == ehci->async->hw->hw_alt_next)
+ mark = '#';
+ else if (td->hw_alt_next != list_end)
+ mark = '/';
+@@ -550,12 +552,15 @@ static ssize_t fill_periodic_buffer(stru
+ next += temp;
+
+ do {
++ struct ehci_qh_hw *hw;
++
+ switch (hc32_to_cpu(ehci, tag)) {
+ case Q_TYPE_QH:
++ hw = p.qh->hw;
+ temp = scnprintf (next, size, " qh%d-%04x/%p",
+ p.qh->period,
+ hc32_to_cpup(ehci,
+- &p.qh->hw_info2)
++ &hw->hw_info2)
+ /* uframe masks */
+ & (QH_CMASK | QH_SMASK),
+ p.qh);
+@@ -576,7 +581,7 @@ static ssize_t fill_periodic_buffer(stru
+ /* show more info the first time around */
+ if (temp == seen_count) {
+ u32 scratch = hc32_to_cpup(ehci,
+- &p.qh->hw_info1);
++ &hw->hw_info1);
+ struct ehci_qtd *qtd;
+ char *type = "";
+
+@@ -609,7 +614,7 @@ static ssize_t fill_periodic_buffer(stru
+ } else
+ temp = 0;
+ if (p.qh) {
+- tag = Q_NEXT_TYPE(ehci, p.qh->hw_next);
++ tag = Q_NEXT_TYPE(ehci, hw->hw_next);
+ p = p.qh->qh_next;
+ }
+ break;
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -299,8 +299,8 @@ union ehci_shadow {
+ * These appear in both the async and (for interrupt) periodic schedules.
+ */
+
+-struct ehci_qh {
+- /* first part defined by EHCI spec */
++/* first part defined by EHCI spec */
++struct ehci_qh_hw {
+ __hc32 hw_next; /* see EHCI 3.6.1 */
+ __hc32 hw_info1; /* see EHCI 3.6.2 */
+ #define QH_HEAD 0x00008000
+@@ -318,7 +318,10 @@ struct ehci_qh {
+ __hc32 hw_token;
+ __hc32 hw_buf [5];
+ __hc32 hw_buf_hi [5];
++} __attribute__ ((aligned(32)));
+
++struct ehci_qh {
++ struct ehci_qh_hw *hw;
+ /* the rest is HCD-private */
+ dma_addr_t qh_dma; /* address of qh */
+ union ehci_shadow qh_next; /* ptr to qh; or periodic */
+@@ -358,7 +361,7 @@ struct ehci_qh {
+
+ struct usb_device *dev; /* access to TT */
+ unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
+-} __attribute__ ((aligned (32)));
++};
+
+ /*-------------------------------------------------------------------------*/
+
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -507,6 +507,7 @@ static int ehci_init(struct usb_hcd *hcd
+ u32 temp;
+ int retval;
+ u32 hcc_params;
++ struct ehci_qh_hw *hw;
+
+ spin_lock_init(&ehci->lock);
+
+@@ -550,12 +551,13 @@ static int ehci_init(struct usb_hcd *hcd
+ * from automatically advancing to the next td after short reads.
+ */
+ ehci->async->qh_next.qh = NULL;
+- ehci->async->hw_next = QH_NEXT(ehci, ehci->async->qh_dma);
+- ehci->async->hw_info1 = cpu_to_hc32(ehci, QH_HEAD);
+- ehci->async->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
+- ehci->async->hw_qtd_next = EHCI_LIST_END(ehci);
++ hw = ehci->async->hw;
++ hw->hw_next = QH_NEXT(ehci, ehci->async->qh_dma);
++ hw->hw_info1 = cpu_to_hc32(ehci, QH_HEAD);
++ hw->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
++ hw->hw_qtd_next = EHCI_LIST_END(ehci);
+ ehci->async->qh_state = QH_STATE_LINKED;
+- ehci->async->hw_alt_next = QTD_NEXT(ehci, ehci->async->dummy->qtd_dma);
++ hw->hw_alt_next = QTD_NEXT(ehci, ehci->async->dummy->qtd_dma);
+
+ /* clear interrupt enables, set irq latency */
+ if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
+@@ -984,7 +986,7 @@ rescan:
+ /* endpoints can be iso streams. for now, we don't
+ * accelerate iso completions ... so spin a while.
+ */
+- if (qh->hw_info1 == 0) {
++ if (qh->hw->hw_info1 == 0) {
+ ehci_vdbg (ehci, "iso delay\n");
+ goto idle_timeout;
+ }
+--- a/drivers/usb/host/ehci-mem.c
++++ b/drivers/usb/host/ehci-mem.c
+@@ -75,7 +75,8 @@ static void qh_destroy(struct ehci_qh *q
+ }
+ if (qh->dummy)
+ ehci_qtd_free (ehci, qh->dummy);
+- dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
++ dma_pool_free(ehci->qh_pool, qh->hw, qh->qh_dma);
++ kfree(qh);
+ }
+
+ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
+@@ -83,12 +84,14 @@ static struct ehci_qh *ehci_qh_alloc (st
+ struct ehci_qh *qh;
+ dma_addr_t dma;
+
+- qh = (struct ehci_qh *)
+- dma_pool_alloc (ehci->qh_pool, flags, &dma);
++ qh = kzalloc(sizeof *qh, GFP_ATOMIC);
+ if (!qh)
+- return qh;
+-
+- memset (qh, 0, sizeof *qh);
++ goto done;
++ qh->hw = (struct ehci_qh_hw *)
++ dma_pool_alloc(ehci->qh_pool, flags, &dma);
++ if (!qh->hw)
++ goto fail;
++ memset(qh->hw, 0, sizeof *qh->hw);
+ qh->refcount = 1;
+ qh->ehci = ehci;
+ qh->qh_dma = dma;
+@@ -99,10 +102,15 @@ static struct ehci_qh *ehci_qh_alloc (st
+ qh->dummy = ehci_qtd_alloc (ehci, flags);
+ if (qh->dummy == NULL) {
+ ehci_dbg (ehci, "no dummy td\n");
+- dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
+- qh = NULL;
++ goto fail1;
+ }
++done:
+ return qh;
++fail1:
++ dma_pool_free(ehci->qh_pool, qh->hw, qh->qh_dma);
++fail:
++ kfree(qh);
++ return NULL;
+ }
+
+ /* to share a qh (cpu threads, or hc) */
+@@ -180,7 +188,7 @@ static int ehci_mem_init (struct ehci_hc
+ /* QHs for control/bulk/intr transfers */
+ ehci->qh_pool = dma_pool_create ("ehci_qh",
+ ehci_to_hcd(ehci)->self.controller,
+- sizeof (struct ehci_qh),
++ sizeof(struct ehci_qh_hw),
+ 32 /* byte alignment (for hw parts) */,
+ 4096 /* can't cross 4K */);
+ if (!ehci->qh_pool) {
+--- a/drivers/usb/host/ehci-q.c
++++ b/drivers/usb/host/ehci-q.c
+@@ -87,31 +87,33 @@ qtd_fill(struct ehci_hcd *ehci, struct e
+ static inline void
+ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
+ {
++ struct ehci_qh_hw *hw = qh->hw;
++
+ /* writes to an active overlay are unsafe */
+ BUG_ON(qh->qh_state != QH_STATE_IDLE);
+
+- qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
+- qh->hw_alt_next = EHCI_LIST_END(ehci);
++ hw->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
++ hw->hw_alt_next = EHCI_LIST_END(ehci);
+
+ /* Except for control endpoints, we make hardware maintain data
+ * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
+ * and set the pseudo-toggle in udev. Only usb_clear_halt() will
+ * ever clear it.
+ */
+- if (!(qh->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
++ if (!(hw->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
+ unsigned is_out, epnum;
+
+ is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8));
+- epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f;
++ epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f;
+ if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
+- qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
++ hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
+ usb_settoggle (qh->dev, epnum, is_out, 1);
+ }
+ }
+
+ /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
+ wmb ();
+- qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING);
++ hw->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING);
+ }
+
+ /* if it weren't for a common silicon quirk (writing the dummy into the qh
+@@ -129,7 +131,7 @@ qh_refresh (struct ehci_hcd *ehci, struc
+ qtd = list_entry (qh->qtd_list.next,
+ struct ehci_qtd, qtd_list);
+ /* first qtd may already be partially processed */
+- if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw_current)
++ if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw->hw_current)
+ qtd = NULL;
+ }
+
+@@ -260,7 +262,7 @@ __acquires(ehci->lock)
+ struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv;
+
+ /* S-mask in a QH means it's an interrupt urb */
+- if ((qh->hw_info2 & cpu_to_hc32(ehci, QH_SMASK)) != 0) {
++ if ((qh->hw->hw_info2 & cpu_to_hc32(ehci, QH_SMASK)) != 0) {
+
+ /* ... update hc-wide periodic stats (for usbfs) */
+ ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
+@@ -315,6 +317,7 @@ qh_completions (struct ehci_hcd *ehci, s
+ unsigned count = 0;
+ u8 state;
+ __le32 halt = HALT_BIT(ehci);
++ struct ehci_qh_hw *hw = qh->hw;
+
+ if (unlikely (list_empty (&qh->qtd_list)))
+ return count;
+@@ -393,7 +396,8 @@ qh_completions (struct ehci_hcd *ehci, s
+ qtd->hw_token = cpu_to_hc32(ehci,
+ token);
+ wmb();
+- qh->hw_token = cpu_to_hc32(ehci, token);
++ hw->hw_token = cpu_to_hc32(ehci,
++ token);
+ goto retry_xacterr;
+ }
+ stopped = 1;
+@@ -436,8 +440,8 @@ qh_completions (struct ehci_hcd *ehci, s
+ /* qh unlinked; token in overlay may be most current */
+ if (state == QH_STATE_IDLE
+ && cpu_to_hc32(ehci, qtd->qtd_dma)
+- == qh->hw_current) {
+- token = hc32_to_cpu(ehci, qh->hw_token);
++ == hw->hw_current) {
++ token = hc32_to_cpu(ehci, hw->hw_token);
+
+ /* An unlink may leave an incomplete
+ * async transaction in the TT buffer.
+@@ -450,9 +454,9 @@ qh_completions (struct ehci_hcd *ehci, s
+ * patch the qh later and so that completions can't
+ * activate it while we "know" it's stopped.
+ */
+- if ((halt & qh->hw_token) == 0) {
++ if ((halt & hw->hw_token) == 0) {
+ halt:
+- qh->hw_token |= halt;
++ hw->hw_token |= halt;
+ wmb ();
+ }
+ }
+@@ -511,7 +515,7 @@ halt:
+ * it after fault cleanup, or recovering from silicon wrongly
+ * overlaying the dummy qtd (which reduces DMA chatter).
+ */
+- if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END(ehci)) {
++ if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci)) {
+ switch (state) {
+ case QH_STATE_IDLE:
+ qh_refresh(ehci, qh);
+@@ -529,7 +533,7 @@ halt:
+ * except maybe high bandwidth ...
+ */
+ if ((cpu_to_hc32(ehci, QH_SMASK)
+- & qh->hw_info2) != 0) {
++ & hw->hw_info2) != 0) {
+ intr_deschedule (ehci, qh);
+ (void) qh_schedule (ehci, qh);
+ } else
+@@ -650,7 +654,7 @@ qh_urb_transaction (
+ * (this will usually be overridden later.)
+ */
+ if (is_input)
+- qtd->hw_alt_next = ehci->async->hw_alt_next;
++ qtd->hw_alt_next = ehci->async->hw->hw_alt_next;
+
+ /* qh makes control packets use qtd toggle; maybe switch it */
+ if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
+@@ -745,6 +749,7 @@ qh_make (
+ int is_input, type;
+ int maxp = 0;
+ struct usb_tt *tt = urb->dev->tt;
++ struct ehci_qh_hw *hw;
+
+ if (!qh)
+ return qh;
+@@ -891,8 +896,9 @@ done:
+
+ /* init as live, toggle clear, advance to dummy */
+ qh->qh_state = QH_STATE_IDLE;
+- qh->hw_info1 = cpu_to_hc32(ehci, info1);
+- qh->hw_info2 = cpu_to_hc32(ehci, info2);
++ hw = qh->hw;
++ hw->hw_info1 = cpu_to_hc32(ehci, info1);
++ hw->hw_info2 = cpu_to_hc32(ehci, info2);
+ usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
+ qh_refresh (ehci, qh);
+ return qh;
+@@ -934,11 +940,11 @@ static void qh_link_async (struct ehci_h
+
+ /* splice right after start */
+ qh->qh_next = head->qh_next;
+- qh->hw_next = head->hw_next;
++ qh->hw->hw_next = head->hw->hw_next;
+ wmb ();
+
+ head->qh_next.qh = qh;
+- head->hw_next = dma;
++ head->hw->hw_next = dma;
+
+ qh->xacterrs = QH_XACTERR_MAX;
+ qh->qh_state = QH_STATE_LINKED;
+@@ -984,7 +990,7 @@ static struct ehci_qh *qh_append_tds (
+
+ /* usb_reset_device() briefly reverts to address 0 */
+ if (usb_pipedevice (urb->pipe) == 0)
+- qh->hw_info1 &= ~qh_addr_mask;
++ qh->hw->hw_info1 &= ~qh_addr_mask;
+ }
+
+ /* just one way to queue requests: swap with the dummy qtd.
+@@ -1170,7 +1176,7 @@ static void start_unlink_async (struct e
+ while (prev->qh_next.qh != qh)
+ prev = prev->qh_next.qh;
+
+- prev->hw_next = qh->hw_next;
++ prev->hw->hw_next = qh->hw->hw_next;
+ prev->qh_next = qh->qh_next;
+ wmb ();
+
+--- a/drivers/usb/host/ehci-sched.c
++++ b/drivers/usb/host/ehci-sched.c
+@@ -60,6 +60,20 @@ periodic_next_shadow(struct ehci_hcd *eh
+ }
+ }
+
++static __hc32 *
++shadow_next_periodic(struct ehci_hcd *ehci, union ehci_shadow *periodic,
++ __hc32 tag)
++{
++ switch (hc32_to_cpu(ehci, tag)) {
++ /* our ehci_shadow.qh is actually software part */
++ case Q_TYPE_QH:
++ return &periodic->qh->hw->hw_next;
++ /* others are hw parts */
++ default:
++ return periodic->hw_next;
++ }
++}
++
+ /* caller must hold ehci->lock */
+ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
+ {
+@@ -71,7 +85,8 @@ static void periodic_unlink (struct ehci
+ while (here.ptr && here.ptr != ptr) {
+ prev_p = periodic_next_shadow(ehci, prev_p,
+ Q_NEXT_TYPE(ehci, *hw_p));
+- hw_p = here.hw_next;
++ hw_p = shadow_next_periodic(ehci, &here,
++ Q_NEXT_TYPE(ehci, *hw_p));
+ here = *prev_p;
+ }
+ /* an interrupt entry (at list end) could have been shared */
+@@ -83,7 +98,7 @@ static void periodic_unlink (struct ehci
+ */
+ *prev_p = *periodic_next_shadow(ehci, &here,
+ Q_NEXT_TYPE(ehci, *hw_p));
+- *hw_p = *here.hw_next;
++ *hw_p = *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p));
+ }
+
+ /* how many of the uframe's 125 usecs are allocated? */
+@@ -93,18 +108,20 @@ periodic_usecs (struct ehci_hcd *ehci, u
+ __hc32 *hw_p = &ehci->periodic [frame];
+ union ehci_shadow *q = &ehci->pshadow [frame];
+ unsigned usecs = 0;
++ struct ehci_qh_hw *hw;
+
+ while (q->ptr) {
+ switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) {
+ case Q_TYPE_QH:
++ hw = q->qh->hw;
+ /* is it in the S-mask? */
+- if (q->qh->hw_info2 & cpu_to_hc32(ehci, 1 << uframe))
++ if (hw->hw_info2 & cpu_to_hc32(ehci, 1 << uframe))
+ usecs += q->qh->usecs;
+ /* ... or C-mask? */
+- if (q->qh->hw_info2 & cpu_to_hc32(ehci,
++ if (hw->hw_info2 & cpu_to_hc32(ehci,
+ 1 << (8 + uframe)))
+ usecs += q->qh->c_usecs;
+- hw_p = &q->qh->hw_next;
++ hw_p = &hw->hw_next;
+ q = &q->qh->qh_next;
+ break;
+ // case Q_TYPE_FSTN:
+@@ -237,10 +254,10 @@ periodic_tt_usecs (
+ continue;
+ case Q_TYPE_QH:
+ if (same_tt(dev, q->qh->dev)) {
+- uf = tt_start_uframe(ehci, q->qh->hw_info2);
++ uf = tt_start_uframe(ehci, q->qh->hw->hw_info2);
+ tt_usecs[uf] += q->qh->tt_usecs;
+ }
+- hw_p = &q->qh->hw_next;
++ hw_p = &q->qh->hw->hw_next;
+ q = &q->qh->qh_next;
+ continue;
+ case Q_TYPE_SITD:
+@@ -375,6 +392,7 @@ static int tt_no_collision (
+ for (; frame < ehci->periodic_size; frame += period) {
+ union ehci_shadow here;
+ __hc32 type;
++ struct ehci_qh_hw *hw;
+
+ here = ehci->pshadow [frame];
+ type = Q_NEXT_TYPE(ehci, ehci->periodic [frame]);
+@@ -385,17 +403,18 @@ static int tt_no_collision (
+ here = here.itd->itd_next;
+ continue;
+ case Q_TYPE_QH:
++ hw = here.qh->hw;
+ if (same_tt (dev, here.qh->dev)) {
+ u32 mask;
+
+ mask = hc32_to_cpu(ehci,
+- here.qh->hw_info2);
++ hw->hw_info2);
+ /* "knows" no gap is needed */
+ mask |= mask >> 8;
+ if (mask & uf_mask)
+ break;
+ }
+- type = Q_NEXT_TYPE(ehci, here.qh->hw_next);
++ type = Q_NEXT_TYPE(ehci, hw->hw_next);
+ here = here.qh->qh_next;
+ continue;
+ case Q_TYPE_SITD:
+@@ -498,7 +517,8 @@ static int qh_link_periodic (struct ehci
+
+ dev_dbg (&qh->dev->dev,
+ "link qh%d-%04x/%p start %d [%d/%d us]\n",
+- period, hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK),
++ period, hc32_to_cpup(ehci, &qh->hw->hw_info2)
++ & (QH_CMASK | QH_SMASK),
+ qh, qh->start, qh->usecs, qh->c_usecs);
+
+ /* high bandwidth, or otherwise every microframe */
+@@ -517,7 +537,7 @@ static int qh_link_periodic (struct ehci
+ if (type == cpu_to_hc32(ehci, Q_TYPE_QH))
+ break;
+ prev = periodic_next_shadow(ehci, prev, type);
+- hw_p = &here.qh->hw_next;
++ hw_p = shadow_next_periodic(ehci, &here, type);
+ here = *prev;
+ }
+
+@@ -528,14 +548,14 @@ static int qh_link_periodic (struct ehci
+ if (qh->period > here.qh->period)
+ break;
+ prev = &here.qh->qh_next;
+- hw_p = &here.qh->hw_next;
++ hw_p = &here.qh->hw->hw_next;
+ here = *prev;
+ }
+ /* link in this qh, unless some earlier pass did that */
+ if (qh != here.qh) {
+ qh->qh_next = here;
+ if (here.qh)
+- qh->hw_next = *hw_p;
++ qh->hw->hw_next = *hw_p;
+ wmb ();
+ prev->qh = qh;
+ *hw_p = QH_NEXT (ehci, qh->qh_dma);
+@@ -580,7 +600,7 @@ static int qh_unlink_periodic(struct ehc
+ dev_dbg (&qh->dev->dev,
+ "unlink qh%d-%04x/%p start %d [%d/%d us]\n",
+ qh->period,
+- hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK),
++ hc32_to_cpup(ehci, &qh->hw->hw_info2) & (QH_CMASK | QH_SMASK),
+ qh, qh->start, qh->usecs, qh->c_usecs);
+
+ /* qh->qh_next still "live" to HC */
+@@ -595,6 +615,7 @@ static int qh_unlink_periodic(struct ehc
+ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
+ {
+ unsigned wait;
++ struct ehci_qh_hw *hw = qh->hw;
+
+ qh_unlink_periodic (ehci, qh);
+
+@@ -605,14 +626,14 @@ static void intr_deschedule (struct ehci
+ */
+ if (list_empty (&qh->qtd_list)
+ || (cpu_to_hc32(ehci, QH_CMASK)
+- & qh->hw_info2) != 0)
++ & hw->hw_info2) != 0)
+ wait = 2;
+ else
+ wait = 55; /* worst case: 3 * 1024 */
+
+ udelay (wait);
+ qh->qh_state = QH_STATE_IDLE;
+- qh->hw_next = EHCI_LIST_END(ehci);
++ hw->hw_next = EHCI_LIST_END(ehci);
+ wmb ();
+ }
+
+@@ -738,14 +759,15 @@ static int qh_schedule(struct ehci_hcd *
+ unsigned uframe;
+ __hc32 c_mask;
+ unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */
++ struct ehci_qh_hw *hw = qh->hw;
+
+ qh_refresh(ehci, qh);
+- qh->hw_next = EHCI_LIST_END(ehci);
++ hw->hw_next = EHCI_LIST_END(ehci);
+ frame = qh->start;
+
+ /* reuse the previous schedule slots, if we can */
+ if (frame < qh->period) {
+- uframe = ffs(hc32_to_cpup(ehci, &qh->hw_info2) & QH_SMASK);
++ uframe = ffs(hc32_to_cpup(ehci, &hw->hw_info2) & QH_SMASK);
+ status = check_intr_schedule (ehci, frame, --uframe,
+ qh, &c_mask);
+ } else {
+@@ -783,11 +805,11 @@ static int qh_schedule(struct ehci_hcd *
+ qh->start = frame;
+
+ /* reset S-frame and (maybe) C-frame masks */
+- qh->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK));
+- qh->hw_info2 |= qh->period
++ hw->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK));
++ hw->hw_info2 |= qh->period
+ ? cpu_to_hc32(ehci, 1 << uframe)
+ : cpu_to_hc32(ehci, QH_SMASK);
+- qh->hw_info2 |= c_mask;
++ hw->hw_info2 |= c_mask;
+ } else
+ ehci_dbg (ehci, "reused qh %p schedule\n", qh);
+
+@@ -2187,7 +2209,7 @@ restart:
+ case Q_TYPE_QH:
+ /* handle any completions */
+ temp.qh = qh_get (q.qh);
+- type = Q_NEXT_TYPE(ehci, q.qh->hw_next);
++ type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
+ q = q.qh->qh_next;
+ modified = qh_completions (ehci, temp.qh);
+ if (unlikely (list_empty (&temp.qh->qtd_list)))
diff --git a/usb/usb-isp1760-allow-platform-devices-to-customize-devflags.patch b/usb/usb-isp1760-allow-platform-devices-to-customize-devflags.patch
new file mode 100644
index 00000000000000..a19fa35f3cee4b
--- /dev/null
+++ b/usb/usb-isp1760-allow-platform-devices-to-customize-devflags.patch
@@ -0,0 +1,125 @@
+From vapier@gentoo.org Thu Jul 16 16:32:29 2009
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Wed, 15 Jul 2009 23:22:54 -0400
+Subject: USB: isp1760: allow platform devices to customize devflags
+To: Greg KH <greg@kroah.com>
+Cc: linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org, Michael Hennerich <michael.hennerich@analog.com>, Bryan Wu <cooloney@kernel.org>
+Message-ID: <1247714574-7445-1-git-send-email-vapier@gentoo.org>
+
+
+From: Michael Hennerich <michael.hennerich@analog.com>
+
+Platform device support was merged earlier, but support for boards to
+customize the devflags aspect of the controller was not. We want this on
+Blackfin systems to control the bus width, but might as well expose all of
+the fields while we're at it.
+
+Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
+Signed-off-by: Bryan Wu <cooloney@kernel.org>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/isp1760-hcd.c | 4 ++++
+ drivers/usb/host/isp1760-hcd.h | 2 ++
+ drivers/usb/host/isp1760-if.c | 21 ++++++++++++++++++++-
+ include/linux/usb/isp1760.h | 18 ++++++++++++++++++
+ 4 files changed, 44 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/isp1760-hcd.c
++++ b/drivers/usb/host/isp1760-hcd.c
+@@ -386,6 +386,10 @@ static int isp1760_hc_setup(struct usb_h
+ hwmode |= HW_DACK_POL_HIGH;
+ if (priv->devflags & ISP1760_FLAG_DREQ_POL_HIGH)
+ hwmode |= HW_DREQ_POL_HIGH;
++ if (priv->devflags & ISP1760_FLAG_INTR_POL_HIGH)
++ hwmode |= HW_INTR_HIGH_ACT;
++ if (priv->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
++ hwmode |= HW_INTR_EDGE_TRIG;
+
+ /*
+ * We have to set this first in case we're in 16-bit mode.
+--- a/drivers/usb/host/isp1760-hcd.h
++++ b/drivers/usb/host/isp1760-hcd.h
+@@ -142,6 +142,8 @@ typedef void (packet_enqueue)(struct usb
+ #define ISP1760_FLAG_DACK_POL_HIGH 0x00000010 /* DACK active high */
+ #define ISP1760_FLAG_DREQ_POL_HIGH 0x00000020 /* DREQ active high */
+ #define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */
++#define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */
++#define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */
+
+ /* chip memory management */
+ struct memory_chunk {
+--- a/drivers/usb/host/isp1760-if.c
++++ b/drivers/usb/host/isp1760-if.c
+@@ -3,6 +3,7 @@
+ * Currently there is support for
+ * - OpenFirmware
+ * - PCI
++ * - PDEV (generic platform device centralized driver model)
+ *
+ * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
+ *
+@@ -11,6 +12,7 @@
+ #include <linux/usb.h>
+ #include <linux/io.h>
+ #include <linux/platform_device.h>
++#include <linux/usb/isp1760.h>
+
+ #include "../core/hcd.h"
+ #include "isp1760-hcd.h"
+@@ -308,6 +310,8 @@ static int __devinit isp1760_plat_probe(
+ struct resource *mem_res;
+ struct resource *irq_res;
+ resource_size_t mem_size;
++ struct isp1760_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);
+@@ -330,8 +334,23 @@ static int __devinit isp1760_plat_probe(
+ }
+ irqflags |= irq_res->flags & IRQF_TRIGGER_MASK;
+
++ if (priv) {
++ if (priv->is_isp1761)
++ devflags |= ISP1760_FLAG_ISP1761;
++ if (priv->bus_width_16)
++ devflags |= ISP1760_FLAG_BUS_WIDTH_16;
++ if (priv->port1_otg)
++ devflags |= ISP1760_FLAG_OTG_EN;
++ if (priv->analog_oc)
++ devflags |= ISP1760_FLAG_ANALOG_OC;
++ if (priv->dack_polarity_high)
++ devflags |= ISP1760_FLAG_DACK_POL_HIGH;
++ if (priv->dreq_polarity_high)
++ devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
++ }
++
+ hcd = isp1760_register(mem_res->start, mem_size, irq_res->start,
+- irqflags, &pdev->dev, dev_name(&pdev->dev), 0);
++ irqflags, &pdev->dev, dev_name(&pdev->dev), devflags);
+ if (IS_ERR(hcd)) {
+ pr_warning("isp1760: Failed to register the HCD device\n");
+ ret = -ENODEV;
+--- /dev/null
++++ b/include/linux/usb/isp1760.h
+@@ -0,0 +1,18 @@
++/*
++ * board initialization should put one of these into dev->platform_data
++ * and place the isp1760 onto platform_bus named "isp1760-hcd".
++ */
++
++#ifndef __LINUX_USB_ISP1760_H
++#define __LINUX_USB_ISP1760_H
++
++struct isp1760_platform_data {
++ unsigned is_isp1761:1; /* Chip is ISP1761 */
++ unsigned bus_width_16:1; /* 16/32-bit data bus width */
++ unsigned port1_otg:1; /* Port 1 supports OTG */
++ unsigned analog_oc:1; /* Analog overcurrent */
++ unsigned dack_polarity_high:1; /* DACK active high */
++ unsigned dreq_polarity_high:1; /* DREQ active high */
++};
++
++#endif /* __LINUX_USB_ISP1760_H */