OSDN Git Service

spi: spi-omap2-mcspi: Support probe deferral for DMA channels
authorVignesh Raghavendra <vigneshr@ti.com>
Tue, 4 Feb 2020 12:48:16 +0000 (18:18 +0530)
committerMark Brown <broonie@kernel.org>
Thu, 6 Feb 2020 15:53:57 +0000 (15:53 +0000)
dma_request_channel() can return -EPROBE_DEFER, if DMA driver is not
ready. Currently driver just falls back to PIO mode on probe deferral.
Fix this by requesting all required channels during probe and
propagating EPROBE_DEFER error code.

Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
Link: https://lore.kernel.org/r/20200204124816.16735-3-vigneshr@ti.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi-omap2-mcspi.c

index e9bc9cf..e9e2567 100644 (file)
@@ -975,20 +975,12 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
  * Note that we currently allow DMA only if we get a channel
  * for both rx and tx. Otherwise we'll do PIO for both rx and tx.
  */
-static int omap2_mcspi_request_dma(struct spi_device *spi)
+static int omap2_mcspi_request_dma(struct omap2_mcspi *mcspi,
+                                  struct omap2_mcspi_dma *mcspi_dma)
 {
-       struct spi_master       *master = spi->master;
-       struct omap2_mcspi      *mcspi;
-       struct omap2_mcspi_dma  *mcspi_dma;
        int ret = 0;
 
-       mcspi = spi_master_get_devdata(master);
-       mcspi_dma = mcspi->dma_channels + spi->chip_select;
-
-       init_completion(&mcspi_dma->dma_rx_completion);
-       init_completion(&mcspi_dma->dma_tx_completion);
-
-       mcspi_dma->dma_rx = dma_request_chan(&master->dev,
+       mcspi_dma->dma_rx = dma_request_chan(mcspi->dev,
                                             mcspi_dma->dma_rx_ch_name);
        if (IS_ERR(mcspi_dma->dma_rx)) {
                ret = PTR_ERR(mcspi_dma->dma_rx);
@@ -996,7 +988,7 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
                goto no_dma;
        }
 
-       mcspi_dma->dma_tx = dma_request_chan(&master->dev,
+       mcspi_dma->dma_tx = dma_request_chan(mcspi->dev,
                                             mcspi_dma->dma_tx_ch_name);
        if (IS_ERR(mcspi_dma->dma_tx)) {
                ret = PTR_ERR(mcspi_dma->dma_tx);
@@ -1005,20 +997,40 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
                mcspi_dma->dma_rx = NULL;
        }
 
+       init_completion(&mcspi_dma->dma_rx_completion);
+       init_completion(&mcspi_dma->dma_tx_completion);
+
 no_dma:
        return ret;
 }
 
+static void omap2_mcspi_release_dma(struct spi_master *master)
+{
+       struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+       struct omap2_mcspi_dma  *mcspi_dma;
+       int i;
+
+       for (i = 0; i < master->num_chipselect; i++) {
+               mcspi_dma = &mcspi->dma_channels[i];
+
+               if (mcspi_dma->dma_rx) {
+                       dma_release_channel(mcspi_dma->dma_rx);
+                       mcspi_dma->dma_rx = NULL;
+               }
+               if (mcspi_dma->dma_tx) {
+                       dma_release_channel(mcspi_dma->dma_tx);
+                       mcspi_dma->dma_tx = NULL;
+               }
+       }
+}
+
 static int omap2_mcspi_setup(struct spi_device *spi)
 {
        int                     ret;
        struct omap2_mcspi      *mcspi = spi_master_get_devdata(spi->master);
        struct omap2_mcspi_regs *ctx = &mcspi->ctx;
-       struct omap2_mcspi_dma  *mcspi_dma;
        struct omap2_mcspi_cs   *cs = spi->controller_state;
 
-       mcspi_dma = &mcspi->dma_channels[spi->chip_select];
-
        if (!cs) {
                cs = kzalloc(sizeof *cs, GFP_KERNEL);
                if (!cs)
@@ -1043,13 +1055,6 @@ static int omap2_mcspi_setup(struct spi_device *spi)
                }
        }
 
-       if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) {
-               ret = omap2_mcspi_request_dma(spi);
-               if (ret)
-                       dev_warn(&spi->dev, "not using DMA for McSPI (%d)\n",
-                                ret);
-       }
-
        ret = pm_runtime_get_sync(mcspi->dev);
        if (ret < 0) {
                pm_runtime_put_noidle(mcspi->dev);
@@ -1066,12 +1071,8 @@ static int omap2_mcspi_setup(struct spi_device *spi)
 
 static void omap2_mcspi_cleanup(struct spi_device *spi)
 {
-       struct omap2_mcspi      *mcspi;
-       struct omap2_mcspi_dma  *mcspi_dma;
        struct omap2_mcspi_cs   *cs;
 
-       mcspi = spi_master_get_devdata(spi->master);
-
        if (spi->controller_state) {
                /* Unlink controller state from context save list */
                cs = spi->controller_state;
@@ -1080,19 +1081,6 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
                kfree(cs);
        }
 
-       if (spi->chip_select < spi->master->num_chipselect) {
-               mcspi_dma = &mcspi->dma_channels[spi->chip_select];
-
-               if (mcspi_dma->dma_rx) {
-                       dma_release_channel(mcspi_dma->dma_rx);
-                       mcspi_dma->dma_rx = NULL;
-               }
-               if (mcspi_dma->dma_tx) {
-                       dma_release_channel(mcspi_dma->dma_tx);
-                       mcspi_dma->dma_tx = NULL;
-               }
-       }
-
        if (gpio_is_valid(spi->cs_gpio))
                gpio_free(spi->cs_gpio);
 }
@@ -1303,6 +1291,9 @@ static bool omap2_mcspi_can_dma(struct spi_master *master,
        if (spi_controller_is_slave(master))
                return true;
 
+       master->dma_rx = mcspi_dma->dma_rx;
+       master->dma_tx = mcspi_dma->dma_tx;
+
        return (xfer->len >= DMA_MIN_BYTES);
 }
 
@@ -1490,6 +1481,11 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
        for (i = 0; i < master->num_chipselect; i++) {
                sprintf(mcspi->dma_channels[i].dma_rx_ch_name, "rx%d", i);
                sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i);
+
+               status = omap2_mcspi_request_dma(mcspi,
+                                                &mcspi->dma_channels[i]);
+               if (status == -EPROBE_DEFER)
+                       goto free_master;
        }
 
        status = platform_get_irq(pdev, 0);
@@ -1527,6 +1523,7 @@ disable_pm:
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 free_master:
+       omap2_mcspi_release_dma(master);
        spi_master_put(master);
        return status;
 }
@@ -1536,6 +1533,8 @@ static int omap2_mcspi_remove(struct platform_device *pdev)
        struct spi_master *master = platform_get_drvdata(pdev);
        struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
 
+       omap2_mcspi_release_dma(master);
+
        pm_runtime_dont_use_autosuspend(mcspi->dev);
        pm_runtime_put_sync(mcspi->dev);
        pm_runtime_disable(&pdev->dev);