diff mbox series

spi: imx: Respect delay_us

Message ID 20211028130500.6727-1-joakim.plate@rt-labs.com (mailing list archive)
State New, archived
Headers show
Series spi: imx: Respect delay_us | expand

Commit Message

Joakim Plate Oct. 28, 2021, 1:05 p.m. UTC
Make the driver respect the set delay between transfers. It will
pre-calculate the maximum delay for the set of requested transfers
and use that between each transfer. The reference manual is
unclear on what happens if you change the period registry
mid stream.

Signed-off-by: Joakim Plate <joakim.plate@rt-labs.com>
---
 drivers/spi/spi-imx.c | 32 +++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

Comments

Joakim Plate Oct. 28, 2021, 1:15 p.m. UTC | #1
Should be added here, that this patch was adapted from a verified
patch that was running on an older kernel revision:
https://github.com/varigit/linux-imx
f0e3c7acf46097fdd1fd9fd3279c26faf8226b4e and was adapted to upstream
master. I've not verified it on master, but I still wanted to get the
patch published.

/Joakim

Ps. Resend as unformatted text.
Joakim Plate Nov. 1, 2021, 4:27 p.m. UTC | #2
I think this patch might be superfluous or at least need more changes
to work as expected. Seems the delay_usec feature is actually
implemented by spi.c. So it works, but not by hardware support. I'll
retract this patch for now.
diff mbox series

Patch

diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index b2dd0a4d2446..03a2986c7246 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -12,6 +12,7 @@ 
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/kernel.h>
+#include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
@@ -97,6 +98,7 @@  struct spi_imx_data {
 	struct clk *clk_ipg;
 	unsigned long spi_clk;
 	unsigned int spi_bus_clk;
+	unsigned int delay_usecs;
 
 	unsigned int bits_per_word;
 	unsigned int spi_drctl;
@@ -283,6 +285,11 @@  static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
 #define MX51_ECSPI_STAT		0x18
 #define MX51_ECSPI_STAT_RR		(1 <<  3)
 
+#define MX51_ECSPI_PERIODREG	0x1C
+#define MX51_ECSPI_PERIODREG_SAMPLEPERIOD(period)	((period) & 0x7FFF)
+#define MX51_ECSPI_PERIODREG_CSRC			BIT(15)
+#define MX51_ECSPI_PERIODREG_CSD(csd)			(((csd) & 0x3f) << 16)
+
 #define MX51_ECSPI_TESTREG	0x20
 #define MX51_ECSPI_TESTREG_LBC	BIT(31)
 
@@ -513,7 +520,7 @@  static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
 	struct spi_transfer *xfer;
 	u32 ctrl = MX51_ECSPI_CTRL_ENABLE;
 	u32 min_speed_hz = ~0U;
-	u32 testreg, delay;
+	u32 testreg, delay, delay_usecs = 0;
 	u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG);
 
 	/* set Master or Slave mode */
@@ -574,6 +581,15 @@  static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
 
 	writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG);
 
+
+	/*
+	 * Store maximum transfers delay to avoid changing in burst
+	 */
+	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+		if (xfer->delay_usecs > delay_usecs)
+			delay_usecs = xfer->delay_usecs;
+	}
+
 	/*
 	 * Wait until the changes in the configuration register CONFIGREG
 	 * propagate into the hardware. It takes exactly one tick of the
@@ -611,6 +627,9 @@  static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,
 {
 	u32 ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
 	u32 clk;
+	u32 period = 0;
+	u64 ticks;
+
 
 	/* Clear BL field and set the right value */
 	ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
@@ -627,6 +646,17 @@  static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,
 	ctrl |= mx51_ecspi_clkdiv(spi_imx, spi_imx->spi_bus_clk, &clk);
 	spi_imx->spi_bus_clk = clk;
 
+	/* set sample rate */
+	ticks = mul_u64_u32_div(spi_imx->delay_usecs, clk, 1000000);
+	if (ticks <= 0x7FFF) {
+		period |= MX51_ECSPI_PERIODREG_SAMPLEPERIOD(ticks);
+	} else {
+		ticks = mul_u64_u32_div(spi_imx->delay_usecs, 32768, 1000000);
+		period |= MX51_ECSPI_PERIODREG_SAMPLEPERIOD(ticks);
+		period |= MX51_ECSPI_PERIODREG_CSRC;
+	}
+	writel(period, spi_imx->base + MX51_ECSPI_PERIODREG);
+
 	/*
 	 * ERR009165: work in XHC mode instead of SMC as PIO on the chips
 	 * before i.mx6ul.