diff options
author | Geert Uytterhoeven <geert+renesas@linux-m68k.org> | 2014-01-30 03:43:50 -0500 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-01-30 11:51:21 -0500 |
commit | 880c6d114fd79a6973708744c78c7f55da6aea4c (patch) | |
tree | 061174d839c9edb06c5df3bfd13471b9fc3c3a26 | |
parent | 426ef76dd8a394a0e04d096941cd9acb49539a3e (diff) |
spi: rspi: Add support for Quad and Dual SPI Transfers on QSPI
Add support for Quad and Dual SPI Transfers on the Renesas Quad Serial
Peripheral Interface, as found in R-Car Gen2 SoCs like R-Car H2 (r8a7790)
and R-Car M2 (r8a7791):
- Add unidirectional transfer methods for Quad/Dual SPI Transfers.
- Program the sequencer to handle SPI messages with multiple transfer
modes when Quad or Dual transfers are enabled for an SPI slave.
Up to 4 transfer modes per SPI message are supported by the hardware.
- Advertise the availability of Quad and Dual SPI modes on QSPI.
Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r-- | drivers/spi/spi-rspi.c | 162 |
1 files changed, 148 insertions, 14 deletions
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index e56fcb5f7f99..34ad4bca8a41 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * SH RSPI driver | 2 | * SH RSPI driver |
3 | * | 3 | * |
4 | * Copyright (C) 2012, 2013 Renesas Solutions Corp. | 4 | * Copyright (C) 2012, 2013 Renesas Solutions Corp. |
5 | * Copyright (C) 2014 Glider bvba | ||
5 | * | 6 | * |
6 | * Based on spi-sh.c: | 7 | * Based on spi-sh.c: |
7 | * Copyright (C) 2011 Renesas Solutions Corp. | 8 | * Copyright (C) 2011 Renesas Solutions Corp. |
@@ -57,6 +58,10 @@ | |||
57 | #define RSPI_SPCMD5 0x1a /* Command Register 5 */ | 58 | #define RSPI_SPCMD5 0x1a /* Command Register 5 */ |
58 | #define RSPI_SPCMD6 0x1c /* Command Register 6 */ | 59 | #define RSPI_SPCMD6 0x1c /* Command Register 6 */ |
59 | #define RSPI_SPCMD7 0x1e /* Command Register 7 */ | 60 | #define RSPI_SPCMD7 0x1e /* Command Register 7 */ |
61 | #define RSPI_SPCMD(i) (RSPI_SPCMD0 + (i) * 2) | ||
62 | #define RSPI_NUM_SPCMD 8 | ||
63 | #define RSPI_RZ_NUM_SPCMD 4 | ||
64 | #define QSPI_NUM_SPCMD 4 | ||
60 | 65 | ||
61 | /* RSPI on RZ only */ | 66 | /* RSPI on RZ only */ |
62 | #define RSPI_SPBFCR 0x20 /* Buffer Control Register */ | 67 | #define RSPI_SPBFCR 0x20 /* Buffer Control Register */ |
@@ -69,6 +74,7 @@ | |||
69 | #define QSPI_SPBMUL1 0x20 /* Transfer Data Length Multiplier Setting Register 1 */ | 74 | #define QSPI_SPBMUL1 0x20 /* Transfer Data Length Multiplier Setting Register 1 */ |
70 | #define QSPI_SPBMUL2 0x24 /* Transfer Data Length Multiplier Setting Register 2 */ | 75 | #define QSPI_SPBMUL2 0x24 /* Transfer Data Length Multiplier Setting Register 2 */ |
71 | #define QSPI_SPBMUL3 0x28 /* Transfer Data Length Multiplier Setting Register 3 */ | 76 | #define QSPI_SPBMUL3 0x28 /* Transfer Data Length Multiplier Setting Register 3 */ |
77 | #define QSPI_SPBMUL(i) (QSPI_SPBMUL0 + (i) * 4) | ||
72 | 78 | ||
73 | /* SPCR - Control Register */ | 79 | /* SPCR - Control Register */ |
74 | #define SPCR_SPRIE 0x80 /* Receive Interrupt Enable */ | 80 | #define SPCR_SPRIE 0x80 /* Receive Interrupt Enable */ |
@@ -152,7 +158,7 @@ | |||
152 | #define SPCMD_LSBF 0x1000 /* LSB First */ | 158 | #define SPCMD_LSBF 0x1000 /* LSB First */ |
153 | #define SPCMD_SPB_MASK 0x0f00 /* Data Length Setting */ | 159 | #define SPCMD_SPB_MASK 0x0f00 /* Data Length Setting */ |
154 | #define SPCMD_SPB_8_TO_16(bit) (((bit - 1) << 8) & SPCMD_SPB_MASK) | 160 | #define SPCMD_SPB_8_TO_16(bit) (((bit - 1) << 8) & SPCMD_SPB_MASK) |
155 | #define SPCMD_SPB_8BIT 0x0000 /* qspi only */ | 161 | #define SPCMD_SPB_8BIT 0x0000 /* QSPI only */ |
156 | #define SPCMD_SPB_16BIT 0x0100 | 162 | #define SPCMD_SPB_16BIT 0x0100 |
157 | #define SPCMD_SPB_20BIT 0x0000 | 163 | #define SPCMD_SPB_20BIT 0x0000 |
158 | #define SPCMD_SPB_24BIT 0x0100 | 164 | #define SPCMD_SPB_24BIT 0x0100 |
@@ -245,6 +251,7 @@ struct spi_ops { | |||
245 | int (*set_config_register)(struct rspi_data *rspi, int access_size); | 251 | int (*set_config_register)(struct rspi_data *rspi, int access_size); |
246 | int (*transfer_one)(struct spi_master *master, struct spi_device *spi, | 252 | int (*transfer_one)(struct spi_master *master, struct spi_device *spi, |
247 | struct spi_transfer *xfer); | 253 | struct spi_transfer *xfer); |
254 | u16 mode_bits; | ||
248 | }; | 255 | }; |
249 | 256 | ||
250 | /* | 257 | /* |
@@ -274,8 +281,8 @@ static int rspi_set_config_register(struct rspi_data *rspi, int access_size) | |||
274 | rspi_write8(rspi, 0x00, RSPI_SPCR2); | 281 | rspi_write8(rspi, 0x00, RSPI_SPCR2); |
275 | 282 | ||
276 | /* Sets SPCMD */ | 283 | /* Sets SPCMD */ |
277 | rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | rspi->spcmd, | 284 | rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size); |
278 | RSPI_SPCMD0); | 285 | rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0); |
279 | 286 | ||
280 | /* Sets RSPI mode */ | 287 | /* Sets RSPI mode */ |
281 | rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR); | 288 | rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR); |
@@ -321,7 +328,6 @@ static int rspi_rz_set_config_register(struct rspi_data *rspi, int access_size) | |||
321 | */ | 328 | */ |
322 | static int qspi_set_config_register(struct rspi_data *rspi, int access_size) | 329 | static int qspi_set_config_register(struct rspi_data *rspi, int access_size) |
323 | { | 330 | { |
324 | u16 spcmd; | ||
325 | int spbr; | 331 | int spbr; |
326 | 332 | ||
327 | /* Sets output mode, MOSI signal, and (optionally) loopback */ | 333 | /* Sets output mode, MOSI signal, and (optionally) loopback */ |
@@ -342,13 +348,13 @@ static int qspi_set_config_register(struct rspi_data *rspi, int access_size) | |||
342 | 348 | ||
343 | /* Data Length Setting */ | 349 | /* Data Length Setting */ |
344 | if (access_size == 8) | 350 | if (access_size == 8) |
345 | spcmd = SPCMD_SPB_8BIT; | 351 | rspi->spcmd |= SPCMD_SPB_8BIT; |
346 | else if (access_size == 16) | 352 | else if (access_size == 16) |
347 | spcmd = SPCMD_SPB_16BIT; | 353 | rspi->spcmd |= SPCMD_SPB_16BIT; |
348 | else | 354 | else |
349 | spcmd = SPCMD_SPB_32BIT; | 355 | rspi->spcmd |= SPCMD_SPB_32BIT; |
350 | 356 | ||
351 | spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | rspi->spcmd | SPCMD_SPNDEN; | 357 | rspi->spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | SPCMD_SPNDEN; |
352 | 358 | ||
353 | /* Resets transfer data length */ | 359 | /* Resets transfer data length */ |
354 | rspi_write32(rspi, 0, QSPI_SPBMUL0); | 360 | rspi_write32(rspi, 0, QSPI_SPBMUL0); |
@@ -359,9 +365,9 @@ static int qspi_set_config_register(struct rspi_data *rspi, int access_size) | |||
359 | rspi_write8(rspi, 0x00, QSPI_SPBFCR); | 365 | rspi_write8(rspi, 0x00, QSPI_SPBFCR); |
360 | 366 | ||
361 | /* Sets SPCMD */ | 367 | /* Sets SPCMD */ |
362 | rspi_write16(rspi, spcmd, RSPI_SPCMD0); | 368 | rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0); |
363 | 369 | ||
364 | /* Enables SPI function in a master mode */ | 370 | /* Enables SPI function in master mode */ |
365 | rspi_write8(rspi, SPCR_SPE | SPCR_MSTR, RSPI_SPCR); | 371 | rspi_write8(rspi, SPCR_SPE | SPCR_MSTR, RSPI_SPCR); |
366 | 372 | ||
367 | return 0; | 373 | return 0; |
@@ -811,12 +817,55 @@ static int qspi_transfer_out_in(struct rspi_data *rspi, | |||
811 | return 0; | 817 | return 0; |
812 | } | 818 | } |
813 | 819 | ||
820 | static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer) | ||
821 | { | ||
822 | const u8 *buf = xfer->tx_buf; | ||
823 | unsigned int i; | ||
824 | int ret; | ||
825 | |||
826 | for (i = 0; i < xfer->len; i++) { | ||
827 | ret = rspi_data_out(rspi, *buf++); | ||
828 | if (ret < 0) | ||
829 | return ret; | ||
830 | } | ||
831 | |||
832 | /* Wait for the last transmission */ | ||
833 | rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); | ||
834 | |||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer) | ||
839 | { | ||
840 | u8 *buf = xfer->rx_buf; | ||
841 | unsigned int i; | ||
842 | int ret; | ||
843 | |||
844 | for (i = 0; i < xfer->len; i++) { | ||
845 | ret = rspi_data_in(rspi); | ||
846 | if (ret < 0) | ||
847 | return ret; | ||
848 | *buf++ = ret; | ||
849 | } | ||
850 | |||
851 | return 0; | ||
852 | } | ||
853 | |||
814 | static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi, | 854 | static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi, |
815 | struct spi_transfer *xfer) | 855 | struct spi_transfer *xfer) |
816 | { | 856 | { |
817 | struct rspi_data *rspi = spi_master_get_devdata(master); | 857 | struct rspi_data *rspi = spi_master_get_devdata(master); |
818 | 858 | ||
819 | return qspi_transfer_out_in(rspi, xfer); | 859 | if (xfer->tx_buf && xfer->tx_nbits > SPI_NBITS_SINGLE) { |
860 | /* Quad or Dual SPI Write */ | ||
861 | return qspi_transfer_out(rspi, xfer); | ||
862 | } else if (xfer->rx_buf && xfer->rx_nbits > SPI_NBITS_SINGLE) { | ||
863 | /* Quad or Dual SPI Read */ | ||
864 | return qspi_transfer_in(rspi, xfer); | ||
865 | } else { | ||
866 | /* Single SPI Transfer */ | ||
867 | return qspi_transfer_out_in(rspi, xfer); | ||
868 | } | ||
820 | } | 869 | } |
821 | 870 | ||
822 | static int rspi_setup(struct spi_device *spi) | 871 | static int rspi_setup(struct spi_device *spi) |
@@ -845,21 +894,101 @@ static void rspi_cleanup(struct spi_device *spi) | |||
845 | { | 894 | { |
846 | } | 895 | } |
847 | 896 | ||
897 | static u16 qspi_transfer_mode(const struct spi_transfer *xfer) | ||
898 | { | ||
899 | if (xfer->tx_buf) | ||
900 | switch (xfer->tx_nbits) { | ||
901 | case SPI_NBITS_QUAD: | ||
902 | return SPCMD_SPIMOD_QUAD; | ||
903 | case SPI_NBITS_DUAL: | ||
904 | return SPCMD_SPIMOD_DUAL; | ||
905 | default: | ||
906 | return 0; | ||
907 | } | ||
908 | if (xfer->rx_buf) | ||
909 | switch (xfer->rx_nbits) { | ||
910 | case SPI_NBITS_QUAD: | ||
911 | return SPCMD_SPIMOD_QUAD | SPCMD_SPRW; | ||
912 | case SPI_NBITS_DUAL: | ||
913 | return SPCMD_SPIMOD_DUAL | SPCMD_SPRW; | ||
914 | default: | ||
915 | return 0; | ||
916 | } | ||
917 | |||
918 | return 0; | ||
919 | } | ||
920 | |||
921 | static int qspi_setup_sequencer(struct rspi_data *rspi, | ||
922 | const struct spi_message *msg) | ||
923 | { | ||
924 | const struct spi_transfer *xfer; | ||
925 | unsigned int i = 0, len = 0; | ||
926 | u16 current_mode = 0xffff, mode; | ||
927 | |||
928 | list_for_each_entry(xfer, &msg->transfers, transfer_list) { | ||
929 | mode = qspi_transfer_mode(xfer); | ||
930 | if (mode == current_mode) { | ||
931 | len += xfer->len; | ||
932 | continue; | ||
933 | } | ||
934 | |||
935 | /* Transfer mode change */ | ||
936 | if (i) { | ||
937 | /* Set transfer data length of previous transfer */ | ||
938 | rspi_write32(rspi, len, QSPI_SPBMUL(i - 1)); | ||
939 | } | ||
940 | |||
941 | if (i >= QSPI_NUM_SPCMD) { | ||
942 | dev_err(&msg->spi->dev, | ||
943 | "Too many different transfer modes"); | ||
944 | return -EINVAL; | ||
945 | } | ||
946 | |||
947 | /* Program transfer mode for this transfer */ | ||
948 | rspi_write16(rspi, rspi->spcmd | mode, RSPI_SPCMD(i)); | ||
949 | current_mode = mode; | ||
950 | len = xfer->len; | ||
951 | i++; | ||
952 | } | ||
953 | if (i) { | ||
954 | /* Set final transfer data length and sequence length */ | ||
955 | rspi_write32(rspi, len, QSPI_SPBMUL(i - 1)); | ||
956 | rspi_write8(rspi, i - 1, RSPI_SPSCR); | ||
957 | } | ||
958 | |||
959 | return 0; | ||
960 | } | ||
961 | |||
848 | static int rspi_prepare_message(struct spi_master *master, | 962 | static int rspi_prepare_message(struct spi_master *master, |
849 | struct spi_message *message) | 963 | struct spi_message *msg) |
850 | { | 964 | { |
851 | struct rspi_data *rspi = spi_master_get_devdata(master); | 965 | struct rspi_data *rspi = spi_master_get_devdata(master); |
966 | int ret; | ||
852 | 967 | ||
968 | if (msg->spi->mode & | ||
969 | (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)) { | ||
970 | /* Setup sequencer for messages with multiple transfer modes */ | ||
971 | ret = qspi_setup_sequencer(rspi, msg); | ||
972 | if (ret < 0) | ||
973 | return ret; | ||
974 | } | ||
975 | |||
976 | /* Enable SPI function in master mode */ | ||
853 | rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR); | 977 | rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR); |
854 | return 0; | 978 | return 0; |
855 | } | 979 | } |
856 | 980 | ||
857 | static int rspi_unprepare_message(struct spi_master *master, | 981 | static int rspi_unprepare_message(struct spi_master *master, |
858 | struct spi_message *message) | 982 | struct spi_message *msg) |
859 | { | 983 | { |
860 | struct rspi_data *rspi = spi_master_get_devdata(master); | 984 | struct rspi_data *rspi = spi_master_get_devdata(master); |
861 | 985 | ||
986 | /* Disable SPI function */ | ||
862 | rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR); | 987 | rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR); |
988 | |||
989 | /* Reset sequencer for Single SPI Transfers */ | ||
990 | rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0); | ||
991 | rspi_write8(rspi, 0, RSPI_SPSCR); | ||
863 | return 0; | 992 | return 0; |
864 | } | 993 | } |
865 | 994 | ||
@@ -989,16 +1118,21 @@ static int rspi_remove(struct platform_device *pdev) | |||
989 | static const struct spi_ops rspi_ops = { | 1118 | static const struct spi_ops rspi_ops = { |
990 | .set_config_register = rspi_set_config_register, | 1119 | .set_config_register = rspi_set_config_register, |
991 | .transfer_one = rspi_transfer_one, | 1120 | .transfer_one = rspi_transfer_one, |
1121 | .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP, | ||
992 | }; | 1122 | }; |
993 | 1123 | ||
994 | static const struct spi_ops rspi_rz_ops = { | 1124 | static const struct spi_ops rspi_rz_ops = { |
995 | .set_config_register = rspi_rz_set_config_register, | 1125 | .set_config_register = rspi_rz_set_config_register, |
996 | .transfer_one = rspi_rz_transfer_one, | 1126 | .transfer_one = rspi_rz_transfer_one, |
1127 | .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP, | ||
997 | }; | 1128 | }; |
998 | 1129 | ||
999 | static const struct spi_ops qspi_ops = { | 1130 | static const struct spi_ops qspi_ops = { |
1000 | .set_config_register = qspi_set_config_register, | 1131 | .set_config_register = qspi_set_config_register, |
1001 | .transfer_one = qspi_transfer_one, | 1132 | .transfer_one = qspi_transfer_one, |
1133 | .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP | | ||
1134 | SPI_TX_DUAL | SPI_TX_QUAD | | ||
1135 | SPI_RX_DUAL | SPI_RX_QUAD, | ||
1002 | }; | 1136 | }; |
1003 | 1137 | ||
1004 | #ifdef CONFIG_OF | 1138 | #ifdef CONFIG_OF |
@@ -1120,7 +1254,7 @@ static int rspi_probe(struct platform_device *pdev) | |||
1120 | master->cleanup = rspi_cleanup; | 1254 | master->cleanup = rspi_cleanup; |
1121 | master->prepare_message = rspi_prepare_message; | 1255 | master->prepare_message = rspi_prepare_message; |
1122 | master->unprepare_message = rspi_unprepare_message; | 1256 | master->unprepare_message = rspi_unprepare_message; |
1123 | master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP; | 1257 | master->mode_bits = ops->mode_bits; |
1124 | master->dev.of_node = pdev->dev.of_node; | 1258 | master->dev.of_node = pdev->dev.of_node; |
1125 | 1259 | ||
1126 | ret = platform_get_irq_byname(pdev, "rx"); | 1260 | ret = platform_get_irq_byname(pdev, "rx"); |