spi: spi-omap2-mcspi: Support probe deferral for DMA channels

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>
This commit is contained in:
Vignesh Raghavendra 2020-02-04 18:18:16 +05:30 committed by Mark Brown
parent e4e8276a4f
commit 32f2fc5dc3
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
1 changed files with 38 additions and 39 deletions

View 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 * 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. * 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; int ret = 0;
mcspi = spi_master_get_devdata(master); mcspi_dma->dma_rx = dma_request_chan(mcspi->dev,
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_ch_name); mcspi_dma->dma_rx_ch_name);
if (IS_ERR(mcspi_dma->dma_rx)) { if (IS_ERR(mcspi_dma->dma_rx)) {
ret = PTR_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; 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); mcspi_dma->dma_tx_ch_name);
if (IS_ERR(mcspi_dma->dma_tx)) { if (IS_ERR(mcspi_dma->dma_tx)) {
ret = PTR_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; mcspi_dma->dma_rx = NULL;
} }
init_completion(&mcspi_dma->dma_rx_completion);
init_completion(&mcspi_dma->dma_tx_completion);
no_dma: no_dma:
return ret; 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) static int omap2_mcspi_setup(struct spi_device *spi)
{ {
int ret; int ret;
struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master); struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
struct omap2_mcspi_regs *ctx = &mcspi->ctx; struct omap2_mcspi_regs *ctx = &mcspi->ctx;
struct omap2_mcspi_dma *mcspi_dma;
struct omap2_mcspi_cs *cs = spi->controller_state; struct omap2_mcspi_cs *cs = spi->controller_state;
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
if (!cs) { if (!cs) {
cs = kzalloc(sizeof *cs, GFP_KERNEL); cs = kzalloc(sizeof *cs, GFP_KERNEL);
if (!cs) 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); ret = pm_runtime_get_sync(mcspi->dev);
if (ret < 0) { if (ret < 0) {
pm_runtime_put_noidle(mcspi->dev); 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) static void omap2_mcspi_cleanup(struct spi_device *spi)
{ {
struct omap2_mcspi *mcspi;
struct omap2_mcspi_dma *mcspi_dma;
struct omap2_mcspi_cs *cs; struct omap2_mcspi_cs *cs;
mcspi = spi_master_get_devdata(spi->master);
if (spi->controller_state) { if (spi->controller_state) {
/* Unlink controller state from context save list */ /* Unlink controller state from context save list */
cs = spi->controller_state; cs = spi->controller_state;
@ -1080,19 +1081,6 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
kfree(cs); 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)) if (gpio_is_valid(spi->cs_gpio))
gpio_free(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)) if (spi_controller_is_slave(master))
return true; return true;
master->dma_rx = mcspi_dma->dma_rx;
master->dma_tx = mcspi_dma->dma_tx;
return (xfer->len >= DMA_MIN_BYTES); 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++) { 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_rx_ch_name, "rx%d", i);
sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%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); status = platform_get_irq(pdev, 0);
@ -1527,6 +1523,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev); pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
free_master: free_master:
omap2_mcspi_release_dma(master);
spi_master_put(master); spi_master_put(master);
return status; return status;
} }
@ -1536,6 +1533,8 @@ static int omap2_mcspi_remove(struct platform_device *pdev)
struct spi_master *master = platform_get_drvdata(pdev); struct spi_master *master = platform_get_drvdata(pdev);
struct omap2_mcspi *mcspi = spi_master_get_devdata(master); struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
omap2_mcspi_release_dma(master);
pm_runtime_dont_use_autosuspend(mcspi->dev); pm_runtime_dont_use_autosuspend(mcspi->dev);
pm_runtime_put_sync(mcspi->dev); pm_runtime_put_sync(mcspi->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);