On Thursday 04 September 2008, Eric Miao wrote:
> As Russell suggested, updated with gpio_is_valid().

He beat me to that comment.  ;)

I like, but that doesn't apply on top of the bugfix patch
which I just cc'd you on...

Related:

 - It's probably worth removing support for the SSFRM
   mechanism and requiring gpio_cs or (at least as a
   transitional scheme) the cs_control() thing.

   I suggest issuing a strong warning for all devices
   which assume the SSFRM mechanism (single device
   on the bus segment too) ... and maybe a weaker one
   if they use cs_control, saying "use gpio_cs".

 - Remove the gpio_cs_inverted thing ... that's exactly
   what SPI_CS_HIGH is there to handle (in spi->mode).

The SSFRM issue is, briefly, that it forces deselect
of the chip between transfer segments even when the
driver doesn't want that.  If it's not disabled, the
transfer() routine needs integrity checks to make
sure it rejects all messages that don't expect that
deselection (unless cs_control/gpio_cs is used for
that particular spi_device).

The cs_control issue is more just simplification:  as
I recall, all users are just wrapping GPIOS, and giving
up potential SPI_CS_HIGH support while doing it.

- Dave


============
From: "Eric Miao" <[EMAIL PROTECTED]>

Most SPI peripherals use GPIOs as their chip select, introduce .gpio_cs
for this, to avoid 

Signed-off-by: Eric Miao <[EMAIL PROTECTED]>
---
 arch/arm/mach-pxa/include/mach/pxa2xx_spi.h |    1 +
 drivers/spi/pxa2xx_spi.c                    |   92 ++++++++++++++++++++++-----
 2 files changed, 78 insertions(+), 15 deletions(-)

diff --git a/arch/arm/mach-pxa/include/mach/pxa2xx_spi.h
b/arch/arm/mach-pxa/include/mach/pxa2xx_spi.h
index 2206cb6..b87cecd 100644
--- a/arch/arm/mach-pxa/include/mach/pxa2xx_spi.h
+++ b/arch/arm/mach-pxa/include/mach/pxa2xx_spi.h
@@ -38,6 +38,7 @@ struct pxa2xx_spi_chip {
        u8 dma_burst_size;
        u32 timeout;
        u8 enable_loopback;
+       int gpio_cs;
        void (*cs_control)(u32 command);
 };

diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index 34c7c98..98d2338 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -28,6 +28,7 @@
 #include <linux/workqueue.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
+#include <linux/gpio.h>

 #include <asm/io.h>
 #include <asm/irq.h>
@@ -164,6 +165,8 @@ struct chip_data {
        u8 enable_dma;
        u8 bits_per_word;
        u32 speed_hz;
+       int gpio_cs;
+       unsigned gpio_cs_inverted : 1;
        int (*write)(struct driver_data *drv_data);
        int (*read)(struct driver_data *drv_data);
        void (*cs_control)(u32 command);
@@ -171,6 +174,32 @@ struct chip_data {

 static void pump_messages(struct work_struct *work);

+static void cs_assert(struct driver_data *drv_data)
+{
+       struct chip_data *chip = drv_data->cur_chip;
+
+       if (chip->cs_control) {
+               chip->cs_control(PXA2XX_CS_ASSERT);
+               return;
+       }
+
+       if (gpio_is_valid(chip->gpio_cs))
+               gpio_set_value(chip->gpio_cs, chip->gpio_cs_inverted);
+}
+
+static void cs_deassert(struct driver_data *drv_data)
+{
+       struct chip_data *chip = drv_data->cur_chip;
+
+       if (chip->cs_control) {
+               chip->cs_control(PXA2XX_CS_DEASSERT);
+               return;
+       }
+
+       if (gpio_is_valid(chip->gpio_cs))
+               gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted);
+}
+
 static int flush(struct driver_data *drv_data)
 {
        unsigned long limit = loops_per_jiffy << 1;
@@ -187,10 +216,6 @@ static int flush(struct driver_data *drv_data)
        return limit;
 }

-static void null_cs_control(u32 command)
-{
-}
-
 static int null_writer(struct driver_data *drv_data)
 {
        void __iomem *reg = drv_data->ioaddr;
@@ -398,7 +423,6 @@ static void giveback(struct driver_data *drv_data)
        msg = drv_data->cur_msg;
        drv_data->cur_msg = NULL;
        drv_data->cur_transfer = NULL;
-       drv_data->cur_chip = NULL;
        queue_work(drv_data->workqueue, &drv_data->pump_messages);
        spin_unlock_irqrestore(&drv_data->lock, flags);

@@ -407,7 +431,9 @@ static void giveback(struct driver_data *drv_data)
                                        transfer_list);

        if (!last_transfer->cs_change)
-               drv_data->cs_control(PXA2XX_CS_DEASSERT);
+               cs_deassert(drv_data);
+
+       drv_data->cur_chip = NULL;

        msg->state = NULL;
        if (msg->complete)
@@ -493,7 +519,7 @@ static void dma_transfer_complete(struct driver_data 
*drv_data)
        /* Release chip select if requested, transfer delays are
         * handled in pump_transfers */
        if (drv_data->cs_change)
-               drv_data->cs_control(PXA2XX_CS_DEASSERT);
+               cs_deassert(drv_data);

        /* Move to next transfer */
        msg->state = next_transfer(drv_data);
@@ -605,7 +631,7 @@ static void int_transfer_complete(struct driver_data 
*drv_data)
        /* Release chip select if requested, transfer delays are
         * handled in pump_transfers */
        if (drv_data->cs_change)
-               drv_data->cs_control(PXA2XX_CS_DEASSERT);
+               cs_deassert(drv_data);

        /* Move to next transfer */
        drv_data->cur_msg->state = next_transfer(drv_data);
@@ -868,7 +894,6 @@ static void pump_transfers(unsigned long data)
        }
        drv_data->n_bytes = chip->n_bytes;
        drv_data->dma_width = chip->dma_width;
