]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - sitara-epos/sitara-epos-kernel.git/blobdiff - drivers/usb/musb/musb_gadget.c
usb: musb_gadget: cppi41: Use pio for interrupt transfer
[sitara-epos/sitara-epos-kernel.git] / drivers / usb / musb / musb_gadget.c
index 922148ff8d2969de64a808046f7ce06c6115ace1..bd44703b3819ca02df3abaad7a40140bf4d62ded 100644 (file)
@@ -40,8 +40,6 @@
 #include <linux/smp.h>
 #include <linux/spinlock.h>
 #include <linux/delay.h>
-#include <linux/moduleparam.h>
-#include <linux/stat.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 
@@ -278,8 +276,6 @@ static inline int max_ep_writesize(struct musb *musb, struct musb_ep *ep)
 }
 
 
-#ifdef CONFIG_USB_INVENTRA_DMA
-
 /* Peripheral tx (IN) using Mentor DMA works as follows:
        Only mode 0 is used for transfers <= wPktSize,
        mode 1 is used for larger transfers,
@@ -310,8 +306,6 @@ static inline int max_ep_writesize(struct musb *musb, struct musb_ep *ep)
  * upleveling from irq-per-packet to irq-per-buffer.
  */
 
-#endif
-
 /*
  * An endpoint is transmitting data. This can be called either from
  * the IRQ routine or from ep.queue() to kickstart a request on an
@@ -372,8 +366,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
 
                /* MUSB_TXCSR_P_ISO is still set correctly */
 
-#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA)
-               {
+               if (is_inventra_dma(musb) || is_ux500_dma(musb)) {
                        if (request_size < musb_ep->packet_sz)
                                musb_ep->dma->desired_mode = 0;
                        else
@@ -410,49 +403,65 @@ static void txstate(struct musb *musb, struct musb_request *req)
 
                                musb_writew(epio, MUSB_TXCSR, csr);
                        }
-               }
+               } else if (is_cppi_enabled(musb) || is_cppi41_enabled(musb)) {
+                       /* program endpoint CSR first, then setup DMA */
+                       csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
 
-#elif defined(CONFIG_USB_TI_CPPI_DMA)
-               /* program endpoint CSR first, then setup DMA */
-               csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
-               csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE |
-                      MUSB_TXCSR_MODE;
-               musb_writew(epio, MUSB_TXCSR,
-                       (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN)
-                               | csr);
+                       if (request_size == 0)
+                               csr &= ~(MUSB_TXCSR_DMAENAB |
+                                       MUSB_TXCSR_DMAMODE);
+                       else
+                               csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE |
+                                      MUSB_TXCSR_MODE;
+                       musb_writew(epio, MUSB_TXCSR,
+                               (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN)
+                                       | csr);
 
-               /* ensure writebuffer is empty */
-               csr = musb_readw(epio, MUSB_TXCSR);
+                       /* ensure writebuffer is empty */
+                       csr = musb_readw(epio, MUSB_TXCSR);
 
-               /* NOTE host side sets DMAENAB later than this; both are
-                * OK since the transfer dma glue (between CPPI and Mentor
-                * fifos) just tells CPPI it could start.  Data only moves
-                * to the USB TX fifo when both fifos are ready.
-                */
+                       /* NOTE host side sets DMAENAB later than this; both are
+                        * OK since the transfer dma glue (between CPPI & Mentor
+                        * fifos) just tells CPPI it could start.  Data only
+                        * moves to the USB TX fifo when both fifos are ready.
+                        */
 
-               /* "mode" is irrelevant here; handle terminating ZLPs like
-                * PIO does, since the hardware RNDIS mode seems unreliable
-                * except for the last-packet-is-already-short case.
-                */
-               use_dma = use_dma && c->channel_program(
-                               musb_ep->dma, musb_ep->packet_sz,
-                               0,
-                               request->dma + request->actual,
-                               request_size);
-               if (!use_dma) {
-                       c->channel_release(musb_ep->dma);
-                       musb_ep->dma = NULL;
-                       csr &= ~MUSB_TXCSR_DMAENAB;
-                       musb_writew(epio, MUSB_TXCSR, csr);
-                       /* invariant: prequest->buf is non-null */
+                       /* "mode" is irrelevant here; handle terminating ZLPs
+                        * like PIO does, since the hardware RNDIS mode seems
+                        * unreliable except for the last-packet-is-already-
+                        * short case.
+                        */
+                       /* for zero byte transfer use pio mode */
+
+                       /* Use pio mode for interrupt transfer of size <= 64
+                        * byte. We have seen TxFiFoEmpty workqueue going into
+                        * infinite loop when a CDC device is connected to
+                        * another EVM. */
+
+                       if ((request_size == 0) || (request_size <= 64 &&
+                               musb_ep->type == USB_ENDPOINT_XFER_INT)) {
+                               use_dma = 0;
+                       } else {
+                               use_dma = use_dma && c->channel_program(
+                                       musb_ep->dma, musb_ep->packet_sz,
+                                       0,
+                                       request->dma + request->actual,
+                                       request_size);
+                               if (!use_dma) {
+                                       c->channel_release(musb_ep->dma);
+                                       musb_ep->dma = NULL;
+                                       csr &= ~MUSB_TXCSR_DMAENAB;
+                                       musb_writew(epio, MUSB_TXCSR, csr);
+                               /* invariant: prequest->buf is non-null */
+                               }
+                       }
+               } else if (tusb_dma_omap(musb)) {
+                       use_dma = use_dma && c->channel_program(
+                                       musb_ep->dma, musb_ep->packet_sz,
+                                       request->zero,
+                                       request->dma + request->actual,
+                                       request_size);
                }
-#elif defined(CONFIG_USB_TUSB_OMAP_DMA)
-               use_dma = use_dma && c->channel_program(
-                               musb_ep->dma, musb_ep->packet_sz,
-                               request->zero,
-                               request->dma + request->actual,
-                               request_size);
-#endif
        }
 #endif
 
