aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi-cadence.c
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2014-07-10 11:26:28 +0200
committerMark Brown <broonie@linaro.org>2014-07-11 14:39:26 +0100
commita39e65e9cc935b84f35d080e934c3fdd9ff86654 (patch)
treecc57d81f14a944e6d833217469b8e525fa9d5939 /drivers/spi/spi-cadence.c
parentLinux 3.16-rc1 (diff)
downloadlinux-dev-a39e65e9cc935b84f35d080e934c3fdd9ff86654.tar.xz
linux-dev-a39e65e9cc935b84f35d080e934c3fdd9ff86654.zip
spi: cadence: Make sure that clock polarity changes are applied
It seems that the cadence SPI controller does not immediately change the clock polarity setting when writing the CR register. Instead the change is delayed until the next transfer starts. This happens after the chip select line has already been asserted. As a result the first transfer after a clock polarity change will generate spurious clock transitions which typically results in the SPI slave not being able to properly understand the message. Toggling the ER register seems to cause the SPI controller to apply the clock polarity changes, so implement this as a workaround to fix the issue. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'drivers/spi/spi-cadence.c')
-rw-r--r--drivers/spi/spi-cadence.c26
1 files changed, 19 insertions, 7 deletions
diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c
index bb758978465d..f55702937052 100644
--- a/drivers/spi/spi-cadence.c
+++ b/drivers/spi/spi-cadence.c
@@ -205,18 +205,30 @@ static void cdns_spi_chipselect(struct spi_device *spi, bool is_high)
static void cdns_spi_config_clock_mode(struct spi_device *spi)
{
struct cdns_spi *xspi = spi_master_get_devdata(spi->master);
- u32 ctrl_reg;
+ u32 ctrl_reg, new_ctrl_reg;
- ctrl_reg = cdns_spi_read(xspi, CDNS_SPI_CR_OFFSET);
+ new_ctrl_reg = ctrl_reg = cdns_spi_read(xspi, CDNS_SPI_CR_OFFSET);
/* Set the SPI clock phase and clock polarity */
- ctrl_reg &= ~(CDNS_SPI_CR_CPHA_MASK | CDNS_SPI_CR_CPOL_MASK);
+ new_ctrl_reg &= ~(CDNS_SPI_CR_CPHA_MASK | CDNS_SPI_CR_CPOL_MASK);
if (spi->mode & SPI_CPHA)
- ctrl_reg |= CDNS_SPI_CR_CPHA_MASK;
+ new_ctrl_reg |= CDNS_SPI_CR_CPHA_MASK;
if (spi->mode & SPI_CPOL)
- ctrl_reg |= CDNS_SPI_CR_CPOL_MASK;
-
- cdns_spi_write(xspi, CDNS_SPI_CR_OFFSET, ctrl_reg);
+ new_ctrl_reg |= CDNS_SPI_CR_CPOL_MASK;
+
+ if (new_ctrl_reg != ctrl_reg) {
+ /*
+ * Just writing the CR register does not seem to apply the clock
+ * setting changes. This is problematic when changing the clock
+ * polarity as it will cause the SPI slave to see spurious clock
+ * transitions. To workaround the issue toggle the ER register.
+ */
+ cdns_spi_write(xspi, CDNS_SPI_ER_OFFSET,
+ CDNS_SPI_ER_DISABLE_MASK);
+ cdns_spi_write(xspi, CDNS_SPI_CR_OFFSET, new_ctrl_reg);
+ cdns_spi_write(xspi, CDNS_SPI_ER_OFFSET,
+ CDNS_SPI_ER_ENABLE_MASK);
+ }
}
/**