diff options
author | Mark Brown <broonie@linaro.org> | 2013-10-05 06:51:14 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2013-10-11 15:10:17 -0400 |
commit | 0732a9d2a1551e3be5fd8a3ea680deb3d9e56193 (patch) | |
tree | 7438d037ad4a4000034c77844c479057cf30ce1e /drivers/spi | |
parent | 2cc6e2e0c8157b9e6ed8dbe5c7284865f6afbd46 (diff) |
spi/s3c64xx: Use core message handling
Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-s3c64xx.c | 152 |
1 files changed, 56 insertions, 96 deletions
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index c7b36c06ef40..25eb352d6a42 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c | |||
@@ -879,121 +879,81 @@ static int s3c64xx_spi_prepare_message(struct spi_master *master, | |||
879 | return 0; | 879 | return 0; |
880 | } | 880 | } |
881 | 881 | ||
882 | static int s3c64xx_spi_transfer_one_message(struct spi_master *master, | 882 | static int s3c64xx_spi_transfer_one(struct spi_master *master, |
883 | struct spi_message *msg) | 883 | struct spi_device *spi, |
884 | struct spi_transfer *xfer) | ||
884 | { | 885 | { |
885 | struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); | 886 | struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); |
886 | struct spi_device *spi = msg->spi; | 887 | int status; |
887 | struct spi_transfer *xfer; | ||
888 | int status = 0, cs_toggle = 0; | ||
889 | u32 speed; | 888 | u32 speed; |
890 | u8 bpw; | 889 | u8 bpw; |
890 | unsigned long flags; | ||
891 | int use_dma; | ||
891 | 892 | ||
892 | list_for_each_entry(xfer, &msg->transfers, transfer_list) { | 893 | INIT_COMPLETION(sdd->xfer_completion); |
893 | |||
894 | unsigned long flags; | ||
895 | int use_dma; | ||
896 | |||
897 | INIT_COMPLETION(sdd->xfer_completion); | ||
898 | |||
899 | /* Only BPW and Speed may change across transfers */ | ||
900 | bpw = xfer->bits_per_word; | ||
901 | speed = xfer->speed_hz ? : spi->max_speed_hz; | ||
902 | |||
903 | if (xfer->len % (bpw / 8)) { | ||
904 | dev_err(&spi->dev, | ||
905 | "Xfer length(%u) not a multiple of word size(%u)\n", | ||
906 | xfer->len, bpw / 8); | ||
907 | status = -EIO; | ||
908 | goto out; | ||
909 | } | ||
910 | |||
911 | if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) { | ||
912 | sdd->cur_bpw = bpw; | ||
913 | sdd->cur_speed = speed; | ||
914 | s3c64xx_spi_config(sdd); | ||
915 | } | ||
916 | |||
917 | /* Slave Select */ | ||
918 | enable_cs(sdd, spi); | ||
919 | |||
920 | /* Polling method for xfers not bigger than FIFO capacity */ | ||
921 | use_dma = 0; | ||
922 | if (!is_polling(sdd) && | ||
923 | (sdd->rx_dma.ch && sdd->tx_dma.ch && | ||
924 | (xfer->len > ((FIFO_LVL_MASK(sdd) >> 1) + 1)))) | ||
925 | use_dma = 1; | ||
926 | |||
927 | spin_lock_irqsave(&sdd->lock, flags); | ||
928 | 894 | ||
929 | /* Pending only which is to be done */ | 895 | /* Only BPW and Speed may change across transfers */ |
930 | sdd->state &= ~RXBUSY; | 896 | bpw = xfer->bits_per_word; |
931 | sdd->state &= ~TXBUSY; | 897 | speed = xfer->speed_hz ? : spi->max_speed_hz; |
932 | 898 | ||
933 | enable_datapath(sdd, spi, xfer, use_dma); | 899 | if (xfer->len % (bpw / 8)) { |
934 | 900 | dev_err(&spi->dev, | |
935 | /* Start the signals */ | 901 | "Xfer length(%u) not a multiple of word size(%u)\n", |
936 | writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); | 902 | xfer->len, bpw / 8); |
903 | return -EIO; | ||
904 | } | ||
937 | 905 | ||
938 | /* Start the signals */ | 906 | if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) { |
939 | writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); | 907 | sdd->cur_bpw = bpw; |
908 | sdd->cur_speed = speed; | ||
909 | s3c64xx_spi_config(sdd); | ||
910 | } | ||
940 | 911 | ||
941 | spin_unlock_irqrestore(&sdd->lock, flags); | 912 | /* Polling method for xfers not bigger than FIFO capacity */ |
913 | use_dma = 0; | ||
914 | if (!is_polling(sdd) && | ||
915 | (sdd->rx_dma.ch && sdd->tx_dma.ch && | ||
916 | (xfer->len > ((FIFO_LVL_MASK(sdd) >> 1) + 1)))) | ||
917 | use_dma = 1; | ||
942 | 918 | ||
943 | status = wait_for_xfer(sdd, xfer, use_dma); | 919 | spin_lock_irqsave(&sdd->lock, flags); |
944 | 920 | ||
945 | if (status) { | 921 | /* Pending only which is to be done */ |
946 | dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n", | 922 | sdd->state &= ~RXBUSY; |
947 | xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0, | 923 | sdd->state &= ~TXBUSY; |
948 | (sdd->state & RXBUSY) ? 'f' : 'p', | ||
949 | (sdd->state & TXBUSY) ? 'f' : 'p', | ||
950 | xfer->len); | ||
951 | 924 | ||
952 | if (use_dma) { | 925 | enable_datapath(sdd, spi, xfer, use_dma); |
953 | if (xfer->tx_buf != NULL | ||
954 | && (sdd->state & TXBUSY)) | ||
955 | s3c64xx_spi_dma_stop(sdd, &sdd->tx_dma); | ||
956 | if (xfer->rx_buf != NULL | ||
957 | && (sdd->state & RXBUSY)) | ||
958 | s3c64xx_spi_dma_stop(sdd, &sdd->rx_dma); | ||
959 | } | ||
960 | 926 | ||
961 | goto out; | 927 | /* Start the signals */ |
962 | } | 928 | writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); |
963 | 929 | ||
964 | flush_fifo(sdd); | 930 | /* Start the signals */ |
931 | writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); | ||
965 | 932 | ||
966 | if (xfer->delay_usecs) | 933 | spin_unlock_irqrestore(&sdd->lock, flags); |
967 | udelay(xfer->delay_usecs); | ||
968 | 934 | ||
969 | if (xfer->cs_change) { | 935 | status = wait_for_xfer(sdd, xfer, use_dma); |
970 | /* Hint that the next mssg is gonna be | 936 | |
971 | for the same device */ | 937 | if (status) { |
972 | if (list_is_last(&xfer->transfer_list, | 938 | dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n", |
973 | &msg->transfers)) | 939 | xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0, |
974 | cs_toggle = 1; | 940 | (sdd->state & RXBUSY) ? 'f' : 'p', |
941 | (sdd->state & TXBUSY) ? 'f' : 'p', | ||
942 | xfer->len); | ||
943 | |||
944 | if (use_dma) { | ||
945 | if (xfer->tx_buf != NULL | ||
946 | && (sdd->state & TXBUSY)) | ||
947 | s3c64xx_spi_dma_stop(sdd, &sdd->tx_dma); | ||
948 | if (xfer->rx_buf != NULL | ||
949 | && (sdd->state & RXBUSY)) | ||
950 | s3c64xx_spi_dma_stop(sdd, &sdd->rx_dma); | ||
975 | } | 951 | } |
976 | |||
977 | msg->actual_length += xfer->len; | ||
978 | } | ||
979 | |||
980 | out: | ||
981 | if (!cs_toggle || status) { | ||
982 | /* Quiese the signals */ | ||
983 | writel(S3C64XX_SPI_SLAVE_SIG_INACT, | ||
984 | sdd->regs + S3C64XX_SPI_SLAVE_SEL); | ||
985 | disable_cs(sdd, spi); | ||
986 | } else { | 952 | } else { |
987 | sdd->tgl_spi = spi; | 953 | flush_fifo(sdd); |
988 | } | 954 | } |
989 | 955 | ||
990 | s3c64xx_spi_unmap_mssg(sdd, msg); | 956 | return status; |
991 | |||
992 | msg->status = status; | ||
993 | |||
994 | spi_finalize_current_message(master); | ||
995 | |||
996 | return 0; | ||
997 | } | 957 | } |
998 | 958 | ||
999 | static int s3c64xx_spi_unprepare_message(struct spi_master *master, | 959 | static int s3c64xx_spi_unprepare_message(struct spi_master *master, |
@@ -1379,7 +1339,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) | |||
1379 | master->cleanup = s3c64xx_spi_cleanup; | 1339 | master->cleanup = s3c64xx_spi_cleanup; |
1380 | master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer; | 1340 | master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer; |
1381 | master->prepare_message = s3c64xx_spi_prepare_message; | 1341 | master->prepare_message = s3c64xx_spi_prepare_message; |
1382 | master->transfer_one_message = s3c64xx_spi_transfer_one_message; | 1342 | master->transfer_one = s3c64xx_spi_transfer_one; |
1383 | master->unprepare_message = s3c64xx_spi_unprepare_message; | 1343 | master->unprepare_message = s3c64xx_spi_unprepare_message; |
1384 | master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer; | 1344 | master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer; |
1385 | master->num_chipselect = sci->num_cs; | 1345 | master->num_chipselect = sci->num_cs; |