]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/usb/musb/musb_gadget.c
Merge branch 'usb-next' into musb-merge
[mv-sheeva.git] / drivers / usb / musb / musb_gadget.c
index edff014edd3af5780aa7edcb3838fb861aa76549..9b162dfaa4fbcb81121e0ecbce52f44285ab3a46 100644 (file)
 
 /* ----------------------------------------------------------------------- */
 
+/* Maps the buffer to dma  */
+
+static inline void map_dma_buffer(struct musb_request *request,
+                               struct musb *musb)
+{
+       if (request->request.dma == DMA_ADDR_INVALID) {
+               request->request.dma = dma_map_single(
+                               musb->controller,
+                               request->request.buf,
+                               request->request.length,
+                               request->tx
+                                       ? DMA_TO_DEVICE
+                                       : DMA_FROM_DEVICE);
+               request->mapped = 1;
+       } else {
+               dma_sync_single_for_device(musb->controller,
+                       request->request.dma,
+                       request->request.length,
+                       request->tx
+                               ? DMA_TO_DEVICE
+                               : DMA_FROM_DEVICE);
+               request->mapped = 0;
+       }
+}
+
+/* Unmap the buffer from dma and maps it back to cpu */
+static inline void unmap_dma_buffer(struct musb_request *request,
+                               struct musb *musb)
+{
+       if (request->request.dma == DMA_ADDR_INVALID) {
+               DBG(20, "not unmapping a never mapped buffer\n");
+               return;
+       }
+       if (request->mapped) {
+               dma_unmap_single(musb->controller,
+                       request->request.dma,
+                       request->request.length,
+                       request->tx
+                               ? DMA_TO_DEVICE
+                               : DMA_FROM_DEVICE);
+               request->request.dma = DMA_ADDR_INVALID;
+               request->mapped = 0;
+       } else {
+               dma_sync_single_for_cpu(musb->controller,
+                       request->request.dma,
+                       request->request.length,
+                       request->tx
+                               ? DMA_TO_DEVICE
+                               : DMA_FROM_DEVICE);
+
+       }
+}
+
 /*
  * Immediately complete a request.
  *
@@ -119,24 +172,8 @@ __acquires(ep->musb->lock)
 
        ep->busy = 1;
        spin_unlock(&musb->lock);
-       if (is_dma_capable()) {
-               if (req->mapped) {
-                       dma_unmap_single(musb->controller,
-                                       req->request.dma,
-                                       req->request.length,
-                                       req->tx
-                                               ? DMA_TO_DEVICE
-                                               : DMA_FROM_DEVICE);
-                       req->request.dma = DMA_ADDR_INVALID;
-                       req->mapped = 0;
-               } else if (req->request.dma != DMA_ADDR_INVALID)
-                       dma_sync_single_for_cpu(musb->controller,
-                                       req->request.dma,
-                                       req->request.length,
-                                       req->tx
-                                               ? DMA_TO_DEVICE
-                                               : DMA_FROM_DEVICE);
-       }
+       if (is_dma_capable() && ep->dma)
+               unmap_dma_buffer(req, musb);
        if (request->status == 0)
                DBG(5, "%s done request %p,  %d/%d\n",
                                ep->end_point.name, request,
@@ -395,6 +432,13 @@ static void txstate(struct musb *musb, struct musb_request *req)
 #endif
 
        if (!use_dma) {
+               /*
+                * Unmap the dma buffer back to cpu if dma channel
+                * programming fails
+                */
+               if (is_dma_capable() && musb_ep->dma)
+                       unmap_dma_buffer(req, musb);
+
                musb_write_fifo(musb_ep->hw_ep, fifo_count,
                                (u8 *) (request->buf + request->actual));
                request->actual += fifo_count;
@@ -644,10 +688,8 @@ static void rxstate(struct musb *musb, struct musb_request *req)
         */
 
                                csr |= MUSB_RXCSR_DMAENAB;
-                               if (!musb_ep->hb_mult &&
-                                       musb_ep->hw_ep->rx_double_buffered)
-                                       csr |= MUSB_RXCSR_AUTOCLEAR;
 #ifdef USE_MODE1
+                               csr |= MUSB_RXCSR_AUTOCLEAR;
                                /* csr |= MUSB_RXCSR_DMAMODE; */
 
                                /* this special sequence (enabling and then
@@ -656,6 +698,10 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                                 */
                                musb_writew(epio, MUSB_RXCSR,
                                        csr | MUSB_RXCSR_DMAMODE);
+#else
+                               if (!musb_ep->hb_mult &&
+                                       musb_ep->hw_ep->rx_double_buffered)
+                                       csr |= MUSB_RXCSR_AUTOCLEAR;
 #endif
                                musb_writew(epio, MUSB_RXCSR, csr);
 
@@ -711,6 +757,21 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                                        return;
                        }
 #endif
