summaryrefslogtreecommitdiffstats
path: root/target/linux/brcm63xx/patches-2.6.35/121-spi-gpio-norxtx-support.patch
diff options
context:
space:
mode:
authorflorian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73>2010-10-17 14:08:39 +0000
committerflorian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73>2010-10-17 14:08:39 +0000
commit238839d6be64ed85044beeddfaa0e7baafd1ec91 (patch)
tree55ef00d3e7b862026f05a20559e112659b072496 /target/linux/brcm63xx/patches-2.6.35/121-spi-gpio-norxtx-support.patch
parent980668b36290683695a76d0a56d6c824e80a09f1 (diff)
[kernel] backport SPI master with no RXTX support (from 2.6.36)
Signed-off-by: Miguel Gaio <miguel.gaio@efixo.com> git-svn-id: svn://svn.openwrt.org/openwrt/trunk@23498 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/brcm63xx/patches-2.6.35/121-spi-gpio-norxtx-support.patch')
-rw-r--r--target/linux/brcm63xx/patches-2.6.35/121-spi-gpio-norxtx-support.patch217
1 files changed, 217 insertions, 0 deletions
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
index 000000000..7ecf39fb0
--- /dev/null
+++ b/target/linux/brcm63xx/patches-2.6.35/121-spi-gpio-norxtx-support.patch
@@ -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