spi: dw: add support for gpio controlled chip select
authorBaruch Siach <baruch@tkos.co.il>
Fri, 31 Jan 2014 10:07:47 +0000 (12:07 +0200)
committerMark Brown <broonie@linaro.org>
Thu, 24 Apr 2014 17:09:05 +0000 (18:09 +0100)
Also, use this opportunity to let spi_chip_sel() handle chip-select
deactivation as well.

Signed-off-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Mark Brown <broonie@linaro.org>
drivers/spi/spi-dw-mmio.c
drivers/spi/spi-dw.c
drivers/spi/spi-dw.h

index 1492f5ee9aaad702b1f6c490be4d38c1ac6091a0..a5cba14ac3d2f6cce6ee27a1caf2c050a98082b8 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/spi/spi.h>
 #include <linux/scatterlist.h>
 #include <linux/module.h>
+#include <linux/of_gpio.h>
 
 #include "spi-dw.h"
 
@@ -70,6 +71,27 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
        dws->num_cs = 4;
        dws->max_freq = clk_get_rate(dwsmmio->clk);
 
+       if (pdev->dev.of_node) {
+               int i;
+
+               for (i = 0; i < dws->num_cs; i++) {
+                       int cs_gpio = of_get_named_gpio(pdev->dev.of_node,
+                                       "cs-gpios", i);
+
+                       if (cs_gpio == -EPROBE_DEFER) {
+                               ret = cs_gpio;
+                               goto out;
+                       }
+
+                       if (gpio_is_valid(cs_gpio)) {
+                               ret = devm_gpio_request(&pdev->dev, cs_gpio,
+                                               dev_name(&pdev->dev));
+                               if (ret)
+                                       goto out;
+                       }
+               }
+       }
+
        ret = dw_spi_add_host(&pdev->dev, dws);
        if (ret)
                goto out;
index 357869a704d60ffe37990598454071fdec57afd0..9965e1b84832fcc69b642a991b043f03061b1e23 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
+#include <linux/gpio.h>
 
 #include "spi-dw.h"
 
@@ -36,9 +37,6 @@
 #define DONE_STATE     ((void *)2)
 #define ERROR_STATE    ((void *)-1)
 
-#define MRST_SPI_DEASSERT      0
-#define MRST_SPI_ASSERT                1
-
 /* Slave spi_dev related */
 struct chip_data {
        u16 cr0;
@@ -272,8 +270,8 @@ static void giveback(struct dw_spi *dws)
        last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
                                        transfer_list);
 
-       if (!last_transfer->cs_change && dws->cs_control)
-               dws->cs_control(MRST_SPI_DEASSERT);
+       if (!last_transfer->cs_change)
+               spi_chip_sel(dws, dws->cur_msg->spi, 0);
 
        spi_finalize_current_message(dws->master);
 }
@@ -493,7 +491,7 @@ static void pump_transfers(unsigned long data)
                        dw_writew(dws, DW_SPI_CTRL0, cr0);
 
                spi_set_clk(dws, clk_div ? clk_div : chip->clk_div);
-               spi_chip_sel(dws, spi->chip_select);
+               spi_chip_sel(dws, spi, 1);
 
                /* Set the interrupt mask, for poll mode just disable all int */
                spi_mask_intr(dws, 0xff);
@@ -544,6 +542,7 @@ static int dw_spi_setup(struct spi_device *spi)
 {
        struct dw_spi_chip *chip_info = NULL;
        struct chip_data *chip;
+       int ret;
 
        /* Only alloc on first setup */
        chip = spi_get_ctldata(spi);
@@ -597,6 +596,13 @@ static int dw_spi_setup(struct spi_device *spi)
                        | (spi->mode  << SPI_MODE_OFFSET)
                        | (chip->tmode << SPI_TMOD_OFFSET);
 
+       if (gpio_is_valid(spi->cs_gpio)) {
+               ret = gpio_direction_output(spi->cs_gpio,
+                               !(spi->mode & SPI_CS_HIGH));
+               if (ret)
+                       return ret;
+       }
+
        return 0;
 }
 
index 3fd7ab599ab4b514606184e06cf792ec37c3a25e..6d2acad34f64f5b56b9e527a14f73729f9cb9e1b 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/io.h>
 #include <linux/scatterlist.h>
+#include <linux/gpio.h>
 
 /* Register offsets */
 #define DW_SPI_CTRL0                   0x00
@@ -178,15 +179,20 @@ static inline void spi_set_clk(struct dw_spi *dws, u16 div)
        dw_writel(dws, DW_SPI_BAUDR, div);
 }
 
-static inline void spi_chip_sel(struct dw_spi *dws, u16 cs)
+static inline void spi_chip_sel(struct dw_spi *dws, struct spi_device *spi,
+               int active)
 {
-       if (cs > dws->num_cs)
-               return;
+       u16 cs = spi->chip_select;
+       int gpio_val = active ? (spi->mode & SPI_CS_HIGH) :
+               !(spi->mode & SPI_CS_HIGH);
 
        if (dws->cs_control)
-               dws->cs_control(1);
+               dws->cs_control(active);
+       if (gpio_is_valid(spi->cs_gpio))
+               gpio_set_value(spi->cs_gpio, gpio_val);
 
-       dw_writel(dws, DW_SPI_SER, 1 << cs);
+       if (active)
+               dw_writel(dws, DW_SPI_SER, 1 << cs);
 }
 
 /* Disable IRQ bits */