diff options
| -rw-r--r-- | drivers/spi/omap2_mcspi.c | 132 |
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 | ||
| 234 | static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active) | 236 | static 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 | } |
| 570 | out: | 648 | out: |
| 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) { |
