Patchwork [U-Boot,2/2] EXYNOS: SPI: Support a delay after deactivate

login
register
mail settings
Submitter Rajeshwari Birje
Date March 22, 2013, 12:28 p.m.
Message ID <1363955297-3707-3-git-send-email-rajeshwari.s@samsung.com>
Download mbox | patch
Permalink /patch/229980/
State Changes Requested
Delegated to: Minkyu Kang
Headers show

Comments

Rajeshwari Birje - March 22, 2013, 12:28 p.m.
For devices that need some time to react after a spi transaction
finishes, add the ability to set a delay.

Implement this as a delay on the first/next transaction to avoid
any delay in the fairly common case where a SPI transaction is
followed by other processing.

Based on:
"EXYNOS: SPI: Support SPI_PREAMBLE mode"
link: http://patchwork.ozlabs.org/patch/229891/

Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
---
 drivers/spi/exynos_spi.c |   19 +++++++++++++++++++
 1 files changed, 19 insertions(+), 0 deletions(-)
Simon Glass - May 11, 2013, 3:08 p.m.
On Fri, Mar 22, 2013 at 6:28 AM, Rajeshwari Shinde
<rajeshwari.s@samsung.com> wrote:
> For devices that need some time to react after a spi transaction
> finishes, add the ability to set a delay.
>
> Implement this as a delay on the first/next transaction to avoid
> any delay in the fairly common case where a SPI transaction is
> followed by other processing.
>
> Based on:
> "EXYNOS: SPI: Support SPI_PREAMBLE mode"
> link: http://patchwork.ozlabs.org/patch/229891/
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>

Acked-by: Simon Glass <sjg@chromium.org>

Patch

diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c
index 09e88d5..c19e227 100644
--- a/drivers/spi/exynos_spi.c
+++ b/drivers/spi/exynos_spi.c
@@ -38,6 +38,7 @@  struct spi_bus {
 	struct exynos_spi *regs;
 	int inited;		/* 1 if this bus is ready for use */
 	int node;
+	uint deactivate_delay_us;	/* Delay to wait after deactivate */
 };
 
 /* A list of spi buses that we know about */
@@ -52,6 +53,8 @@  struct exynos_spi_slave {
 	enum periph_id periph_id;	/* Peripheral ID for this device */
 	unsigned int fifo_size;
 	int skip_preamble;
+	struct spi_bus *bus;		/* Pointer to our SPI bus info */
+	ulong last_transaction_us;	/* Time of last transaction end */
 };
 
 static struct spi_bus *spi_get_bus(unsigned dev_index)
@@ -97,6 +100,7 @@  struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
 	}
 
 	bus = &spi_bus[busnum];
+	spi_slave->bus = bus;
 	spi_slave->slave.bus = busnum;
 	spi_slave->slave.cs = cs;
 	spi_slave->regs = bus->regs;
@@ -109,6 +113,7 @@  struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
 		spi_slave->fifo_size = 256;
 
 	spi_slave->skip_preamble = 0;
+	spi_slave->last_transaction_us = timer_get_us();
 
 	spi_slave->freq = bus->frequency;
 	if (max_hz)
@@ -370,9 +375,21 @@  void spi_cs_activate(struct spi_slave *slave)
 {
 	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
 
+	/* If it's too soon to do another transaction, wait */
+	if (spi_slave->bus->deactivate_delay_us &&
+		spi_slave->last_transaction_us) {
+		ulong delay_us;		/* The delay completed so far */
+		delay_us = timer_get_us() - spi_slave->last_transaction_us;
+		if (delay_us < spi_slave->bus->deactivate_delay_us)
+			udelay(spi_slave->bus->deactivate_delay_us - delay_us);
+	}
 	clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT);
 	debug("Activate CS, bus %d\n", spi_slave->slave.bus);
 	spi_slave->skip_preamble = spi_slave->mode & SPI_PREAMBLE;
+
+	/* Remember time of this transaction so we can honour the bus delay */
+	if (spi_slave->bus->deactivate_delay_us)
+		spi_slave->last_transaction_us = timer_get_us();
 }
 
 /**
@@ -421,6 +438,8 @@  static int spi_get_config(const void *blob, int node, struct spi_bus *bus)
 	/* Use 500KHz as a suitable default */
 	bus->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
 					500000);
+	bus->deactivate_delay_us = fdtdec_get_int(blob, node,
+					"spi-deactivate-delay", 0);
 
 	return 0;
 }