diff mbox

[1/6] DaVinci: SPI Driver for DaVinci and DA8xx SOC's

Message ID 200907301449.52674.david-b@pacbell.net (mailing list archive)
State Superseded
Headers show

Commit Message

David Brownell July 30, 2009, 9:49 p.m. UTC
On Thursday 16 July 2009, David Brownell wrote:
> On Wednesday 15 July 2009, s-paulraj@ti.com wrote:
> >  arch/arm/mach-davinci/include/mach/spi.h |   45 ++
> >  drivers/spi/Kconfig                      |    7 +
> >  drivers/spi/Makefile                     |    1 +
> >  drivers/spi/davinci_spi.c                |  751 ++++++++++++++++++++++++++++++
> >  drivers/spi/davinci_spi.h                |  163 +++++++
> >  5 files changed, 967 insertions(+), 0 deletions(-)
> 
> It's getting a lot closer.  See the appended ... the issues I
> see remaining are partly performance (if you only set the FMT
> register in the setup code the per-message overhead will be
> a lot less) and partly functional (those per-device settings
> that are treated as global, or wrongly held back on v1 parts).
> 
> Let me know if you plan to address either of those.
> 
> - Dave
> 

I saw a followup from you that was incorrect (failed when
spi_setup was called with an operation pending) ... so here's
a second fixup, going on top of that 16-july patch, which
moves almost everything out of per-message overhead.  Verified
on dm355evm and dm365evm

Please let me know if there's a reason I shouldn't send
your [1/6] patch upstream after combining it with the two
fixup patches I've sent.

- Dave
diff mbox

Patch

======== CUT HERE
A few more fixes vs my previous patch:

 - Remove needless spi->bits_per_word default, now handled
   by the SPI core;
 
 - Move SPIFMTx setting to the spi_setup() code, out of
   the per-message overhead;
 
 - Move some never-change SPI settings to probe(), again
   out of the per-message overhead.

This keeps a lot of setup code from being per-message overhead.
---
 drivers/spi/davinci_spi.c |   89 ++++++++++++++++++++++----------------------
 1 file changed, 46 insertions(+), 43 deletions(-)

--- a/drivers/spi/davinci_spi.c
+++ b/drivers/spi/davinci_spi.c
@@ -198,10 +198,6 @@  static int davinci_spi_setup(struct spi_
 
 	davinci_spi = spi_master_get_devdata(spi->master);
 
-	/* if bits per word length is zero then set it default 8 */
-	if (!spi->bits_per_word)
-		spi->bits_per_word = 8;
-
 	/*
 	 * SPI in DaVinci and DA8xx operate between
 	 * 600 KHz and 50 MHz
@@ -209,23 +205,13 @@  static int davinci_spi_setup(struct spi_
 	if (spi->max_speed_hz < 600000 || spi->max_speed_hz > 50000000)
 		return -EINVAL;
 
-	retval = davinci_spi_setup_transfer(spi, NULL);
-
-	return retval;
-}
-
-static int davinci_spi_bufs_prep(struct spi_device *spi,
-				 struct davinci_spi *davinci_spi)
-{
-	int op_mode = 0;
-
 	/*
-	 * Set up device-specific SPI configuration parameters.
-	 * Most of these would normally be handled in spi_setup(),
-	 * updating the per-chipselect FMT registers, but some of
-	 * them use global controls like SPI_LOOP and SPI_READY.
+	 * Set up SPIFMTn register, unique to this chipselect.
+	 *
+	 * NOTE: we could do all of these with one write.  Also, some
+	 * of the "version 2" features are found in chips that don't
+	 * support all of them...
 	 */
-
 	if (spi->mode & SPI_LSB_FIRST)
 		set_fmt_bits(davinci_spi->base, SPIFMT_SHIFTDIR_MASK,
 				spi->chip_select);
@@ -247,6 +233,19 @@  static int davinci_spi_bufs_prep(struct 
 		clear_fmt_bits(davinci_spi->base, SPIFMT_PHASE_MASK,
 				spi->chip_select);
 
+	/*
+	 * Version 1 hardware supports two basic SPI modes:
+	 *  - Standard SPI mode uses 4 pins, with chipselect
+	 *  - 3 pin SPI is a 4 pin variant without CS (SPI_NO_CS)
+	 *	(distinct from SPI_3WIRE, with just one data wire;
+	 *	or similar variants without MOSI or without MISO)
+	 *
+	 * Version 2 hardware supports an optional handshaking signal,
+	 * so it can support two more modes:
+	 *  - 5 pin SPI variant is standard SPI plus SPI_READY
+	 *  - 4 pin with enable is (SPI_READY | SPI_NO_CS)
+	 */
+
 	if (davinci_spi->version == SPI_VERSION_2) {
 		clear_fmt_bits(davinci_spi->base, SPIFMT_WDELAY_MASK,
 				spi->chip_select);
@@ -293,33 +292,21 @@  static int davinci_spi_bufs_prep(struct 
 					spi->chip_select);
 	}
 
-	/* Clock internal */
-	if (davinci_spi->pdata->clk_internal)
-		set_io_bits(davinci_spi->base + SPIGCR1,
-				SPIGCR1_CLKMOD_MASK);
-	else
-		clear_io_bits(davinci_spi->base + SPIGCR1,
-				SPIGCR1_CLKMOD_MASK);
+	retval = davinci_spi_setup_transfer(spi, NULL);
 
-	/* master mode default */
-	set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_MASTER_MASK);
+	return retval;
+}
 
