]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/spi/spi-dw.c
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
[karo-tx-linux.git] / drivers / spi / spi-dw.c
index 712ac5629cd46cea34fa6713a5a0462186aa6de0..29f33143b795651e773ea7b9d5cc0f80c7cb2575 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"
 
 #define DONE_STATE     ((void *)2)
 #define ERROR_STATE    ((void *)-1)
 
-#define QUEUE_RUNNING  0
-#define QUEUE_STOPPED  1
-
-#define MRST_SPI_DEASSERT      0
-#define MRST_SPI_ASSERT                1
-
 /* Slave spi_dev related */
 struct chip_data {
        u16 cr0;
@@ -263,28 +258,22 @@ static int map_dma_buffers(struct dw_spi *dws)
 static void giveback(struct dw_spi *dws)
 {
        struct spi_transfer *last_transfer;
-       unsigned long flags;
        struct spi_message *msg;
 
-       spin_lock_irqsave(&dws->lock, flags);
        msg = dws->cur_msg;
        dws->cur_msg = NULL;
        dws->cur_transfer = NULL;
        dws->prev_chip = dws->cur_chip;
        dws->cur_chip = NULL;
        dws->dma_mapped = 0;
-       queue_work(dws->workqueue, &dws->pump_messages);
-       spin_unlock_irqrestore(&dws->lock, flags);
 
        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);
 
-       msg->state = NULL;
-       if (msg->complete)
-               msg->complete(msg->context);
+       spi_finalize_current_message(dws->master);
 }
 
 static void int_error_stop(struct dw_spi *dws, const char *msg)
@@ -502,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);
@@ -529,30 +518,12 @@ early_exit:
        return;
 }
 
-static void pump_messages(struct work_struct *work)
+static int dw_spi_transfer_one_message(struct spi_master *master,
+               struct spi_message *msg)
 {
-       struct dw_spi *dws =
-               container_of(work, struct dw_spi, pump_messages);
-       unsigned long flags;
-
-       /* Lock queue and check for queue work */
-       spin_lock_irqsave(&dws->lock, flags);
-       if (list_empty(&dws->queue) || dws->run == QUEUE_STOPPED) {
-               dws->busy = 0;
-               spin_unlock_irqrestore(&dws->lock, flags);
-               return;
-       }
-
-       /* Make sure we are not already running a message */
-       if (dws->cur_msg) {
-               spin_unlock_irqrestore(&dws->lock, flags);
-               return;
-       }
-
-       /* Extract head of queue */
-       dws->cur_msg = list_entry(dws->queue.next, struct spi_message, queue);
-       list_del_init(&dws->cur_msg->queue);
+       struct dw_spi *dws = spi_master_get_devdata(master);
 
+       dws->cur_msg = msg;
        /* Initial message state*/
        dws->cur_msg->state = START_STATE;
        dws->cur_transfer = list_entry(dws->cur_msg->transfers.next,
@@ -560,46 +531,9 @@ static void pump_messages(struct work_struct *work)
                                                transfer_list);
        dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi);
 
-       /* Mark as busy and launch transfers */
+       /* Launch transfers */
        tasklet_schedule(&dws->pump_transfers);
 
-       dws->busy = 1;
-       spin_unlock_irqrestore(&dws->lock, flags);
-}
-
-/* spi_device use this to queue in their spi_msg */
-static int dw_spi_transfer(struct spi_device *spi, struct spi_message *msg)
-{
-       struct dw_spi *dws = spi_master_get_devdata(spi->master);
-       unsigned long flags;
-
-       spin_lock_irqsave(&dws->lock, flags);
-
-       if (dws->run == QUEUE_STOPPED) {
-               spin_unlock_irqrestore(&dws->lock, flags);
-               return -ESHUTDOWN;
-       }
-
-       msg->actual_length = 0;
-       msg->status = -EINPROGRESS;
-       msg->state = START_STATE;
-
-       list_add_tail(&msg->queue, &dws->queue);
-
-       if (dws->run == QUEUE_RUNNING && !dws->busy) {
-
-               if (dws->cur_transfer || dws->cur_msg)
-                       queue_work(dws->workqueue,
-                                       &dws->pump_messages);
-               else {
-                       /* If no other data transaction in air, just go */
-                       spin_unlock_irqrestore(&dws->lock, flags);
-                       pump_messages(&dws->pump_messages);
-                       return 0;
-               }
-       }
-
-       spin_unlock_irqrestore(&dws->lock, flags);
        return 0;
 }
 
@@ -608,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);
@@ -661,81 +596,13 @@ static int dw_spi_setup(struct spi_device *spi)
                        | (spi->mode  << SPI_MODE_OFFSET)
                        | (chip->tmode << SPI_TMOD_OFFSET);
 
