]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
spi: bitbang: Implement support for MOSI idle state configuration
authorMarcelo Schmitt <marcelo.schmitt@analog.com>
Fri, 12 Jul 2024 19:21:03 +0000 (16:21 -0300)
committerMark Brown <broonie@kernel.org>
Mon, 29 Jul 2024 00:19:52 +0000 (01:19 +0100)
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>
drivers/spi/spi-bitbang.c
include/linux/spi/spi_bitbang.h

index afb1b1105ec2b012a4c97f91b6d4086597fdc936..ebe18f0b5d23e42006ed9d59f4f3eebfaa6518d4 100644 (file)
@@ -54,21 +54,28 @@ static unsigned int bitbang_txrx_8(struct spi_device *spi,
        struct spi_transfer     *t,
        unsigned int flags)
 {
+       struct spi_bitbang      *bitbang;
        unsigned int            bits = t->bits_per_word;
        unsigned int            count = t->len;
        const u8                *tx = t->tx_buf;
        u8                      *rx = t->rx_buf;
 
+       bitbang = spi_controller_get_devdata(spi->controller);
        while (likely(count > 0)) {
                u8              word = 0;
 
                if (tx)
                        word = *tx++;
+               else
+                       word = spi->mode & SPI_MOSI_IDLE_HIGH ? 0xFF : 0;
                word = txrx_word(spi, ns, word, bits, flags);
                if (rx)
                        *rx++ = word;
                count -= 1;
        }
+       if (bitbang->set_mosi_idle)
+               bitbang->set_mosi_idle(spi);
+
        return t->len - count;
 }
 
@@ -78,21 +85,28 @@ static unsigned int bitbang_txrx_16(struct spi_device *spi,
        struct spi_transfer     *t,
        unsigned int flags)
 {
+       struct spi_bitbang      *bitbang;
        unsigned int            bits = t->bits_per_word;
        unsigned int            count = t->len;
        const u16               *tx = t->tx_buf;
        u16                     *rx = t->rx_buf;
 
+       bitbang = spi_controller_get_devdata(spi->controller);
        while (likely(count > 1)) {
                u16             word = 0;
 
                if (tx)
                        word = *tx++;
+               else
+                       word = spi->mode & SPI_MOSI_IDLE_HIGH ? 0xFFFF : 0;
                word = txrx_word(spi, ns, word, bits, flags);
                if (rx)
                        *rx++ = word;
                count -= 2;
        }
+       if (bitbang->set_mosi_idle)
+               bitbang->set_mosi_idle(spi);
+
        return t->len - count;
 }
 
@@ -102,21 +116,28 @@ static unsigned int bitbang_txrx_32(struct spi_device *spi,
        struct spi_transfer     *t,
        unsigned int flags)
 {
+       struct spi_bitbang      *bitbang;
        unsigned int            bits = t->bits_per_word;
        unsigned int            count = t->len;
        const u32               *tx = t->tx_buf;
        u32                     *rx = t->rx_buf;
 
+       bitbang = spi_controller_get_devdata(spi->controller);
        while (likely(count > 3)) {
                u32             word = 0;
 
                if (tx)
                        word = *tx++;
+               else
+                       word = spi->mode & SPI_MOSI_IDLE_HIGH ? 0xFFFFFFFF : 0;
                word = txrx_word(spi, ns, word, bits, flags);
                if (rx)
                        *rx++ = word;
                count -= 4;
        }
+       if (bitbang->set_mosi_idle)
+               bitbang->set_mosi_idle(spi);
+
        return t->len - count;
 }
 
@@ -192,6 +213,9 @@ int spi_bitbang_setup(struct spi_device *spi)
                        goto err_free;
        }
 
+       if (bitbang->set_mosi_idle)
+               bitbang->set_mosi_idle(spi);
+
        dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs);
 
        return 0;
index d4cb83195f7a9a9a6d3143b13da40b4237bb30c3..c92cd43a47f421f8a89d5f16ebf43514aa177d86 100644 (file)
@@ -24,6 +24,7 @@ struct spi_bitbang {
 #define        BITBANG_CS_ACTIVE       1       /* normally nCS, active low */
 #define        BITBANG_CS_INACTIVE     0
 
+       void    (*set_mosi_idle)(struct spi_device *spi);
        /* txrx_bufs() may handle dma mapping for transfers that don't
         * already have one (transfer.{tx,rx}_dma is zero), or use PIO
         */