[kernel] backport SPI master with no RXTX support (from 2.6.36)
authorFlorian Fainelli <florian@openwrt.org>
Sun, 17 Oct 2010 14:08:39 +0000 (14:08 +0000)
committerFlorian Fainelli <florian@openwrt.org>
Sun, 17 Oct 2010 14:08:39 +0000 (14:08 +0000)
Signed-off-by: Miguel Gaio <miguel.gaio@efixo.com>
SVN-Revision: 23498

target/linux/brcm63xx/patches-2.6.35/120-spi-bitbang-norxtx-support.patch [new file with mode: 0644]
target/linux/brcm63xx/patches-2.6.35/121-spi-gpio-norxtx-support.patch [new file with mode: 0644]

diff --git a/target/linux/brcm63xx/patches-2.6.35/120-spi-bitbang-norxtx-support.patch b/target/linux/brcm63xx/patches-2.6.35/120-spi-bitbang-norxtx-support.patch
new file mode 100644 (file)
index 0000000..762bc66
--- /dev/null
@@ -0,0 +1,237 @@
+From 04bb2a031cf95b34b7432dd47b318a932a895b4c Mon Sep 17 00:00:00 2001
+From: Marek Szyprowski <m.szyprowski@samsung.com>
+Date: Wed, 30 Jun 2010 14:27:32 -0600
+Subject: [PATCH] spi/bitbang: add support for SPI_MASTER_NO_{TX, RX} modes
+
+This patch adds a new flags argument to bitbang_txrx_be_cpha0 and
+bitbang_txrx_be_cpha1 transfer functions. This enables support for
+SPI_MASTER_NO_{TX,RX} transfer modes. The change should have no impact
+on speed of the existing drivers. bitbank_txrx_* functions are usually
+inlined into the drivers. When the argument is equal to constant zero,
+the optimizer would be able to eliminate the dead code (flags checks)
+easily. Tested on ARM and GCC 4.4.x and in all cases the checks were
+eliminated in the inlined function.
+
+Reviewed-by: Kyungmin Park <kyungmin.park@samsung.com>
+Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Acked-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
+---
+ drivers/spi/spi_bitbang_txrx.h |   16 ++++++++++------
+ drivers/spi/spi_butterfly.c    |    2 +-
+ drivers/spi/spi_gpio.c         |    8 ++++----
+ drivers/spi/spi_lm70llp.c      |    2 +-
+ drivers/spi/spi_s3c24xx_gpio.c |    8 ++++----
+ drivers/spi/spi_sh_sci.c       |    8 ++++----
+ 6 files changed, 24 insertions(+), 20 deletions(-)
+
+--- a/drivers/spi/spi_bitbang_txrx.h
++++ b/drivers/spi/spi_bitbang_txrx.h
+@@ -44,7 +44,7 @@
+ static inline u32
+ bitbang_txrx_be_cpha0(struct spi_device *spi,
+-              unsigned nsecs, unsigned cpol,
++              unsigned nsecs, unsigned cpol, unsigned flags,
+               u32 word, u8 bits)
+ {
+       /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */
+@@ -53,7 +53,8 @@ bitbang_txrx_be_cpha0(struct spi_device
+       for (word <<= (32 - bits); likely(bits); bits--) {
+               /* setup MSB (to slave) on trailing edge */
+-              setmosi(spi, word & (1 << 31));
++              if ((flags & SPI_MASTER_NO_TX) == 0)
++                      setmosi(spi, word & (1 << 31));
+               spidelay(nsecs);        /* T(setup) */
+               setsck(spi, !cpol);
+@@ -61,7 +62,8 @@ bitbang_txrx_be_cpha0(struct spi_device
+               /* sample MSB (from slave) on leading edge */
+               word <<= 1;
+-              word |= getmiso(spi);
++              if ((flags & SPI_MASTER_NO_RX) == 0)
++                      word |= getmiso(spi);
+               setsck(spi, cpol);
+       }
+       return word;
+@@ -69,7 +71,7 @@ bitbang_txrx_be_cpha0(struct spi_device
+ static inline u32
+ bitbang_txrx_be_cpha1(struct spi_device *spi,
+-              unsigned nsecs, unsigned cpol,
++              unsigned nsecs, unsigned cpol, unsigned flags,
+               u32 word, u8 bits)
+ {
+       /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */
+@@ -79,7 +81,8 @@ bitbang_txrx_be_cpha1(struct spi_device
+               /* setup MSB (to slave) on leading edge */
+               setsck(spi, !cpol);
+-              setmosi(spi, word & (1 << 31));
++              if ((flags & SPI_MASTER_NO_TX) == 0)
++                      setmosi(spi, word & (1 << 31));
+               spidelay(nsecs); /* T(setup) */
+               setsck(spi, cpol);
+@@ -87,7 +90,8 @@ bitbang_txrx_be_cpha1(struct spi_device
+               /* sample MSB (from slave) on trailing edge */
+               word <<= 1;
+-              word |= getmiso(spi);
++              if ((flags & SPI_MASTER_NO_RX) == 0)
++                      word |= getmiso(spi);
+       }
+       return word;
+ }
+--- a/drivers/spi/spi_butterfly.c
++++ b/drivers/spi/spi_butterfly.c
+@@ -156,7 +156,7 @@ butterfly_txrx_word_mode0(struct spi_dev
+               unsigned nsecs,
+               u32 word, u8 bits)
+ {
+-      return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
++      return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
+ }
+ /*----------------------------------------------------------------------*/
+--- a/drivers/spi/spi_gpio.c
++++ b/drivers/spi/spi_gpio.c
+@@ -157,25 +157,25 @@ static inline void spidelay(unsigned nse
+ static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi,
+               unsigned nsecs, u32 word, u8 bits)
+ {
+-      return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
++      return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
+ }
+ static u32 spi_gpio_txrx_word_mode1(struct spi_device *spi,
+               unsigned nsecs, u32 word, u8 bits)
+ {
+-      return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
++      return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits);
+ }
+ static u32 spi_gpio_txrx_word_mode2(struct spi_device *spi,
+               unsigned nsecs, u32 word, u8 bits)
+ {
+-      return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
++      return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits);
+ }
+ static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi,
+               unsigned nsecs, u32 word, u8 bits)
+ {
+-      return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
++      return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits);
+ }
+ /*----------------------------------------------------------------------*/
+--- a/drivers/spi/spi_lm70llp.c
++++ b/drivers/spi/spi_lm70llp.c
+@@ -191,7 +191,7 @@ static void lm70_chipselect(struct spi_d
+  */
+ static u32 lm70_txrx(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits)
+ {
+-      return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
++      return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
+ }
+ static void spi_lm70llp_attach(struct parport *p)
+--- a/drivers/spi/spi_s3c24xx_gpio.c
++++ b/drivers/spi/spi_s3c24xx_gpio.c
+@@ -64,25 +64,25 @@ static inline u32 getmiso(struct spi_dev
+ static u32 s3c2410_spigpio_txrx_mode0(struct spi_device *spi,
+                                     unsigned nsecs, u32 word, u8 bits)
+ {
+-      return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
++      return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
+ }
+ static u32 s3c2410_spigpio_txrx_mode1(struct spi_device *spi,
+                                     unsigned nsecs, u32 word, u8 bits)
+ {
+-      return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
++      return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits);
+ }
+ static u32 s3c2410_spigpio_txrx_mode2(struct spi_device *spi,
+                                     unsigned nsecs, u32 word, u8 bits)
+ {
+-      return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
++      return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits);
+ }
+ static u32 s3c2410_spigpio_txrx_mode3(struct spi_device *spi,
+                                     unsigned nsecs, u32 word, u8 bits)
+ {
+-      return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
++      return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits);
+ }
+--- a/drivers/spi/spi_sh_sci.c
++++ b/drivers/spi/spi_sh_sci.c
+@@ -83,25 +83,25 @@ static inline u32 getmiso(struct spi_dev
+ static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi,
+                                     unsigned nsecs, u32 word, u8 bits)
+ {
+-      return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
++      return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
+ }
+ static u32 sh_sci_spi_txrx_mode1(struct spi_device *spi,
+                                     unsigned nsecs, u32 word, u8 bits)
+ {
+-      return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
++      return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits);
+ }
+ static u32 sh_sci_spi_txrx_mode2(struct spi_device *spi,
+                                     unsigned nsecs, u32 word, u8 bits)
+ {
+-      return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
++      return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits);
+ }
+ static u32 sh_sci_spi_txrx_mode3(struct spi_device *spi,
+                                     unsigned nsecs, u32 word, u8 bits)
+ {
+-      return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
++      return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits);
+ }
+ static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
+--- a/drivers/spi/spi_gpio_old.c
++++ b/drivers/spi/spi_gpio_old.c
+@@ -80,25 +80,25 @@ static inline void do_spidelay(struct sp
+ static u32 spi_gpio_txrx_mode0(struct spi_device *spi,
+                              unsigned nsecs, u32 word, u8 bits)
+ {
+-      return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
++      return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
+ }
+ static u32 spi_gpio_txrx_mode1(struct spi_device *spi,
+                              unsigned nsecs, u32 word, u8 bits)
+ {
+-      return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
++      return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits);
+ }
+ static u32 spi_gpio_txrx_mode2(struct spi_device *spi,
+                              unsigned nsecs, u32 word, u8 bits)
+ {
+-      return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
++      return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits);
+ }
+ static u32 spi_gpio_txrx_mode3(struct spi_device *spi,
+                              unsigned nsecs, u32 word, u8 bits)
+ {
+-      return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
++      return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits);
+ }
+ static void spi_gpio_chipselect(struct spi_device *dev, int on)
diff --git a/target/linux/brcm63xx/patches-2.6.35/121-spi-gpio-norxtx-support.patch b/target/linux/brcm63xx/patches-2.6.35/121-spi-gpio-norxtx-support.patch
new file mode 100644 (file)
index 0000000..7ecf39f
--- /dev/null
@@ -0,0 +1,217 @@
+From 3c8e1a84fd6b984a7bce8816db2e3defc57bbfe4 Mon Sep 17 00:00:00 2001
+From: Marek Szyprowski <m.szyprowski@samsung.com>
+Date: Wed, 30 Jun 2010 14:27:37 -0600
+Subject: [PATCH] spi/spi-gpio: add support for controllers without MISO or MOSI pin
+
+There are some boards that do not strictly follow SPI standard and use
+only 3 wires (SCLK, MOSI or MISO, SS) for connecting some simple auxiliary
+chips and controls them with GPIO based 'spi controller'. In this
+configuration the MISO or MOSI line is missing (it is not required if the
+chip does not transfer any data back to host or host only reads data from
+chip).
+
+This patch adds support for such non-standard configuration in GPIO-based
+SPI controller. It has been tested in configuration without MISO pin.
+
+Reviewed-by: Kyungmin Park <kyungmin.park@samsung.com>
+Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Acked-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
+---
+ drivers/spi/spi_gpio.c       |  101 ++++++++++++++++++++++++++++++++++-------
+ include/linux/spi/spi_gpio.h |    5 ++
+ 2 files changed, 88 insertions(+), 18 deletions(-)
+
+--- a/drivers/spi/spi_gpio.c
++++ b/drivers/spi/spi_gpio.c
+@@ -178,6 +178,44 @@ static u32 spi_gpio_txrx_word_mode3(stru
+       return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits);
+ }
++/*
++ * These functions do not call setmosi or getmiso if respective flag
++ * (SPI_MASTER_NO_RX or SPI_MASTER_NO_TX) is set, so they are safe to
++ * call when such pin is not present or defined in the controller.
++ * A separate set of callbacks is defined to get highest possible
++ * speed in the generic case (when both MISO and MOSI lines are
++ * available), as optimiser will remove the checks when argument is
++ * constant.
++ */
++
++static u32 spi_gpio_spec_txrx_word_mode0(struct spi_device *spi,
++              unsigned nsecs, u32 word, u8 bits)
++{
++      unsigned flags = spi->master->flags;
++      return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
++}
++
++static u32 spi_gpio_spec_txrx_word_mode1(struct spi_device *spi,
++              unsigned nsecs, u32 word, u8 bits)
++{
++      unsigned flags = spi->master->flags;
++      return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits);
++}
++
++static u32 spi_gpio_spec_txrx_word_mode2(struct spi_device *spi,
++              unsigned nsecs, u32 word, u8 bits)
++{
++      unsigned flags = spi->master->flags;
++      return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits);
++}
++
++static u32 spi_gpio_spec_txrx_word_mode3(struct spi_device *spi,
++              unsigned nsecs, u32 word, u8 bits)
++{
++      unsigned flags = spi->master->flags;
++      return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits);
++}
++
+ /*----------------------------------------------------------------------*/
+ static void spi_gpio_chipselect(struct spi_device *spi, int is_active)
+@@ -243,19 +281,30 @@ static int __devinit spi_gpio_alloc(unsi
+ }
+ static int __devinit
+-spi_gpio_request(struct spi_gpio_platform_data *pdata, const char *label)
++spi_gpio_request(struct spi_gpio_platform_data *pdata, const char *label,
++      u16 *res_flags)
+ {
+       int value;
+       /* NOTE:  SPI_*_GPIO symbols may reference "pdata" */
+-      value = spi_gpio_alloc(SPI_MOSI_GPIO, label, false);
+-      if (value)
+-              goto done;
+-
+-      value = spi_gpio_alloc(SPI_MISO_GPIO, label, true);
+-      if (value)
+-              goto free_mosi;
++      if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI) {
++              value = spi_gpio_alloc(SPI_MOSI_GPIO, label, false);
++              if (value)
++                      goto done;
++      } else {
++              /* HW configuration without MOSI pin */
++              *res_flags |= SPI_MASTER_NO_TX;
++      }
++
++      if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO) {
++              value = spi_gpio_alloc(SPI_MISO_GPIO, label, true);
++              if (value)
++                      goto free_mosi;
++      } else {
++              /* HW configuration without MISO pin */
++              *res_flags |= SPI_MASTER_NO_RX;
++      }
+       value = spi_gpio_alloc(SPI_SCK_GPIO, label, false);
+       if (value)
+@@ -264,9 +313,11 @@ spi_gpio_request(struct spi_gpio_platfor
+       goto done;
+ free_miso:
+-      gpio_free(SPI_MISO_GPIO);
++      if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
++              gpio_free(SPI_MISO_GPIO);
+ free_mosi:
+-      gpio_free(SPI_MOSI_GPIO);
++      if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
++              gpio_free(SPI_MOSI_GPIO);
+ done:
+       return value;
+ }
+@@ -277,6 +328,7 @@ static int __devinit spi_gpio_probe(stru
+       struct spi_master               *master;
+       struct spi_gpio                 *spi_gpio;
+       struct spi_gpio_platform_data   *pdata;
++      u16 master_flags = 0;
+       pdata = pdev->dev.platform_data;
+ #ifdef GENERIC_BITBANG
+@@ -284,7 +336,7 @@ static int __devinit spi_gpio_probe(stru
+               return -ENODEV;
+ #endif
+-      status = spi_gpio_request(pdata, dev_name(&pdev->dev));
++      status = spi_gpio_request(pdata, dev_name(&pdev->dev), &master_flags);
+       if (status < 0)
+               return status;
+@@ -300,6 +352,7 @@ static int __devinit spi_gpio_probe(stru
+       if (pdata)
+               spi_gpio->pdata = *pdata;
++      master->flags = master_flags;
+       master->bus_num = pdev->id;
+       master->num_chipselect = SPI_N_CHIPSEL;
+       master->setup = spi_gpio_setup;
+@@ -307,10 +360,18 @@ static int __devinit spi_gpio_probe(stru
+       spi_gpio->bitbang.master = spi_master_get(master);
+       spi_gpio->bitbang.chipselect = spi_gpio_chipselect;
+-      spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;
+-      spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1;
+-      spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2;
+-      spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_word_mode3;
++
++      if ((master_flags & (SPI_MASTER_NO_RX | SPI_MASTER_NO_RX)) == 0) {
++              spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;
++              spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1;
++              spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2;
++              spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_word_mode3;
++      } else {
++              spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_spec_txrx_word_mode0;
++              spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_spec_txrx_word_mode1;
++              spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_spec_txrx_word_mode2;
++              spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_spec_txrx_word_mode3;
++      }
+       spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer;
+       spi_gpio->bitbang.flags = SPI_CS_HIGH;
+@@ -318,8 +379,10 @@ static int __devinit spi_gpio_probe(stru
+       if (status < 0) {
+               spi_master_put(spi_gpio->bitbang.master);
+ gpio_free:
+-              gpio_free(SPI_MISO_GPIO);
+-              gpio_free(SPI_MOSI_GPIO);
++              if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
++                      gpio_free(SPI_MISO_GPIO);
++              if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
++                      gpio_free(SPI_MOSI_GPIO);
+               gpio_free(SPI_SCK_GPIO);
+               spi_master_put(master);
+       }
+@@ -342,8 +405,10 @@ static int __devexit spi_gpio_remove(str
+       platform_set_drvdata(pdev, NULL);
+-      gpio_free(SPI_MISO_GPIO);
+-      gpio_free(SPI_MOSI_GPIO);
++      if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
++              gpio_free(SPI_MISO_GPIO);
++      if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
++              gpio_free(SPI_MOSI_GPIO);
+       gpio_free(SPI_SCK_GPIO);
+       return status;
+--- a/include/linux/spi/spi_gpio.h
++++ b/include/linux/spi/spi_gpio.h
+@@ -29,11 +29,16 @@
+  * SPI_GPIO_NO_CHIPSELECT to the controller_data:
+  *            .controller_data = (void *) SPI_GPIO_NO_CHIPSELECT;
+  *
++ * If the MISO or MOSI pin is not available then it should be set to
++ * SPI_GPIO_NO_MISO or SPI_GPIO_NO_MOSI.
++ *
+  * If the bitbanged bus is later switched to a "native" controller,
+  * that platform_device and controller_data should be removed.
+  */
+ #define SPI_GPIO_NO_CHIPSELECT                ((unsigned long)-1l)
++#define SPI_GPIO_NO_MISO              ((unsigned long)-1l)
++#define SPI_GPIO_NO_MOSI              ((unsigned long)-1l)
+ /**
+  * struct spi_gpio_platform_data - parameter for bitbanged SPI master