Merge branch 'core/softlockup' of git://git.kernel.org/pub/scm/linux/kernel/git/tip...
[sfrench/cifs-2.6.git] / drivers / spi / pxa2xx_spi.c
index 33fcef3150d4c63ae0ef67b24b7566ef495bd145..c1688c71f052e252acdad47df85bae6f4fe5282a 100644 (file)
@@ -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>
@@ -53,6 +54,7 @@ MODULE_ALIAS("platform:pxa2xx-spi");
 #define RESET_DMA_CHANNEL      (DCSR_NODESC | DMA_INT_MASK)
 #define IS_DMA_ALIGNED(x)      ((((u32)(x)) & 0x07) == 0)
 #define MAX_DMA_LEN            8191
+#define DMA_ALIGNMENT          8
 
 /*
  * for testing SSCR1 changes that require SSP restart, basically
@@ -166,6 +168,8 @@ struct chip_data {
        u8 enable_dma;
        u8 bits_per_word;
        u32 speed_hz;
+       int gpio_cs;
+       int gpio_cs_inverted;
        int (*write)(struct driver_data *drv_data);
        int (*read)(struct driver_data *drv_data);
        void (*cs_control)(u32 command);
@@ -173,6 +177,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_ASSERT);
+               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;
@@ -189,10 +219,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;
@@ -400,7 +426,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);
 
@@ -416,7 +441,7 @@ static void giveback(struct driver_data *drv_data)
         * a message with an error, or next message is for another chip
         */
        if (!last_transfer->cs_change)
-               drv_data->cs_control(PXA2XX_CS_DEASSERT);
+               cs_deassert(drv_data);
        else {
                struct spi_message *next_msg;
 
@@ -445,12 +470,14 @@ static void giveback(struct driver_data *drv_data)
                if (next_msg && next_msg->spi != msg->spi)
                        next_msg = NULL;
                if (!next_msg || msg->state == ERROR_STATE)
-                       drv_data->cs_control(PXA2XX_CS_DEASSERT);
+                       cs_deassert(drv_data);
        }
 
        msg->state = NULL;
        if (msg->complete)
                msg->complete(msg->context);
+
+       drv_data->cur_chip = NULL;
 }
 
 static int wait_ssp_rx_stall(void const __iomem *ioaddr)
@@ -887,7 +914,7 @@ static void pump_transfers(unsigned long data)
 
                /* Drop chip select only if cs_change is requested */
                if (previous->cs_change)
-                       drv_data->cs_control(PXA2XX_CS_DEASSERT);
+                       cs_deassert(drv_data);
        }
 
        /* Check for transfers that need multiple DMA segments */
@@ -922,7 +949,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;
@@ -1084,11 +1110,7 @@ static void pump_transfers(unsigned long data)
                        write_SSTO(chip->timeout, reg);
        }
 
-       /* FIXME, need to handle cs polarity,
-        * 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 */
@@ -1166,6 +1188,44 @@ 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 == NULL || chip_info == NULL)
+               return 0;
+
+       /* NOTE: setup() can be called multiple times, possibly with
+        * different chip_info, release previously requested GPIO
+        */
+       if (gpio_is_valid(chip->gpio_cs))
+               gpio_free(chip->gpio_cs);
+
+       /* If (*cs_control) is provided, ignore GPIO chip select */
+       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 chip select "
+                                       "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;
+
+               err = 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;
@@ -1211,7 +1271,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 = TIMOUT_DFLT;
                chip->dma_burst_size = drv_data->master_info->enable_dma ?
@@ -1225,8 +1285,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;
                if (chip_info->timeout)
                        chip->timeout = chip_info->timeout;
                if (chip_info->tx_threshold)
@@ -1308,13 +1366,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);
 }
 
@@ -1438,6 +1499,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
 
        master->bus_num = pdev->id;
        master->num_chipselect = platform_info->num_chipselect;
+       master->dma_alignment = DMA_ALIGNMENT;
        master->cleanup = cleanup;
        master->setup = setup;
        master->transfer = transfer;