aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2014-07-10 05:26:28 -0400
committerMark Brown <broonie@linaro.org>2014-07-11 09:39:26 -0400
commita39e65e9cc935b84f35d080e934c3fdd9ff86654 (patch)
treecc57d81f14a944e6d833217469b8e525fa9d5939
parent7171511eaec5bf23fb06078f59784a3a0626b38f (diff)
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>
-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)
205static void cdns_spi_config_clock_mode(struct spi_device *spi) 205static void cdns_spi_config_clock_mode(struct spi_device *spi)
206{ 206{
207 struct cdns_spi *xspi = spi_master_get_devdata(spi->master); 207 struct cdns_spi *xspi = spi_master_get_devdata(spi->master);
208 u32 ctrl_reg; 208 u32 ctrl_reg, new_ctrl_reg;
209 209
210 ctrl_reg = cdns_spi_read(xspi, CDNS_SPI_CR_OFFSET); 210 new_ctrl_reg = ctrl_reg = cdns_spi_read(xspi, CDNS_SPI_CR_OFFSET);
211 211
212 /* Set the SPI clock phase and clock polarity */ 212 /* Set the SPI clock phase and clock polarity */
213 ctrl_reg &= ~(CDNS_SPI_CR_CPHA_MASK | CDNS_SPI_CR_CPOL_MASK); 213 new_ctrl_reg &= ~(CDNS_SPI_CR_CPHA_MASK | CDNS_SPI_CR_CPOL_MASK);
214 if (spi->mode & SPI_CPHA) 214 if (spi->mode & SPI_CPHA)
215 ctrl_reg |= CDNS_SPI_CR_CPHA_MASK; 215 new_ctrl_reg |= CDNS_SPI_CR_CPHA_MASK;
216 if (spi->mode & SPI_CPOL) 216 if (spi->mode & SPI_CPOL)
217 ctrl_reg |= CDNS_SPI_CR_CPOL_MASK; 217 new_ctrl_reg |= CDNS_SPI_CR_CPOL_MASK;
218 218
219 cdns_spi_write(xspi, CDNS_SPI_CR_OFFSET, ctrl_reg); 219 if (new_ctrl_reg != ctrl_reg) {
220 /*
221 * Just writing the CR register does not seem to apply the clock
222 * setting changes. This is problematic when changing the clock
223 * polarity as it will cause the SPI slave to see spurious clock
224 * transitions. To workaround the issue toggle the ER register.
225 */
226 cdns_spi_write(xspi, CDNS_SPI_ER_OFFSET,
227 CDNS_SPI_ER_DISABLE_MASK);
228 cdns_spi_write(xspi, CDNS_SPI_CR_OFFSET, new_ctrl_reg);
229 cdns_spi_write(xspi, CDNS_SPI_ER_OFFSET,
230 CDNS_SPI_ER_ENABLE_MASK);
231 }
220} 232}
221 233
222/** 234/**