Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

spi: gpio: Implement LSB First bitbang support

Add support for slave DT property spi-lsb-first, i.e., SPI_LSB_FIRST mode.
Duplicate the inline helpers bitbang_txrx_be_cpha{0,1} as LE versions.
Conditionally call them from all the spi-gpio txrx_word callbacks.

Some alternatives to this implementation approach were discussed back
then [0], but eventually it was considered reasonable.

[0] https://lore.kernel.org/linux-arm-kernel/20191212033952.5967-8-afaerber@suse.de/

Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Tested-by: Christian Hewitt <christianshewitt@gmail.com>
Link: https://lore.kernel.org/r/feac3377-4ad1-77d8-9a18-3588d80fb909@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Andreas Färber and committed by
Mark Brown
1847e304 5741150c

+99 -9
+66
drivers/spi/spi-bitbang-txrx.h
··· 41 41 * chips need ... there may be several reasons you'd need to tweak timings 42 42 * in these routines, not just to make it faster or slower to match a 43 43 * particular CPU clock rate. 44 + * 45 + * ToDo: Maybe the bitrev macros can be used to improve the code? 44 46 */ 45 47 46 48 static inline u32 ··· 105 103 word <<= 1; 106 104 if ((flags & SPI_MASTER_NO_RX) == 0) 107 105 word |= getmiso(spi); 106 + } 107 + return word; 108 + } 109 + 110 + static inline u32 111 + bitbang_txrx_le_cpha0(struct spi_device *spi, 112 + unsigned int nsecs, unsigned int cpol, unsigned int flags, 113 + u32 word, u8 bits) 114 + { 115 + /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */ 116 + 117 + u32 oldbit = !(word & 1); 118 + /* clock starts at inactive polarity */ 119 + for (; likely(bits); bits--) { 120 + 121 + /* setup LSB (to slave) on trailing edge */ 122 + if ((flags & SPI_MASTER_NO_TX) == 0) { 123 + if ((word & 1) != oldbit) { 124 + setmosi(spi, word & 1); 125 + oldbit = word & 1; 126 + } 127 + } 128 + spidelay(nsecs); /* T(setup) */ 129 + 130 + setsck(spi, !cpol); 131 + spidelay(nsecs); 132 + 133 + /* sample LSB (from slave) on leading edge */ 134 + word >>= 1; 135 + if ((flags & SPI_MASTER_NO_RX) == 0) 136 + word |= getmiso(spi) << (bits - 1); 137 + setsck(spi, cpol); 138 + } 139 + return word; 140 + } 141 + 142 + static inline u32 143 + bitbang_txrx_le_cpha1(struct spi_device *spi, 144 + unsigned int nsecs, unsigned int cpol, unsigned int flags, 145 + u32 word, u8 bits) 146 + { 147 + /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */ 148 + 149 + u32 oldbit = !(word & 1); 150 + /* clock starts at inactive polarity */ 151 + for (; likely(bits); bits--) { 152 + 153 + /* setup LSB (to slave) on leading edge */ 154 + setsck(spi, !cpol); 155 + if ((flags & SPI_MASTER_NO_TX) == 0) { 156 + if ((word & 1) != oldbit) { 157 + setmosi(spi, word & 1); 158 + oldbit = word & 1; 159 + } 160 + } 161 + spidelay(nsecs); /* T(setup) */ 162 + 163 + setsck(spi, cpol); 164 + spidelay(nsecs); 165 + 166 + /* sample LSB (from slave) on trailing edge */ 167 + word >>= 1; 168 + if ((flags & SPI_MASTER_NO_RX) == 0) 169 + word |= getmiso(spi) << (bits - 1); 108 170 } 109 171 return word; 110 172 }
+33 -9
drivers/spi/spi-gpio.c
··· 135 135 static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi, 136 136 unsigned nsecs, u32 word, u8 bits, unsigned flags) 137 137 { 138 - return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits); 138 + if (unlikely(spi->mode & SPI_LSB_FIRST)) 139 + return bitbang_txrx_le_cpha0(spi, nsecs, 0, flags, word, bits); 140 + else 141 + return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits); 139 142 } 140 143 141 144 static u32 spi_gpio_txrx_word_mode1(struct spi_device *spi, 142 145 unsigned nsecs, u32 word, u8 bits, unsigned flags) 143 146 { 144 - return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits); 147 + if (unlikely(spi->mode & SPI_LSB_FIRST)) 148 + return bitbang_txrx_le_cpha1(spi, nsecs, 0, flags, word, bits); 149 + else 150 + return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits); 145 151 } 146 152 147 153 static u32 spi_gpio_txrx_word_mode2(struct spi_device *spi, 148 154 unsigned nsecs, u32 word, u8 bits, unsigned flags) 149 155 { 150 - return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits); 156 + if (unlikely(spi->mode & SPI_LSB_FIRST)) 157 + return bitbang_txrx_le_cpha0(spi, nsecs, 1, flags, word, bits); 158 + else 159 + return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits); 151 160 } 152 161 153 162 static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi, 154 163 unsigned nsecs, u32 word, u8 bits, unsigned flags) 155 164 { 156 - return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits); 165 + if (unlikely(spi->mode & SPI_LSB_FIRST)) 166 + return bitbang_txrx_le_cpha1(spi, nsecs, 1, flags, word, bits); 167 + else 168 + return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits); 157 169 } 158 170 159 171 /* ··· 182 170 unsigned nsecs, u32 word, u8 bits, unsigned flags) 183 171 { 184 172 flags = spi->master->flags; 185 - return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits); 173 + if (unlikely(spi->mode & SPI_LSB_FIRST)) 174 + return bitbang_txrx_le_cpha0(spi, nsecs, 0, flags, word, bits); 175 + else 176 + return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits); 186 177 } 187 178 188 179 static u32 spi_gpio_spec_txrx_word_mode1(struct spi_device *spi, 189 180 unsigned nsecs, u32 word, u8 bits, unsigned flags) 190 181 { 191 182 flags = spi->master->flags; 192 - return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits); 183 + if (unlikely(spi->mode & SPI_LSB_FIRST)) 184 + return bitbang_txrx_le_cpha1(spi, nsecs, 0, flags, word, bits); 185 + else 186 + return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits); 193 187 } 194 188 195 189 static u32 spi_gpio_spec_txrx_word_mode2(struct spi_device *spi, 196 190 unsigned nsecs, u32 word, u8 bits, unsigned flags) 197 191 { 198 192 flags = spi->master->flags; 199 - return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits); 193 + if (unlikely(spi->mode & SPI_LSB_FIRST)) 194 + return bitbang_txrx_le_cpha0(spi, nsecs, 1, flags, word, bits); 195 + else 196 + return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits); 200 197 } 201 198 202 199 static u32 spi_gpio_spec_txrx_word_mode3(struct spi_device *spi, 203 200 unsigned nsecs, u32 word, u8 bits, unsigned flags) 204 201 { 205 202 flags = spi->master->flags; 206 - return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits); 203 + if (unlikely(spi->mode & SPI_LSB_FIRST)) 204 + return bitbang_txrx_le_cpha1(spi, nsecs, 1, flags, word, bits); 205 + else 206 + return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits); 207 207 } 208 208 209 209 /*----------------------------------------------------------------------*/ ··· 402 378 403 379 master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); 404 380 master->mode_bits = SPI_3WIRE | SPI_3WIRE_HIZ | SPI_CPHA | SPI_CPOL | 405 - SPI_CS_HIGH; 381 + SPI_CS_HIGH | SPI_LSB_FIRST; 406 382 if (!spi_gpio->mosi) { 407 383 /* HW configuration without MOSI pin 408 384 *