From 0cfbb6d637c1534967a3fdf0ae8eb652fc789056 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sun, 17 Oct 2010 14:08:39 +0000 Subject: [PATCH] [kernel] backport SPI master with no RXTX support (from 2.6.36) Signed-off-by: Miguel Gaio SVN-Revision: 23498 --- .../120-spi-bitbang-norxtx-support.patch | 237 ++++++++++++++++++ .../121-spi-gpio-norxtx-support.patch | 217 ++++++++++++++++ 2 files changed, 454 insertions(+) create mode 100644 target/linux/brcm63xx/patches-2.6.35/120-spi-bitbang-norxtx-support.patch create mode 100644 target/linux/brcm63xx/patches-2.6.35/121-spi-gpio-norxtx-support.patch 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 index 0000000000..762bc66fd4 --- /dev/null +++ b/target/linux/brcm63xx/patches-2.6.35/120-spi-bitbang-norxtx-support.patch @@ -0,0 +1,237 @@ +From 04bb2a031cf95b34b7432dd47b318a932a895b4c Mon Sep 17 00:00:00 2001 +From: Marek Szyprowski +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 +Signed-off-by: Marek Szyprowski +Acked-by: David Brownell +Signed-off-by: Grant Likely +--- + 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 index 0000000000..7ecf39fb04 --- /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 +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 +Signed-off-by: Marek Szyprowski +Acked-by: David Brownell +Signed-off-by: Grant Likely +--- + 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 -- 2.30.2