]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/spi/spi-imx.c
spi: imx: drop unnecessary read/modify/write
[karo-tx-linux.git] / drivers / spi / spi-imx.c
index d98c33cb64f9b4825998eb1faa2316b1e4796a7d..ec033043734aa4cda701dd3998c2b25754611259 100644 (file)
@@ -56,7 +56,6 @@
 
 /* The maximum  bytes that a sdma BD can transfer.*/
 #define MAX_SDMA_BD_BYTES  (1 << 15)
-#define IMX_DMA_TIMEOUT (msecs_to_jiffies(3000))
 struct spi_imx_config {
        unsigned int speed_hz;
        unsigned int bpw;
@@ -86,12 +85,14 @@ struct spi_imx_devtype_data {
 
 struct spi_imx_data {
        struct spi_bitbang bitbang;
+       struct device *dev;
 
        struct completion xfer_done;
        void __iomem *base;
        struct clk *clk_per;
        struct clk *clk_ipg;
        unsigned long spi_clk;
+       unsigned int spi_bus_clk;
 
        unsigned int count;
        void (*tx)(struct spi_imx_data *);
@@ -204,8 +205,8 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
 {
        struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
 
-       if (spi_imx->dma_is_inited &&
-           transfer->len > spi_imx->wml * sizeof(u32))
+       if (spi_imx->dma_is_inited && transfer->len >= spi_imx->wml &&
+           (transfer->len % spi_imx->wml) == 0)
                return true;
        return false;
 }
@@ -239,9 +240,9 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
 #define MX51_ECSPI_DMA_RXT_WML_OFFSET  24
 #define MX51_ECSPI_DMA_RXT_WML_MASK    (0x3F << 24)
 
-#define MX51_ECSPI_DMA_TEDEN_OFFSET    7
-#define MX51_ECSPI_DMA_RXDEN_OFFSET    23
-#define MX51_ECSPI_DMA_RXTDEN_OFFSET   31
+#define MX51_ECSPI_DMA_TEDEN           (1 << 7)
+#define MX51_ECSPI_DMA_RXDEN           (1 << 23)
+#define MX51_ECSPI_DMA_RXTDEN          (1 << 31)
 
 #define MX51_ECSPI_STAT                0x18
 #define MX51_ECSPI_STAT_RR             (1 <<  3)
@@ -250,14 +251,15 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
 #define MX51_ECSPI_TESTREG_LBC BIT(31)
 
 /* MX51 eCSPI */
-static unsigned int mx51_ecspi_clkdiv(unsigned int fin, unsigned int fspi,
-                                     unsigned int *fres)
+static unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx,
+                                     unsigned int fspi, unsigned int *fres)
 {
        /*
         * there are two 4-bit dividers, the pre-divider divides by
         * $pre, the post-divider by 2^$post
         */
        unsigned int pre, post;
+       unsigned int fin = spi_imx->spi_clk;
 
        if (unlikely(fspi > fin))
                return 0;
@@ -270,14 +272,14 @@ static unsigned int mx51_ecspi_clkdiv(unsigned int fin, unsigned int fspi,
 
        post = max(4U, post) - 4;
        if (unlikely(post > 0xf)) {
-               pr_err("%s: cannot set clock freq: %u (base freq: %u)\n",
-                               __func__, fspi, fin);
+               dev_err(spi_imx->dev, "cannot set clock freq: %u (base freq: %u)\n",
+                               fspi, fin);
                return 0xff;
        }
 
        pre = DIV_ROUND_UP(fin, fspi << post) - 1;
 
-       pr_debug("%s: fin: %u, fspi: %u, post: %u, pre: %u\n",
+       dev_dbg(spi_imx->dev, "%s: fin: %u, fspi: %u, post: %u, pre: %u\n",
                        __func__, fin, fspi, post, pre);
 
        /* Resulting frequency for the SCLK line. */
@@ -316,8 +318,7 @@ static void __maybe_unused mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
 static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
                struct spi_imx_config *config)
 {
-       u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0, dma = 0;
-       u32 tx_wml_cfg, rx_wml_cfg, rxt_wml_cfg;
+       u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0;
        u32 clk = config->speed_hz, delay, reg;
 
        /*
@@ -330,7 +331,8 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
        ctrl |= MX51_ECSPI_CTRL_MODE_MASK;
 
        /* set clock speed */
-       ctrl |= mx51_ecspi_clkdiv(spi_imx->spi_clk, config->speed_hz, &clk);
+       ctrl |= mx51_ecspi_clkdiv(spi_imx, config->speed_hz, &clk);
+       spi_imx->spi_bus_clk = clk;
 
        /* set chip select to use */
        ctrl |= MX51_ECSPI_CTRL_CS(config->cs);
@@ -389,22 +391,12 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
         * Configure the DMA register: setup the watermark
         * and enable DMA request.
         */
-       if (spi_imx->dma_is_inited) {
-               dma = readl(spi_imx->base + MX51_ECSPI_DMA);
-
-               rx_wml_cfg = spi_imx->wml << MX51_ECSPI_DMA_RX_WML_OFFSET;
-               tx_wml_cfg = spi_imx->wml << MX51_ECSPI_DMA_TX_WML_OFFSET;
-               rxt_wml_cfg = spi_imx->wml << MX51_ECSPI_DMA_RXT_WML_OFFSET;
-               dma = (dma & ~MX51_ECSPI_DMA_TX_WML_MASK
-                          & ~MX51_ECSPI_DMA_RX_WML_MASK
-                          & ~MX51_ECSPI_DMA_RXT_WML_MASK)
-                          | rx_wml_cfg | tx_wml_cfg | rxt_wml_cfg
-                          |(1 << MX51_ECSPI_DMA_TEDEN_OFFSET)
-                          |(1 << MX51_ECSPI_DMA_RXDEN_OFFSET)
-                          |(1 << MX51_ECSPI_DMA_RXTDEN_OFFSET);
-
-               writel(dma, spi_imx->base + MX51_ECSPI_DMA);
-       }
+
+       writel(spi_imx->wml << MX51_ECSPI_DMA_RX_WML_OFFSET |
+               spi_imx->wml << MX51_ECSPI_DMA_TX_WML_OFFSET |
+               spi_imx->wml << MX51_ECSPI_DMA_RXT_WML_OFFSET |
+               MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN |
+               MX51_ECSPI_DMA_RXTDEN, spi_imx->base + MX51_ECSPI_DMA);
 
        return 0;
 }
@@ -812,6 +804,11 @@ static int spi_imx_setupxfer(struct spi_device *spi,
                spi_imx->tx = spi_imx_buf_tx_u32;
        }
 
+       if (spi_imx_can_dma(spi_imx->bitbang.master, spi, t))
+               spi_imx->usedma = 1;
+       else
+               spi_imx->usedma = 0;
+
        spi_imx->devtype_data->config(spi_imx, &config);
 
        return 0;
@@ -913,14 +910,27 @@ static void spi_imx_dma_tx_callback(void *cookie)
        complete(&spi_imx->dma_tx_completion);
 }
 
+static int spi_imx_calculate_timeout(struct spi_imx_data *spi_imx, int size)
+{
+       unsigned long timeout = 0;
+
+       /* Time with actual data transfer and CS change delay related to HW */
+       timeout = (8 + 4) * size / spi_imx->spi_bus_clk;
+
+       /* Add extra second for scheduler related activities */
+       timeout += 1;
+
+       /* Double calculated timeout */
+       return msecs_to_jiffies(2 * timeout * MSEC_PER_SEC);
+}
+
 static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
                                struct spi_transfer *transfer)
 {
        struct dma_async_tx_descriptor *desc_tx = NULL, *desc_rx = NULL;
        int ret;
+       unsigned long transfer_timeout;
        unsigned long timeout;
-       u32 dma;
-       int left;
        struct spi_master *master = spi_imx->bitbang.master;
        struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
 
@@ -929,7 +939,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
                                        tx->sgl, tx->nents, DMA_MEM_TO_DEV,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
                if (!desc_tx)
-                       goto no_dma;
+                       return -EINVAL;
 
                desc_tx->callback = spi_imx_dma_tx_callback;
                desc_tx->callback_param = (void *)spi_imx;
@@ -940,8 +950,10 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
                desc_rx = dmaengine_prep_slave_sg(master->dma_rx,
                                        rx->sgl, rx->nents, DMA_DEV_TO_MEM,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-               if (!desc_rx)
-                       goto no_dma;
+               if (!desc_rx) {
+                       dmaengine_terminate_all(master->dma_tx);
+                       return -EINVAL;
+               }
 
                desc_rx->callback = spi_imx_dma_rx_callback;
                desc_rx->callback_param = (void *)spi_imx;
@@ -954,13 +966,6 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
        /* Trigger the cspi module. */
        spi_imx->dma_finished = 0;
 
-       dma = readl(spi_imx->base + MX51_ECSPI_DMA);
-       dma = dma & (~MX51_ECSPI_DMA_RXT_WML_MASK);
-       /* Change RX_DMA_LENGTH trigger dma fetch tail data */
-       left = transfer->len % spi_imx->wml;
-       if (left)
-               writel(dma | (left << MX51_ECSPI_DMA_RXT_WML_OFFSET),
-                               spi_imx->base + MX51_ECSPI_DMA);
        /*
         * Set these order to avoid potential RX overflow. The overflow may
         * happen if we enable SPI HW before starting RX DMA due to rescheduling
@@ -973,29 +978,23 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
        dma_async_issue_pending(master->dma_tx);
        spi_imx->devtype_data->trigger(spi_imx);
 
+       transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len);
+
        /* Wait SDMA to finish the data transfer.*/
        timeout = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
-                                               IMX_DMA_TIMEOUT);
+                                               transfer_timeout);
        if (!timeout) {
-               pr_warn("%s %s: I/O Error in DMA TX\n",
-                       dev_driver_string(&master->dev),
-                       dev_name(&master->dev));
+               dev_err(spi_imx->dev, "I/O Error in DMA TX\n");
                dmaengine_terminate_all(master->dma_tx);
                dmaengine_terminate_all(master->dma_rx);
        } else {
                timeout = wait_for_completion_timeout(
-                               &spi_imx->dma_rx_completion, IMX_DMA_TIMEOUT);
+                               &spi_imx->dma_rx_completion, transfer_timeout);
                if (!timeout) {
-                       pr_warn("%s %s: I/O Error in DMA RX\n",
-                               dev_driver_string(&master->dev),
-                               dev_name(&master->dev));
+                       dev_err(spi_imx->dev, "I/O Error in DMA RX\n");
                        spi_imx->devtype_data->reset(spi_imx);
                        dmaengine_terminate_all(master->dma_rx);
                }
-               dma &= ~MX51_ECSPI_DMA_RXT_WML_MASK;
-               writel(dma |
-                      spi_imx->wml << MX51_ECSPI_DMA_RXT_WML_OFFSET,
-                      spi_imx->base + MX51_ECSPI_DMA);
        }
 
        spi_imx->dma_finished = 1;
@@ -1007,12 +1006,6 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
                ret = transfer->len;
 
        return ret;
-
-no_dma:
-       pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
-                    dev_driver_string(&master->dev),
-                    dev_name(&master->dev));
-       return -EAGAIN;
 }
 
 static int spi_imx_pio_transfer(struct spi_device *spi,
@@ -1039,19 +1032,12 @@ static int spi_imx_pio_transfer(struct spi_device *spi,
 static int spi_imx_transfer(struct spi_device *spi,
                                struct spi_transfer *transfer)
 {
-       int ret;
        struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
 
-       if (spi_imx->bitbang.master->can_dma &&
-           spi_imx_can_dma(spi_imx->bitbang.master, spi, transfer)) {
-               spi_imx->usedma = true;
-               ret = spi_imx_dma_transfer(spi_imx, transfer);
-               if (ret != -EAGAIN)
-                       return ret;
-       }
-       spi_imx->usedma = false;
-
-       return spi_imx_pio_transfer(spi, transfer);
+       if (spi_imx->usedma)
+               return spi_imx_dma_transfer(spi_imx, transfer);
+       else
+               return spi_imx_pio_transfer(spi, transfer);
 }
 
 static int spi_imx_setup(struct spi_device *spi)
@@ -1141,6 +1127,7 @@ static int spi_imx_probe(struct platform_device *pdev)
 
        spi_imx = spi_master_get_devdata(master);
        spi_imx->bitbang.master = master;
+       spi_imx->dev = &pdev->dev;
 
        spi_imx->devtype_data = of_id ? of_id->data :
                (struct spi_imx_devtype_data *)pdev->id_entry->driver_data;