-       return 0;
-}
-
-static int init_queue(struct dw_spi *dws)
-{
-       INIT_LIST_HEAD(&dws->queue);
-       spin_lock_init(&dws->lock);
-
-       dws->run = QUEUE_STOPPED;
-       dws->busy = 0;
-
-       tasklet_init(&dws->pump_transfers,
-                       pump_transfers, (unsigned long)dws);
-
-       INIT_WORK(&dws->pump_messages, pump_messages);
-       dws->workqueue = create_singlethread_workqueue(
-                                       dev_name(dws->master->dev.parent));
-       if (dws->workqueue == NULL)
-               return -EBUSY;
-
-       return 0;
-}
-
-static int start_queue(struct dw_spi *dws)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&dws->lock, flags);
-
-       if (dws->run == QUEUE_RUNNING || dws->busy) {
-               spin_unlock_irqrestore(&dws->lock, flags);
-               return -EBUSY;
+       if (gpio_is_valid(spi->cs_gpio)) {
+               ret = gpio_direction_output(spi->cs_gpio,
+                               !(spi->mode & SPI_CS_HIGH));
+               if (ret)
+                       return ret;
        }
 
-       dws->run = QUEUE_RUNNING;
-       dws->cur_msg = NULL;
-       dws->cur_transfer = NULL;
-       dws->cur_chip = NULL;
-       dws->prev_chip = NULL;
-       spin_unlock_irqrestore(&dws->lock, flags);
-
-       queue_work(dws->workqueue, &dws->pump_messages);
-
-       return 0;
-}
-
-static int stop_queue(struct dw_spi *dws)
-{
-       unsigned long flags;
-       unsigned limit = 50;
-       int status = 0;
-
-       spin_lock_irqsave(&dws->lock, flags);
-       dws->run = QUEUE_STOPPED;
-       while ((!list_empty(&dws->queue) || dws->busy) && limit--) {
-               spin_unlock_irqrestore(&dws->lock, flags);
-               msleep(10);
-               spin_lock_irqsave(&dws->lock, flags);
-       }
-
-       if (!list_empty(&dws->queue) || dws->busy)
-               status = -EBUSY;
-       spin_unlock_irqrestore(&dws->lock, flags);
-
-       return status;
-}
-
-static int destroy_queue(struct dw_spi *dws)
-{
-       int status;
-
-       status = stop_queue(dws);
-       if (status != 0)
-               return status;
-       destroy_workqueue(dws->workqueue);
        return 0;
 }
 
@@ -794,7 +661,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
        master->bus_num = dws->bus_num;
        master->num_chipselect = dws->num_cs;
        master->setup = dw_spi_setup;
-       master->transfer = dw_spi_transfer;
+       master->transfer_one_message = dw_spi_transfer_one_message;
        master->max_speed_hz = dws->max_freq;
 
        /* Basic HW init */
@@ -808,33 +675,21 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
                }
        }
 
-       /* Initial and start queue */
-       ret = init_queue(dws);
-       if (ret) {
-               dev_err(&master->dev, "problem initializing queue\n");
-               goto err_diable_hw;
-       }
-       ret = start_queue(dws);
-       if (ret) {
-               dev_err(&master->dev, "problem starting queue\n");
-               goto err_diable_hw;
-       }
+       tasklet_init(&dws->pump_transfers, pump_transfers, (unsigned long)dws);
 
        spi_master_set_devdata(master, dws);
        ret = devm_spi_register_master(dev, master);
        if (ret) {
                dev_err(&master->dev, "problem registering spi master\n");
-               goto err_queue_alloc;
+               goto err_dma_exit;
        }
 
        mrst_spi_debugfs_init(dws);
        return 0;
 
-err_queue_alloc:
-       destroy_queue(dws);
+err_dma_exit:
        if (dws->dma_ops && dws->dma_ops->dma_exit)
                dws->dma_ops->dma_exit(dws);
-err_diable_hw:
        spi_enable_chip(dws, 0);
 err_free_master:
        spi_master_put(master);
@@ -844,18 +699,10 @@ EXPORT_SYMBOL_GPL(dw_spi_add_host);
 
 void dw_spi_remove_host(struct dw_spi *dws)
 {
-       int status = 0;
-
        if (!dws)
                return;
        mrst_spi_debugfs_remove(dws);
 
-       /* Remove the queue */
-       status = destroy_queue(dws);
-       if (status != 0)
-               dev_err(&dws->master->dev,
-                       "dw_spi_remove: workqueue will not complete, message memory not freed\n");
-
        if (dws->dma_ops && dws->dma_ops->dma_exit)
                dws->dma_ops->dma_exit(dws);
        spi_enable_chip(dws, 0);
@@ -868,7 +715,7 @@ int dw_spi_suspend_host(struct dw_spi *dws)
 {
        int ret = 0;
 
-       ret = stop_queue(dws);
+       ret = spi_master_suspend(dws->master);
        if (ret)
                return ret;
        spi_enable_chip(dws, 0);
@@ -882,7 +729,7 @@ int dw_spi_resume_host(struct dw_spi *dws)
        int ret;
 
        spi_hw_init(dws);
-       ret = start_queue(dws);
+       ret = spi_master_resume(dws->master);
        if (ret)
                dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret);
        return ret;