From: Marcin Wojtas <mw@xxxxxxxxxxxx> Some SPI devices, such as SLIC (Subscriber Line Interface Card) require toggling the CS every transferred byte. Enable such possibility by creating a new DT property and enabling SPI device mode update. Add according support in the spi-orion driver. Signed-off-by: Marcin Wojtas <mw@xxxxxxxxxxxx> Signed-off-by: Konstantin Porotchkin <kostap@xxxxxxxxxxx> --- drivers/spi/spi-orion.c | 20 +++++++++++++++++++- drivers/spi/spi.c | 6 ++++-- include/linux/spi/spi.h | 1 + 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 3bfda4225d45..7db9034b0879 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -369,8 +369,15 @@ orion_spi_write_read_8bit(struct spi_device *spi, { void __iomem *tx_reg, *rx_reg, *int_reg; struct orion_spi *orion_spi; + bool cs_single_byte; + + cs_single_byte = spi->mode & SPI_1BYTE_CS; orion_spi = spi_master_get_devdata(spi->master); + + if (cs_single_byte) + orion_spi_set_cs(spi, 0); + tx_reg = spi_reg(orion_spi, ORION_SPI_DATA_OUT_REG); rx_reg = spi_reg(orion_spi, ORION_SPI_DATA_IN_REG); int_reg = spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG); @@ -384,6 +391,11 @@ orion_spi_write_read_8bit(struct spi_device *spi, writel(0, tx_reg); if (orion_spi_wait_till_ready(orion_spi) < 0) { + if (cs_single_byte) { + orion_spi_set_cs(spi, 1); + /* Satisfy some SLIC devices requirements */ + udelay(4); + } dev_err(&spi->dev, "TXS timed out\n"); return -1; } @@ -391,6 +403,12 @@ orion_spi_write_read_8bit(struct spi_device *spi, if (rx_buf && *rx_buf) *(*rx_buf)++ = readl(rx_reg); + if (cs_single_byte) { + orion_spi_set_cs(spi, 1); + /* Satisfy some SLIC devices requirements */ + udelay(4); + } + return 1; } @@ -626,7 +644,7 @@ static int orion_spi_probe(struct platform_device *pdev) } /* we support all 4 SPI modes and LSB first option */ - master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST; + master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST | SPI_1BYTE_CS; master->set_cs = orion_spi_set_cs; master->transfer_one = orion_spi_transfer_one; master->num_chipselect = ORION_NUM_CHIPSELECTS; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 51d7c004fbab..998579807a04 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1937,6 +1937,8 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, spi->mode |= SPI_LSB_FIRST; if (of_property_read_bool(nc, "spi-cs-high")) spi->mode |= SPI_CS_HIGH; + if (of_find_property(nc, "spi-1byte-cs", NULL)) + spi->mode |= SPI_1BYTE_CS; /* Device DUAL/QUAD mode */ if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) { @@ -3419,15 +3421,15 @@ int spi_setup(struct spi_device *spi) spi_set_thread_rt(spi->controller); } - dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s%u bits/w, %u Hz max --> %d\n", + dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s%s%u bits/w, %u Hz max --> %d\n", (int) (spi->mode & (SPI_CPOL | SPI_CPHA)), (spi->mode & SPI_CS_HIGH) ? "cs_high, " : "", (spi->mode & SPI_LSB_FIRST) ? "lsb, " : "", (spi->mode & SPI_3WIRE) ? "3wire, " : "", (spi->mode & SPI_LOOP) ? "loopback, " : "", + (spi->mode & SPI_1BYTE_CS) ? "single_cs_byte, " : "", spi->bits_per_word, spi->max_speed_hz, status); - return status; } EXPORT_SYMBOL_GPL(spi_setup); diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index aa09fdc8042d..7f65ff6fc25d 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -186,6 +186,7 @@ struct spi_device { #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 */ +#define SPI_1BYTE_CS 0x10000 /* toggle cs after each byte */ int irq; void *controller_state; void *controller_data; -- 2.17.1