ARM64: DTS: Add rk3399-firefly uart4 device, node as /dev/ttyS1
[firefly-linux-kernel-4.4.55.git] / drivers / spi / spi-rockchip.c
index 79a8bc4f6cec9e32ec9c78627a2e68fc85ab5e12..42c8fcd82758d9b08864b975aeae3021b1c3c48e 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,8 +186,6 @@ 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;
@@ -265,7 +257,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 +285,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 +316,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 +430,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 +446,15 @@ 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;
+               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 +465,18 @@ 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;
+               txconf.dst_maxburst = 16;
                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 +498,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 +509,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);
@@ -520,7 +527,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
        if (WARN_ON(rs->speed > MAX_SCLK_OUT))
                rs->speed = MAX_SCLK_OUT;
 
-       /* the minimum divsor is 2 */
+       /* the minimum divisor is 2 */
        if (rs->max_freq < 2 * rs->speed) {
                clk_set_rate(rs->spiclk, 2 * rs->speed);
                rs->max_freq = clk_get_rate(rs->spiclk);
@@ -550,7 +557,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
        writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_TXFTLR);
        writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
 
-       writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMATDLR);
+       writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR);
        writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR);
        writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR);
 
@@ -606,12 +613,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 +724,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) {
@@ -749,6 +762,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
        return 0;
 
 err_register_master:
+       pm_runtime_disable(&pdev->dev);
        if (rs->dma_tx.ch)
                dma_release_channel(rs->dma_tx.ch);
        if (rs->dma_rx.ch)
@@ -778,6 +792,8 @@ static int rockchip_spi_remove(struct platform_device *pdev)
        if (rs->dma_rx.ch)
                dma_release_channel(rs->dma_rx.ch);
 
+       spi_master_put(master);
+
        return 0;
 }
 
@@ -797,6 +813,8 @@ static int rockchip_spi_suspend(struct device *dev)
                clk_disable_unprepare(rs->apb_pclk);
        }
 
+       pinctrl_pm_select_sleep_state(dev);
+
        return ret;
 }
 
@@ -806,6 +824,8 @@ static int rockchip_spi_resume(struct device *dev)
        struct spi_master *master = dev_get_drvdata(dev);
        struct rockchip_spi *rs = spi_master_get_devdata(master);
 
+       pinctrl_pm_select_default_state(dev);
+
        if (!pm_runtime_suspended(dev)) {
                ret = clk_prepare_enable(rs->apb_pclk);
                if (ret < 0)
@@ -865,9 +885,13 @@ static const struct dev_pm_ops rockchip_spi_pm = {
 };
 
 static const struct of_device_id rockchip_spi_dt_match[] = {
+       { .compatible = "rockchip,rk3036-spi", },
        { .compatible = "rockchip,rk3066-spi", },
        { .compatible = "rockchip,rk3188-spi", },
+       { .compatible = "rockchip,rk3228-spi", },
        { .compatible = "rockchip,rk3288-spi", },
+       { .compatible = "rockchip,rk3368-spi", },
+       { .compatible = "rockchip,rk3399-spi", },
        { },
 };
 MODULE_DEVICE_TABLE(of, rockchip_spi_dt_match);