Skip to content

Commit

Permalink
spi: orion: enable support for switching CS every transferred byte
Browse files Browse the repository at this point in the history
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>
Link: https://lore.kernel.org/r/20201223103827.29721-3-kostap@marvell.com
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Marcin Wojtas authored and Mark Brown committed Dec 28, 2020
1 parent e2be703 commit 22a6d41
Showing 1 changed file with 28 additions and 4 deletions.
32 changes: 28 additions & 4 deletions drivers/spi/spi-orion.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,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);
Expand All @@ -390,13 +397,24 @@ 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;
}

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;
}

Expand All @@ -407,6 +425,11 @@ orion_spi_write_read_16bit(struct spi_device *spi,
void __iomem *tx_reg, *rx_reg, *int_reg;
struct orion_spi *orion_spi;

if (spi->mode & SPI_CS_WORD) {
dev_err(&spi->dev, "SPI_CS_WORD is only supported for 8 bit words\n");
return -1;
}

orion_spi = spi_master_get_devdata(spi->master);
tx_reg = spi_reg(orion_spi, ORION_SPI_DATA_OUT_REG);
rx_reg = spi_reg(orion_spi, ORION_SPI_DATA_IN_REG);
Expand Down Expand Up @@ -446,12 +469,13 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
orion_spi = spi_master_get_devdata(spi->master);

/*
* Use SPI direct write mode if base address is available. Otherwise
* fall back to PIO mode for this transfer.
* Use SPI direct write mode if base address is available
* and SPI_CS_WORD flag is not set.
* Otherwise fall back to PIO mode for this transfer.
*/
vaddr = orion_spi->child[cs].direct_access.vaddr;

if (vaddr && xfer->tx_buf && word_len == 8) {
if (vaddr && xfer->tx_buf && word_len == 8 && (spi->mode & SPI_CS_WORD) == 0) {
unsigned int cnt = count / 4;
unsigned int rem = count % 4;

Expand Down Expand Up @@ -636,7 +660,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;
Expand Down

0 comments on commit 22a6d41

Please sign in to comment.