diff mbox series

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

Message ID 20201217112708.3473-3-kostap@marvell.com
State New
Headers show
Series spi: new feature and fix for Marvell Orion driver | expand

Commit Message

Kostya Porotchkin Dec. 17, 2020, 11:27 a.m. UTC
From: Marcin Wojtas <mw@semihalf.com>

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@semihalf.com>
Signed-off-by: Konstantin Porotchkin <kostap@marvell.com>
---
 drivers/spi/spi-orion.c | 20 +++++++++++++++++++-
 drivers/spi/spi.c       |  6 ++++--
 include/linux/spi/spi.h |  1 +
 3 files changed, 24 insertions(+), 3 deletions(-)

Comments

Marcin Wojtas Dec. 17, 2020, 1:56 p.m. UTC | #1
Hi Mark,

czw., 17 gru 2020 o 12:27 <kostap@marvell.com> napisał(a):
>
> From: Marcin Wojtas <mw@semihalf.com>
>
> 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@semihalf.com>
> Signed-off-by: Konstantin Porotchkin <kostap@marvell.com>
> ---
>  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;

Regarding your comment from patch 3/3 that "spi-1byte-cs" should be
replaced by handling based on the compatible string - do you mean
dropping above parsing and updating SPI bus mode field with
SPI_1BYTE_CS flag in the relevant SPI device driver?

Best regards,
Marcin

>
>         /* 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
>
Mark Brown Dec. 17, 2020, 2:15 p.m. UTC | #2
On Thu, Dec 17, 2020 at 01:27:07PM +0200, kostap@marvell.com wrote:

> 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.

I'm pretty sure we already support this - if the client driver sets the
word length to 8 bits then SPI_CS_WORD ought to do what your change
describes as far as I can see.  What's missing there?

> ---
>  drivers/spi/spi-orion.c | 20 +++++++++++++++++++-
>  drivers/spi/spi.c       |  6 ++++--
>  include/linux/spi/spi.h |  1 +
>  3 files changed, 24 insertions(+), 3 deletions(-)

This is introducing something into the core and adding a user of it, it
should be two separate patches.
Marcin Wojtas Dec. 17, 2020, 2:48 p.m. UTC | #3
czw., 17 gru 2020 o 15:15 Mark Brown <broonie@kernel.org> napisał(a):
>
> On Thu, Dec 17, 2020 at 01:27:07PM +0200, kostap@marvell.com wrote:
>
> > 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.
>
> I'm pretty sure we already support this - if the client driver sets the
> word length to 8 bits then SPI_CS_WORD ought to do what your change
> describes as far as I can see.  What's missing there?

Sure, that needs to be confirmed on HW, but it looks like the required
functionality can be handled with SPI_CS_WORD.

As for the justification, the new flag was developed on a kernel
revision without it and applied easily, hence the possible oversight.

>
> > ---
> >  drivers/spi/spi-orion.c | 20 +++++++++++++++++++-
> >  drivers/spi/spi.c       |  6 ++++--
> >  include/linux/spi/spi.h |  1 +
> >  3 files changed, 24 insertions(+), 3 deletions(-)
>
> This is introducing something into the core and adding a user of it, it
> should be two separate patches.

Agree.

Thanks,
Marcin
diff mbox series

Patch

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;