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

spi: bitbang: Fix lsb-first Rx

Shifting the recieved bit by "bits" inserts it at the top of the
*currently remaining* Tx data, so we end up accumulating the whole
transfer into bit 0 of the output word. Oops.

For the algorithm to work as intended, we need to remember where the
top of the *original* word was, and shift Rx to there.

Fixes: 1847e3046c52 ("spi: gpio: Implement LSB First bitbang support")
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Link: https://lore.kernel.org/r/28324d8622da80461cce35a82859b003d6f6c4b0.1659538737.git.robin.murphy@arm.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Robin Murphy and committed by
Mark Brown
46f7ac3d 568035b0

+4 -2
+4 -2
drivers/spi/spi-bitbang-txrx.h
··· 116 116 { 117 117 /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */ 118 118 119 + u8 rxbit = bits - 1; 119 120 u32 oldbit = !(word & 1); 120 121 /* clock starts at inactive polarity */ 121 122 for (; likely(bits); bits--) { ··· 136 135 /* sample LSB (from slave) on leading edge */ 137 136 word >>= 1; 138 137 if ((flags & SPI_MASTER_NO_RX) == 0) 139 - word |= getmiso(spi) << (bits - 1); 138 + word |= getmiso(spi) << rxbit; 140 139 setsck(spi, cpol); 141 140 } 142 141 return word; ··· 149 148 { 150 149 /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */ 151 150 151 + u8 rxbit = bits - 1; 152 152 u32 oldbit = !(word & 1); 153 153 /* clock starts at inactive polarity */ 154 154 for (; likely(bits); bits--) { ··· 170 168 /* sample LSB (from slave) on trailing edge */ 171 169 word >>= 1; 172 170 if ((flags & SPI_MASTER_NO_RX) == 0) 173 - word |= getmiso(spi) << (bits - 1); 171 + word |= getmiso(spi) << rxbit; 174 172 } 175 173 return word; 176 174 }