diff options
Diffstat (limited to 'drivers/usb/host/isp1760-hcd.c')
-rw-r--r-- | drivers/usb/host/isp1760-hcd.c | 418 |
1 files changed, 270 insertions, 148 deletions
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index 840beda66dd9..27dfab80ed8f 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -21,8 +21,10 @@ #include <linux/uaccess.h> #include <linux/io.h> #include <linux/mm.h> +#include <linux/timer.h> #include <asm/unaligned.h> #include <asm/cacheflush.h> +#include <linux/gpio.h> #include "isp1760-hcd.h" @@ -39,7 +41,6 @@ struct isp1760_hcd { int int_done_map; struct memory_chunk memory_pool[BLOCKS]; struct list_head controlqhs, bulkqhs, interruptqhs; - int active_ptds; /* periodic schedule support */ #define DEFAULT_I_TDPS 1024 @@ -48,6 +49,8 @@ struct isp1760_hcd { unsigned long reset_done; unsigned long next_statechange; unsigned int devflags; + + int rst_gpio; }; static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd) @@ -114,6 +117,7 @@ struct isp1760_qh { u32 toggle; u32 ping; int slot; + int tt_buffer_dirty; /* See USB2.0 spec section 11.17.5 */ }; struct urb_listitem { @@ -432,6 +436,18 @@ static int isp1760_hc_setup(struct usb_hcd *hcd) int result; u32 scratch, hwmode; + /* low-level chip reset */ + if (gpio_is_valid(priv->rst_gpio)) { + unsigned int rst_lvl; + + rst_lvl = (priv->devflags & + ISP1760_FLAG_RESET_ACTIVE_HIGH) ? 1 : 0; + + gpio_set_value(priv->rst_gpio, rst_lvl); + mdelay(50); + gpio_set_value(priv->rst_gpio, !rst_lvl); + } + /* Setup HW Mode Control: This assumes a level active-low interrupt */ hwmode = HW_DATA_BUS_32BIT; @@ -489,10 +505,6 @@ static int isp1760_hc_setup(struct usb_hcd *hcd) 16 : 32, (priv->devflags & ISP1760_FLAG_ANALOG_OC) ? "analog" : "digital"); - /* This is weird: at the first plug-in of a device there seems to be - one packet queued that never gets returned? */ - priv->active_ptds = -1; - /* ATL reset */ reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET); mdelay(10); @@ -514,83 +526,6 @@ static int isp1760_hc_setup(struct usb_hcd *hcd) return priv_init(hcd); } -static void isp1760_init_maps(struct usb_hcd *hcd) -{ - /*set last maps, for iso its only 1, else 32 tds bitmap*/ - reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000); - reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000); - reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001); - - reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff); - reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff); - reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff); - - reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, - ATL_BUF_FILL | INT_BUF_FILL); -} - -static void isp1760_enable_interrupts(struct usb_hcd *hcd) -{ - reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0); - reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff); - reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0); - reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff); - reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0); - reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff); - /* step 23 passed */ -} - -static int isp1760_run(struct usb_hcd *hcd) -{ - int retval; - u32 temp; - u32 command; - u32 chipid; - - hcd->uses_new_polling = 1; - - hcd->state = HC_STATE_RUNNING; - isp1760_enable_interrupts(hcd); - temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL); - reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN); - - command = reg_read32(hcd->regs, HC_USBCMD); - command &= ~(CMD_LRESET|CMD_RESET); - command |= CMD_RUN; - reg_write32(hcd->regs, HC_USBCMD, command); - - retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000); - if (retval) - return retval; - - /* - * XXX - * Spec says to write FLAG_CF as last config action, priv code grabs - * the semaphore while doing so. - */ - down_write(&ehci_cf_port_reset_rwsem); - reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF); - - retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000); - up_write(&ehci_cf_port_reset_rwsem); - if (retval) - return retval; - - chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG); - dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n", - chipid & 0xffff, chipid >> 16); - - /* PTD Register Init Part 2, Step 28 */ - /* enable INTs */ - isp1760_init_maps(hcd); - - /* GRR this is run-once init(), being done every time the HC starts. - * So long as they're part of class devices, we can't do it init() - * since the class device isn't created that early. - */ - return 0; -} - static u32 base_to_chip(u32 base) { return ((base - 0x400) >> 3); @@ -813,28 +748,29 @@ static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot, WARN_ON(slots[slot].qh); WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC); - slots[slot].qtd = qtd; - slots[slot].qh = qh; - qh->slot = slot; - qtd->status = QTD_XFER_STARTED; /* Set this before writing ptd, since - interrupt routine may preempt and expects this value. */ - ptd_write(hcd->regs, ptd_offset, slot, ptd); - priv->active_ptds++; - /* Make sure done map has not triggered from some unlinked transfer */ if (ptd_offset == ATL_PTD_OFFSET) { priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG); - priv->atl_done_map &= ~(1 << qh->slot); + priv->atl_done_map &= ~(1 << slot); + } else { + priv->int_done_map |= reg_read32(hcd->regs, + HC_INT_PTD_DONEMAP_REG); + priv->int_done_map &= ~(1 << slot); + } + + qh->slot = slot; + qtd->status = QTD_XFER_STARTED; + slots[slot].timestamp = jiffies; + slots[slot].qtd = qtd; + slots[slot].qh = qh; + ptd_write(hcd->regs, ptd_offset, slot, ptd); + if (ptd_offset == ATL_PTD_OFFSET) { skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); skip_map &= ~(1 << qh->slot); reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map); } else { - priv->int_done_map |= reg_read32(hcd->regs, - HC_INT_PTD_DONEMAP_REG); - priv->int_done_map &= ~(1 << qh->slot); - skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); skip_map &= ~(1 << qh->slot); reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map); @@ -858,10 +794,7 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh, if (qtd->status < QTD_XFER_COMPLETE) break; - if (list_is_last(&qtd->qtd_list, &qh->qtd_list)) - last_qtd = 1; - else - last_qtd = qtd->urb != qtd_next->urb; + last_qtd = last_qtd_of_urb(qtd, qh); if ((!last_qtd) && (qtd->status == QTD_RETIRE)) qtd_next->status = QTD_RETIRE; @@ -902,7 +835,7 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh, urb_listitem = kmem_cache_zalloc(urb_listitem_cachep, GFP_ATOMIC); if (unlikely(!urb_listitem)) - break; + break; /* Try again on next call */ urb_listitem->urb = qtd->urb; list_add_tail(&urb_listitem->urb_list, urb_list); } @@ -928,6 +861,10 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh) return; } + /* Make sure this endpoint's TT buffer is clean before queueing ptds */ + if (qh->tt_buffer_dirty) + return; + if (usb_pipeint(list_entry(qh->qtd_list.next, struct isp1760_qtd, qtd_list)->urb->pipe)) { ptd_offset = INT_PTD_OFFSET; @@ -1168,11 +1105,9 @@ static int check_atl_transfer(struct usb_hcd *hcd, struct ptd *ptd, return PTD_STATE_QTD_DONE; } -static irqreturn_t isp1760_irq(struct usb_hcd *hcd) +static void handle_done_ptds(struct usb_hcd *hcd) { struct isp1760_hcd *priv = hcd_to_priv(hcd); - u32 imask; - irqreturn_t irqret = IRQ_NONE; struct ptd ptd; struct isp1760_qh *qh; int slot; @@ -1181,27 +1116,14 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd) u32 ptd_offset; struct isp1760_qtd *qtd; int modified; - static int last_active_ptds; - int int_skip_map, atl_skip_map; - - spin_lock(&priv->lock); - - if (!(hcd->state & HC_STATE_RUNNING)) - goto leave; - - imask = reg_read32(hcd->regs, HC_INTERRUPT_REG); - if (unlikely(!imask)) - goto leave; - reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */ + int skip_map; - int_skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); - atl_skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); - priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG); - priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG); - priv->int_done_map &= ~int_skip_map; - priv->atl_done_map &= ~atl_skip_map; + skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); + priv->int_done_map &= ~skip_map; + skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); + priv->atl_done_map &= ~skip_map; - modified = priv->int_done_map | priv->atl_done_map; + modified = priv->int_done_map || priv->atl_done_map; while (priv->int_done_map || priv->atl_done_map) { if (priv->int_done_map) { @@ -1240,7 +1162,6 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd) slots[slot].qtd = NULL; qh = slots[slot].qh; slots[slot].qh = NULL; - priv->active_ptds--; qh->slot = -1; WARN_ON(qtd->status != QTD_XFER_STARTED); @@ -1281,6 +1202,15 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd) case PTD_STATE_URB_RETIRE: qtd->status = QTD_RETIRE; + if ((qtd->urb->dev->speed != USB_SPEED_HIGH) && + (qtd->urb->status != -EPIPE) && + (qtd->urb->status != -EREMOTEIO)) { + qh->tt_buffer_dirty = 1; + if (usb_hub_clear_tt_buffer(qtd->urb)) + /* Clear failed; let's hope things work + anyway */ + qh->tt_buffer_dirty = 0; + } qtd = NULL; qh->toggle = 0; qh->ping = 0; @@ -1311,22 +1241,28 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd) if (modified) schedule_ptds(hcd); +} - /* ISP1760 Errata 2 explains that interrupts may be missed (or not - happen?) if two USB devices are running simultaneously. Perhaps - this happens when a PTD is finished during interrupt handling; - enable SOF interrupts if PTDs are still scheduled when exiting this - interrupt handler, just to be safe. */ +static irqreturn_t isp1760_irq(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 imask; + irqreturn_t irqret = IRQ_NONE; - if (priv->active_ptds != last_active_ptds) { - if (priv->active_ptds > 0) - reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, - INTERRUPT_ENABLE_SOT_MASK); - else - reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, - INTERRUPT_ENABLE_MASK); - last_active_ptds = priv->active_ptds; - } + spin_lock(&priv->lock); + + if (!(hcd->state & HC_STATE_RUNNING)) + goto leave; + + imask = reg_read32(hcd->regs, HC_INTERRUPT_REG); + if (unlikely(!imask)) + goto leave; + reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */ + + priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG); + priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG); + + handle_done_ptds(hcd); irqret = IRQ_HANDLED; leave: @@ -1335,6 +1271,138 @@ leave: return irqret; } +/* + * Workaround for problem described in chip errata 2: + * + * Sometimes interrupts are not generated when ATL (not INT?) completion occurs. + * One solution suggested in the errata is to use SOF interrupts _instead_of_ + * ATL done interrupts (the "instead of" might be important since it seems + * enabling ATL interrupts also causes the chip to sometimes - rarely - "forget" + * to set the PTD's done bit in addition to not generating an interrupt!). + * + * So if we use SOF + ATL interrupts, we sometimes get stale PTDs since their + * done bit is not being set. This is bad - it blocks the endpoint until reboot. + * + * If we use SOF interrupts only, we get latency between ptd completion and the + * actual handling. This is very noticeable in testusb runs which takes several + * minutes longer without ATL interrupts. + * + * A better solution is to run the code below every SLOT_CHECK_PERIOD ms. If it + * finds active ATL slots which are older than SLOT_TIMEOUT ms, it checks the + * slot's ACTIVE and VALID bits. If these are not set, the ptd is considered + * completed and its done map bit is set. + * + * The values of SLOT_TIMEOUT and SLOT_CHECK_PERIOD have been arbitrarily chosen + * not to cause too much lag when this HW bug occurs, while still hopefully + * ensuring that the check does not falsely trigger. + */ +#define SLOT_TIMEOUT 300 +#define SLOT_CHECK_PERIOD 200 +static struct timer_list errata2_timer; + +void errata2_function(unsigned long data) +{ + struct usb_hcd *hcd = (struct usb_hcd *) data; + struct isp1760_hcd *priv = hcd_to_priv(hcd); + int slot; + struct ptd ptd; + unsigned long spinflags; + + spin_lock_irqsave(&priv->lock, spinflags); + + for (slot = 0; slot < 32; slot++) + if (priv->atl_slots[slot].qh && time_after(jiffies, + priv->atl_slots[slot].timestamp + + SLOT_TIMEOUT * HZ / 1000)) { + ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd); + if (!FROM_DW0_VALID(ptd.dw0) && + !FROM_DW3_ACTIVE(ptd.dw3)) + priv->atl_done_map |= 1 << slot; + } + + if (priv->atl_done_map) + handle_done_ptds(hcd); + + spin_unlock_irqrestore(&priv->lock, spinflags); + + errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000; + add_timer(&errata2_timer); +} + +static int isp1760_run(struct usb_hcd *hcd) +{ + int retval; + u32 temp; + u32 command; + u32 chipid; + + hcd->uses_new_polling = 1; + + hcd->state = HC_STATE_RUNNING; + + /* Set PTD interrupt AND & OR maps */ + reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0); + reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff); + reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0); + reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff); + reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0); + reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff); + /* step 23 passed */ + + temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL); + reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN); + + command = reg_read32(hcd->regs, HC_USBCMD); + command &= ~(CMD_LRESET|CMD_RESET); + command |= CMD_RUN; + reg_write32(hcd->regs, HC_USBCMD, command); + + retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000); + if (retval) + return retval; + + /* + * XXX + * Spec says to write FLAG_CF as last config action, priv code grabs + * the semaphore while doing so. + */ + down_write(&ehci_cf_port_reset_rwsem); + reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF); + + retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000); + up_write(&ehci_cf_port_reset_rwsem); + if (retval) + return retval; + + init_timer(&errata2_timer); + errata2_timer.function = errata2_function; + errata2_timer.data = (unsigned long) hcd; + errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000; + add_timer(&errata2_timer); + + chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG); + dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n", + chipid & 0xffff, chipid >> 16); + + /* PTD Register Init Part 2, Step 28 */ + + /* Setup registers controlling PTD checking */ + reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000); + reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000); + reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001); + reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff); + reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff); + reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff); + reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, + ATL_BUF_FILL | INT_BUF_FILL); + + /* GRR this is run-once init(), being done every time the HC starts. + * So long as they're part of class devices, we can't do it init() + * since the class device isn't created that early. + */ + return 0; +} + static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len) { qtd->data_buffer = databuffer; @@ -1503,7 +1571,6 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, packetize_urb(hcd, urb, &new_qtds, mem_flags); if (list_empty(&new_qtds)) return -ENOMEM; - urb->hcpriv = NULL; /* Used to signal unlink to interrupt handler */ retval = 0; spin_lock_irqsave(&priv->lock, spinflags); @@ -1531,6 +1598,7 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, qh = qh_alloc(GFP_ATOMIC); if (!qh) { retval = -ENOMEM; + usb_hcd_unlink_urb_from_ep(hcd, urb); goto out; } list_add_tail(&qh->qh_list, ep_queue); @@ -1570,7 +1638,41 @@ static void kill_transfer(struct usb_hcd *hcd, struct urb *urb, } qh->slot = -1; - priv->active_ptds--; +} + +/* + * Retire the qtds beginning at 'qtd' and belonging all to the same urb, killing + * any active transfer belonging to the urb in the process. + */ +static void dequeue_urb_from_qtd(struct usb_hcd *hcd, struct isp1760_qh *qh, + struct isp1760_qtd *qtd) +{ + struct urb *urb; + int urb_was_running; + + urb = qtd->urb; + urb_was_running = 0; + list_for_each_entry_from(qtd, &qh->qtd_list, qtd_list) { + if (qtd->urb != urb) + break; + + if (qtd->status >= QTD_XFER_STARTED) + urb_was_running = 1; + if (last_qtd_of_urb(qtd, qh) && + (qtd->status >= QTD_XFER_COMPLETE)) + urb_was_running = 0; + + if (qtd->status == QTD_XFER_STARTED) + kill_transfer(hcd, urb, qh); + qtd->status = QTD_RETIRE; + } + + if ((urb->dev->speed != USB_SPEED_HIGH) && urb_was_running) { + qh->tt_buffer_dirty = 1; + if (usb_hub_clear_tt_buffer(urb)) + /* Clear failed; let's hope things work anyway */ + qh->tt_buffer_dirty = 0; + } } static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, @@ -1595,9 +1697,8 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, list_for_each_entry(qtd, &qh->qtd_list, qtd_list) if (qtd->urb == urb) { - if (qtd->status == QTD_XFER_STARTED) - kill_transfer(hcd, urb, qh); - qtd->status = QTD_RETIRE; + dequeue_urb_from_qtd(hcd, qh, qtd); + break; } urb->status = status; @@ -1622,12 +1723,11 @@ static void isp1760_endpoint_disable(struct usb_hcd *hcd, if (!qh) goto out; - list_for_each_entry(qtd, &qh->qtd_list, qtd_list) { - if (qtd->status == QTD_XFER_STARTED) - kill_transfer(hcd, qtd->urb, qh); - qtd->status = QTD_RETIRE; - qtd->urb->status = -ECONNRESET; - } + list_for_each_entry(qtd, &qh->qtd_list, qtd_list) + if (qtd->status != QTD_RETIRE) { + dequeue_urb_from_qtd(hcd, qh, qtd); + qtd->urb->status = -ECONNRESET; + } ep->hcpriv = NULL; /* Cannot free qh here since it will be parsed by schedule_ptds() */ @@ -2021,6 +2121,8 @@ static void isp1760_stop(struct usb_hcd *hcd) struct isp1760_hcd *priv = hcd_to_priv(hcd); u32 temp; + del_timer(&errata2_timer); + isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1, NULL, 0); mdelay(20); @@ -2048,6 +2150,23 @@ static void isp1760_shutdown(struct usb_hcd *hcd) reg_write32(hcd->regs, HC_USBCMD, command); } +static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd, + struct usb_host_endpoint *ep) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + struct isp1760_qh *qh = ep->hcpriv; + unsigned long spinflags; + + if (!qh) + return; + + spin_lock_irqsave(&priv->lock, spinflags); + qh->tt_buffer_dirty = 0; + schedule_ptds(hcd); + spin_unlock_irqrestore(&priv->lock, spinflags); +} + + static const struct hc_driver isp1760_hc_driver = { .description = "isp1760-hcd", .product_desc = "NXP ISP1760 USB Host Controller", @@ -2064,6 +2183,7 @@ static const struct hc_driver isp1760_hc_driver = { .get_frame_number = isp1760_get_frame, .hub_status_data = isp1760_hub_status_data, .hub_control = isp1760_hub_control, + .clear_tt_buffer_complete = isp1760_clear_tt_buffer_complete, }; int __init init_kmem_once(void) @@ -2102,6 +2222,7 @@ void deinit_kmem_cache(void) struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len, int irq, unsigned long irqflags, + int rst_gpio, struct device *dev, const char *busname, unsigned int devflags) { @@ -2121,6 +2242,7 @@ struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len, priv = hcd_to_priv(hcd); priv->devflags = devflags; + priv->rst_gpio = rst_gpio; init_memory(priv); hcd->regs = ioremap(res_start, res_len); if (!hcd->regs) { |