aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/musb/musb_host.c43
1 files changed, 29 insertions, 14 deletions
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index ff095956ca96..521fd83f5b9d 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -125,6 +125,29 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)
125 } 125 }
126} 126}
127 127
128static void musb_h_ep0_flush_fifo(struct musb_hw_ep *ep)
129{
130 void __iomem *epio = ep->regs;
131 u16 csr;
132 int retries = 5;
133
134 /* scrub any data left in the fifo */
135 do {
136 csr = musb_readw(epio, MUSB_TXCSR);
137 if (!(csr & (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_RXPKTRDY)))
138 break;
139 musb_writew(epio, MUSB_TXCSR, MUSB_CSR0_FLUSHFIFO);
140 csr = musb_readw(epio, MUSB_TXCSR);
141 udelay(10);
142 } while (--retries);
143
144 WARN(!retries, "Could not flush host TX%d fifo: csr: %04x\n",
145 ep->epnum, csr);
146
147 /* and reset for the next transfer */
148 musb_writew(epio, MUSB_TXCSR, 0);
149}
150
128/* 151/*
129 * Start transmit. Caller is responsible for locking shared resources. 152 * Start transmit. Caller is responsible for locking shared resources.
130 * musb must be locked. 153 * musb must be locked.
@@ -694,10 +717,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
694 csr = musb_readw(epio, MUSB_TXCSR); 717 csr = musb_readw(epio, MUSB_TXCSR);
695 } else { 718 } else {
696 /* endpoint 0: just flush */ 719 /* endpoint 0: just flush */
697 musb_writew(epio, MUSB_CSR0, 720 musb_h_ep0_flush_fifo(hw_ep);
698 csr | MUSB_CSR0_FLUSHFIFO);
699 musb_writew(epio, MUSB_CSR0,
700 csr | MUSB_CSR0_FLUSHFIFO);
701 } 721 }
702 722
703 /* target addr and (for multipoint) hub addr/port */ 723 /* target addr and (for multipoint) hub addr/port */
@@ -1063,11 +1083,7 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)
1063 csr &= ~MUSB_CSR0_H_NAKTIMEOUT; 1083 csr &= ~MUSB_CSR0_H_NAKTIMEOUT;
1064 musb_writew(epio, MUSB_CSR0, csr); 1084 musb_writew(epio, MUSB_CSR0, csr);
1065 } else { 1085 } else {
1066 csr |= MUSB_CSR0_FLUSHFIFO; 1086 musb_h_ep0_flush_fifo(hw_ep);
1067 musb_writew(epio, MUSB_CSR0, csr);
1068 musb_writew(epio, MUSB_CSR0, csr);
1069 csr &= ~MUSB_CSR0_H_NAKTIMEOUT;
1070 musb_writew(epio, MUSB_CSR0, csr);
1071 } 1087 }
1072 1088
1073 musb_writeb(epio, MUSB_NAKLIMIT0, 0); 1089 musb_writeb(epio, MUSB_NAKLIMIT0, 0);
@@ -1081,10 +1097,7 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)
1081 * SHOULD NEVER HAPPEN! */ 1097 * SHOULD NEVER HAPPEN! */
1082 ERR("no URB for end 0\n"); 1098 ERR("no URB for end 0\n");
1083 1099
1084 musb_writew(epio, MUSB_CSR0, MUSB_CSR0_FLUSHFIFO); 1100 musb_h_ep0_flush_fifo(hw_ep);
1085 musb_writew(epio, MUSB_CSR0, MUSB_CSR0_FLUSHFIFO);
1086 musb_writew(epio, MUSB_CSR0, 0);
1087
1088 goto done; 1101 goto done;
1089 } 1102 }
1090 1103
@@ -2043,7 +2056,7 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in)
2043 * endpoint's irq status here to avoid bogus irqs. 2056 * endpoint's irq status here to avoid bogus irqs.
2044 * clearing that status is platform-specific... 2057 * clearing that status is platform-specific...
2045 */ 2058 */
2046 } else { 2059 } else if (ep->epnum) {
2047 musb_h_tx_flush_fifo(ep); 2060 musb_h_tx_flush_fifo(ep);
2048 csr = musb_readw(epio, MUSB_TXCSR); 2061 csr = musb_readw(epio, MUSB_TXCSR);
2049 csr &= ~(MUSB_TXCSR_AUTOSET 2062 csr &= ~(MUSB_TXCSR_AUTOSET
@@ -2057,6 +2070,8 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in)
2057 musb_writew(epio, MUSB_TXCSR, csr); 2070 musb_writew(epio, MUSB_TXCSR, csr);
2058 /* flush cpu writebuffer */ 2071 /* flush cpu writebuffer */
2059 csr = musb_readw(epio, MUSB_TXCSR); 2072 csr = musb_readw(epio, MUSB_TXCSR);
2073 } else {
2074 musb_h_ep0_flush_fifo(ep);
2060 } 2075 }
2061 if (status == 0) 2076 if (status == 0)
2062 musb_advance_schedule(ep->musb, urb, ep, is_in); 2077 musb_advance_schedule(ep->musb, urb, ep, is_in);