diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2009-07-16 16:39:39 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-07-16 16:39:39 -0700 |
| commit | c5c368ca56835336674e621f30277a574d596654 (patch) | |
| tree | 46c94e971452cb1e5168f10d6e34cf571de5dc8d /usb | |
| parent | 416838ff55d0ecbf421e0ede91a6c151beec8921 (diff) | |
| download | patches-c5c368ca56835336674e621f30277a574d596654.tar.gz | |
more staging and usb patches
Diffstat (limited to 'usb')
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 */ |
