]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
spi: davinci: enable GPIO lines to be used as chip selects
authorBrian Niebuhr <bniebuhr@efjohnson.com>
Fri, 13 Aug 2010 05:27:44 +0000 (10:57 +0530)
committerSekhar Nori <nsekhar@ti.com>
Thu, 18 Nov 2010 13:08:25 +0000 (18:38 +0530)
Sometimes, the chip selects provided by SPI module are
muxed with other functionality and cannot be used in
some designs. In such cases, it becomes convenient to use
an available GPIO line as chip select.

This patch enables the DaVinci SPI driver to treat specific
GPIO lines as chip selects based on information provided in
platform data.

Signed-off-by: Brian Niebuhr <bniebuhr@efjohnson.com>
Tested-By: Michael Williamson <michael.williamson@criticallink.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
arch/arm/mach-davinci/include/mach/spi.h
drivers/spi/davinci_spi.c

index 2cb326e536bb378bf9df73bab131bd75c38271b5..734d1fb99614222743b067c55f82d8668e81c4d9 100644 (file)
@@ -19,6 +19,8 @@
 #ifndef __ARCH_ARM_DAVINCI_SPI_H
 #define __ARCH_ARM_DAVINCI_SPI_H
 
+#define SPI_INTERN_CS  0xFF
+
 enum {
        SPI_VERSION_1, /* For DM355/DM365/DM6467 */
        SPI_VERSION_2, /* For DA8xx */
@@ -38,6 +40,7 @@ struct davinci_spi_platform_data {
        u8      use_dma;
        u8      c2tdelay;
        u8      t2cdelay;
+       u8      *chip_sel;
 };
 
 #endif /* __ARCH_ARM_DAVINCI_SPI_H */
index 82dddf83daf741daea088d471f6d52cc82920d94..d5d7014e6ae28263b5d18b89e5101d852cd5821c 100644 (file)
@@ -238,20 +238,32 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
        struct davinci_spi_platform_data *pdata;
        u8 chip_sel = spi->chip_select;
        u16 spidat1_cfg = CS_DEFAULT;
+       bool gpio_chipsel = false;
 
        davinci_spi = spi_master_get_devdata(spi->master);
        pdata = davinci_spi->pdata;
 
+       if (pdata->chip_sel && chip_sel < pdata->num_chipselect &&
+                               pdata->chip_sel[chip_sel] != SPI_INTERN_CS)
+               gpio_chipsel = true;
+
        /*
         * Board specific chip select logic decides the polarity and cs
         * line for the controller
         */
-       if (value == BITBANG_CS_ACTIVE) {
-               spidat1_cfg |= SPIDAT1_CSHOLD_MASK;
-               spidat1_cfg &= ~(0x1 << chip_sel);
-       }
+       if (gpio_chipsel) {
+               if (value == BITBANG_CS_ACTIVE)
+                       gpio_set_value(pdata->chip_sel[chip_sel], 0);
+               else
+                       gpio_set_value(pdata->chip_sel[chip_sel], 1);
+       } else {
+               if (value == BITBANG_CS_ACTIVE) {
+                       spidat1_cfg |= SPIDAT1_CSHOLD_MASK;
+                       spidat1_cfg &= ~(0x1 << chip_sel);
+               }
 
-       iowrite16(spidat1_cfg, davinci_spi->base + SPIDAT1 + 2);
+               iowrite16(spidat1_cfg, davinci_spi->base + SPIDAT1 + 2);
+       }
 }
 
 /**
@@ -546,6 +558,7 @@ static void davinci_spi_cleanup(struct spi_device *spi)
 static int davinci_spi_bufs_prep(struct spi_device *spi,
                                 struct davinci_spi *davinci_spi)
 {
+       struct davinci_spi_platform_data *pdata;
        int op_mode = 0;
 
        /*
@@ -558,8 +571,12 @@ static int davinci_spi_bufs_prep(struct spi_device *spi,
        op_mode = SPIPC0_DIFUN_MASK
                | SPIPC0_DOFUN_MASK
                | SPIPC0_CLKFUN_MASK;
-       if (!(spi->mode & SPI_NO_CS))
-               op_mode |= 1 << spi->chip_select;
+       if (!(spi->mode & SPI_NO_CS)) {
+               pdata = davinci_spi->pdata;
+               if (!pdata->chip_sel ||
+                    pdata->chip_sel[spi->chip_select] == SPI_INTERN_CS)
+                       op_mode |= 1 << spi->chip_select;
+       }
        if (spi->mode & SPI_READY)
                op_mode |= SPIPC0_SPIENA_MASK;
 
@@ -1101,6 +1118,14 @@ static int davinci_spi_probe(struct platform_device *pdev)
        udelay(100);
        iowrite32(1, davinci_spi->base + SPIGCR0);
 
+       /* initialize chip selects */
+       if (pdata->chip_sel) {
+               for (i = 0; i < pdata->num_chipselect; i++) {
+                       if (pdata->chip_sel[i] != SPI_INTERN_CS)
+                               gpio_direction_output(pdata->chip_sel[i], 1);
+               }
+       }
+
        /* Clock internal */
        if (davinci_spi->pdata->clk_internal)
                set_io_bits(davinci_spi->base + SPIGCR1,