Merge remote-tracking branches 'spi/topic/atmel', 'spi/topic/bcm63xx', 'spi/topic...
authorMark Brown <broonie@kernel.org>
Wed, 26 Apr 2017 14:57:59 +0000 (15:57 +0100)
committerMark Brown <broonie@kernel.org>
Wed, 26 Apr 2017 14:57:59 +0000 (15:57 +0100)
Documentation/devicetree/bindings/spi/spi-bcm63xx-hsspi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-bcm63xx.txt [new file with mode: 0644]
drivers/spi/spi-atmel.c
drivers/spi/spi-bcm63xx-hsspi.c
drivers/spi/spi-bcm63xx.c
drivers/spi/spi-cadence.c
drivers/spi/spi-davinci.c

diff --git a/Documentation/devicetree/bindings/spi/spi-bcm63xx-hsspi.txt b/Documentation/devicetree/bindings/spi/spi-bcm63xx-hsspi.txt
new file mode 100644 (file)
index 0000000..37b29ee
--- /dev/null
@@ -0,0 +1,33 @@
+Binding for Broadcom BCM6328 High Speed SPI controller
+
+Required properties:
+- compatible: must contain of "brcm,bcm6328-hsspi".
+- reg: Base address and size of the controllers memory area.
+- interrupts: Interrupt for the SPI block.
+- clocks: phandles of the SPI clock and the PLL clock.
+- clock-names: must be "hsspi", "pll".
+- #address-cells: <1>, as required by generic SPI binding.
+- #size-cells: <0>, also as required by generic SPI binding.
+
+Optional properties:
+- num-cs: some controllers have less than 8 cs signals. Defaults to 8
+  if absent.
+
+Child nodes as per the generic SPI binding.
+
+Example:
+
+       spi@10001000 {
+               compatible = "brcm,bcm6328-hsspi";
+               reg = <0x10001000 0x600>;
+
+               interrupts = <29>;
+
+               clocks = <&clkctl 9>, <&hsspi_pll>;
+               clock-names = "hsspi", "pll";
+
+               num-cs = <2>;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
diff --git a/Documentation/devicetree/bindings/spi/spi-bcm63xx.txt b/Documentation/devicetree/bindings/spi/spi-bcm63xx.txt
new file mode 100644 (file)
index 0000000..1c16f66
--- /dev/null
@@ -0,0 +1,33 @@
+Binding for Broadcom BCM6348/BCM6358 SPI controller
+
+Required properties:
+- compatible: must contain one of "brcm,bcm6348-spi", "brcm,bcm6358-spi".
+- reg: Base address and size of the controllers memory area.
+- interrupts: Interrupt for the SPI block.
+- clocks: phandle of the SPI clock.
+- clock-names: has to be "spi".
+- #address-cells: <1>, as required by generic SPI binding.
+- #size-cells: <0>, also as required by generic SPI binding.
+
+Optional properties:
+- num-cs: some controllers have less than 8 cs signals. Defaults to 8
+  if absent.
+
+Child nodes as per the generic SPI binding.
+
+Example:
+
+       spi@10000800 {
+               compatible = "brcm,bcm6368-spi", "brcm,bcm6358-spi";
+               reg = <0x10000800 0x70c>;
+
+               interrupts = <1>;
+
+               clocks = <&clkctl 9>;
+               clock-names = "spi";
+
+               num-cs = <5>;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
index 0e7712bac3b6e1411e49890a5668c068371631f0..1eb83c9613d59cb0a3ab709aea61516e59226c4a 100644 (file)
@@ -1464,6 +1464,25 @@ static int atmel_spi_gpio_cs(struct platform_device *pdev)
        return 0;
 }
 
+static void atmel_spi_init(struct atmel_spi *as)
+{
+       spi_writel(as, CR, SPI_BIT(SWRST));
+       spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
+       if (as->caps.has_wdrbt) {
+               spi_writel(as, MR, SPI_BIT(WDRBT) | SPI_BIT(MODFDIS)
+                               | SPI_BIT(MSTR));
+       } else {
+               spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
+       }
+
+       if (as->use_pdc)
+               spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
+       spi_writel(as, CR, SPI_BIT(SPIEN));
+
+       if (as->fifo_size)
+               spi_writel(as, CR, SPI_BIT(FIFOEN));
+}
+
 static int atmel_spi_probe(struct platform_device *pdev)
 {
        struct resource         *regs;
@@ -1572,26 +1591,14 @@ static int atmel_spi_probe(struct platform_device *pdev)
 
        as->spi_clk = clk_get_rate(clk);
 
-       spi_writel(as, CR, SPI_BIT(SWRST));
-       spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
-       if (as->caps.has_wdrbt) {
-               spi_writel(as, MR, SPI_BIT(WDRBT) | SPI_BIT(MODFDIS)
-                               | SPI_BIT(MSTR));
-       } else {
-               spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
-       }
-
-       if (as->use_pdc)
-               spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
-       spi_writel(as, CR, SPI_BIT(SPIEN));
-
        as->fifo_size = 0;
        if (!of_property_read_u32(pdev->dev.of_node, "atmel,fifo-size",
                                  &as->fifo_size)) {
                dev_info(&pdev->dev, "Using FIFO (%u data)\n", as->fifo_size);
-               spi_writel(as, CR, SPI_BIT(FIFOEN));
        }
 
+       atmel_spi_init(as);
+
        pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT);
        pm_runtime_use_autosuspend(&pdev->dev);
        pm_runtime_set_active(&pdev->dev);
@@ -1695,8 +1702,17 @@ static int atmel_spi_suspend(struct device *dev)
 static int atmel_spi_resume(struct device *dev)
 {
        struct spi_master *master = dev_get_drvdata(dev);
+       struct atmel_spi *as = spi_master_get_devdata(master);
        int ret;
 
+       ret = clk_prepare_enable(as->clk);
+       if (ret)
+               return ret;
+
+       atmel_spi_init(as);
+
+       clk_disable_unprepare(as->clk);
+
        if (!pm_runtime_suspended(dev)) {
                ret = atmel_spi_runtime_resume(dev);
                if (ret)
index 55789f7cda9280b2f0d21b65b6a7f3c019780047..5514cd02e93a565d49b4429d6f4e35eb39b15991 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/interrupt.h>
 #include <linux/spi/spi.h>
 #include <linux/mutex.h>
+#include <linux/of.h>
 
 #define HSSPI_GLOBAL_CTRL_REG                  0x0
 #define GLOBAL_CTRL_CS_POLARITY_SHIFT          0
@@ -91,6 +92,7 @@
 
 #define HSSPI_MAX_SYNC_CLOCK                   30000000
 
+#define HSSPI_SPI_MAX_CS                       8
 #define HSSPI_BUS_NUM                          1 /* 0 is legacy SPI */
 
 struct bcm63xx_hsspi {
@@ -332,7 +334,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct clk *clk;
        int irq, ret;
-       u32 reg, rate;
+       u32 reg, rate, num_cs = HSSPI_SPI_MAX_CS;
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
@@ -351,8 +353,16 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
                return PTR_ERR(clk);
 
        rate = clk_get_rate(clk);
-       if (!rate)
-               return -EINVAL;
+       if (!rate) {
+               struct clk *pll_clk = devm_clk_get(dev, "pll");
+
+               if (IS_ERR(pll_clk))
+                       return PTR_ERR(pll_clk);
+
+               rate = clk_get_rate(pll_clk);
+               if (!rate)
+                       return -EINVAL;
+       }
 
        ret = clk_prepare_enable(clk);
        if (ret)
@@ -374,8 +384,17 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
        mutex_init(&bs->bus_mutex);
        init_completion(&bs->done);
 
-       master->bus_num = HSSPI_BUS_NUM;
-       master->num_chipselect = 8;
+       master->dev.of_node = dev->of_node;
+       if (!dev->of_node)
+               master->bus_num = HSSPI_BUS_NUM;
+
+       of_property_read_u32(dev->of_node, "num-cs", &num_cs);
+       if (num_cs > 8) {
+               dev_warn(dev, "unsupported number of cs (%i), reducing to 8\n",
+                        num_cs);
+               num_cs = HSSPI_SPI_MAX_CS;
+       }
+       master->num_chipselect = num_cs;
        master->setup = bcm63xx_hsspi_setup;
        master->transfer_one_message = bcm63xx_hsspi_transfer_one;
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
@@ -461,10 +480,16 @@ static int bcm63xx_hsspi_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(bcm63xx_hsspi_pm_ops, bcm63xx_hsspi_suspend,
                         bcm63xx_hsspi_resume);
 
+static const struct of_device_id bcm63xx_hsspi_of_match[] = {
+       { .compatible = "brcm,bcm6328-hsspi", },
+       { },
+};
+
 static struct platform_driver bcm63xx_hsspi_driver = {
        .driver = {
                .name   = "bcm63xx-hsspi",
                .pm     = &bcm63xx_hsspi_pm_ops,
+               .of_match_table = bcm63xx_hsspi_of_match,
        },
        .probe          = bcm63xx_hsspi_probe,
        .remove         = bcm63xx_hsspi_remove,
index fee747030ee67e4cf2e81ab0a8e6329e861675eb..247f71b022350aa3a951458a6f67492d2ba5f8c6 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/completion.h>
 #include <linux/err.h>
 #include <linux/pm_runtime.h>
+#include <linux/of.h>
 
 /* BCM 6338/6348 SPI core */
 #define SPI_6348_RSET_SIZE             64
@@ -428,6 +429,13 @@ static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static size_t bcm63xx_spi_max_length(struct spi_device *spi)
+{
+       struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
+
+       return bs->fifo_size;
+}
+
 static const unsigned long bcm6348_spi_reg_offsets[] = {
        [SPI_CMD]               = SPI_6348_CMD,
        [SPI_INT_STATUS]        = SPI_6348_INT_STATUS,
@@ -477,21 +485,48 @@ static const struct platform_device_id bcm63xx_spi_dev_match[] = {
        },
 };
 
+static const struct of_device_id bcm63xx_spi_of_match[] = {
+       { .compatible = "brcm,bcm6348-spi", .data = &bcm6348_spi_reg_offsets },
+       { .compatible = "brcm,bcm6358-spi", .data = &bcm6358_spi_reg_offsets },
+       { },
+};
+
 static int bcm63xx_spi_probe(struct platform_device *pdev)
 {
        struct resource *r;
        const unsigned long *bcm63xx_spireg;
        struct device *dev = &pdev->dev;
-       int irq;
+       int irq, bus_num;
        struct spi_master *master;
        struct clk *clk;
        struct bcm63xx_spi *bs;
        int ret;
+       u32 num_cs = BCM63XX_SPI_MAX_CS;
 
-       if (!pdev->id_entry->driver_data)
-               return -EINVAL;
+       if (dev->of_node) {
+               const struct of_device_id *match;
+
+               match = of_match_node(bcm63xx_spi_of_match, dev->of_node);
+               if (!match)
+                       return -EINVAL;
+               bcm63xx_spireg = match->data;
+
+               of_property_read_u32(dev->of_node, "num-cs", &num_cs);
+               if (num_cs > BCM63XX_SPI_MAX_CS) {
+                       dev_warn(dev, "unsupported number of cs (%i), reducing to 8\n",
+                                num_cs);
+                       num_cs = BCM63XX_SPI_MAX_CS;
+               }
 
-       bcm63xx_spireg = (const unsigned long *)pdev->id_entry->driver_data;
+               bus_num = -1;
+       } else if (pdev->id_entry->driver_data) {
+               const struct platform_device_id *match = pdev->id_entry;
+
+               bcm63xx_spireg = (const unsigned long *)match->driver_data;
+               bus_num = BCM63XX_SPI_BUS_NUM;
+       } else {
+               return -EINVAL;
+       }
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
@@ -536,11 +571,14 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
                goto out_err;
        }
 
-       master->bus_num = BCM63XX_SPI_BUS_NUM;
-       master->num_chipselect = BCM63XX_SPI_MAX_CS;
+       master->dev.of_node = dev->of_node;
+       master->bus_num = bus_num;
+       master->num_chipselect = num_cs;
        master->transfer_one_message = bcm63xx_spi_transfer_one;
        master->mode_bits = MODEBITS;
        master->bits_per_word_mask = SPI_BPW_MASK(8);
+       master->max_transfer_size = bcm63xx_spi_max_length;
+       master->max_message_size = bcm63xx_spi_max_length;
        master->auto_runtime_pm = true;
        bs->msg_type_shift = bs->reg_offsets[SPI_MSG_TYPE_SHIFT];
        bs->msg_ctl_width = bs->reg_offsets[SPI_MSG_CTL_WIDTH];
@@ -624,6 +662,7 @@ static struct platform_driver bcm63xx_spi_driver = {
        .driver = {
                .name   = "bcm63xx-spi",
                .pm     = &bcm63xx_spi_pm_ops,
+               .of_match_table = bcm63xx_spi_of_match,
        },
        .id_table       = bcm63xx_spi_dev_match,
        .probe          = bcm63xx_spi_probe,
index 1c57ce64abba029a209fca1caf5495f294c5fa85..f0b5c7b91f37b0921410f599cf485a775152e691 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
@@ -127,6 +128,10 @@ struct cdns_spi {
        u32 is_decoded_cs;
 };
 
+struct cdns_spi_device_data {
+       bool gpio_requested;
+};
+
 /* Macros for the SPI controller read/write */
 static inline u32 cdns_spi_read(struct cdns_spi *xspi, u32 offset)
 {
@@ -456,6 +461,64 @@ static int cdns_unprepare_transfer_hardware(struct spi_master *master)
        return 0;
 }
 
+static int cdns_spi_setup(struct spi_device *spi)
+{
+
+       int ret = -EINVAL;
+       struct cdns_spi_device_data *cdns_spi_data = spi_get_ctldata(spi);
+
+       /* this is a pin managed by the controller, leave it alone */
+       if (spi->cs_gpio == -ENOENT)
+               return 0;
+
+       /* this seems to be the first time we're here */
+       if (!cdns_spi_data) {
+               cdns_spi_data = kzalloc(sizeof(*cdns_spi_data), GFP_KERNEL);
+               if (!cdns_spi_data)
+                       return -ENOMEM;
+               cdns_spi_data->gpio_requested = false;
+               spi_set_ctldata(spi, cdns_spi_data);
+       }
+
+       /* if we haven't done so, grab the gpio */
+       if (!cdns_spi_data->gpio_requested && gpio_is_valid(spi->cs_gpio)) {
+               ret = gpio_request_one(spi->cs_gpio,
+                                      (spi->mode & SPI_CS_HIGH) ?
+                                      GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
+                                      dev_name(&spi->dev));
+               if (ret)
+                       dev_err(&spi->dev, "can't request chipselect gpio %d\n",
+                               spi->cs_gpio);
+               else
+                       cdns_spi_data->gpio_requested = true;
+       } else {
+               if (gpio_is_valid(spi->cs_gpio)) {
+                       int mode = ((spi->mode & SPI_CS_HIGH) ?
+                                   GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH);
+
+                       ret = gpio_direction_output(spi->cs_gpio, mode);
+                       if (ret)
+                               dev_err(&spi->dev, "chipselect gpio %d setup failed (%d)\n",
+                                       spi->cs_gpio, ret);
+               }
+       }
+
+       return ret;
+}
+
+static void cdns_spi_cleanup(struct spi_device *spi)
+{
+       struct cdns_spi_device_data *cdns_spi_data = spi_get_ctldata(spi);
+
+       if (cdns_spi_data) {
+               if (cdns_spi_data->gpio_requested)
+                       gpio_free(spi->cs_gpio);
+               kfree(cdns_spi_data);
+               spi_set_ctldata(spi, NULL);
+       }
+
+}
+
 /**
  * cdns_spi_probe - Probe method for the SPI driver
  * @pdev:      Pointer to the platform_device structure
@@ -555,6 +618,8 @@ static int cdns_spi_probe(struct platform_device *pdev)
        master->transfer_one = cdns_transfer_one;
        master->unprepare_transfer_hardware = cdns_unprepare_transfer_hardware;
        master->set_cs = cdns_spi_chipselect;
+       master->setup = cdns_spi_setup;
+       master->cleanup = cdns_spi_cleanup;
        master->auto_runtime_pm = true;
        master->mode_bits = SPI_CPOL | SPI_CPHA;
 
index 02fb96797ac8b9ec52f41c8a13f93b290db0fc1c..595acdcfc7d0832fbe7ef1b232e039b005788541 100644 (file)
 #define SPIDEF         0x4c
 #define SPIFMT0                0x50
 
+#define DMA_MIN_BYTES  16
+
 /* SPI Controller driver's private data. */
 struct davinci_spi {
        struct spi_bitbang      bitbang;
@@ -389,6 +391,7 @@ static int davinci_spi_of_setup(struct spi_device *spi)
 {
        struct davinci_spi_config *spicfg = spi->controller_data;
        struct device_node *np = spi->dev.of_node;
+       struct davinci_spi *dspi = spi_master_get_devdata(spi->master);
        u32 prop;
 
        if (spicfg == NULL && np) {
@@ -400,6 +403,9 @@ static int davinci_spi_of_setup(struct spi_device *spi)
                if (!of_property_read_u32(np, "ti,spi-wdelay", &prop))
                        spicfg->wdelay = (u8)prop;
                spi->controller_data = spicfg;
+
+               if (dspi->dma_rx && dspi->dma_tx)
+                       spicfg->io_type = SPI_IO_TYPE_DMA;
        }
 
        return 0;
@@ -467,6 +473,22 @@ static void davinci_spi_cleanup(struct spi_device *spi)
                kfree(spicfg);
 }
 
+static bool davinci_spi_can_dma(struct spi_master *master,
+                               struct spi_device *spi,
+                               struct spi_transfer *xfer)
+{
+       struct davinci_spi_config *spicfg = spi->controller_data;
+       bool can_dma = false;
+
+       if (spicfg)
+               can_dma = (spicfg->io_type == SPI_IO_TYPE_DMA) &&
+                       (xfer->len >= DMA_MIN_BYTES) &&
+                       !is_vmalloc_addr(xfer->rx_buf) &&
+                       !is_vmalloc_addr(xfer->tx_buf);
+
+       return can_dma;
+}
+
 static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status)
 {
        struct device *sdev = dspi->bitbang.master->dev.parent;
@@ -581,8 +603,6 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
        struct davinci_spi_config *spicfg;
        struct davinci_spi_platform_data *pdata;
        unsigned uninitialized_var(rx_buf_count);
-       void *dummy_buf = NULL;
-       struct scatterlist sg_rx, sg_tx;
 
        dspi = spi_master_get_devdata(spi->master);
        pdata = &dspi->pdata;
@@ -605,10 +625,9 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
 
        reinit_completion(&dspi->done);
 
-       if (spicfg->io_type == SPI_IO_TYPE_INTR)
-               set_io_bits(dspi->base + SPIINT, SPIINT_MASKINT);
-
-       if (spicfg->io_type != SPI_IO_TYPE_DMA) {
+       if (!davinci_spi_can_dma(spi->master, spi, t)) {
+               if (spicfg->io_type != SPI_IO_TYPE_POLL)
+                       set_io_bits(dspi->base + SPIINT, SPIINT_MASKINT);
                /* start the transfer */
                dspi->wcount--;
                tx_data = dspi->get_tx(dspi);
@@ -630,51 +649,28 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
                };
                struct dma_async_tx_descriptor *rxdesc;
                struct dma_async_tx_descriptor *txdesc;
-               void *buf;
-
-               dummy_buf = kzalloc(t->len, GFP_KERNEL);
-               if (!dummy_buf)
-                       goto err_alloc_dummy_buf;
 
                dmaengine_slave_config(dspi->dma_rx, &dma_rx_conf);
                dmaengine_slave_config(dspi->dma_tx, &dma_tx_conf);
 
-               sg_init_table(&sg_rx, 1);
-               if (!t->rx_buf)
-                       buf = dummy_buf;
-               else
-                       buf = t->rx_buf;
-               t->rx_dma = dma_map_single(&spi->dev, buf,
-                               t->len, DMA_FROM_DEVICE);
-               if (dma_mapping_error(&spi->dev, !t->rx_dma)) {
-                       ret = -EFAULT;
-                       goto err_rx_map;
-               }
-               sg_dma_address(&sg_rx) = t->rx_dma;
-               sg_dma_len(&sg_rx) = t->len;
-
-               sg_init_table(&sg_tx, 1);
-               if (!t->tx_buf)
-                       buf = dummy_buf;
-               else
-                       buf = (void *)t->tx_buf;
-               t->tx_dma = dma_map_single(&spi->dev, buf,
-                               t->len, DMA_TO_DEVICE);
-               if (dma_mapping_error(&spi->dev, t->tx_dma)) {
-                       ret = -EFAULT;
-                       goto err_tx_map;
-               }
-               sg_dma_address(&sg_tx) = t->tx_dma;
-               sg_dma_len(&sg_tx) = t->len;
-
                rxdesc = dmaengine_prep_slave_sg(dspi->dma_rx,
-                               &sg_rx, 1, DMA_DEV_TO_MEM,
+                               t->rx_sg.sgl, t->rx_sg.nents, DMA_DEV_TO_MEM,
                                DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
                if (!rxdesc)
                        goto err_desc;
 
+               if (!t->tx_buf) {
+                       /* To avoid errors when doing rx-only transfers with
+                        * many SG entries (> 20), use the rx buffer as the
+                        * dummy tx buffer so that dma reloads are done at the
+                        * same time for rx and tx.
+                        */
+                       t->tx_sg.sgl = t->rx_sg.sgl;
+                       t->tx_sg.nents = t->rx_sg.nents;
+               }
+
                txdesc = dmaengine_prep_slave_sg(dspi->dma_tx,
-                               &sg_tx, 1, DMA_MEM_TO_DEV,
+                               t->tx_sg.sgl, t->tx_sg.nents, DMA_MEM_TO_DEV,
                                DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
                if (!txdesc)
                        goto err_desc;
@@ -710,16 +706,9 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
        }
 
        clear_io_bits(dspi->base + SPIINT, SPIINT_MASKALL);
-       if (spicfg->io_type == SPI_IO_TYPE_DMA) {
+       if (davinci_spi_can_dma(spi->master, spi, t))
                clear_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN);
 
-               dma_unmap_single(&spi->dev, t->rx_dma,
-                               t->len, DMA_FROM_DEVICE);
-               dma_unmap_single(&spi->dev, t->tx_dma,
-                               t->len, DMA_TO_DEVICE);
-               kfree(dummy_buf);
-       }
-
        clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
        set_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
 
@@ -742,12 +731,6 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
        return t->len;
 
 err_desc:
-       dma_unmap_single(&spi->dev, t->tx_dma, t->len, DMA_TO_DEVICE);
-err_tx_map:
-       dma_unmap_single(&spi->dev, t->rx_dma, t->len, DMA_FROM_DEVICE);
-err_rx_map:
-       kfree(dummy_buf);
-err_alloc_dummy_buf:
        return ret;
 }
 
@@ -988,8 +971,10 @@ static int davinci_spi_probe(struct platform_device *pdev)
        master->bus_num = pdev->id;
        master->num_chipselect = pdata->num_chipselect;
        master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16);
+       master->flags = SPI_MASTER_MUST_RX;
        master->setup = davinci_spi_setup;
        master->cleanup = davinci_spi_cleanup;
+       master->can_dma = davinci_spi_can_dma;
 
        dspi->bitbang.chipselect = davinci_spi_chipselect;
        dspi->bitbang.setup_transfer = davinci_spi_setup_transfer;