-	if (davinci_spi->pdata->intr_level)
-		iowrite32(SPI_INTLVL_1, davinci_spi->base + SPILVL);
-	else
-		iowrite32(SPI_INTLVL_0, davinci_spi->base + SPILVL);
+static int davinci_spi_bufs_prep(struct spi_device *spi,
+				 struct davinci_spi *davinci_spi)
+{
+	int op_mode = 0;
 
 	/*
-	 * Version 1 hardware supports two basic SPI modes:
-	 *  - Standard SPI mode uses 4 pins, with chipselect
-	 *  - 3 pin SPI is a 4 pin variant without CS (SPI_NO_CS)
-	 *	(distinct from SPI_3WIRE, with just one data wire;
-	 *	or similar variants without MOSI or without MISO)
-	 *
-	 * Version 2 hardware supports an optional handshaking signal,
-	 * so it can support two more modes:
-	 *  - 5 pin SPI variant is standard SPI plus SPI_READY
-	 *  - 4 pin with enable is (SPI_READY | SPI_NO_CS)
+	 * REVISIT  unless devices disagree about SPI_LOOP or
+	 * SPI_READY (SPI_NO_CS only allows one device!), this
+	 * should not need to be done before each message...
+	 * optimize for both flags staying cleared.
 	 */
 
 	op_mode = SPIPC0_DIFUN_MASK
@@ -672,11 +659,27 @@  static int davinci_spi_probe(struct plat
 
 	init_completion(&davinci_spi->done);
 
-	/* Reset In/OUT SPI modle */
+	/* Reset In/OUT SPI module */
 	iowrite32(0, davinci_spi->base + SPIGCR0);
 	udelay(100);
 	iowrite32(1, davinci_spi->base + SPIGCR0);
 
+	/* Clock internal */
+	if (davinci_spi->pdata->clk_internal)
+		set_io_bits(davinci_spi->base + SPIGCR1,
+				SPIGCR1_CLKMOD_MASK);
+	else
+		clear_io_bits(davinci_spi->base + SPIGCR1,
+				SPIGCR1_CLKMOD_MASK);
+
+	/* master mode default */
+	set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_MASTER_MASK);
+
+	if (davinci_spi->pdata->intr_level)
+		iowrite32(SPI_INTLVL_1, davinci_spi->base + SPILVL);
+	else
+		iowrite32(SPI_INTLVL_0, davinci_spi->base + SPILVL);
+
 	ret = spi_bitbang_start(&davinci_spi->bitbang);
 	if (ret != 0)
 		goto free_clk;