diff options
Diffstat (limited to 'drivers/usb/musb/musb_host.c')
| -rw-r--r-- | drivers/usb/musb/musb_host.c | 145 |
1 files changed, 122 insertions, 23 deletions
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 9d3044bdebe..eb06291a40c 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -39,14 +39,12 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/list.h> #include <linux/dma-mapping.h> #include "musb_core.h" #include "musb_host.h" - /* MUSB HOST status 22-mar-2006 * * - There's still lots of partial code duplication for fault paths, so @@ -96,6 +94,11 @@ * of transfers between endpoints, or anything clever. */ +struct musb *hcd_to_musb(struct usb_hcd *hcd) +{ + return *(struct musb **) hcd->hcd_priv; +} + static void musb_ep_program(struct musb *musb, u8 epnum, struct urb *urb, int is_out, @@ -249,7 +252,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) case USB_ENDPOINT_XFER_BULK: s = "-bulk"; break; case USB_ENDPOINT_XFER_ISOC: s = "-iso"; break; default: s = "-intr"; break; - }; s; }), + } s; }), epnum, buf + offset, len); /* Configure endpoint */ @@ -269,8 +272,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) /* FIXME this doesn't implement that scheduling policy ... * or handle framecounter wrapping */ - if ((urb->transfer_flags & URB_ISO_ASAP) - || (frame >= urb->start_frame)) { + if (1) { /* Always assume URB_ISO_ASAP */ /* REVISIT the SOF irq handler shouldn't duplicate * this code; and we don't init urb->start_frame... */ @@ -311,9 +313,9 @@ __acquires(musb->lock) urb->actual_length, urb->transfer_buffer_length ); - usb_hcd_unlink_urb_from_ep(musb_to_hcd(musb), urb); + usb_hcd_unlink_urb_from_ep(musb->hcd, urb); spin_unlock(&musb->lock); - usb_hcd_giveback_urb(musb_to_hcd(musb), urb, status); + usb_hcd_giveback_urb(musb->hcd, urb, status); spin_lock(&musb->lock); } @@ -625,7 +627,7 @@ static bool musb_tx_dma_program(struct dma_controller *dma, u16 csr; u8 mode; -#ifdef CONFIG_USB_INVENTRA_DMA +#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) if (length > channel->max_len) length = channel->max_len; @@ -1181,6 +1183,9 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb) csr = MUSB_CSR0_H_STATUSPKT | MUSB_CSR0_TXPKTRDY; + /* disable ping token in status phase */ + csr |= MUSB_CSR0_H_DIS_PING; + /* flag status stage */ musb->ep0_stage = MUSB_EP0_STATUS; @@ -1455,7 +1460,7 @@ done: if (length > qh->maxpacket) length = qh->maxpacket; /* Unmap the buffer so that CPU can use it */ - usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb); + usb_hcd_unmap_urb_for_dma(musb->hcd, urb); /* * We need to map sg if the transfer_buffer is @@ -1657,7 +1662,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) /* FIXME this is _way_ too much in-line logic for Mentor DMA */ -#ifndef CONFIG_USB_INVENTRA_DMA +#if !defined(CONFIG_USB_INVENTRA_DMA) && !defined(CONFIG_USB_UX500_DMA) if (rx_csr & MUSB_RXCSR_H_REQPKT) { /* REVISIT this happened for a while on some short reads... * the cleanup still needs investigation... looks bad... @@ -1689,7 +1694,8 @@ void musb_host_rx(struct musb *musb, u8 epnum) | MUSB_RXCSR_RXPKTRDY); musb_writew(hw_ep->regs, MUSB_RXCSR, val); -#ifdef CONFIG_USB_INVENTRA_DMA +#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) || \ + defined(CONFIG_USB_TI_CPPI41_DMA) if (usb_pipeisoc(pipe)) { struct usb_iso_packet_descriptor *d; @@ -1702,10 +1708,30 @@ void musb_host_rx(struct musb *musb, u8 epnum) if (d->status != -EILSEQ && d->status != -EOVERFLOW) d->status = 0; - if (++qh->iso_idx >= urb->number_of_packets) + if (++qh->iso_idx >= urb->number_of_packets) { done = true; - else + } else { +#if defined(CONFIG_USB_TI_CPPI41_DMA) + struct dma_controller *c; + dma_addr_t *buf; + u32 length, ret; + + c = musb->dma_controller; + buf = (void *) + urb->iso_frame_desc[qh->iso_idx].offset + + (u32)urb->transfer_dma; + + length = + urb->iso_frame_desc[qh->iso_idx].length; + + val |= MUSB_RXCSR_DMAENAB; + musb_writew(hw_ep->regs, MUSB_RXCSR, val); + + ret = c->channel_program(dma, qh->maxpacket, + 0, (u32) buf, length); +#endif done = false; + } } else { /* done if urb buffer is full or short packet is recd */ @@ -1745,7 +1771,8 @@ void musb_host_rx(struct musb *musb, u8 epnum) } /* we are expecting IN packets */ -#ifdef CONFIG_USB_INVENTRA_DMA +#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) || \ + defined(CONFIG_USB_TI_CPPI41_DMA) if (dma) { struct dma_controller *c; u16 rx_count; @@ -1754,10 +1781,10 @@ void musb_host_rx(struct musb *musb, u8 epnum) rx_count = musb_readw(epio, MUSB_RXCOUNT); - dev_dbg(musb->controller, "RX%d count %d, buffer 0x%x len %d/%d\n", + dev_dbg(musb->controller, "RX%d count %d, buffer 0x%llx len %d/%d\n", epnum, rx_count, - urb->transfer_dma - + urb->actual_length, + (unsigned long long) urb->transfer_dma + + urb->actual_length, qh->offset, urb->transfer_buffer_length); @@ -1869,7 +1896,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) unsigned int received_len; /* Unmap the buffer so that CPU can use it */ - usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb); + usb_hcd_unmap_urb_for_dma(musb->hcd, urb); /* * We need to map sg if the transfer_buffer is @@ -2010,7 +2037,7 @@ static int musb_schedule( head = &musb->out_bulk; /* Enable bulk RX/TX NAK timeout scheme when bulk requests are - * multiplexed. This scheme doen't work in high speed to full + * multiplexed. This scheme does not work in high speed to full * speed scenario as NAK interrupts are not coming from a * full speed device connected to a high speed device. * NAK timeout interval is 8 (128 uframe or 16ms) for HS and @@ -2430,6 +2457,8 @@ static int musb_bus_suspend(struct usb_hcd *hcd) struct musb *musb = hcd_to_musb(hcd); u8 devctl; + musb_port_suspend(musb, true); + if (!is_host_active(musb)) return 0; @@ -2459,11 +2488,15 @@ static int musb_bus_suspend(struct usb_hcd *hcd) static int musb_bus_resume(struct usb_hcd *hcd) { - /* resuming child port does the work */ + struct musb *musb = hcd_to_musb(hcd); + + if (musb->config && + musb->config->host_port_deassert_reset_at_resume) + musb_port_reset(musb, false); + return 0; } - #ifndef CONFIG_MUSB_PIO_ONLY #define MUSB_USB_DMA_ALIGN 4 @@ -2575,10 +2608,10 @@ static void musb_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) } #endif /* !CONFIG_MUSB_PIO_ONLY */ -const struct hc_driver musb_hc_driver = { +static const struct hc_driver musb_hc_driver = { .description = "musb-hcd", .product_desc = "MUSB HDRC host driver", - .hcd_priv_size = sizeof(struct musb), + .hcd_priv_size = sizeof(struct musb *), .flags = HCD_USB2 | HCD_MEMORY, /* not using irq handler or reset hooks from usbcore, since @@ -2606,3 +2639,69 @@ const struct hc_driver musb_hc_driver = { /* .start_port_reset = NULL, */ /* .hub_irq_enable = NULL, */ }; + +int musb_host_alloc(struct musb *musb) +{ + struct device *dev = musb->controller; + + /* usbcore sets dev->driver_data to hcd, and sometimes uses that... */ + musb->hcd = usb_create_hcd(&musb_hc_driver, dev, dev_name(dev)); + if (!musb->hcd) + return -EINVAL; + + *musb->hcd->hcd_priv = (unsigned long) musb; + musb->hcd->self.uses_pio_for_control = 1; + musb->hcd->uses_new_polling = 1; + musb->hcd->has_tt = 1; + + return 0; +} + +void musb_host_cleanup(struct musb *musb) +{ + if (musb->port_mode == MUSB_PORT_MODE_GADGET) + return; + usb_remove_hcd(musb->hcd); + musb->hcd = NULL; +} + +void musb_host_free(struct musb *musb) +{ + usb_put_hcd(musb->hcd); +} + +int musb_host_setup(struct musb *musb, int power_budget) +{ + int ret; + struct usb_hcd *hcd = musb->hcd; + + MUSB_HST_MODE(musb); + musb->xceiv->otg->default_a = 1; + musb->xceiv->state = OTG_STATE_A_IDLE; + + otg_set_host(musb->xceiv->otg, &hcd->self); + hcd->self.otg_port = 1; + musb->xceiv->otg->host = &hcd->self; + hcd->power_budget = 2 * (power_budget ? : 250); + + ret = usb_add_hcd(hcd, 0, 0); + if (ret < 0) + return ret; + + device_wakeup_enable(hcd->self.controller); + return 0; +} + +void musb_host_resume_root_hub(struct musb *musb) +{ + usb_hcd_resume_root_hub(musb->hcd); +} + +void musb_host_poke_root_hub(struct musb *musb) +{ + MUSB_HST_MODE(musb); + if (musb->hcd->status_urb) + usb_hcd_poll_rh_status(musb->hcd); + else + usb_hcd_resume_root_hub(musb->hcd); +} |