+                       /*
+                        * Unmap the dma buffer back to cpu if dma channel
+                        * programming fails. This buffer is mapped if the
+                        * channel allocation is successful
+                        */
+                        if (is_dma_capable() && musb_ep->dma) {
+                               unmap_dma_buffer(req, musb);
+
+                               /*
+                                * Clear DMAENAB and AUTOCLEAR for the
+                                * PIO mode transfer
+                                */
+                               csr &= ~(MUSB_RXCSR_DMAENAB | MUSB_RXCSR_AUTOCLEAR);
+                               musb_writew(epio, MUSB_RXCSR, csr);
+                       }
 
                        musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *)
                                        (request->buf + request->actual));
@@ -807,7 +868,7 @@ void musb_g_rx(struct musb *musb, u8 epnum)
 
 #if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA)
                /* Autoclear doesn't clear RxPktRdy for short packets */
-               if ((dma->desired_mode == 0)
+               if ((dma->desired_mode == 0 && !hw_ep->rx_double_buffered)
                                || (dma->actual_len
                                        & (musb_ep->packet_sz - 1))) {
                        /* ack the read! */
@@ -818,8 +879,16 @@ void musb_g_rx(struct musb *musb, u8 epnum)
                /* incomplete, and not short? wait for next IN packet */
                if ((request->actual < request->length)
                                && (musb_ep->dma->actual_len
-                                       == musb_ep->packet_sz))
+                                       == 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;
+               }
 #endif
                musb_g_giveback(musb_ep, request, 0);
 
@@ -827,7 +896,9 @@ void musb_g_rx(struct musb *musb, u8 epnum)
                if (!request)
                        return;
        }
-
+#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA)
+exit:
+#endif
        /* Analyze request */
        rxstate(musb, to_musb_request(request));
 }
@@ -916,13 +987,9 @@ static int musb_gadget_enable(struct usb_ep *ep,
                 * likewise high bandwidth periodic tx
                 */
                /* Set TXMAXP with the FIFO size of the endpoint
-                * to disable double buffering mode. Currently, It seems that double
-                * buffering has problem if musb RTL revision number < 2.0.
+                * to disable double buffering mode.
                 */
-               if (musb->hwvers < MUSB_HWVERS_2000)
-                       musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx);
-               else
-                       musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
+               musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
 
                csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG;
                if (musb_readw(regs, MUSB_TXCSR)
@@ -958,10 +1025,7 @@ static int musb_gadget_enable(struct usb_ep *ep,
                /* Set RXMAXP with the FIFO size of the endpoint
                 * to disable double buffering mode.
                 */
-               if (musb->hwvers < MUSB_HWVERS_2000)
-                       musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_rx);
-               else
-                       musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
+               musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
 
                /* force shared fifo to OUT-only mode */
                if (hw_ep->is_shared_fifo) {
@@ -1150,28 +1214,9 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
        request->epnum = musb_ep->current_epnum;
        request->tx = musb_ep->is_in;
 
-       if (is_dma_capable() && musb_ep->dma) {
-               if (request->request.dma == DMA_ADDR_INVALID) {
-                       request->request.dma = dma_map_single(
-                                       musb->controller,
-                                       request->request.buf,
-                                       request->request.length,
-                                       request->tx
-                                               ? DMA_TO_DEVICE
-                                               : DMA_FROM_DEVICE);
-                       request->mapped = 1;
-               } else {
-                       dma_sync_single_for_device(musb->controller,
-                                       request->request.dma,
-                                       request->request.length,
-                                       request->tx
-                                               ? DMA_TO_DEVICE
-                                               : DMA_FROM_DEVICE);
-                       request->mapped = 0;
-               }
-       } else if (!req->buf) {
-               return -ENODATA;
-       } else
+       if (is_dma_capable() && musb_ep->dma)
+               map_dma_buffer(request, musb);
+       else
                request->mapped = 0;
 
        spin_lock_irqsave(&musb->lock, lockflags);
@@ -1698,8 +1743,10 @@ int __init musb_gadget_setup(struct musb *musb)
        musb_platform_try_idle(musb, 0);
 
        status = device_register(&musb->g.dev);
-       if (status != 0)
+       if (status != 0) {
+               put_device(&musb->g.dev);
                the_gadget = NULL;
+       }
        return status;
 }
 
@@ -1789,6 +1836,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
                spin_unlock_irqrestore(&musb->lock, flags);
 
                if (is_otg_enabled(musb)) {
+                       struct usb_hcd  *hcd = musb_to_hcd(musb);
+
                        DBG(3, "OTG startup...\n");
 
                        /* REVISIT:  funcall to other code, which also
@@ -1803,6 +1852,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
                                musb->gadget_driver = NULL;
                                musb->g.dev.driver = NULL;
                                spin_unlock_irqrestore(&musb->lock, flags);
+                       } else {
+                               hcd->self.uses_pio_for_control = 1;
                        }
                }
        }