aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi-bcm63xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/spi-bcm63xx.c')
-rw-r--r--drivers/spi/spi-bcm63xx.c179
1 files changed, 125 insertions, 54 deletions
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index f44ab5508535..9578af782a77 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -37,6 +37,8 @@
37 37
38#define PFX KBUILD_MODNAME 38#define PFX KBUILD_MODNAME
39 39
40#define BCM63XX_SPI_MAX_PREPEND 15
41
40struct bcm63xx_spi { 42struct bcm63xx_spi {
41 struct completion done; 43 struct completion done;
42 44
@@ -49,16 +51,10 @@ struct bcm63xx_spi {
49 unsigned int msg_type_shift; 51 unsigned int msg_type_shift;
50 unsigned int msg_ctl_width; 52 unsigned int msg_ctl_width;
51 53
52 /* Data buffers */
53 const unsigned char *tx_ptr;
54 unsigned char *rx_ptr;
55
56 /* data iomem */ 54 /* data iomem */
57 u8 __iomem *tx_io; 55 u8 __iomem *tx_io;
58 const u8 __iomem *rx_io; 56 const u8 __iomem *rx_io;
59 57
60 int remaining_bytes;
61
62 struct clk *clk; 58 struct clk *clk;
63 struct platform_device *pdev; 59 struct platform_device *pdev;
64}; 60};
@@ -175,24 +171,17 @@ static int bcm63xx_spi_setup(struct spi_device *spi)
175 return 0; 171 return 0;
176} 172}
177 173
178/* Fill the TX FIFO with as many bytes as possible */ 174static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
179static void bcm63xx_spi_fill_tx_fifo(struct bcm63xx_spi *bs) 175 unsigned int num_transfers)
180{
181 u8 size;
182
183 /* Fill the Tx FIFO with as many bytes as possible */
184 size = bs->remaining_bytes < bs->fifo_size ? bs->remaining_bytes :
185 bs->fifo_size;
186 memcpy_toio(bs->tx_io, bs->tx_ptr, size);
187 bs->remaining_bytes -= size;
188}
189
190static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi,
191 struct spi_transfer *t)
192{ 176{
193 struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master); 177 struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
194 u16 msg_ctl; 178 u16 msg_ctl;
195 u16 cmd; 179 u16 cmd;
180 u8 rx_tail;
181 unsigned int i, timeout = 0, prepend_len = 0, len = 0;
182 struct spi_transfer *t = first;
183 bool do_rx = false;
184 bool do_tx = false;
196 185
197 /* Disable the CMD_DONE interrupt */ 186 /* Disable the CMD_DONE interrupt */
198 bcm_spi_writeb(bs, 0, SPI_INT_MASK); 187 bcm_spi_writeb(bs, 0, SPI_INT_MASK);
@@ -200,25 +189,45 @@ static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi,
200 dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n", 189 dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
201 t->tx_buf, t->rx_buf, t->len); 190 t->tx_buf, t->rx_buf, t->len);
202 191
203 /* Transmitter is inhibited */ 192 if (num_transfers > 1 && t->tx_buf && t->len <= BCM63XX_SPI_MAX_PREPEND)
204 bs->tx_ptr = t->tx_buf; 193 prepend_len = t->len;
205 bs->rx_ptr = t->rx_buf;
206 194
207 if (t->tx_buf) { 195 /* prepare the buffer */
208 bs->remaining_bytes = t->len; 196 for (i = 0; i < num_transfers; i++) {
209 bcm63xx_spi_fill_tx_fifo(bs); 197 if (t->tx_buf) {
198 do_tx = true;
199 memcpy_toio(bs->tx_io + len, t->tx_buf, t->len);
200
201 /* don't prepend more than one tx */
202 if (t != first)
203 prepend_len = 0;
204 }
205
206 if (t->rx_buf) {
207 do_rx = true;
208 /* prepend is half-duplex write only */
209 if (t == first)
210 prepend_len = 0;
211 }
212
213 len += t->len;
214
215 t = list_entry(t->transfer_list.next, struct spi_transfer,
216 transfer_list);
210 } 217 }
211 218
219 len -= prepend_len;
220
212 init_completion(&bs->done); 221 init_completion(&bs->done);
213 222
214 /* Fill in the Message control register */ 223 /* Fill in the Message control register */
215 msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT); 224 msg_ctl = (len << SPI_BYTE_CNT_SHIFT);
216 225
217 if (t->rx_buf && t->tx_buf) 226 if (do_rx && do_tx && prepend_len == 0)
218 msg_ctl |= (SPI_FD_RW << bs->msg_type_shift); 227 msg_ctl |= (SPI_FD_RW << bs->msg_type_shift);
219 else if (t->rx_buf) 228 else if (do_rx)
220 msg_ctl |= (SPI_HD_R << bs->msg_type_shift); 229 msg_ctl |= (SPI_HD_R << bs->msg_type_shift);
221 else if (t->tx_buf) 230 else if (do_tx)
222 msg_ctl |= (SPI_HD_W << bs->msg_type_shift); 231 msg_ctl |= (SPI_HD_W << bs->msg_type_shift);
223 232
224 switch (bs->msg_ctl_width) { 233 switch (bs->msg_ctl_width) {
@@ -232,14 +241,41 @@ static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi,
232 241
233 /* Issue the transfer */ 242 /* Issue the transfer */
234 cmd = SPI_CMD_START_IMMEDIATE; 243 cmd = SPI_CMD_START_IMMEDIATE;
235 cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT); 244 cmd |= (prepend_len << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
236 cmd |= (spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT); 245 cmd |= (spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT);
237 bcm_spi_writew(bs, cmd, SPI_CMD); 246 bcm_spi_writew(bs, cmd, SPI_CMD);
238 247
239 /* Enable the CMD_DONE interrupt */ 248 /* Enable the CMD_DONE interrupt */
240 bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK); 249 bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
241 250
242 return t->len - bs->remaining_bytes; 251 timeout = wait_for_completion_timeout(&bs->done, HZ);
252 if (!timeout)
253 return -ETIMEDOUT;
254
255 /* read out all data */
256 rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
257
258 if (do_rx && rx_tail != len)
259 return -EIO;
260
261 if (!rx_tail)
262 return 0;
263
264 len = 0;
265 t = first;
266 /* Read out all the data */
267 for (i = 0; i < num_transfers; i++) {
268 if (t->rx_buf)
269 memcpy_fromio(t->rx_buf, bs->rx_io + len, t->len);
270
271 if (t != first || prepend_len == 0)
272 len += t->len;
273
274 t = list_entry(t->transfer_list.next, struct spi_transfer,
275 transfer_list);
276 }
277
278 return 0;
243} 279}
244 280
245static int bcm63xx_spi_prepare_transfer(struct spi_master *master) 281static int bcm63xx_spi_prepare_transfer(struct spi_master *master)
@@ -264,41 +300,76 @@ static int bcm63xx_spi_transfer_one(struct spi_master *master,
264 struct spi_message *m) 300 struct spi_message *m)
265{ 301{
266 struct bcm63xx_spi *bs = spi_master_get_devdata(master); 302 struct bcm63xx_spi *bs = spi_master_get_devdata(master);
267 struct spi_transfer *t; 303 struct spi_transfer *t, *first = NULL;
268 struct spi_device *spi = m->spi; 304 struct spi_device *spi = m->spi;
269 int status = 0; 305 int status = 0;
270 unsigned int timeout = 0; 306 unsigned int n_transfers = 0, total_len = 0;
271 307 bool can_use_prepend = false;
308
309 /*
310 * This SPI controller does not support keeping CS active after a
311 * transfer.
312 * Work around this by merging as many transfers we can into one big
313 * full-duplex transfers.
314 */
272 list_for_each_entry(t, &m->transfers, transfer_list) { 315 list_for_each_entry(t, &m->transfers, transfer_list) {
273 unsigned int len = t->len;
274 u8 rx_tail;
275
276 status = bcm63xx_spi_check_transfer(spi, t); 316 status = bcm63xx_spi_check_transfer(spi, t);
277 if (status < 0) 317 if (status < 0)
278 goto exit; 318 goto exit;
279 319
280 /* configure adapter for a new transfer */ 320 if (!first)
281 bcm63xx_spi_setup_transfer(spi, t); 321 first = t;
322
323 n_transfers++;
324 total_len += t->len;
325
326 if (n_transfers == 2 && !first->rx_buf && !t->tx_buf &&
327 first->len <= BCM63XX_SPI_MAX_PREPEND)
328 can_use_prepend = true;
329 else if (can_use_prepend && t->tx_buf)
330 can_use_prepend = false;
331
332 /* we can only transfer one fifo worth of data */
333 if ((can_use_prepend &&
334 total_len > (bs->fifo_size + BCM63XX_SPI_MAX_PREPEND)) ||
335 (!can_use_prepend && total_len > bs->fifo_size)) {
336 dev_err(&spi->dev, "unable to do transfers larger than FIFO size (%i > %i)\n",
337 total_len, bs->fifo_size);
338 status = -EINVAL;
339 goto exit;
340 }
341
342 /* all combined transfers have to have the same speed */
343 if (t->speed_hz != first->speed_hz) {
344 dev_err(&spi->dev, "unable to change speed between transfers\n");
345 status = -EINVAL;
346 goto exit;
347 }
282 348
283 while (len) { 349 /* CS will be deasserted directly after transfer */
284 /* send the data */ 350 if (t->delay_usecs) {
285 len -= bcm63xx_txrx_bufs(spi, t); 351 dev_err(&spi->dev, "unable to keep CS asserted after transfer\n");
352 status = -EINVAL;
353 goto exit;
354 }
355
356 if (t->cs_change ||
357 list_is_last(&t->transfer_list, &m->transfers)) {
358 /* configure adapter for a new transfer */
359 bcm63xx_spi_setup_transfer(spi, first);
286 360
287 timeout = wait_for_completion_timeout(&bs->done, HZ); 361 /* send the data */
288 if (!timeout) { 362 status = bcm63xx_txrx_bufs(spi, first, n_transfers);
289 status = -ETIMEDOUT; 363 if (status)
290 goto exit; 364 goto exit;
291 }
292 365
293 /* read out all data */ 366 m->actual_length += total_len;
294 rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
295 367
296 /* Read out all the data */ 368 first = NULL;
297 if (rx_tail) 369 n_transfers = 0;
298 memcpy_fromio(bs->rx_ptr, bs->rx_io, rx_tail); 370 total_len = 0;
371 can_use_prepend = false;
299 } 372 }
300
301 m->actual_length += t->len;
302 } 373 }
303exit: 374exit:
304 m->status = status; 375 m->status = status;