diff options
Diffstat (limited to 'target/linux/xburst/patches-2.6.35/400-spi-gpio-3wire.patch')
-rw-r--r-- | target/linux/xburst/patches-2.6.35/400-spi-gpio-3wire.patch | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/target/linux/xburst/patches-2.6.35/400-spi-gpio-3wire.patch b/target/linux/xburst/patches-2.6.35/400-spi-gpio-3wire.patch new file mode 100644 index 0000000..d60a851 --- /dev/null +++ b/target/linux/xburst/patches-2.6.35/400-spi-gpio-3wire.patch @@ -0,0 +1,180 @@ +From 62b6a295d39417293adcc81dc36b7edc56546814 Mon Sep 17 00:00:00 2001 +From: Lars-Peter Clausen <lars@metafoo.de> +Date: Sat, 24 Apr 2010 12:23:01 +0200 +Subject: [PATCH] gpio spi 3wire + +--- + drivers/spi/spi_bitbang.c | 2 + + drivers/spi/spi_gpio.c | 60 ++++++++++++++++++++++++++------------ + include/linux/spi/spi_bitbang.h | 2 + + 3 files changed, 45 insertions(+), 19 deletions(-) + +--- a/drivers/spi/spi_bitbang.c ++++ b/drivers/spi/spi_bitbang.c +@@ -335,6 +335,8 @@ static void bitbang_work(struct work_str + */ + if (!m->is_dma_mapped) + t->rx_dma = t->tx_dma = 0; ++ if ((spi->mode & SPI_3WIRE) && bitbang->set_direction) ++ bitbang->set_direction(spi, t->tx_buf != NULL); + status = bitbang->txrx_bufs(spi, t); + } + if (status > 0) +--- a/drivers/spi/spi_gpio.c ++++ b/drivers/spi/spi_gpio.c +@@ -46,6 +46,8 @@ struct spi_gpio { + struct spi_bitbang bitbang; + struct spi_gpio_platform_data pdata; + struct platform_device *pdev; ++ ++ int miso_pin; + }; + + /*----------------------------------------------------------------------*/ +@@ -91,19 +93,16 @@ struct spi_gpio { + + /*----------------------------------------------------------------------*/ + +-static inline const struct spi_gpio_platform_data * __pure +-spi_to_pdata(const struct spi_device *spi) ++static inline const struct spi_gpio * __pure ++spi_to_spi_gpio(const struct spi_device *spi) + { + const struct spi_bitbang *bang; +- const struct spi_gpio *spi_gpio; + + bang = spi_master_get_devdata(spi->master); +- spi_gpio = container_of(bang, struct spi_gpio, bitbang); +- return &spi_gpio->pdata; ++ return container_of(bang, struct spi_gpio, bitbang); + } + +-/* this is #defined to avoid unused-variable warnings when inlining */ +-#define pdata spi_to_pdata(spi) ++#define pdata &(spi_to_spi_gpio(spi)->pdata) + + static inline void setsck(const struct spi_device *spi, int is_on) + { +@@ -117,10 +116,9 @@ static inline void setmosi(const struct + + static inline int getmiso(const struct spi_device *spi) + { +- return !!gpio_get_value(SPI_MISO_GPIO); ++ return !!gpio_get_value(spi_to_spi_gpio(spi)->miso_pin); + } + +-#undef pdata + + /* + * NOTE: to clock "as fast as we can", set spi_device.max_speed_hz +@@ -183,10 +181,16 @@ static u32 spi_gpio_txrx_word_mode3(stru + static void spi_gpio_chipselect(struct spi_device *spi, int is_active) + { + unsigned long cs = (unsigned long) spi->controller_data; ++ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); + + /* set initial clock polarity */ +- if (is_active) ++ if (is_active) { + setsck(spi, spi->mode & SPI_CPOL); ++ if (spi->mode & SPI_3WIRE) ++ spi_gpio->miso_pin = SPI_MOSI_GPIO; ++ else ++ spi_gpio->miso_pin = SPI_MISO_GPIO; ++ } + + if (cs != SPI_GPIO_NO_CHIPSELECT) { + /* SPI is normally active-low */ +@@ -202,6 +206,9 @@ static int spi_gpio_setup(struct spi_dev + if (spi->bits_per_word > 32) + return -EINVAL; + ++ if (!(spi->mode & SPI_3WIRE) && !gpio_is_valid(SPI_MISO_GPIO)) ++ return -EINVAL; ++ + if (!spi->controller_state) { + if (cs != SPI_GPIO_NO_CHIPSELECT) { + status = gpio_request(cs, dev_name(&spi->dev)); +@@ -219,6 +226,16 @@ static int spi_gpio_setup(struct spi_dev + return status; + } + ++static void spi_gpio_set_direction(struct spi_device *spi, bool is_tx) ++{ ++ if (is_tx) ++ gpio_direction_output(SPI_MISO_GPIO, 0); ++ else ++ gpio_direction_input(SPI_MISO_GPIO); ++} ++ ++#undef pdata ++ + static void spi_gpio_cleanup(struct spi_device *spi) + { + unsigned long cs = (unsigned long) spi->controller_data; +@@ -253,18 +270,20 @@ spi_gpio_request(struct spi_gpio_platfor + if (value) + goto done; + +- value = spi_gpio_alloc(SPI_MISO_GPIO, label, true); ++ value = spi_gpio_alloc(SPI_SCK_GPIO, label, false); + if (value) + goto free_mosi; + +- value = spi_gpio_alloc(SPI_SCK_GPIO, label, false); +- if (value) +- goto free_miso; ++ if (gpio_is_valid(SPI_MISO_GPIO)) { ++ value = spi_gpio_alloc(SPI_MISO_GPIO, label, true); ++ if (value) ++ goto free_sck; ++ } + + goto done; + +-free_miso: +- gpio_free(SPI_MISO_GPIO); ++free_sck: ++ gpio_free(SPI_SCK_GPIO); + free_mosi: + gpio_free(SPI_MOSI_GPIO); + done: +@@ -312,13 +331,15 @@ static int __devinit spi_gpio_probe(stru + 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; + spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer; +- spi_gpio->bitbang.flags = SPI_CS_HIGH; ++ spi_gpio->bitbang.set_direction = spi_gpio_set_direction; ++ spi_gpio->bitbang.flags = SPI_CS_HIGH | SPI_3WIRE; + + status = spi_bitbang_start(&spi_gpio->bitbang); + if (status < 0) { + spi_master_put(spi_gpio->bitbang.master); + gpio_free: +- gpio_free(SPI_MISO_GPIO); ++ if (gpio_is_valid(SPI_MOSI_GPIO)) ++ gpio_free(SPI_MISO_GPIO); + gpio_free(SPI_MOSI_GPIO); + gpio_free(SPI_SCK_GPIO); + spi_master_put(master); +@@ -342,7 +363,8 @@ static int __devexit spi_gpio_remove(str + + platform_set_drvdata(pdev, NULL); + +- gpio_free(SPI_MISO_GPIO); ++ if (gpio_is_valid(SPI_MISO_GPIO)) ++ gpio_free(SPI_MISO_GPIO); + gpio_free(SPI_MOSI_GPIO); + gpio_free(SPI_SCK_GPIO); + +--- a/include/linux/spi/spi_bitbang.h ++++ b/include/linux/spi/spi_bitbang.h +@@ -34,6 +34,8 @@ struct spi_bitbang { + u32 (*txrx_word[4])(struct spi_device *spi, + unsigned nsecs, + u32 word, u8 bits); ++ ++ void (*set_direction)(struct spi_device *, bool is_tx); + }; + + /* you can call these default bitbang->master methods from your custom |