wifipineapple-openwrt/target/linux/xburst/patches-2.6.35/400-spi-gpio-3wire.patch

181 lines
5.3 KiB
Diff

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