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

spi: bitbang: Implement support for MOSI idle state configuration

Some SPI peripherals may require strict MOSI line state when the controller
is not clocking out data. Implement support for MOSI idle state
configuration (low or high) by setting the data output line level on
controller setup and after transfers. Bitbang operations now call
controller specific set_mosi_idle() callback to set MOSI to its idle state.
The MOSI line is kept at its idle state if no tx buffer is provided.

Acked-by: Nuno Sa <nuno.sa@analog.com>
Reviewed-by: David Lechner <dlechner@baylibre.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
Link: https://patch.msgid.link/de61a600b56ed9cb714d5ea87afa88948e70041e.1720810545.git.marcelo.schmitt@analog.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Marcelo Schmitt and committed by
Mark Brown
320f6693 f58872f4

+25
+24
drivers/spi/spi-bitbang.c
··· 54 54 struct spi_transfer *t, 55 55 unsigned int flags) 56 56 { 57 + struct spi_bitbang *bitbang; 57 58 unsigned int bits = t->bits_per_word; 58 59 unsigned int count = t->len; 59 60 const u8 *tx = t->tx_buf; 60 61 u8 *rx = t->rx_buf; 61 62 63 + bitbang = spi_controller_get_devdata(spi->controller); 62 64 while (likely(count > 0)) { 63 65 u8 word = 0; 64 66 65 67 if (tx) 66 68 word = *tx++; 69 + else 70 + word = spi->mode & SPI_MOSI_IDLE_HIGH ? 0xFF : 0; 67 71 word = txrx_word(spi, ns, word, bits, flags); 68 72 if (rx) 69 73 *rx++ = word; 70 74 count -= 1; 71 75 } 76 + if (bitbang->set_mosi_idle) 77 + bitbang->set_mosi_idle(spi); 78 + 72 79 return t->len - count; 73 80 } 74 81 ··· 85 78 struct spi_transfer *t, 86 79 unsigned int flags) 87 80 { 81 + struct spi_bitbang *bitbang; 88 82 unsigned int bits = t->bits_per_word; 89 83 unsigned int count = t->len; 90 84 const u16 *tx = t->tx_buf; 91 85 u16 *rx = t->rx_buf; 92 86 87 + bitbang = spi_controller_get_devdata(spi->controller); 93 88 while (likely(count > 1)) { 94 89 u16 word = 0; 95 90 96 91 if (tx) 97 92 word = *tx++; 93 + else 94 + word = spi->mode & SPI_MOSI_IDLE_HIGH ? 0xFFFF : 0; 98 95 word = txrx_word(spi, ns, word, bits, flags); 99 96 if (rx) 100 97 *rx++ = word; 101 98 count -= 2; 102 99 } 100 + if (bitbang->set_mosi_idle) 101 + bitbang->set_mosi_idle(spi); 102 + 103 103 return t->len - count; 104 104 } 105 105 ··· 116 102 struct spi_transfer *t, 117 103 unsigned int flags) 118 104 { 105 + struct spi_bitbang *bitbang; 119 106 unsigned int bits = t->bits_per_word; 120 107 unsigned int count = t->len; 121 108 const u32 *tx = t->tx_buf; 122 109 u32 *rx = t->rx_buf; 123 110 111 + bitbang = spi_controller_get_devdata(spi->controller); 124 112 while (likely(count > 3)) { 125 113 u32 word = 0; 126 114 127 115 if (tx) 128 116 word = *tx++; 117 + else 118 + word = spi->mode & SPI_MOSI_IDLE_HIGH ? 0xFFFFFFFF : 0; 129 119 word = txrx_word(spi, ns, word, bits, flags); 130 120 if (rx) 131 121 *rx++ = word; 132 122 count -= 4; 133 123 } 124 + if (bitbang->set_mosi_idle) 125 + bitbang->set_mosi_idle(spi); 126 + 134 127 return t->len - count; 135 128 } 136 129 ··· 212 191 if (retval < 0) 213 192 goto err_free; 214 193 } 194 + 195 + if (bitbang->set_mosi_idle) 196 + bitbang->set_mosi_idle(spi); 215 197 216 198 dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs); 217 199
+1
include/linux/spi/spi_bitbang.h
··· 24 24 #define BITBANG_CS_ACTIVE 1 /* normally nCS, active low */ 25 25 #define BITBANG_CS_INACTIVE 0 26 26 27 + void (*set_mosi_idle)(struct spi_device *spi); 27 28 /* txrx_bufs() may handle dma mapping for transfers that don't 28 29 * already have one (transfer.{tx,rx}_dma is zero), or use PIO 29 30 */