@@ -463,7 +472,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
                 */
                unmap_dma_buffer(req, musb);
 
-               musb_write_fifo(musb_ep->hw_ep, fifo_count,
+               musb->ops->write_fifo(musb_ep->hw_ep, fifo_count,
                                (u8 *) (request->buf + request->actual));
                request->actual += fifo_count;
                csr |= MUSB_TXCSR_TXPKTRDY;
@@ -494,7 +503,7 @@ void musb_g_tx(struct musb *musb, u8 epnum)
        void __iomem            *epio = musb->endpoints[epnum].regs;
        struct dma_channel      *dma;
 
-       musb_ep_select(mbase, epnum);
+       musb_ep_select(musb, mbase, epnum);
        req = next_request(musb_ep);
        request = &req->request;
 
@@ -555,11 +564,9 @@ void musb_g_tx(struct musb *musb, u8 epnum)
                if ((request->zero && request->length
                        && (request->length % musb_ep->packet_sz == 0)
                        && (request->actual == request->length))
-#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA)
-                       || (is_dma && (!dma->desired_mode ||
-                               (request->actual &
-                                       (musb_ep->packet_sz - 1))))
-#endif
+                       || ((is_inventra_dma(musb) || is_ux500_dma(musb)) &&
+                       is_dma && (!dma->desired_mode || (request->actual &
+                       (musb_ep->packet_sz - 1))))
                ) {
                        /*
                         * On DMA completion, FIFO may not be
@@ -590,8 +597,6 @@ void musb_g_tx(struct musb *musb, u8 epnum)
 
 /* ------------------------------------------------------------ */
 
-#ifdef CONFIG_USB_INVENTRA_DMA
-
 /* Peripheral rx (OUT) using Mentor DMA works as follows:
        - Only mode 0 is used.
 
@@ -619,8 +624,6 @@ void musb_g_tx(struct musb *musb, u8 epnum)
  * Non-Mentor DMA engines can of course work differently.
  */
 
-#endif
-
 /*
  * Context: controller locked, IRQs blocked, endpoint selected
  */
@@ -655,7 +658,8 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                return;
        }
 
-       if (is_cppi_enabled() && is_buffer_mapped(req)) {
+       if ((is_cppi_enabled(musb) || is_cppi41_enabled(musb)) &&
+                                       is_buffer_mapped(req)) {
                struct dma_controller   *c = musb->dma_controller;
                struct dma_channel      *channel = musb_ep->dma;
 
@@ -697,8 +701,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                        use_mode_1 = 0;
 
                if (request->actual < request->length) {
-#ifdef CONFIG_USB_INVENTRA_DMA
-                       if (is_buffer_mapped(req)) {
+                       if (is_buffer_mapped(req) && is_inventra_dma(musb)) {
                                struct dma_controller   *c;
                                struct dma_channel      *channel;
                                int                     use_dma = 0;
@@ -775,8 +778,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                                if (use_dma)
                                        return;
                        }
-#elif defined(CONFIG_USB_UX500_DMA)
-                       if ((is_buffer_mapped(req)) &&
+                       if (is_ux500_dma(musb) && (is_buffer_mapped(req)) &&
                                (request->actual < request->length)) {
 
                                struct dma_controller *c;
@@ -822,7 +824,6 @@ static void rxstate(struct musb *musb, struct musb_request *req)
 
                                        return;
                        }
-#endif /* Mentor's DMA */
 
                        fifo_count = request->length - request->actual;
                        dev_dbg(musb->controller, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n",
@@ -832,8 +833,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
 
                        fifo_count = min_t(unsigned, len, fifo_count);
 
-#ifdef CONFIG_USB_TUSB_OMAP_DMA
-                       if (tusb_dma_omap() && is_buffer_mapped(req)) {
+                       if (tusb_dma_omap(musb) && is_buffer_mapped(req)) {
                                struct dma_controller *c = musb->dma_controller;
                                struct dma_channel *channel = musb_ep->dma;
                                u32 dma_addr = request->dma + request->actual;
@@ -847,7 +847,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                                if (ret)
                                        return;
                        }
-#endif
+
                        /*
                         * Unmap the dma buffer back to cpu if dma channel
                         * programming fails. This buffer is mapped if the
@@ -864,7 +864,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                                musb_writew(epio, MUSB_RXCSR, csr);
                        }
 
-                       musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *)
+                       musb->ops->read_fifo(musb_ep->hw_ep, fifo_count, (u8 *)
                                        (request->buf + request->actual));
                        request->actual += fifo_count;
 
@@ -903,7 +903,7 @@ void musb_g_rx(struct musb *musb, u8 epnum)
        else
                musb_ep = &hw_ep->ep_out;
 
-       musb_ep_select(mbase, epnum);
+       musb_ep_select(musb, mbase, epnum);
 
        req = next_request(musb_ep);
        if (!req)
@@ -959,41 +959,37 @@ void musb_g_rx(struct musb *musb, u8 epnum)
                        musb_readw(epio, MUSB_RXCSR),
                        musb_ep->dma->actual_len, request);
 
-#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) || \
-       defined(CONFIG_USB_UX500_DMA)
-               /* Autoclear doesn't clear RxPktRdy for short packets */
-               if ((dma->desired_mode == 0 && !hw_ep->rx_double_buffered)
-                               || (dma->actual_len
-                                       & (musb_ep->packet_sz - 1))) {
-                       /* ack the read! */
-                       csr &= ~MUSB_RXCSR_RXPKTRDY;
-                       musb_writew(epio, MUSB_RXCSR, csr);
-               }
+               if (is_inventra_dma(musb) || tusb_dma_omap(musb)
+                               || is_ux500_dma(musb)) {
+                       /* Autoclear doesn't clear RxPktRdy for short packets */
+                       if ((dma->desired_mode == 0 && !hw_ep->rx_double_buffered)
+                                       || (dma->actual_len
+                                               & (musb_ep->packet_sz - 1))) {
+                               /* ack the read! */
+                               csr &= ~MUSB_RXCSR_RXPKTRDY;
+                               musb_writew(epio, MUSB_RXCSR, csr);
+                       }
 
-               /* incomplete, and not short? wait for next IN packet */
-               if ((request->actual < request->length)
-                               && (musb_ep->dma->actual_len
-                                       == musb_ep->packet_sz)) {
-                       /* In double buffer case, continue to unload fifo if
-                        * there is Rx packet in FIFO.
-                        **/
-                       csr = musb_readw(epio, MUSB_RXCSR);
-                       if ((csr & MUSB_RXCSR_RXPKTRDY) &&
-                               hw_ep->rx_double_buffered)
-                               goto exit;
-                       return;
+                       /* incomplete, and not short? wait for next IN packet */
+                       if ((request->actual < request->length)
+                                       && (musb_ep->dma->actual_len
+                                               == musb_ep->packet_sz)) {
+                               /* In double buffer case, continue to unload
+                                * fifo if there is Rx packet in FIFO.
+                                **/
+                               csr = musb_readw(epio, MUSB_RXCSR);
+                               if ((csr & MUSB_RXCSR_RXPKTRDY) &&
+                                       hw_ep->rx_double_buffered)
+                                       rxstate(musb, to_musb_request(request));
+                               return;
+                       }
                }
-#endif
                musb_g_giveback(musb_ep, request, 0);
 
                req = next_request(musb_ep);
                if (!req)
                        return;
        }
-#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) || \
-       defined(CONFIG_USB_UX500_DMA)
-exit:
-#endif
        /* Analyze request */
        rxstate(musb, req);
 }
@@ -1061,7 +1057,7 @@ static int musb_gadget_enable(struct usb_ep *ep,
        /* enable the interrupts for the endpoint, set the endpoint
         * packet size (or fail), set the mode, clear the fifo
         */
-       musb_ep_select(mbase, epnum);
+       musb_ep_select(musb, mbase, epnum);
        if (usb_endpoint_dir_in(desc)) {
                u16 int_txe = musb_readw(mbase, MUSB_INTRTXE);
 
@@ -1200,7 +1196,7 @@ static int musb_gadget_disable(struct usb_ep *ep)
        epio = musb->endpoints[epnum].regs;
 
        spin_lock_irqsave(&musb->lock, flags);
-       musb_ep_select(musb->mregs, epnum);
+       musb_ep_select(musb, musb->mregs, epnum);
 
        /* zero the endpoint sizes */
        if (musb_ep->is_in) {
@@ -1279,7 +1275,7 @@ void musb_ep_restart(struct musb *musb, struct musb_request *req)
                req->tx ? "TX/IN" : "RX/OUT",
                &req->request, req->request.length, req->epnum);
 
-       musb_ep_select(musb->mregs, req->epnum);
+       musb_ep_select(musb, musb->mregs, req->epnum);
        if (req->tx)
                txstate(musb, req);
        else
@@ -1373,7 +1369,7 @@ static int musb_gadget_dequeue(struct usb_ep *ep, struct usb_request *request)
        else if (is_dma_capable() && musb_ep->dma) {
                struct dma_controller   *c = musb->dma_controller;
 
-               musb_ep_select(musb->mregs, musb_ep->current_epnum);
+               musb_ep_select(musb, musb->mregs, musb_ep->current_epnum);
                if (c->channel_abort)
                        status = c->channel_abort(musb_ep->dma);
                else
@@ -1421,7 +1417,7 @@ static int musb_gadget_set_halt(struct usb_ep *ep, int value)
                goto done;
        }
 
-       musb_ep_select(mbase, epnum);
+       musb_ep_select(musb, mbase, epnum);
 
        request = next_request(musb_ep);
        if (value) {
@@ -1509,7 +1505,7 @@ static int musb_gadget_fifo_status(struct usb_ep *ep)
 
                spin_lock_irqsave(&musb->lock, flags);
 
-               musb_ep_select(mbase, epnum);
+               musb_ep_select(musb, mbase, epnum);
                /* FIXME return zero unless RXPKTRDY is set */
                retval = musb_readw(epio, MUSB_RXCOUNT);
 
@@ -1531,7 +1527,7 @@ static void musb_gadget_fifo_flush(struct usb_ep *ep)
        mbase = musb->mregs;
 
        spin_lock_irqsave(&musb->lock, flags);
-       musb_ep_select(mbase, (u8) epnum);
+       musb_ep_select(musb, mbase, (u8) epnum);
 
        /* disable interrupts */
        int_txe = musb_readw(mbase, MUSB_INTRTXE);
@@ -1764,7 +1760,7 @@ static void musb_gadget_release(struct device *dev)
 }
 
 
-static void __init
+static void __devinit
 init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)
 {
        struct musb_hw_ep       *hw_ep = musb->endpoints + epnum;
@@ -1801,7 +1797,7 @@ init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)
  * Initialize the endpoints exposed to peripheral drivers, with backlinks
  * to the rest of the driver state.
  */
-static inline void __init musb_g_init_endpoints(struct musb *musb)
+static inline void __devinit musb_g_init_endpoints(struct musb *musb)
 {
        u8                      epnum;
        struct musb_hw_ep       *hw_ep;
@@ -1834,7 +1830,7 @@ static inline void __init musb_g_init_endpoints(struct musb *musb)
 /* called once during driver setup to initialize and link into
  * the driver model; memory is zeroed.
  */
-int __init musb_gadget_setup(struct musb *musb)
+int __devinit musb_gadget_setup(struct musb *musb)
 {
        int status;
 
@@ -1844,7 +1840,7 @@ int __init musb_gadget_setup(struct musb *musb)
         */
 
        musb->g.ops = &musb_gadget_operations;
-       musb->g.is_dualspeed = 1;
+       musb->g.max_speed = USB_SPEED_HIGH;
        musb->g.speed = USB_SPEED_UNKNOWN;
 
        /* this "gadget" abstracts/virtualizes the controller */
@@ -1903,7 +1899,7 @@ static int musb_gadget_start(struct usb_gadget *g,
        unsigned long           flags;
        int                     retval = -EINVAL;
 
-       if (driver->speed < USB_SPEED_HIGH)
+       if (driver->max_speed < USB_SPEED_HIGH)
                goto err0;
 
        pm_runtime_get_sync(musb->controller);
@@ -1989,7 +1985,7 @@ static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver)
                for (i = 0, hw_ep = musb->endpoints;
                                i < musb->nr_endpoints;
                                i++, hw_ep++) {
-                       musb_ep_select(musb->mregs, i);
+                       musb_ep_select(musb, musb->mregs, i);
                        if (hw_ep->is_shared_fifo /* || !epnum */) {
                                nuke(&hw_ep->ep_in, -ESHUTDOWN);
                        } else {
@@ -2024,7 +2020,8 @@ static int musb_gadget_stop(struct usb_gadget *g,
 
        spin_lock_irqsave(&musb->lock, flags);
 
-       musb_hnp_stop(musb);
+       if (is_otg_enabled(musb))
+               musb_hnp_stop(musb);
 
        (void) musb_gadget_vbus_draw(&musb->g, 0);
 
@@ -2138,17 +2135,20 @@ void musb_g_disconnect(struct musb *musb)
 
        switch (musb->xceiv->state) {
        default:
-               dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n",
-                       otg_state_string(musb->xceiv->state));
-               musb->xceiv->state = OTG_STATE_A_IDLE;
-               MUSB_HST_MODE(musb);
-               break;
+               if (is_otg_enabled(musb)) {
+                       dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n",
+                               otg_state_string(musb->xceiv->state));
+                       musb->xceiv->state = OTG_STATE_A_IDLE;
+                       break;
+               }
        case OTG_STATE_A_PERIPHERAL:
-               musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
-               MUSB_HST_MODE(musb);
+               if (is_otg_enabled(musb))
+                       musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
                break;
        case OTG_STATE_B_WAIT_ACON:
        case OTG_STATE_B_HOST:
+               if (!is_otg_enabled(musb))
+                       break;
        case OTG_STATE_B_PERIPHERAL:
        case OTG_STATE_B_IDLE:
                musb->xceiv->state = OTG_STATE_B_IDLE;