Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
[deliverable/linux.git] / drivers / spi / spi-rockchip.c
index 7cb1b2d710c10f7aab6c245a31d34e5439dfcbf0..8f50a4020f6fff6f7c1d7e1c1f43964c734e5c3f 100644 (file)
  *
  */
 
-#include <linux/init.h>
-#include <linux/module.h>
 #include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
-#include <linux/slab.h>
 #include <linux/spi/spi.h>
-#include <linux/scatterlist.h>
-#include <linux/of.h>
 #include <linux/pm_runtime.h>
-#include <linux/io.h>
-#include <linux/dmaengine.h>
+#include <linux/scatterlist.h>
 
 #define DRIVER_NAME "rockchip-spi"
 
@@ -179,7 +173,7 @@ struct rockchip_spi {
        u8 tmode;
        u8 bpw;
        u8 n_bytes;
-       u8 rsd_nsecs;
+       u32 rsd_nsecs;
        unsigned len;
        u32 speed;
 
@@ -192,13 +186,12 @@ struct rockchip_spi {
        /* protect state */
        spinlock_t lock;
 
-       struct completion xfer_completion;
-
        u32 use_dma;
        struct sg_table tx_sg;
        struct sg_table rx_sg;
        struct rockchip_spi_dma_data dma_rx;
        struct rockchip_spi_dma_data dma_tx;
+       struct dma_slave_caps dma_caps;
 };
 
 static inline void spi_enable_chip(struct rockchip_spi *rs, int enable)
@@ -265,7 +258,10 @@ static inline u32 rx_max(struct rockchip_spi *rs)
 static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
 {
        u32 ser;
-       struct rockchip_spi *rs = spi_master_get_devdata(spi->master);
+       struct spi_master *master = spi->master;
+       struct rockchip_spi *rs = spi_master_get_devdata(master);
+
+       pm_runtime_get_sync(rs->dev);
 
        ser = readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) & SER_MASK;
 
@@ -290,6 +286,8 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
                ser &= ~(1 << spi->chip_select);
 
        writel_relaxed(ser, rs->regs + ROCKCHIP_SPI_SER);
+
+       pm_runtime_put_sync(rs->dev);
 }
 
 static int rockchip_spi_prepare_message(struct spi_master *master,
@@ -319,12 +317,12 @@ static void rockchip_spi_handle_err(struct spi_master *master,
         */
        if (rs->use_dma) {
                if (rs->state & RXBUSY) {
-                       dmaengine_terminate_all(rs->dma_rx.ch);
+                       dmaengine_terminate_async(rs->dma_rx.ch);
                        flush_fifo(rs);
                }
 
                if (rs->state & TXBUSY)
-                       dmaengine_terminate_all(rs->dma_tx.ch);
+                       dmaengine_terminate_async(rs->dma_tx.ch);
        }
 
        spin_unlock_irqrestore(&rs->lock, flags);
@@ -433,7 +431,7 @@ static void rockchip_spi_dma_txcb(void *data)
        spin_unlock_irqrestore(&rs->lock, flags);
 }
 
-static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
+static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
 {
        unsigned long flags;
        struct dma_slave_config rxconf, txconf;
@@ -449,13 +447,18 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
                rxconf.direction = rs->dma_rx.direction;
                rxconf.src_addr = rs->dma_rx.addr;
                rxconf.src_addr_width = rs->n_bytes;
-               rxconf.src_maxburst = rs->n_bytes;
+               if (rs->dma_caps.max_burst > 4)
+                       rxconf.src_maxburst = 4;
+               else
+                       rxconf.src_maxburst = 1;
                dmaengine_slave_config(rs->dma_rx.ch, &rxconf);
 
                rxdesc = dmaengine_prep_slave_sg(
                                rs->dma_rx.ch,
                                rs->rx_sg.sgl, rs->rx_sg.nents,
                                rs->dma_rx.direction, DMA_PREP_INTERRUPT);
+               if (!rxdesc)
+                       return -EINVAL;
 
                rxdesc->callback = rockchip_spi_dma_rxcb;
                rxdesc->callback_param = rs;
@@ -466,13 +469,21 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
                txconf.direction = rs->dma_tx.direction;
                txconf.dst_addr = rs->dma_tx.addr;
                txconf.dst_addr_width = rs->n_bytes;
-               txconf.dst_maxburst = rs->n_bytes;
+               if (rs->dma_caps.max_burst > 4)
+                       txconf.dst_maxburst = 4;
+               else
+                       txconf.dst_maxburst = 1;
                dmaengine_slave_config(rs->dma_tx.ch, &txconf);
 
                txdesc = dmaengine_prep_slave_sg(
                                rs->dma_tx.ch,
                                rs->tx_sg.sgl, rs->tx_sg.nents,
                                rs->dma_tx.direction, DMA_PREP_INTERRUPT);
+               if (!txdesc) {
+                       if (rxdesc)
+                               dmaengine_terminate_sync(rs->dma_rx.ch);
+                       return -EINVAL;
+               }
 
                txdesc->callback = rockchip_spi_dma_txcb;
                txdesc->callback_param = rs;
@@ -494,6 +505,8 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
                dmaengine_submit(txdesc);
                dma_async_issue_pending(rs->dma_tx.ch);
        }
+
+       return 0;
 }
 
 static void rockchip_spi_config(struct rockchip_spi *rs)
