spi: soft_spi: Add support for SPI_3WIRE

When 3-wire mode is claimed on the bus, use the MOSI (output) pin to
receive data. In this mode, since the transfer can only be either TX
or RX, return -EINVAL if both are required at the same time.

Signed-off-by: Hironori KIKUCHI <kikuchan98@gmail.com>
This commit is contained in:
Hironori KIKUCHI 2025-01-31 10:38:41 +09:00 committed by Tom Rini
parent 8fe2c68c32
commit 064556910e

View file

@ -124,8 +124,19 @@ static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen,
u8 *rxd = din; u8 *rxd = din;
int cpha = !!(priv->mode & SPI_CPHA); int cpha = !!(priv->mode & SPI_CPHA);
int cidle = !!(priv->mode & SPI_CPOL); int cidle = !!(priv->mode & SPI_CPOL);
int txrx = plat->flags;
unsigned int j; unsigned int j;
if (priv->mode & SPI_3WIRE) {
if (txd && rxd)
return -EINVAL;
txrx = txd ? SPI_MASTER_NO_RX : SPI_MASTER_NO_TX;
dm_gpio_set_dir_flags(&plat->mosi,
txd ? GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE :
GPIOD_IS_IN | GPIOD_PULL_UP);
}
debug("spi_xfer: slave %s:%s dout %08X din %08X bitlen %u\n", debug("spi_xfer: slave %s:%s dout %08X din %08X bitlen %u\n",
dev->parent->name, dev->name, *(uint *)txd, *(uint *)rxd, dev->parent->name, dev->name, *(uint *)txd, *(uint *)rxd,
bitlen); bitlen);
@ -160,7 +171,7 @@ static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen,
*/ */
if (cpha) if (cpha)
soft_spi_scl(dev, !cidle); soft_spi_scl(dev, !cidle);
if ((plat->flags & SPI_MASTER_NO_TX) == 0) if ((txrx & SPI_MASTER_NO_TX) == 0)
soft_spi_sda(dev, !!(tmpdout & 0x80)); soft_spi_sda(dev, !!(tmpdout & 0x80));
udelay(plat->spi_delay_us); udelay(plat->spi_delay_us);
@ -174,8 +185,10 @@ static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen,
else else
soft_spi_scl(dev, cidle); soft_spi_scl(dev, cidle);
tmpdin <<= 1; tmpdin <<= 1;
if ((plat->flags & SPI_MASTER_NO_RX) == 0) if ((txrx & SPI_MASTER_NO_RX) == 0)
tmpdin |= dm_gpio_get_value(&plat->miso); tmpdin |= dm_gpio_get_value((priv->mode & SPI_3WIRE) ?
&plat->mosi :
&plat->miso);
tmpdout <<= 1; tmpdout <<= 1;
udelay(plat->spi_delay_us); udelay(plat->spi_delay_us);