diff options
author | Mark Brown <broonie@linaro.org> | 2013-10-25 04:51:40 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2013-10-25 04:51:40 -0400 |
commit | 176c51c1e4fbe04c273d564cf9ccf569606b5fd2 (patch) | |
tree | 7ccea0fdae71ecd90c9a3e9712b833b3983cfb2b /drivers/spi | |
parent | f88df3a72c257d6071641164945ee51b379e1f44 (diff) | |
parent | f4fade12d506e14867a2b0a5e2f7aaf227297d8b (diff) |
Merge remote-tracking branch 'spi/topic/tegra114' into spi-next
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-tegra114.c | 85 |
1 files changed, 68 insertions, 17 deletions
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index b3821fb9da3f..9146bb3c2489 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c | |||
@@ -182,6 +182,7 @@ struct tegra_spi_data { | |||
182 | u32 cur_speed; | 182 | u32 cur_speed; |
183 | 183 | ||
184 | struct spi_device *cur_spi; | 184 | struct spi_device *cur_spi; |
185 | struct spi_device *cs_control; | ||
185 | unsigned cur_pos; | 186 | unsigned cur_pos; |
186 | unsigned cur_len; | 187 | unsigned cur_len; |
187 | unsigned words_per_32bit; | 188 | unsigned words_per_32bit; |
@@ -676,15 +677,12 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi, | |||
676 | dma_release_channel(dma_chan); | 677 | dma_release_channel(dma_chan); |
677 | } | 678 | } |
678 | 679 | ||
679 | static int tegra_spi_start_transfer_one(struct spi_device *spi, | 680 | static unsigned long tegra_spi_setup_transfer_one(struct spi_device *spi, |
680 | struct spi_transfer *t, bool is_first_of_msg, | 681 | struct spi_transfer *t, bool is_first_of_msg) |
681 | bool is_single_xfer) | ||
682 | { | 682 | { |
683 | struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); | 683 | struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); |
684 | u32 speed = t->speed_hz; | 684 | u32 speed = t->speed_hz; |
685 | u8 bits_per_word = t->bits_per_word; | 685 | u8 bits_per_word = t->bits_per_word; |
686 | unsigned total_fifo_words; | ||
687 | int ret; | ||
688 | unsigned long command1; | 686 | unsigned long command1; |
689 | int req_mode; | 687 | int req_mode; |
690 | 688 | ||
@@ -698,7 +696,6 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi, | |||
698 | tspi->cur_rx_pos = 0; | 696 | tspi->cur_rx_pos = 0; |
699 | tspi->cur_tx_pos = 0; | 697 | tspi->cur_tx_pos = 0; |
700 | tspi->curr_xfer = t; | 698 | tspi->curr_xfer = t; |
701 | total_fifo_words = tegra_spi_calculate_curr_xfer_param(spi, tspi, t); | ||
702 | 699 | ||
703 | if (is_first_of_msg) { | 700 | if (is_first_of_msg) { |
704 | tegra_spi_clear_status(tspi); | 701 | tegra_spi_clear_status(tspi); |
@@ -717,7 +714,12 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi, | |||
717 | else if (req_mode == SPI_MODE_3) | 714 | else if (req_mode == SPI_MODE_3) |
718 | command1 |= SPI_CONTROL_MODE_3; | 715 | command1 |= SPI_CONTROL_MODE_3; |
719 | 716 | ||
720 | tegra_spi_writel(tspi, command1, SPI_COMMAND1); | 717 | if (tspi->cs_control) { |
718 | if (tspi->cs_control != spi) | ||
719 | tegra_spi_writel(tspi, command1, SPI_COMMAND1); | ||
720 | tspi->cs_control = NULL; | ||
721 | } else | ||
722 | tegra_spi_writel(tspi, command1, SPI_COMMAND1); | ||
721 | 723 | ||
722 | command1 |= SPI_CS_SW_HW; | 724 | command1 |= SPI_CS_SW_HW; |
723 | if (spi->mode & SPI_CS_HIGH) | 725 | if (spi->mode & SPI_CS_HIGH) |
@@ -732,6 +734,18 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi, | |||
732 | command1 |= SPI_BIT_LENGTH(bits_per_word - 1); | 734 | command1 |= SPI_BIT_LENGTH(bits_per_word - 1); |
733 | } | 735 | } |
734 | 736 | ||
737 | return command1; | ||
738 | } | ||
739 | |||
740 | static int tegra_spi_start_transfer_one(struct spi_device *spi, | ||
741 | struct spi_transfer *t, unsigned long command1) | ||
742 | { | ||
743 | struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); | ||
744 | unsigned total_fifo_words; | ||
745 | int ret; | ||
746 | |||
747 | total_fifo_words = tegra_spi_calculate_curr_xfer_param(spi, tspi, t); | ||
748 | |||
735 | if (tspi->is_packed) | 749 | if (tspi->is_packed) |
736 | command1 |= SPI_PACKED; | 750 | command1 |= SPI_PACKED; |
737 | 751 | ||
@@ -803,29 +817,50 @@ static int tegra_spi_setup(struct spi_device *spi) | |||
803 | return 0; | 817 | return 0; |
804 | } | 818 | } |
805 | 819 | ||
820 | static void tegra_spi_transfer_delay(int delay) | ||
821 | { | ||
822 | if (!delay) | ||
823 | return; | ||
824 | |||
825 | if (delay >= 1000) | ||
826 | mdelay(delay / 1000); | ||
827 | |||
828 | udelay(delay % 1000); | ||
829 | } | ||
830 | |||
806 | static int tegra_spi_transfer_one_message(struct spi_master *master, | 831 | static int tegra_spi_transfer_one_message(struct spi_master *master, |
807 | struct spi_message *msg) | 832 | struct spi_message *msg) |
808 | { | 833 | { |
809 | bool is_first_msg = true; | 834 | bool is_first_msg = true; |
810 | int single_xfer; | ||
811 | struct tegra_spi_data *tspi = spi_master_get_devdata(master); | 835 | struct tegra_spi_data *tspi = spi_master_get_devdata(master); |
812 | struct spi_transfer *xfer; | 836 | struct spi_transfer *xfer; |
813 | struct spi_device *spi = msg->spi; | 837 | struct spi_device *spi = msg->spi; |
814 | int ret; | 838 | int ret; |
839 | bool skip = false; | ||
815 | 840 | ||
816 | msg->status = 0; | 841 | msg->status = 0; |
817 | msg->actual_length = 0; | 842 | msg->actual_length = 0; |
818 | 843 | ||
819 | single_xfer = list_is_singular(&msg->transfers); | ||
820 | list_for_each_entry(xfer, &msg->transfers, transfer_list) { | 844 | list_for_each_entry(xfer, &msg->transfers, transfer_list) { |
845 | unsigned long cmd1; | ||
846 | |||
821 | INIT_COMPLETION(tspi->xfer_completion); | 847 | INIT_COMPLETION(tspi->xfer_completion); |
822 | ret = tegra_spi_start_transfer_one(spi, xfer, | 848 | |
823 | is_first_msg, single_xfer); | 849 | cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg); |
850 | |||
851 | if (!xfer->len) { | ||
852 | ret = 0; | ||
853 | skip = true; | ||
854 | goto complete_xfer; | ||
855 | } | ||
856 | |||
857 | ret = tegra_spi_start_transfer_one(spi, xfer, cmd1); | ||
824 | if (ret < 0) { | 858 | if (ret < 0) { |
825 | dev_err(tspi->dev, | 859 | dev_err(tspi->dev, |
826 | "spi can not start transfer, err %d\n", ret); | 860 | "spi can not start transfer, err %d\n", ret); |
827 | goto exit; | 861 | goto complete_xfer; |
828 | } | 862 | } |
863 | |||
829 | is_first_msg = false; | 864 | is_first_msg = false; |
830 | ret = wait_for_completion_timeout(&tspi->xfer_completion, | 865 | ret = wait_for_completion_timeout(&tspi->xfer_completion, |
831 | SPI_DMA_TIMEOUT); | 866 | SPI_DMA_TIMEOUT); |
@@ -833,24 +868,40 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, | |||
833 | dev_err(tspi->dev, | 868 | dev_err(tspi->dev, |
834 | "spi trasfer timeout, err %d\n", ret); | 869 | "spi trasfer timeout, err %d\n", ret); |
835 | ret = -EIO; | 870 | ret = -EIO; |
836 | goto exit; | 871 | goto complete_xfer; |
837 | } | 872 | } |
838 | 873 | ||
839 | if (tspi->tx_status || tspi->rx_status) { | 874 | if (tspi->tx_status || tspi->rx_status) { |
840 | dev_err(tspi->dev, "Error in Transfer\n"); | 875 | dev_err(tspi->dev, "Error in Transfer\n"); |
841 | ret = -EIO; | 876 | ret = -EIO; |
842 | goto exit; | 877 | goto complete_xfer; |
843 | } | 878 | } |
844 | msg->actual_length += xfer->len; | 879 | msg->actual_length += xfer->len; |
845 | if (xfer->cs_change && xfer->delay_usecs) { | 880 | |
881 | complete_xfer: | ||
882 | if (ret < 0 || skip) { | ||
846 | tegra_spi_writel(tspi, tspi->def_command1_reg, | 883 | tegra_spi_writel(tspi, tspi->def_command1_reg, |
847 | SPI_COMMAND1); | 884 | SPI_COMMAND1); |
848 | udelay(xfer->delay_usecs); | 885 | tegra_spi_transfer_delay(xfer->delay_usecs); |
886 | goto exit; | ||
887 | } else if (msg->transfers.prev == &xfer->transfer_list) { | ||
888 | /* This is the last transfer in message */ | ||
889 | if (xfer->cs_change) | ||
890 | tspi->cs_control = spi; | ||
891 | else { | ||
892 | tegra_spi_writel(tspi, tspi->def_command1_reg, | ||
893 | SPI_COMMAND1); | ||
894 | tegra_spi_transfer_delay(xfer->delay_usecs); | ||
895 | } | ||
896 | } else if (xfer->cs_change) { | ||
897 | tegra_spi_writel(tspi, tspi->def_command1_reg, | ||
898 | SPI_COMMAND1); | ||
899 | tegra_spi_transfer_delay(xfer->delay_usecs); | ||
849 | } | 900 | } |
901 | |||
850 | } | 902 | } |
851 | ret = 0; | 903 | ret = 0; |
852 | exit: | 904 | exit: |
853 | tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1); | ||
854 | msg->status = ret; | 905 | msg->status = ret; |
855 | spi_finalize_current_message(master); | 906 | spi_finalize_current_message(master); |
856 | return ret; | 907 | return ret; |