]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/spi/dw_spi.c
spi/dw_spi: add DMA support
[karo-tx-linux.git] / drivers / spi / dw_spi.c
index b50bf5ba873f65628f43f6b438903599921f5cf5..497ecb3ab83f68c744efee09b2ee693a1f723ca1 100644 (file)
@@ -288,8 +288,10 @@ static void *next_transfer(struct dw_spi *dws)
  */
 static int map_dma_buffers(struct dw_spi *dws)
 {
-       if (!dws->cur_msg->is_dma_mapped || !dws->dma_inited
-               || !dws->cur_chip->enable_dma)
+       if (!dws->cur_msg->is_dma_mapped
+               || !dws->dma_inited
+               || !dws->cur_chip->enable_dma
+               || !dws->dma_ops)
                return 0;
 
        if (dws->cur_transfer->tx_dma)
@@ -341,7 +343,7 @@ static void int_error_stop(struct dw_spi *dws, const char *msg)
        tasklet_schedule(&dws->pump_transfers);
 }
 
-static void transfer_complete(struct dw_spi *dws)
+void dw_spi_xfer_done(struct dw_spi *dws)
 {
        /* Update total byte transfered return count actual bytes read */
        dws->cur_msg->actual_length += dws->len;
@@ -356,6 +358,7 @@ static void transfer_complete(struct dw_spi *dws)
        } else
                tasklet_schedule(&dws->pump_transfers);
 }
+EXPORT_SYMBOL_GPL(dw_spi_xfer_done);
 
 static irqreturn_t interrupt_transfer(struct dw_spi *dws)
 {
@@ -387,7 +390,7 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
                if (dws->tx_end > dws->tx)
                        spi_umask_intr(dws, SPI_INT_TXEI);
                else
-                       transfer_complete(dws);
+                       dw_spi_xfer_done(dws);
        }
 
        return IRQ_HANDLED;
@@ -422,11 +425,7 @@ static void poll_transfer(struct dw_spi *dws)
         */
        dws->read(dws);
 
-       transfer_complete(dws);
-}
-
-static void dma_transfer(struct dw_spi *dws, int cs_change)
-{
+       dw_spi_xfer_done(dws);
 }
 
 static void pump_transfers(unsigned long data)
@@ -608,7 +607,7 @@ static void pump_transfers(unsigned long data)
        }
 
        if (dws->dma_mapped)
-               dma_transfer(dws, cs_change);
+               dws->dma_ops->dma_transfer(dws, cs_change);
 
        if (chip->poll_mode)
                poll_transfer(dws);
@@ -904,11 +903,17 @@ int __devinit dw_spi_add_host(struct dw_spi *dws)
        master->setup = dw_spi_setup;
        master->transfer = dw_spi_transfer;
 
-       dws->dma_inited = 0;
-
        /* Basic HW init */
        spi_hw_init(dws);
 
+       if (dws->dma_ops && dws->dma_ops->dma_init) {
+               ret = dws->dma_ops->dma_init(dws);
+               if (ret) {
+                       dev_warn(&master->dev, "DMA init failed\n");
+                       dws->dma_inited = 0;
+               }
+       }
+
        /* Initial and start queue */
        ret = init_queue(dws);
        if (ret) {
@@ -933,6 +938,8 @@ int __devinit dw_spi_add_host(struct dw_spi *dws)
 
 err_queue_alloc:
        destroy_queue(dws);
+       if (dws->dma_ops && dws->dma_ops->dma_exit)
+               dws->dma_ops->dma_exit(dws);
 err_diable_hw:
        spi_enable_chip(dws, 0);
        free_irq(dws->irq, dws);
@@ -957,6 +964,8 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws)
                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);
        /* Disable clk */
        spi_set_clk(dws, 0);