index 922148ff8d2969de64a808046f7ce06c6115ace1..bd44703b3819ca02df3abaad7a40140bf4d62ded 100644 (file)
#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>
}
-#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,
* 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
/* 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
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
*/
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;
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;
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
/* ------------------------------------------------------------ */
-#ifdef CONFIG_USB_INVENTRA_DMA
-
/* Peripheral rx (OUT) using Mentor DMA works as follows:
- Only mode 0 is used.
* Non-Mentor DMA engines can of course work differently.
*/
-#endif
-
/*
* Context: controller locked, IRQs blocked, endpoint selected
*/
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;
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;
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;
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",
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;
if (ret)
return;
}
-#endif
+
/*
* Unmap the dma buffer back to cpu if dma channel
* programming fails. This buffer is mapped if the
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;
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)
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);
}
/* 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);
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) {
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
goto done;
}
- musb_ep_select(mbase, epnum);
+ musb_ep_select(musb, mbase, epnum);
request = next_request(musb_ep);
if (value) {
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);
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);
}
-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;
/* 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;
*/
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 */
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 {
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);
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;