|
@@ -206,7 +206,8 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin,
|
|
#define MX51_ECSPI_STAT_RR (1 << 3)
|
|
#define MX51_ECSPI_STAT_RR (1 << 3)
|
|
|
|
|
|
/* MX51 eCSPI */
|
|
/* MX51 eCSPI */
|
|
-static unsigned int mx51_ecspi_clkdiv(unsigned int fin, unsigned int fspi)
|
|
|
|
|
|
+static unsigned int mx51_ecspi_clkdiv(unsigned int fin, unsigned int fspi,
|
|
|
|
+ unsigned int *fres)
|
|
{
|
|
{
|
|
/*
|
|
/*
|
|
* there are two 4-bit dividers, the pre-divider divides by
|
|
* 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)
|
|
|
|
|
|
pr_debug("%s: fin: %u, fspi: %u, post: %u, pre: %u\n",
|
|
pr_debug("%s: fin: %u, fspi: %u, post: %u, pre: %u\n",
|
|
__func__, fin, fspi, post, pre);
|
|
__func__, fin, fspi, post, pre);
|
|
|
|
+
|
|
|
|
+ /* Resulting frequency for the SCLK line. */
|
|
|
|
+ *fres = (fin / (pre + 1)) >> post;
|
|
|
|
+
|
|
return (pre << MX51_ECSPI_CTRL_PREDIV_OFFSET) |
|
|
return (pre << MX51_ECSPI_CTRL_PREDIV_OFFSET) |
|
|
(post << MX51_ECSPI_CTRL_POSTDIV_OFFSET);
|
|
(post << MX51_ECSPI_CTRL_POSTDIV_OFFSET);
|
|
}
|
|
}
|
|
@@ -264,6 +269,7 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
|
|
struct spi_imx_config *config)
|
|
struct spi_imx_config *config)
|
|
{
|
|
{
|
|
u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0;
|
|
u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0;
|
|
|
|
+ u32 clk = config->speed_hz, delay;
|
|
|
|
|
|
/*
|
|
/*
|
|
* The hardware seems to have a race condition when changing modes. The
|
|
* 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,
|
|
ctrl |= MX51_ECSPI_CTRL_MODE_MASK;
|
|
ctrl |= MX51_ECSPI_CTRL_MODE_MASK;
|
|
|
|
|
|
/* set clock speed */
|
|
/* set clock speed */
|
|
- ctrl |= mx51_ecspi_clkdiv(spi_imx->spi_clk, config->speed_hz);
|
|
|
|
|
|
+ ctrl |= mx51_ecspi_clkdiv(spi_imx->spi_clk, config->speed_hz, &clk);
|
|
|
|
|
|
/* set chip select to use */
|
|
/* set chip select to use */
|
|
ctrl |= MX51_ECSPI_CTRL_CS(config->cs);
|
|
ctrl |= MX51_ECSPI_CTRL_CS(config->cs);
|
|
@@ -297,6 +303,23 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
|
|
writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
|
|
writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
|
|
writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG);
|
|
writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG);
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Wait until the changes in the configuration register CONFIGREG
|
|
|
|
+ * propagate into the hardware. It takes exactly one tick of the
|
|
|
|
+ * SCLK clock, but we will wait two SCLK clock just to be sure. The
|
|
|
|
+ * effect of the delay it takes for the hardware to apply changes
|
|
|
|
+ * is noticable if the SCLK clock run very slow. In such a case, if
|
|
|
|
+ * the polarity of SCLK should be inverted, the GPIO ChipSelect might
|
|
|
|
+ * be asserted before the SCLK polarity changes, which would disrupt
|
|
|
|
+ * the SPI communication as the device on the other end would consider
|
|
|
|
+ * the change of SCLK polarity as a clock tick already.
|
|
|
|
+ */
|
|
|
|
+ delay = (2 * 1000000) / clk;
|
|
|
|
+ if (likely(delay < 10)) /* SCLK is faster than 100 kHz */
|
|
|
|
+ udelay(delay);
|
|
|
|
+ else /* SCLK is _very_ slow */
|
|
|
|
+ usleep_range(delay, delay + 10);
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|