aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi-imx.c
diff options
context:
space:
mode:
authorMarek Vasut <marex@denx.de>2013-12-18 12:31:47 -0500
committerMark Brown <broonie@linaro.org>2013-12-20 06:53:57 -0500
commit6fd8b8503a0dcf66510314dc054745087ae89f94 (patch)
treeb063aa60bd1d7c02806a87768da67253ac1ee2eb /drivers/spi/spi-imx.c
parent6ce4eac1f600b34f2f7f58f9cd8f0503d79e42ae (diff)
spi: spi-imx: Fix out-of-order CS/SCLK operation at low speeds
Problem: -------- The problem this patch addresses has the following assumptions about the SPI bus setup: - The hardware used to find this is Freescale i.MX537 @ 1200MHz - The SPI SCLK operate at very low speed, less than 200 kHz - There are two SPI devices attached to the bus - Each device uses different GPIO for chipselect - Each device requires different SCLK signal polarity The observation of the SCLK and GPIO chipselect lines with a logic analyzer shows, that the SCLK polarity change does sometimes happen after the GPIO chipselect is asserted. The SPI slave device reacts on that by counting the SCLK polarity change as a clock pulse, which disrupts the communication with the SPI slave device. Explanation: ------------ We found an interesting correlation, that the maximum delay between the write into the ECSPIx_CONFIGREG register and the change of SCLK polarity at each SCLK frequency of 10 kHz, 20 kHz, 50 kHz and 100 kHz is 100 uS, 50 uS, 20 uS and 10 uS respectively. This lead us to a theory, that at SCLK frequency of 1 Hz, the delay would be 1 S. Therefore, the time it takes for the write to ECSPIx_CONFIGREG to take effect in the hardware is up to the duration of 1 tick of the SCLK clock. During this delay period, if the SCLK frequency is too low, the execution of the spi-imx.c driver can advance so much, that the GPIO chipselect will be asserted. The GPIO chipselect is asserted almost immediatelly. Solution: --------- The solution this patch presents is simple. We calculate the resulting SCLK clock first by dividing the ECSPI block clock by both dividers that are to be programmed into the configuration register. Based on the resulting SCLK clock, we derive the delay it will take for the changes to get really applied. We are extra careful here so we delay twice as long as we should. Note that the patch does not create additional overhead at high speeds as the delay will likely be close to zero there. Signed-off-by: Marek Vasut <marex@denx.de> To: linux-spi@vger.kernel.org Cc: Fabio Estevam <fabio.estevam@freescale.com> Cc: Huang Shijie <b32955@freescale.com> Cc: Mark Brown <broonie@kernel.org> Cc: Sascha Hauer <s.hauer@pengutronix.de> Cc: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'drivers/spi/spi-imx.c')
-rw-r--r--drivers/spi/spi-imx.c27
1 files changed, 25 insertions, 2 deletions
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index b80f2f70fef7..a5474ef9d2a0 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -206,7 +206,8 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin,
206#define MX51_ECSPI_STAT_RR (1 << 3) 206#define MX51_ECSPI_STAT_RR (1 << 3)
207 207
208/* MX51 eCSPI */ 208/* MX51 eCSPI */
209static unsigned int mx51_ecspi_clkdiv(unsigned int fin, unsigned int fspi) 209static unsigned int mx51_ecspi_clkdiv(unsigned int fin, unsigned int fspi,
210 unsigned int *fres)
210{ 211{
211 /* 212 /*
212 * there are two 4-bit dividers, the pre-divider divides by 213 * there are two 4-bit dividers, the pre-divider divides by
@@ -234,6 +235,10 @@ static unsigned int mx51_ecspi_clkdiv(unsigned int fin, unsigned int fspi)
234 235
235 pr_debug("%s: fin: %u, fspi: %u, post: %u, pre: %u\n", 236 pr_debug("%s: fin: %u, fspi: %u, post: %u, pre: %u\n",
236 __func__, fin, fspi, post, pre); 237 __func__, fin, fspi, post, pre);
238
239 /* Resulting frequency for the SCLK line. */
240 *fres = (fin / (pre + 1)) >> post;
241
237 return (pre << MX51_ECSPI_CTRL_PREDIV_OFFSET) | 242 return (pre << MX51_ECSPI_CTRL_PREDIV_OFFSET) |
238 (post << MX51_ECSPI_CTRL_POSTDIV_OFFSET); 243 (post << MX51_ECSPI_CTRL_POSTDIV_OFFSET);
239} 244}
@@ -264,6 +269,7 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
264 struct spi_imx_config *config) 269 struct spi_imx_config *config)
265{ 270{
266 u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0; 271 u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0;
272 u32 clk = config->speed_hz, delay;
267 273
268 /* 274 /*
269 * The hardware seems to have a race condition when changing modes. The 275 * The hardware seems to have a race condition when changing modes. The
@@ -275,7 +281,7 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
275 ctrl |= MX51_ECSPI_CTRL_MODE_MASK; 281 ctrl |= MX51_ECSPI_CTRL_MODE_MASK;
276 282
277 /* set clock speed */ 283 /* set clock speed */
278 ctrl |= mx51_ecspi_clkdiv(spi_imx->spi_clk, config->speed_hz); 284 ctrl |= mx51_ecspi_clkdiv(spi_imx->spi_clk, config->speed_hz, &clk);
279 285
280 /* set chip select to use */ 286 /* set chip select to use */
281 ctrl |= MX51_ECSPI_CTRL_CS(config->cs); 287 ctrl |= MX51_ECSPI_CTRL_CS(config->cs);
@@ -297,6 +303,23 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
297 writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); 303 writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
298 writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG); 304 writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG);
299 305
306 /*
307 * Wait until the changes in the configuration register CONFIGREG
308 * propagate into the hardware. It takes exactly one tick of the
309 * SCLK clock, but we will wait two SCLK clock just to be sure. The
310 * effect of the delay it takes for the hardware to apply changes
311 * is noticable if the SCLK clock run very slow. In such a case, if
312 * the polarity of SCLK should be inverted, the GPIO ChipSelect might
313 * be asserted before the SCLK polarity changes, which would disrupt
314 * the SPI communication as the device on the other end would consider
315 * the change of SCLK polarity as a clock tick already.
316 */
317 delay = (2 * 1000000) / clk;
318 if (likely(delay < 10)) /* SCLK is faster than 100 kHz */
319 udelay(delay);
320 else /* SCLK is _very_ slow */
321 usleep_range(delay, delay + 10);
322
300 return 0; 323 return 0;
301} 324}
302 325