Commit ed14666c authored by Nathan Rossi's avatar Nathan Rossi Committed by Mark Brown

spi: orion: Prevent incorrect chip select behaviour

When clearing the chip-select mask, the controller will switch to chip
selecting the native CS0 line. Because the control register chip-select
mask is not updated in a single write this will cause undesirable
chip-selection of CS0 even when requesting to select other native
chip-select lines. This is additionally problematic as the chip-select
may still be asserted. With the ARMADA 38x SoC the controller will
assert both the desired native chip-select and CS0.

To avoid any undesirable behaviour with the chip-select lines, update
the control register with a single write. This avoids selecting CS0 and
causes the (de-)assert to apply at the same time.
Signed-off-by: default avatarNathan Rossi <nathan.rossi@digi.com>
Link: https://lore.kernel.org/r/20210816050228.3223661-1-nathan@nathanrossi.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 0395be96
...@@ -328,8 +328,16 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) ...@@ -328,8 +328,16 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
static void orion_spi_set_cs(struct spi_device *spi, bool enable) static void orion_spi_set_cs(struct spi_device *spi, bool enable)
{ {
struct orion_spi *orion_spi; struct orion_spi *orion_spi;
void __iomem *ctrl_reg;
u32 val;
orion_spi = spi_master_get_devdata(spi->master); orion_spi = spi_master_get_devdata(spi->master);
ctrl_reg = spi_reg(orion_spi, ORION_SPI_IF_CTRL_REG);
val = readl(ctrl_reg);
/* Clear existing chip-select and assertion state */
val &= ~(ORION_SPI_CS_MASK | 0x1);
/* /*
* If this line is using a GPIO to control chip select, this internal * If this line is using a GPIO to control chip select, this internal
...@@ -338,9 +346,7 @@ static void orion_spi_set_cs(struct spi_device *spi, bool enable) ...@@ -338,9 +346,7 @@ static void orion_spi_set_cs(struct spi_device *spi, bool enable)
* as it is handled by a GPIO, but that doesn't matter. What we need * as it is handled by a GPIO, but that doesn't matter. What we need
* is to deassert the old chip select and assert some other chip select. * is to deassert the old chip select and assert some other chip select.
*/ */
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, ORION_SPI_CS_MASK); val |= ORION_SPI_CS(spi->chip_select);
orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG,
ORION_SPI_CS(spi->chip_select));
/* /*
* Chip select logic is inverted from spi_set_cs(). For lines using a * Chip select logic is inverted from spi_set_cs(). For lines using a
...@@ -350,9 +356,13 @@ static void orion_spi_set_cs(struct spi_device *spi, bool enable) ...@@ -350,9 +356,13 @@ static void orion_spi_set_cs(struct spi_device *spi, bool enable)
* doesn't matter. * doesn't matter.
*/ */
if (!enable) if (!enable)
orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1); val |= 0x1;
else
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1); /*
* To avoid toggling unwanted chip selects update the register
* with a single write.
*/
writel(val, ctrl_reg);
} }
static inline int orion_spi_wait_till_ready(struct orion_spi *orion_spi) static inline int orion_spi_wait_till_ready(struct orion_spi *orion_spi)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment