diff options
| -rw-r--r-- | drivers/spi/spi-s3c64xx.c | 202 |
1 files changed, 143 insertions, 59 deletions
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 32ba3555f8b9..eb53df27e7ea 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c | |||
| @@ -39,6 +39,7 @@ | |||
| 39 | #endif | 39 | #endif |
| 40 | 40 | ||
| 41 | #define MAX_SPI_PORTS 3 | 41 | #define MAX_SPI_PORTS 3 |
| 42 | #define S3C64XX_SPI_QUIRK_POLL (1 << 0) | ||
| 42 | 43 | ||
| 43 | /* Registers and bit-fields */ | 44 | /* Registers and bit-fields */ |
| 44 | 45 | ||
| @@ -130,6 +131,7 @@ | |||
| 130 | #define S3C64XX_SPI_TRAILCNT S3C64XX_SPI_MAX_TRAILCNT | 131 | #define S3C64XX_SPI_TRAILCNT S3C64XX_SPI_MAX_TRAILCNT |
| 131 | 132 | ||
| 132 | #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) | 133 | #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) |
| 134 | #define is_polling(x) (x->port_conf->quirks & S3C64XX_SPI_QUIRK_POLL) | ||
| 133 | 135 | ||
| 134 | #define RXBUSY (1<<2) | 136 | #define RXBUSY (1<<2) |
| 135 | #define TXBUSY (1<<3) | 137 | #define TXBUSY (1<<3) |
| @@ -158,6 +160,7 @@ struct s3c64xx_spi_port_config { | |||
| 158 | int fifo_lvl_mask[MAX_SPI_PORTS]; | 160 | int fifo_lvl_mask[MAX_SPI_PORTS]; |
| 159 | int rx_lvl_offset; | 161 | int rx_lvl_offset; |
| 160 | int tx_st_done; | 162 | int tx_st_done; |
| 163 | int quirks; | ||
| 161 | bool high_speed; | 164 | bool high_speed; |
| 162 | bool clk_from_cmu; | 165 | bool clk_from_cmu; |
| 163 | }; | 166 | }; |
| @@ -205,6 +208,7 @@ struct s3c64xx_spi_driver_data { | |||
| 205 | struct s3c64xx_spi_port_config *port_conf; | 208 | struct s3c64xx_spi_port_config *port_conf; |
| 206 | unsigned int port_id; | 209 | unsigned int port_id; |
| 207 | unsigned long gpios[4]; | 210 | unsigned long gpios[4]; |
| 211 | bool cs_gpio; | ||
| 208 | }; | 212 | }; |
| 209 | 213 | ||
| 210 | static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) | 214 | static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) |
| @@ -344,8 +348,12 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) | |||
| 344 | { | 348 | { |
| 345 | struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); | 349 | struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); |
| 346 | 350 | ||
| 347 | /* Acquire DMA channels */ | 351 | /* |
| 348 | while (!acquire_dma(sdd)) | 352 | * If DMA resource was not available during |
| 353 | * probe, no need to continue with dma requests | ||
| 354 | * else Acquire DMA channels | ||
| 355 | */ | ||
| 356 | while (!is_polling(sdd) && !acquire_dma(sdd)) | ||
| 349 | usleep_range(10000, 11000); | 357 | usleep_range(10000, 11000); |
| 350 | 358 | ||
| 351 | pm_runtime_get_sync(&sdd->pdev->dev); | 359 | pm_runtime_get_sync(&sdd->pdev->dev); |
| @@ -358,9 +366,12 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) | |||
| 358 | struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); | 366 | struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); |
| 359 | 367 | ||
| 360 | /* Free DMA channels */ | 368 | /* Free DMA channels */ |
| 361 | sdd->ops->release((enum dma_ch)sdd->rx_dma.ch, &s3c64xx_spi_dma_client); | 369 | if (!is_polling(sdd)) { |
| 362 | sdd->ops->release((enum dma_ch)sdd->tx_dma.ch, &s3c64xx_spi_dma_client); | 370 | sdd->ops->release((enum dma_ch)sdd->rx_dma.ch, |
| 363 | 371 | &s3c64xx_spi_dma_client); | |
| 372 | sdd->ops->release((enum dma_ch)sdd->tx_dma.ch, | ||
| 373 | &s3c64xx_spi_dma_client); | ||
| 374 | } | ||
| 364 | pm_runtime_put(&sdd->pdev->dev); | 375 | pm_runtime_put(&sdd->pdev->dev); |
| 365 | 376 | ||
| 366 | return 0; | 377 | return 0; |
| @@ -464,8 +475,10 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) | |||
| 464 | struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); | 475 | struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); |
| 465 | 476 | ||
| 466 | /* Free DMA channels */ | 477 | /* Free DMA channels */ |
| 467 | dma_release_channel(sdd->rx_dma.ch); | 478 | if (!is_polling(sdd)) { |
| 468 | dma_release_channel(sdd->tx_dma.ch); | 479 | dma_release_channel(sdd->rx_dma.ch); |
| 480 | dma_release_channel(sdd->tx_dma.ch); | ||
| 481 | } | ||
| 469 | 482 | ||
| 470 | pm_runtime_put(&sdd->pdev->dev); | 483 | pm_runtime_put(&sdd->pdev->dev); |
| 471 | return 0; | 484 | return 0; |
| @@ -558,14 +571,40 @@ static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd, | |||
| 558 | if (sdd->tgl_spi != spi) { /* if last mssg on diff device */ | 571 | if (sdd->tgl_spi != spi) { /* if last mssg on diff device */ |
| 559 | /* Deselect the last toggled device */ | 572 | /* Deselect the last toggled device */ |
| 560 | cs = sdd->tgl_spi->controller_data; | 573 | cs = sdd->tgl_spi->controller_data; |
| 561 | gpio_set_value(cs->line, | 574 | if (sdd->cs_gpio) |
| 562 | spi->mode & SPI_CS_HIGH ? 0 : 1); | 575 | gpio_set_value(cs->line, |
| 576 | spi->mode & SPI_CS_HIGH ? 0 : 1); | ||
| 563 | } | 577 | } |
| 564 | sdd->tgl_spi = NULL; | 578 | sdd->tgl_spi = NULL; |
| 565 | } | 579 | } |
| 566 | 580 | ||
| 567 | cs = spi->controller_data; | 581 | cs = spi->controller_data; |
| 568 | gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0); | 582 | if (sdd->cs_gpio) |
| 583 | gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0); | ||
| 584 | |||
| 585 | /* Start the signals */ | ||
| 586 | writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); | ||
| 587 | } | ||
| 588 | |||
| 589 | static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd, | ||
| 590 | int timeout_ms) | ||
| 591 | { | ||
| 592 | void __iomem *regs = sdd->regs; | ||
| 593 | unsigned long val = 1; | ||
| 594 | u32 status; | ||
| 595 | |||
| 596 | /* max fifo depth available */ | ||
| 597 | u32 max_fifo = (FIFO_LVL_MASK(sdd) >> 1) + 1; | ||
| 598 | |||
| 599 | if (timeout_ms) | ||
| 600 | val = msecs_to_loops(timeout_ms); | ||
| 601 | |||
| 602 | do { | ||
| 603 | status = readl(regs + S3C64XX_SPI_STATUS); | ||
| 604 | } while (RX_FIFO_LVL(status, sdd) < max_fifo && --val); | ||
| 605 | |||
| 606 | /* return the actual received data length */ | ||
| 607 | return RX_FIFO_LVL(status, sdd); | ||
| 569 | } | 608 | } |
| 570 | 609 | ||
| 571 | static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, | 610 | static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, |
| @@ -590,20 +629,19 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, | |||
| 590 | } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val); | 629 | } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val); |
| 591 | } | 630 | } |
| 592 | 631 | ||
| 593 | if (!val) | ||
| 594 | return -EIO; | ||
| 595 | |||
| 596 | if (dma_mode) { | 632 | if (dma_mode) { |
| 597 | u32 status; | 633 | u32 status; |
| 598 | 634 | ||
| 599 | /* | 635 | /* |
| 636 | * If the previous xfer was completed within timeout, then | ||
| 637 | * proceed further else return -EIO. | ||
| 600 | * DmaTx returns after simply writing data in the FIFO, | 638 | * DmaTx returns after simply writing data in the FIFO, |
| 601 | * w/o waiting for real transmission on the bus to finish. | 639 | * w/o waiting for real transmission on the bus to finish. |
| 602 | * DmaRx returns only after Dma read data from FIFO which | 640 | * DmaRx returns only after Dma read data from FIFO which |
| 603 | * needs bus transmission to finish, so we don't worry if | 641 | * needs bus transmission to finish, so we don't worry if |
| 604 | * Xfer involved Rx(with or without Tx). | 642 | * Xfer involved Rx(with or without Tx). |
| 605 | */ | 643 | */ |
| 606 | if (xfer->rx_buf == NULL) { | 644 | if (val && !xfer->rx_buf) { |
| 607 | val = msecs_to_loops(10); | 645 | val = msecs_to_loops(10); |
| 608 | status = readl(regs + S3C64XX_SPI_STATUS); | 646 | status = readl(regs + S3C64XX_SPI_STATUS); |
| 609 | while ((TX_FIFO_LVL(status, sdd) | 647 | while ((TX_FIFO_LVL(status, sdd) |
| @@ -613,30 +651,54 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, | |||
| 613 | status = readl(regs + S3C64XX_SPI_STATUS); | 651 | status = readl(regs + S3C64XX_SPI_STATUS); |
| 614 | } | 652 | } |
| 615 | 653 | ||
| 616 | if (!val) | ||
| 617 | return -EIO; | ||
| 618 | } | 654 | } |
| 655 | |||
| 656 | /* If timed out while checking rx/tx status return error */ | ||
| 657 | if (!val) | ||
| 658 | return -EIO; | ||
| 619 | } else { | 659 | } else { |
| 660 | int loops; | ||
| 661 | u32 cpy_len; | ||
| 662 | u8 *buf; | ||
| 663 | |||
| 620 | /* If it was only Tx */ | 664 | /* If it was only Tx */ |
| 621 | if (xfer->rx_buf == NULL) { | 665 | if (!xfer->rx_buf) { |
| 622 | sdd->state &= ~TXBUSY; | 666 | sdd->state &= ~TXBUSY; |
| 623 | return 0; | 667 | return 0; |
| 624 | } | 668 | } |
| 625 | |||
