mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 20:22:09 +00:00
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:
parent
e4e8276a4f
commit
32f2fc5dc3
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user