diff options
Diffstat (limited to 'drivers/spi/spi-mpc512x-psc.c')
-rw-r--r-- | drivers/spi/spi-mpc512x-psc.c | 141 |
1 files changed, 107 insertions, 34 deletions
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 759a937d5fa7..53c7899a8aba 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c | |||
@@ -137,6 +137,7 @@ static int mpc512x_psc_spi_transfer_rxtx(struct spi_device *spi, | |||
137 | struct mpc52xx_psc __iomem *psc = mps->psc; | 137 | struct mpc52xx_psc __iomem *psc = mps->psc; |
138 | struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; | 138 | struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; |
139 | size_t tx_len = t->len; | 139 | size_t tx_len = t->len; |
140 | size_t rx_len = t->len; | ||
140 | u8 *tx_buf = (u8 *)t->tx_buf; | 141 | u8 *tx_buf = (u8 *)t->tx_buf; |
141 | u8 *rx_buf = (u8 *)t->rx_buf; | 142 | u8 *rx_buf = (u8 *)t->rx_buf; |
142 | 143 | ||
@@ -150,57 +151,129 @@ static int mpc512x_psc_spi_transfer_rxtx(struct spi_device *spi, | |||
150 | /* enable transmiter/receiver */ | 151 | /* enable transmiter/receiver */ |
151 | out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); | 152 | out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); |
152 | 153 | ||
153 | while (tx_len) { | 154 | while (rx_len || tx_len) { |
154 | size_t txcount; | 155 | size_t txcount; |
155 | int i; | ||
156 | u8 data; | 156 | u8 data; |
157 | size_t fifosz; | 157 | size_t fifosz; |
158 | size_t rxcount; | 158 | size_t rxcount; |
159 | int rxtries; | ||
159 | 160 | ||
160 | /* | 161 | /* |
161 | * The number of bytes that can be sent at a time | 162 | * send the TX bytes in as large a chunk as possible |
162 | * depends on the fifo size. | 163 | * but neither exceed the TX nor the RX FIFOs |
163 | */ | 164 | */ |
164 | fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->txsz)); | 165 | fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->txsz)); |
165 | txcount = min(fifosz, tx_len); | 166 | txcount = min(fifosz, tx_len); |
167 | fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->rxsz)); | ||
168 | fifosz -= in_be32(&fifo->rxcnt) + 1; | ||
169 | txcount = min(fifosz, txcount); | ||
170 | if (txcount) { | ||
171 | |||
172 | /* fill the TX FIFO */ | ||
173 | while (txcount-- > 0) { | ||
174 | data = tx_buf ? *tx_buf++ : 0; | ||
175 | if (tx_len == EOFBYTE && t->cs_change) | ||
176 | setbits32(&fifo->txcmd, | ||
177 | MPC512x_PSC_FIFO_EOF); | ||
178 | out_8(&fifo->txdata_8, data); | ||
179 | tx_len--; | ||
180 | } | ||
166 | 181 | ||
167 | for (i = txcount; i > 0; i--) { | 182 | /* have the ISR trigger when the TX FIFO is empty */ |
168 | data = tx_buf ? *tx_buf++ : 0; | 183 | INIT_COMPLETION(mps->txisrdone); |
169 | if (tx_len == EOFBYTE && t->cs_change) | 184 | out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY); |
170 | setbits32(&fifo->txcmd, MPC512x_PSC_FIFO_EOF); | 185 | out_be32(&fifo->tximr, MPC512x_PSC_FIFO_EMPTY); |
171 | out_8(&fifo->txdata_8, data); | 186 | wait_for_completion(&mps->txisrdone); |
172 | tx_len--; | ||
173 | } | 187 | } |
174 | 188 | ||
175 | INIT_COMPLETION(mps->txisrdone); | 189 | /* |
176 | 190 | * consume as much RX data as the FIFO holds, while we | |
177 | /* interrupt on tx fifo empty */ | 191 | * iterate over the transfer's TX data length |
178 | out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY); | 192 | * |
179 | out_be32(&fifo->tximr, MPC512x_PSC_FIFO_EMPTY); | 193 | * only insist in draining all the remaining RX bytes |
180 | 194 | * when the TX bytes were exhausted (that's at the very | |
181 | wait_for_completion(&mps->txisrdone); | 195 | * end of this transfer, not when still iterating over |
182 | 196 | * the transfer's chunks) | |
183 | mdelay(1); | 197 | */ |
198 | rxtries = 50; | ||
199 | do { | ||
200 | |||
201 | /* | ||
202 | * grab whatever was in the FIFO when we started | ||
203 | * looking, don't bother fetching what was added to | ||
204 | * the FIFO while we read from it -- we'll return | ||
205 | * here eventually and prefer sending out remaining | ||
206 | * TX data | ||
207 | */ | ||
208 | fifosz = in_be32(&fifo->rxcnt); | ||
209 | rxcount = min(fifosz, rx_len); | ||
210 | while (rxcount-- > 0) { | ||
211 | data = in_8(&fifo->rxdata_8); | ||
212 | if (rx_buf) | ||
213 | *rx_buf++ = data; | ||
214 | rx_len--; | ||
215 | } | ||
184 | 216 | ||
185 | /* rx fifo should have txcount bytes in it */ | 217 | /* |
186 | rxcount = in_be32(&fifo->rxcnt); | 218 | * come back later if there still is TX data to send, |
187 | if (rxcount != txcount) | 219 | * bail out of the RX drain loop if all of the TX data |
188 | mdelay(1); | 220 | * was sent and all of the RX data was received (i.e. |
221 | * when the transmission has completed) | ||
222 | */ | ||
223 | if (tx_len) | ||
224 | break; | ||
225 | if (!rx_len) | ||
226 | break; | ||
189 | 227 | ||
190 | rxcount = in_be32(&fifo->rxcnt); | 228 | /* |
191 | if (rxcount != txcount) { | 229 | * TX data transmission has completed while RX data |
192 | dev_warn(&spi->dev, "expected %d bytes in rx fifo " | 230 | * is still pending -- that's a transient situation |
193 | "but got %d\n", txcount, rxcount); | 231 | * which depends on wire speed and specific |
232 | * hardware implementation details (buffering) yet | ||
233 | * should resolve very quickly | ||
234 | * | ||
235 | * just yield for a moment to not hog the CPU for | ||
236 | * too long when running SPI at low speed | ||
237 | * | ||
238 | * the timeout range is rather arbitrary and tries | ||
239 | * to balance throughput against system load; the | ||
240 | * chosen values result in a minimal timeout of 50 | ||
241 | * times 10us and thus work at speeds as low as | ||
242 | * some 20kbps, while the maximum timeout at the | ||
243 | * transfer's end could be 5ms _if_ nothing else | ||
244 | * ticks in the system _and_ RX data still wasn't | ||
245 | * received, which only occurs in situations that | ||
246 | * are exceptional; removing the unpredictability | ||
247 | * of the timeout either decreases throughput | ||
248 | * (longer timeouts), or puts more load on the | ||
249 | * system (fixed short timeouts) or requires the | ||
250 | * use of a timeout API instead of a counter and an | ||
251 | * unknown inner delay | ||
252 | */ | ||
253 | usleep_range(10, 100); | ||
254 | |||
255 | } while (--rxtries > 0); | ||
256 | if (!tx_len && rx_len && !rxtries) { | ||
257 | /* | ||
258 | * not enough RX bytes even after several retries | ||
259 | * and the resulting rather long timeout? | ||
260 | */ | ||
261 | rxcount = in_be32(&fifo->rxcnt); | ||
262 | dev_warn(&spi->dev, | ||
263 | "short xfer, missing %zd RX bytes, FIFO level %zd\n", | ||
264 | rx_len, rxcount); | ||
194 | } | 265 | } |
195 | 266 | ||
196 | rxcount = min(rxcount, txcount); | 267 | /* |
197 | for (i = rxcount; i > 0; i--) { | 268 | * drain and drop RX data which "should not be there" in |
198 | data = in_8(&fifo->rxdata_8); | 269 | * the first place, for undisturbed transmission this turns |
199 | if (rx_buf) | 270 | * into a NOP (except for the FIFO level fetch) |
200 | *rx_buf++ = data; | 271 | */ |
272 | if (!tx_len && !rx_len) { | ||
273 | while (in_be32(&fifo->rxcnt)) | ||
274 | in_8(&fifo->rxdata_8); | ||
201 | } | 275 | } |
202 | while (in_be32(&fifo->rxcnt)) | 276 | |
203 | in_8(&fifo->rxdata_8); | ||
204 | } | 277 | } |
205 | /* disable transmiter/receiver and fifo interrupt */ | 278 | /* disable transmiter/receiver and fifo interrupt */ |
206 | out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); | 279 | out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); |