aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/omap2_mcspi.c
diff options
context:
space:
mode:
authorRoman Tereshonkov <roman.tereshonkov@nokia.com>2010-04-13 06:41:51 -0400
committerGrant Likely <grant.likely@secretlab.ca>2010-05-25 02:23:15 -0400
commit4743a0f88c4000dfa3c422ecc4d750d3a3410550 (patch)
tree5e5e75696651a949129e3bf5488e6e85818766d4 /drivers/spi/omap2_mcspi.c
parent8b66c13474e1683d53255f3b2948231b61cdaefd (diff)
spi/omap2_mcspi: add turbo mode support
Turbo mode allows to read data to shift register when rx-buffer is full thus improving the perfomance. This feature is available for RX-only mode. In PIO turbo mode when the penultimate word is available in RX-buffer the controller should be disabled before reading data to prevent the next transaction triggering. The controller itself handles the last word to be correctly loaded to shift-register and then transferred to RX-buffer. The turbo mode is enabled by setting turbo_mode parameter to 1. This parameter is a part of omap2_mcspi_device_config structure which is passed through the spi_device controller_data pointer. Signed-off-by: Roman Tereshonkov <roman.tereshonkov@nokia.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/spi/omap2_mcspi.c')
-rw-r--r--drivers/spi/omap2_mcspi.c132
1 files changed, 111 insertions, 21 deletions
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
index e6d08b844156..6df85537bd19 100644
--- a/drivers/spi/omap2_mcspi.c
+++ b/drivers/spi/omap2_mcspi.c
@@ -38,7 +38,7 @@
38 38
39#include <plat/dma.h> 39#include <plat/dma.h>
40#include <plat/clock.h> 40#include <plat/clock.h>
41 41#include <plat/mcspi.h>
42 42
43#define OMAP2_MCSPI_MAX_FREQ 48000000 43#define OMAP2_MCSPI_MAX_FREQ 48000000
44 44
@@ -229,6 +229,8 @@ static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
229 229
230 l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0; 230 l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0;
231 mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l); 231 mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l);
232 /* Flash post-writes */
233 mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
232} 234}
233 235
234static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active) 236static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active)
@@ -303,11 +305,14 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
303 unsigned int count, c; 305 unsigned int count, c;
304 unsigned long base, tx_reg, rx_reg; 306 unsigned long base, tx_reg, rx_reg;
305 int word_len, data_type, element_count; 307 int word_len, data_type, element_count;
308 int elements;
309 u32 l;
306 u8 * rx; 310 u8 * rx;
307 const u8 * tx; 311 const u8 * tx;
308 312
309 mcspi = spi_master_get_devdata(spi->master); 313 mcspi = spi_master_get_devdata(spi->master);
310 mcspi_dma = &mcspi->dma_channels[spi->chip_select]; 314 mcspi_dma = &mcspi->dma_channels[spi->chip_select];
315 l = mcspi_cached_chconf0(spi);
311 316
312 count = xfer->len; 317 count = xfer->len;
313 c = count; 318 c = count;
@@ -346,8 +351,12 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
346 } 351 }
347 352
348 if (rx != NULL) { 353 if (rx != NULL) {
354 elements = element_count - 1;
355 if (l & OMAP2_MCSPI_CHCONF_TURBO)
356 elements--;
357
349 omap_set_dma_transfer_params(mcspi_dma->dma_rx_channel, 358 omap_set_dma_transfer_params(mcspi_dma->dma_rx_channel,
350 data_type, element_count - 1, 1, 359 data_type, elements, 1,
351 OMAP_DMA_SYNC_ELEMENT, 360 OMAP_DMA_SYNC_ELEMENT,
352 mcspi_dma->dma_rx_sync_dev, 1); 361 mcspi_dma->dma_rx_sync_dev, 1);
353 362
@@ -379,17 +388,42 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
379 wait_for_completion(&mcspi_dma->dma_rx_completion); 388 wait_for_completion(&mcspi_dma->dma_rx_completion);
380 dma_unmap_single(NULL, xfer->rx_dma, count, DMA_FROM_DEVICE); 389 dma_unmap_single(NULL, xfer->rx_dma, count, DMA_FROM_DEVICE);
381 omap2_mcspi_set_enable(spi, 0); 390 omap2_mcspi_set_enable(spi, 0);
391
392 if (l & OMAP2_MCSPI_CHCONF_TURBO) {
393
394 if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
395 & OMAP2_MCSPI_CHSTAT_RXS)) {
396 u32 w;
397
398 w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
399 if (word_len <= 8)
400 ((u8 *)xfer->rx_buf)[elements++] = w;
401 else if (word_len <= 16)
402 ((u16 *)xfer->rx_buf)[elements++] = w;
403 else /* word_len <= 32 */
404 ((u32 *)xfer->rx_buf)[elements++] = w;
405 } else {
406 dev_err(&spi->dev,
407 "DMA RX penultimate word empty");
408 count -= (word_len <= 8) ? 2 :
409 (word_len <= 16) ? 4 :
410 /* word_len <= 32 */ 8;
411 omap2_mcspi_set_enable(spi, 1);
412 return count;
413 }
414 }
415
382 if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0) 416 if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
383 & OMAP2_MCSPI_CHSTAT_RXS)) { 417 & OMAP2_MCSPI_CHSTAT_RXS)) {
384 u32 w; 418 u32 w;
385 419
386 w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0); 420 w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
387 if (word_len <= 8) 421 if (word_len <= 8)
388 ((u8 *)xfer->rx_buf)[element_count - 1] = w; 422 ((u8 *)xfer->rx_buf)[elements] = w;
389 else if (word_len <= 16) 423 else if (word_len <= 16)
390 ((u16 *)xfer->rx_buf)[element_count - 1] = w; 424 ((u16 *)xfer->rx_buf)[elements] = w;
391 else /* word_len <= 32 */ 425 else /* word_len <= 32 */
392 ((u32 *)xfer->rx_buf)[element_count - 1] = w; 426 ((u32 *)xfer->rx_buf)[elements] = w;
393 } else { 427 } else {
394 dev_err(&spi->dev, "DMA RX last word empty"); 428 dev_err(&spi->dev, "DMA RX last word empty");
395 count -= (word_len <= 8) ? 1 : 429 count -= (word_len <= 8) ? 1 :
@@ -433,7 +467,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
433 word_len = cs->word_len; 467 word_len = cs->word_len;
434 468
435 l = mcspi_cached_chconf0(spi); 469 l = mcspi_cached_chconf0(spi);
436 l &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
437 470
438 /* We store the pre-calculated register addresses on stack to speed 471 /* We store the pre-calculated register addresses on stack to speed
439 * up the transfer loop. */ 472 * up the transfer loop. */
@@ -468,11 +501,26 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
468 dev_err(&spi->dev, "RXS timed out\n"); 501 dev_err(&spi->dev, "RXS timed out\n");
469 goto out; 502 goto out;
470 } 503 }
471 /* prevent last RX_ONLY read from triggering 504
472 * more word i/o: switch to rx+tx 505 if (c == 1 && tx == NULL &&
473 */ 506 (l & OMAP2_MCSPI_CHCONF_TURBO)) {
474 if (c == 0 && tx == NULL) 507 omap2_mcspi_set_enable(spi, 0);
475 mcspi_write_chconf0(spi, l); 508 *rx++ = __raw_readl(rx_reg);
509#ifdef VERBOSE
510 dev_dbg(&spi->dev, "read-%d %02x\n",
511 word_len, *(rx - 1));
512#endif
513 if (mcspi_wait_for_reg_bit(chstat_reg,
514 OMAP2_MCSPI_CHSTAT_RXS) < 0) {
515 dev_err(&spi->dev,
516 "RXS timed out\n");
517 goto out;
518 }
519 c = 0;
520 } else if (c == 0 && tx == NULL) {
521 omap2_mcspi_set_enable(spi, 0);
522 }
523
476 *rx++ = __raw_readl(rx_reg); 524 *rx++ = __raw_readl(rx_reg);
477#ifdef VERBOSE 525#ifdef VERBOSE
478 dev_dbg(&spi->dev, "read-%d %02x\n", 526 dev_dbg(&spi->dev, "read-%d %02x\n",
@@ -506,11 +554,26 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
506 dev_err(&spi->dev, "RXS timed out\n"); 554 dev_err(&spi->dev, "RXS timed out\n");
507 goto out; 555 goto out;
508 } 556 }
509 /* prevent last RX_ONLY read from triggering 557
510 * more word i/o: switch to rx+tx 558 if (c == 2 && tx == NULL &&
511 */ 559 (l & OMAP2_MCSPI_CHCONF_TURBO)) {
512 if (c == 0 && tx == NULL) 560 omap2_mcspi_set_enable(spi, 0);
513 mcspi_write_chconf0(spi, l); 561 *rx++ = __raw_readl(rx_reg);
562#ifdef VERBOSE
563 dev_dbg(&spi->dev, "read-%d %04x\n",
564 word_len, *(rx - 1));
565#endif
566 if (mcspi_wait_for_reg_bit(chstat_reg,
567 OMAP2_MCSPI_CHSTAT_RXS) < 0) {
568 dev_err(&spi->dev,
569 "RXS timed out\n");
570 goto out;
571 }
572 c = 0;
573 } else if (c == 0 && tx == NULL) {
574 omap2_mcspi_set_enable(spi, 0);
575 }
576
514 *rx++ = __raw_readl(rx_reg); 577 *rx++ = __raw_readl(rx_reg);
515#ifdef VERBOSE 578#ifdef VERBOSE
516 dev_dbg(&spi->dev, "read-%d %04x\n", 579 dev_dbg(&spi->dev, "read-%d %04x\n",
@@ -544,11 +607,26 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
544 dev_err(&spi->dev, "RXS timed out\n"); 607 dev_err(&spi->dev, "RXS timed out\n");
545 goto out; 608 goto out;
546 } 609 }
547 /* prevent last RX_ONLY read from triggering 610
548 * more word i/o: switch to rx+tx 611 if (c == 4 && tx == NULL &&
549 */ 612 (l & OMAP2_MCSPI_CHCONF_TURBO)) {
550 if (c == 0 && tx == NULL) 613 omap2_mcspi_set_enable(spi, 0);
551 mcspi_write_chconf0(spi, l); 614 *rx++ = __raw_readl(rx_reg);
615#ifdef VERBOSE
616 dev_dbg(&spi->dev, "read-%d %08x\n",
617 word_len, *(rx - 1));
618#endif
619 if (mcspi_wait_for_reg_bit(chstat_reg,
620 OMAP2_MCSPI_CHSTAT_RXS) < 0) {
621 dev_err(&spi->dev,
622 "RXS timed out\n");
623 goto out;
624 }
625 c = 0;
626 } else if (c == 0 && tx == NULL) {
627 omap2_mcspi_set_enable(spi, 0);
628 }
629
552 *rx++ = __raw_readl(rx_reg); 630 *rx++ = __raw_readl(rx_reg);
553#ifdef VERBOSE 631#ifdef VERBOSE
554 dev_dbg(&spi->dev, "read-%d %08x\n", 632 dev_dbg(&spi->dev, "read-%d %08x\n",
@@ -568,6 +646,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
568 dev_err(&spi->dev, "EOT timed out\n"); 646 dev_err(&spi->dev, "EOT timed out\n");
569 } 647 }
570out: 648out:
649 omap2_mcspi_set_enable(spi, 1);
571 return count - c; 650 return count - c;
572} 651}
573 652
@@ -797,6 +876,7 @@ static void omap2_mcspi_work(struct work_struct *work)
797 struct spi_transfer *t = NULL; 876 struct spi_transfer *t = NULL;
798 int cs_active = 0; 877 int cs_active = 0;
799 struct omap2_mcspi_cs *cs; 878 struct omap2_mcspi_cs *cs;
879 struct omap2_mcspi_device_config *cd;
800 int par_override = 0; 880 int par_override = 0;
801 int status = 0; 881 int status = 0;
802 u32 chconf; 882 u32 chconf;
@@ -809,6 +889,7 @@ static void omap2_mcspi_work(struct work_struct *work)
809 889
810 spi = m->spi; 890 spi = m->spi;
811 cs = spi->controller_state; 891 cs = spi->controller_state;
892 cd = spi->controller_data;
812 893
813 omap2_mcspi_set_enable(spi, 1); 894 omap2_mcspi_set_enable(spi, 1);
814 list_for_each_entry(t, &m->transfers, transfer_list) { 895 list_for_each_entry(t, &m->transfers, transfer_list) {
@@ -832,10 +913,19 @@ static void omap2_mcspi_work(struct work_struct *work)
832 913
833 chconf = mcspi_cached_chconf0(spi); 914 chconf = mcspi_cached_chconf0(spi);
834 chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK; 915 chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
916 chconf &= ~OMAP2_MCSPI_CHCONF_TURBO;
917
835 if (t->tx_buf == NULL) 918 if (t->tx_buf == NULL)
836 chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY; 919 chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
837 else if (t->rx_buf == NULL) 920 else if (t->rx_buf == NULL)
838 chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY; 921 chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
922
923 if (cd && cd->turbo_mode && t->tx_buf == NULL) {
924 /* Turbo mode is for more than one word */
925 if (t->len > ((cs->word_len + 7) >> 3))
926 chconf |= OMAP2_MCSPI_CHCONF_TURBO;
927 }
928
839 mcspi_write_chconf0(spi, chconf); 929 mcspi_write_chconf0(spi, chconf);
840 930
841 if (t->len) { 931 if (t->len) {