diff mbox series

[v2,2/2] spi: orion: enable support for switching CS every transferred byte

Message ID 20201217170933.10717-3-kostap@marvell.com (mailing list archive)
State Superseded
Headers show
Series spi: new feature and fix for Marvell Orion driver | expand

Commit Message

Kostya Porotchkin Dec. 17, 2020, 5:09 p.m. UTC
From: Marcin Wojtas <mw@semihalf.com>

Some SPI devices, require toggling the CS every transferred byte.
Enable such possibility in the spi-orion driver.

Note that in order to use it, in the driver of a secondary device
attached to this controller, the SPI bus 'mode' field must be
updated with SPI_CS_WORD flag before calling spi_setup() routine.

In addition to that include a work-around - some devices, such as
certain models of SLIC (Subscriber Line Interface Card),
may require extra delay after CS toggling, so add a minimal
timing relaxation in relevant places.

Signed-off-by: Marcin Wojtas <mw@semihalf.com>
Signed-off-by: Konstantin Porotchkin <kostap@marvell.com>
---
 drivers/spi/spi-orion.c | 24 +++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

Comments

Mark Brown Dec. 17, 2020, 5:42 p.m. UTC | #1
On Thu, Dec 17, 2020 at 07:09:32PM +0200, kostap@marvell.com wrote:

> +++ b/drivers/spi/spi-orion.c
> @@ -369,8 +369,15 @@ orion_spi_write_read_8bit(struct spi_device *spi,
>  {

This is only supporting SPI_CS_WORD for 8 bit operations but the driver
also supports 16 bit words, it should at least report an error if
there's an attempt to use SPI_CS_WORD for 16 bit transfers.  It also
looks like this won't work on systems where direct access is supported
since those use a separate I/O path, that can be fixed by just adding an
additional check when deciding to go down that path.

The driver should also pay attention to SPI_CS_HIGH if it's going to try
to control chip select by hand as it does, which is generally frowned
upon.  TBH I'm wondering if it might not be better to just rely on the
core support for implementing SPI_CS_WORD on controllers that can't do
it in hardware - it *is* much higher overhead since it needs to split
the transfers up but it depends how performance critical and frequent
access to such devices is likely to be.
diff mbox series

Patch

diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index 3bfda4225d45..0f92dd026bee 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_CS_WORD;
 
 	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,16 @@  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);
+		/*
+		 * Some devices, such as certain models of SLIC
+		 * (Subscriber Line Interface Card)
+		 * may require extra delay after CS toggling.
+		 */
+		udelay(4);
+	}
+
 	return 1;
 }
 
@@ -626,7 +648,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_CS_WORD;
 	master->set_cs = orion_spi_set_cs;
 	master->transfer_one = orion_spi_transfer_one;
 	master->num_chipselect = ORION_NUM_CHIPSELECTS;