-       drv_data->cs_control = chip->cs_control;
        drv_data->tx = (void *)transfer->tx_buf;
        drv_data->tx_end = drv_data->tx + transfer->len;
        drv_data->rx = transfer->rx_buf;
@@ -1020,7 +1045,7 @@ static void pump_transfers(unsigned long data)
         * this driver uses struct pxa2xx_spi_chip.cs_control to
         * specify a CS handling function, and it ignores most
         * struct spi_device.mode[s], including SPI_CS_HIGH */
-       drv_data->cs_control(PXA2XX_CS_ASSERT);
+       cs_assert(drv_data);

        /* after chip select, release the data by enabling service
         * requests and interrupts, without changing any mode bits */
@@ -1098,6 +1123,43 @@ static int transfer(struct spi_device *spi, struct 
spi_message *msg)
 /* the spi->mode bits understood by this driver: */
 #define MODEBITS (SPI_CPOL | SPI_CPHA)

+static int setup_cs(struct spi_device *spi, struct chip_data *chip,
+                   struct pxa2xx_spi_chip *chip_info)
+{
+       int err = 0;
+       
+       if (chip_info == NULL)
+               return 0;
+
+       /* NOTE: setup() can be called multiple times, possibly with
+        * different chip_info, previously requested GPIO shall be
+        * released, stumped :(
+        */
+       if (gpio_is_valid(chip->gpio_cs))
+               gpio_free(chip->gpio_cs);
+
+       if (chip_info->cs_control) {
+               chip->cs_control = chip_info->cs_control;
+               return 0;
+       }
+
+       if (gpio_is_valid(chip_info->gpio_cs)) {
+               err = gpio_request(chip_info->gpio_cs, "SPI_CS");
+               if (err) {
+                       dev_err(&spi->dev, "failed to request CS GPIO%d\n",
+                                       chip_info->gpio_cs);
+                       return err;
+               }
+
+               chip->gpio_cs = chip_info->gpio_cs;
+               chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH;
+
+               gpio_direction_output(chip->gpio_cs, !chip->gpio_cs_inverted);
+       }
+
+       return err;
+}
+
 static int setup(struct spi_device *spi)
 {
        struct pxa2xx_spi_chip *chip_info = NULL;
@@ -1141,7 +1203,7 @@ static int setup(struct spi_device *spi)
                        return -ENOMEM;
                }

-               chip->cs_control = null_cs_control;
+               chip->gpio_cs = -1;
                chip->enable_dma = 0;
                chip->timeout = 1000;
                chip->threshold = SSCR1_RxTresh(1) | SSCR1_TxTresh(1);
@@ -1156,9 +1218,6 @@ static int setup(struct spi_device *spi)
        /* chip_info isn't always needed */
        chip->cr1 = 0;
        if (chip_info) {
-               if (chip_info->cs_control)
-                       chip->cs_control = chip_info->cs_control;
-
                chip->timeout = chip_info->timeout;

                chip->threshold = (SSCR1_RxTresh(chip_info->rx_threshold) &
@@ -1238,13 +1297,16 @@ static int setup(struct spi_device *spi)

        spi_set_ctldata(spi, chip);

-       return 0;
+       return setup_cs(spi, chip, chip_info);
 }

 static void cleanup(struct spi_device *spi)
 {
        struct chip_data *chip = spi_get_ctldata(spi);

+       if (gpio_is_valid(chip->gpio_cs))
+               gpio_free(chip->gpio_cs);
+
        kfree(chip);
 }

-- 
1.5.4.3


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
spi-devel-general mailing list
spi-devel-general@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

Reply via email to