diff options
-rw-r--r-- | drivers/spi/spi-gpio.c | 24 | ||||
-rw-r--r-- | include/linux/spi/spi.h | 1 |
2 files changed, 22 insertions, 3 deletions
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 45973ee3ae11..a4aee26028cd 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -256,11 +256,29 @@ static int spi_gpio_setup(struct spi_device *spi) static int spi_gpio_set_direction(struct spi_device *spi, bool output) { struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); + int ret; if (output) return gpiod_direction_output(spi_gpio->mosi, 1); - else - return gpiod_direction_input(spi_gpio->mosi); + + ret = gpiod_direction_input(spi_gpio->mosi); + if (ret) + return ret; + /* + * Send a turnaround high impedance cycle when switching + * from output to input. Theoretically there should be + * a clock delay here, but as has been noted above, the + * nsec delay function for bit-banged GPIO is simply + * {} because bit-banging just doesn't get fast enough + * anyway. + */ + if (spi->mode & SPI_3WIRE_HIZ) { + gpiod_set_value_cansleep(spi_gpio->sck, + !(spi->mode & SPI_CPOL)); + gpiod_set_value_cansleep(spi_gpio->sck, + !!(spi->mode & SPI_CPOL)); + } + return 0; } static void spi_gpio_cleanup(struct spi_device *spi) @@ -410,7 +428,7 @@ static int spi_gpio_probe(struct platform_device *pdev) return status; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); - master->mode_bits = SPI_3WIRE | SPI_CPHA | SPI_CPOL; + master->mode_bits = SPI_3WIRE | SPI_3WIRE_HIZ | SPI_CPHA | SPI_CPOL; master->flags = master_flags; master->bus_num = pdev->id; /* The master needs to think there is a chipselect even if not connected */ diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 0c1ca5dedbb4..314d922ca607 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -157,6 +157,7 @@ struct spi_device { #define SPI_CS_WORD 0x1000 /* toggle cs after each word */ #define SPI_TX_OCTAL 0x2000 /* transmit with 8 wires */ #define SPI_RX_OCTAL 0x4000 /* receive with 8 wires */ +#define SPI_3WIRE_HIZ 0x8000 /* high impedance turnaround */ int irq; void *controller_state; void *controller_data; |