diff options
Diffstat (limited to 'kernel/drivers/usb/musb')
-rw-r--r-- | kernel/drivers/usb/musb/blackfin.c | 1 | ||||
-rw-r--r-- | kernel/drivers/usb/musb/musb_core.c | 3 | ||||
-rw-r--r-- | kernel/drivers/usb/musb/musb_core.h | 7 | ||||
-rw-r--r-- | kernel/drivers/usb/musb/musb_dsps.c | 12 | ||||
-rw-r--r-- | kernel/drivers/usb/musb/musb_host.c | 41 | ||||
-rw-r--r-- | kernel/drivers/usb/musb/musbhsdma.h | 2 |
6 files changed, 44 insertions, 22 deletions
diff --git a/kernel/drivers/usb/musb/blackfin.c b/kernel/drivers/usb/musb/blackfin.c index 310238c6b..896798071 100644 --- a/kernel/drivers/usb/musb/blackfin.c +++ b/kernel/drivers/usb/musb/blackfin.c @@ -469,6 +469,7 @@ static const struct musb_platform_ops bfin_ops = { .init = bfin_musb_init, .exit = bfin_musb_exit, + .fifo_offset = bfin_fifo_offset, .readb = bfin_readb, .writeb = bfin_writeb, .readw = bfin_readw, diff --git a/kernel/drivers/usb/musb/musb_core.c b/kernel/drivers/usb/musb/musb_core.c index ee9ff7028..00eed5d66 100644 --- a/kernel/drivers/usb/musb/musb_core.c +++ b/kernel/drivers/usb/musb/musb_core.c @@ -2401,7 +2401,8 @@ static void musb_restore_context(struct musb *musb) musb_writew(musb_base, MUSB_INTRTXE, musb->intrtxe); musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe); musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe); - musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl); + if (musb->context.devctl & MUSB_DEVCTL_SESSION) + musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl); for (i = 0; i < musb->config->num_eps; ++i) { struct musb_hw_ep *hw_ep; diff --git a/kernel/drivers/usb/musb/musb_core.h b/kernel/drivers/usb/musb/musb_core.h index 2337d7a7d..90de7900e 100644 --- a/kernel/drivers/usb/musb/musb_core.h +++ b/kernel/drivers/usb/musb/musb_core.h @@ -214,6 +214,7 @@ struct musb_platform_ops { dma_addr_t *dma_addr, u32 *len); void (*pre_root_reset_end)(struct musb *musb); void (*post_root_reset_end)(struct musb *musb); + void (*clear_ep_rxintr)(struct musb *musb, int epnum); }; /* @@ -612,4 +613,10 @@ static inline void musb_platform_post_root_reset_end(struct musb *musb) musb->ops->post_root_reset_end(musb); } +static inline void musb_platform_clear_ep_rxintr(struct musb *musb, int epnum) +{ + if (musb->ops->clear_ep_rxintr) + musb->ops->clear_ep_rxintr(musb, epnum); +} + #endif /* __MUSB_CORE_H__ */ diff --git a/kernel/drivers/usb/musb/musb_dsps.c b/kernel/drivers/usb/musb/musb_dsps.c index eeb7d9ecf..5a021b26d 100644 --- a/kernel/drivers/usb/musb/musb_dsps.c +++ b/kernel/drivers/usb/musb/musb_dsps.c @@ -301,6 +301,17 @@ static void otg_timer(unsigned long _musb) spin_unlock_irqrestore(&musb->lock, flags); } +void dsps_musb_clear_ep_rxintr(struct musb *musb, int epnum) +{ + u32 epintr; + struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); + const struct dsps_musb_wrapper *wrp = glue->wrp; + + /* musb->lock might already been held */ + epintr = (1 << epnum) << wrp->rxep_shift; + musb_writel(musb->ctrl_base, wrp->epintr_status, epintr); +} + static irqreturn_t dsps_interrupt(int irq, void *hci) { struct musb *musb = hci; @@ -647,6 +658,7 @@ static struct musb_platform_ops dsps_ops = { .try_idle = dsps_musb_try_idle, .set_mode = dsps_musb_set_mode, .recover = dsps_musb_recover, + .clear_ep_rxintr = dsps_musb_clear_ep_rxintr, }; static u64 musb_dmamask = DMA_BIT_MASK(32); diff --git a/kernel/drivers/usb/musb/musb_host.c b/kernel/drivers/usb/musb/musb_host.c index 795a45b1b..13d5614f3 100644 --- a/kernel/drivers/usb/musb/musb_host.c +++ b/kernel/drivers/usb/musb/musb_host.c @@ -594,14 +594,13 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, u8 epnum) musb_writew(ep->regs, MUSB_TXCSR, 0); /* scrub all previous state, clearing toggle */ - } else { - csr = musb_readw(ep->regs, MUSB_RXCSR); - if (csr & MUSB_RXCSR_RXPKTRDY) - WARNING("rx%d, packet/%d ready?\n", ep->epnum, - musb_readw(ep->regs, MUSB_RXCOUNT)); - - musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG); } + csr = musb_readw(ep->regs, MUSB_RXCSR); + if (csr & MUSB_RXCSR_RXPKTRDY) + WARNING("rx%d, packet/%d ready?\n", ep->epnum, + musb_readw(ep->regs, MUSB_RXCOUNT)); + + musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG); /* target addr and (for multipoint) hub addr/port */ if (musb->is_multipoint) { @@ -662,7 +661,7 @@ static int musb_tx_dma_set_mode_mentor(struct dma_controller *dma, csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE); csr |= MUSB_TXCSR_DMAENAB; /* against programmer's guide */ } - channel->desired_mode = mode; + channel->desired_mode = *mode; musb_writew(epio, MUSB_TXCSR, csr); return 0; @@ -995,9 +994,15 @@ static void musb_bulk_nak_timeout(struct musb *musb, struct musb_hw_ep *ep, if (is_in) { dma = is_dma_capable() ? ep->rx_channel : NULL; - /* clear nak timeout bit */ + /* + * Need to stop the transaction by clearing REQPKT first + * then the NAK Timeout bit ref MUSBMHDRC USB 2.0 HIGH-SPEED + * DUAL-ROLE CONTROLLER Programmer's Guide, section 9.2.2 + */ rx_csr = musb_readw(epio, MUSB_RXCSR); rx_csr |= MUSB_RXCSR_H_WZC_BITS; + rx_csr &= ~MUSB_RXCSR_H_REQPKT; + musb_writew(epio, MUSB_RXCSR, rx_csr); rx_csr &= ~MUSB_RXCSR_DATAERROR; musb_writew(epio, MUSB_RXCSR, rx_csr); @@ -1551,7 +1556,7 @@ static int musb_rx_dma_iso_cppi41(struct dma_controller *dma, struct urb *urb, size_t len) { - struct dma_channel *channel = hw_ep->tx_channel; + struct dma_channel *channel = hw_ep->rx_channel; void __iomem *epio = hw_ep->regs; dma_addr_t *buf; u32 length, res; @@ -2003,10 +2008,8 @@ void musb_host_rx(struct musb *musb, u8 epnum) qh->offset, urb->transfer_buffer_length); - done = musb_rx_dma_in_inventra_cppi41(c, hw_ep, qh, - urb, xfer_len, - iso_err); - if (done) + if (musb_rx_dma_in_inventra_cppi41(c, hw_ep, qh, urb, + xfer_len, iso_err)) goto finish; else dev_err(musb->controller, "error: rx_dma failed\n"); @@ -2387,12 +2390,11 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh) int is_in = usb_pipein(urb->pipe); int status = 0; u16 csr; + struct dma_channel *dma = NULL; musb_ep_select(regs, hw_end); if (is_dma_capable()) { - struct dma_channel *dma; - dma = is_in ? ep->rx_channel : ep->tx_channel; if (dma) { status = ep->musb->dma_controller->channel_abort(dma); @@ -2409,10 +2411,9 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh) /* giveback saves bulk toggle */ csr = musb_h_flush_rxfifo(ep, 0); - /* REVISIT we still get an irq; should likely clear the - * endpoint's irq status here to avoid bogus irqs. - * clearing that status is platform-specific... - */ + /* clear the endpoint's irq status here to avoid bogus irqs */ + if (is_dma_capable() && dma) + musb_platform_clear_ep_rxintr(musb, ep->epnum); } else if (ep->epnum) { musb_h_tx_flush_fifo(ep); csr = musb_readw(epio, MUSB_TXCSR); diff --git a/kernel/drivers/usb/musb/musbhsdma.h b/kernel/drivers/usb/musb/musbhsdma.h index f7b13fd25..a3dcbd55e 100644 --- a/kernel/drivers/usb/musb/musbhsdma.h +++ b/kernel/drivers/usb/musb/musbhsdma.h @@ -157,5 +157,5 @@ struct musb_dma_controller { void __iomem *base; u8 channel_count; u8 used_channels; - u8 irq; + int irq; }; |