@@ -503,7 +516,8 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
        int rsd = 0;
 
        u32 cr0 = (CR0_BHT_8BIT << CR0_BHT_OFFSET)
-               | (CR0_SSD_ONE << CR0_SSD_OFFSET);
+               | (CR0_SSD_ONE << CR0_SSD_OFFSET)
+               | (CR0_EM_BIG << CR0_EM_OFFSET);
 
        cr0 |= (rs->n_bytes << CR0_DFS_OFFSET);
        cr0 |= ((rs->mode & 0x3) << CR0_SCPH_OFFSET);
@@ -606,12 +620,12 @@ static int rockchip_spi_transfer_one(
        if (rs->use_dma) {
                if (rs->tmode == CR0_XFM_RO) {
                        /* rx: dma must be prepared first */
-                       rockchip_spi_prepare_dma(rs);
+                       ret = rockchip_spi_prepare_dma(rs);
                        spi_enable_chip(rs, 1);
                } else {
                        /* tx or tr: spi must be enabled first */
                        spi_enable_chip(rs, 1);
-                       rockchip_spi_prepare_dma(rs);
+                       ret = rockchip_spi_prepare_dma(rs);
                }
        } else {
                spi_enable_chip(rs, 1);
@@ -717,8 +731,14 @@ static int rockchip_spi_probe(struct platform_device *pdev)
        master->handle_err = rockchip_spi_handle_err;
 
        rs->dma_tx.ch = dma_request_slave_channel(rs->dev, "tx");
-       if (!rs->dma_tx.ch)
+       if (IS_ERR_OR_NULL(rs->dma_tx.ch)) {
+               /* Check tx to see if we need defer probing driver */
+               if (PTR_ERR(rs->dma_tx.ch) == -EPROBE_DEFER) {
+                       ret = -EPROBE_DEFER;
+                       goto err_get_fifo_len;
+               }
                dev_warn(rs->dev, "Failed to request TX DMA channel\n");
+       }
 
        rs->dma_rx.ch = dma_request_slave_channel(rs->dev, "rx");
        if (!rs->dma_rx.ch) {
@@ -730,6 +750,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
        }
 
        if (rs->dma_tx.ch && rs->dma_rx.ch) {
+               dma_get_slave_caps(rs->dma_rx.ch, &(rs->dma_caps));
                rs->dma_tx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_TXDR);
                rs->dma_rx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_RXDR);
                rs->dma_tx.direction = DMA_MEM_TO_DEV;
@@ -871,6 +892,7 @@ static const struct of_device_id rockchip_spi_dt_match[] = {
        { .compatible = "rockchip,rk3066-spi", },
        { .compatible = "rockchip,rk3188-spi", },
        { .compatible = "rockchip,rk3288-spi", },
+       { .compatible = "rockchip,rk3399-spi", },
        { },
 };
 MODULE_DEVICE_TABLE(of, rockchip_spi_dt_match);
This page took 0.02795 seconds and 5 git commands to generate.