From 4cee37dd779deeb01f263995e8bd5e7b8457965b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen 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(-) diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index 5265330..2bec91c 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -335,6 +335,8 @@ static void bitbang_work(struct work_struct *work) */ 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) diff --git a/drivers/spi/spi_gpio.c b/drivers/spi/spi_gpio.c index 26bd03e..ca769b8 100644 --- a/drivers/spi/spi_gpio.c +++ b/drivers/spi/spi_gpio.c @@ -45,6 +45,8 @@ struct spi_gpio { struct spi_bitbang bitbang; struct spi_gpio_platform_data pdata; struct platform_device *pdev; + + int miso_pin; }; /*----------------------------------------------------------------------*/ @@ -88,19 +90,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) { @@ -114,10 +113,9 @@ static inline void setmosi(const struct spi_device *spi, int is_on) 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: this clocks "as fast as we can". It "should" be a function of the @@ -173,10 +171,16 @@ static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi, 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 */ @@ -192,6 +196,9 @@ static int spi_gpio_setup(struct spi_device *spi) 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)); @@ -209,6 +216,16 @@ static int spi_gpio_setup(struct spi_device *spi) 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; @@ -243,18 +260,20 @@ spi_gpio_request(struct spi_gpio_platform_data *pdata, const char *label) 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: @@ -302,13 +321,15 @@ static int __init spi_gpio_probe(struct platform_device *pdev) 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); @@ -332,7 +353,8 @@ static int __exit spi_gpio_remove(struct platform_device *pdev) 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); diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h index 3274c50..0a466c9 100644 --- a/include/linux/spi/spi_bitbang.h +++ b/include/linux/spi/spi_bitbang.h @@ -52,6 +52,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 -- 1.5.6.5