mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 04:34:08 +08:00
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>
This commit is contained in:
parent
f58872f45c
commit
320f669309
@ -54,21 +54,28 @@ static unsigned int bitbang_txrx_8(struct spi_device *spi,
|
|||||||
struct spi_transfer *t,
|
struct spi_transfer *t,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
|
struct spi_bitbang *bitbang;
|
||||||
unsigned int bits = t->bits_per_word;
|
unsigned int bits = t->bits_per_word;
|
||||||
unsigned int count = t->len;
|
unsigned int count = t->len;
|
||||||
const u8 *tx = t->tx_buf;
|
const u8 *tx = t->tx_buf;
|
||||||
u8 *rx = t->rx_buf;
|
u8 *rx = t->rx_buf;
|
||||||
|
|
||||||
|
bitbang = spi_controller_get_devdata(spi->controller);
|
||||||
while (likely(count > 0)) {
|
while (likely(count > 0)) {
|
||||||
u8 word = 0;
|
u8 word = 0;
|
||||||
|
|
||||||
if (tx)
|
if (tx)
|
||||||
word = *tx++;
|
word = *tx++;
|
||||||
|
else
|
||||||
|
word = spi->mode & SPI_MOSI_IDLE_HIGH ? 0xFF : 0;
|
||||||
word = txrx_word(spi, ns, word, bits, flags);
|
word = txrx_word(spi, ns, word, bits, flags);
|
||||||
if (rx)
|
if (rx)
|
||||||
*rx++ = word;
|
*rx++ = word;
|
||||||
count -= 1;
|
count -= 1;
|
||||||
}
|
}
|
||||||
|
if (bitbang->set_mosi_idle)
|
||||||
|
bitbang->set_mosi_idle(spi);
|
||||||
|
|
||||||
return t->len - count;
|
return t->len - count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,21 +85,28 @@ static unsigned int bitbang_txrx_16(struct spi_device *spi,
|
|||||||
struct spi_transfer *t,
|
struct spi_transfer *t,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
|
struct spi_bitbang *bitbang;
|
||||||
unsigned int bits = t->bits_per_word;
|
unsigned int bits = t->bits_per_word;
|
||||||
unsigned int count = t->len;
|
unsigned int count = t->len;
|
||||||
const u16 *tx = t->tx_buf;
|
const u16 *tx = t->tx_buf;
|
||||||
u16 *rx = t->rx_buf;
|
u16 *rx = t->rx_buf;
|
||||||
|
|
||||||
|
bitbang = spi_controller_get_devdata(spi->controller);
|
||||||
while (likely(count > 1)) {
|
while (likely(count > 1)) {
|
||||||
u16 word = 0;
|
u16 word = 0;
|
||||||
|
|
||||||
if (tx)
|
if (tx)
|
||||||
word = *tx++;
|
word = *tx++;
|
||||||
|
else
|
||||||
|
word = spi->mode & SPI_MOSI_IDLE_HIGH ? 0xFFFF : 0;
|
||||||
word = txrx_word(spi, ns, word, bits, flags);
|
word = txrx_word(spi, ns, word, bits, flags);
|
||||||
if (rx)
|
if (rx)
|
||||||
*rx++ = word;
|
*rx++ = word;
|
||||||
count -= 2;
|
count -= 2;
|
||||||
}
|
}
|
||||||
|
if (bitbang->set_mosi_idle)
|
||||||
|
bitbang->set_mosi_idle(spi);
|
||||||
|
|
||||||
return t->len - count;
|
return t->len - count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,21 +116,28 @@ static unsigned int bitbang_txrx_32(struct spi_device *spi,
|
|||||||
struct spi_transfer *t,
|
struct spi_transfer *t,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
|
struct spi_bitbang *bitbang;
|
||||||
unsigned int bits = t->bits_per_word;
|
unsigned int bits = t->bits_per_word;
|
||||||
unsigned int count = t->len;
|
unsigned int count = t->len;
|
||||||
const u32 *tx = t->tx_buf;
|
const u32 *tx = t->tx_buf;
|
||||||
u32 *rx = t->rx_buf;
|
u32 *rx = t->rx_buf;
|
||||||
|
|
||||||
|
bitbang = spi_controller_get_devdata(spi->controller);
|
||||||
while (likely(count > 3)) {
|
while (likely(count > 3)) {
|
||||||
u32 word = 0;
|
u32 word = 0;
|
||||||
|
|
||||||
if (tx)
|
if (tx)
|
||||||
word = *tx++;
|
word = *tx++;
|
||||||
|
else
|
||||||
|
word = spi->mode & SPI_MOSI_IDLE_HIGH ? 0xFFFFFFFF : 0;
|
||||||
word = txrx_word(spi, ns, word, bits, flags);
|
word = txrx_word(spi, ns, word, bits, flags);
|
||||||
if (rx)
|
if (rx)
|
||||||
*rx++ = word;
|
*rx++ = word;
|
||||||
count -= 4;
|
count -= 4;
|
||||||
}
|
}
|
||||||
|
if (bitbang->set_mosi_idle)
|
||||||
|
bitbang->set_mosi_idle(spi);
|
||||||
|
|
||||||
return t->len - count;
|
return t->len - count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,6 +213,9 @@ int spi_bitbang_setup(struct spi_device *spi)
|
|||||||
goto err_free;
|
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);
|
dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -24,6 +24,7 @@ struct spi_bitbang {
|
|||||||
#define BITBANG_CS_ACTIVE 1 /* normally nCS, active low */
|
#define BITBANG_CS_ACTIVE 1 /* normally nCS, active low */
|
||||||
#define BITBANG_CS_INACTIVE 0
|
#define BITBANG_CS_INACTIVE 0
|
||||||
|
|
||||||
|
void (*set_mosi_idle)(struct spi_device *spi);
|
||||||
/* txrx_bufs() may handle dma mapping for transfers that don't
|
/* txrx_bufs() may handle dma mapping for transfers that don't
|
||||||
* already have one (transfer.{tx,rx}_dma is zero), or use PIO
|
* already have one (transfer.{tx,rx}_dma is zero), or use PIO
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user