diff options
author | Robin Gong <yibin.gong@nxp.com> | 2020-05-20 22:34:17 +0200 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2020-05-28 14:41:48 +0200 |
commit | bcd8e7761ec9c128b9102b0833d9c7052ae2dbcf (patch) | |
tree | e45b9a9159a6093865aa8fa2ec2eca841b386690 /drivers/spi | |
parent | spi: spi-fsl-lpspi: Fix runtime PM imbalance on error (diff) | |
download | linux-bcd8e7761ec9c128b9102b0833d9c7052ae2dbcf.tar.xz linux-bcd8e7761ec9c128b9102b0833d9c7052ae2dbcf.zip |
spi: imx: fallback to PIO if dma setup failure
Fallback to PIO in case dma setup failed. For example, sdma firmware not
updated but ERR009165 workaroud added in kernel.
Signed-off-by: Robin Gong <yibin.gong@nxp.com>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
Link: https://lore.kernel.org/r/1590006865-20900-6-git-send-email-yibin.gong@nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-imx.c | 31 |
1 files changed, 27 insertions, 4 deletions
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index f4f28a400a96..b7a85e3fe1c1 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -71,6 +71,7 @@ struct spi_imx_devtype_data { void (*reset)(struct spi_imx_data *); void (*setup_wml)(struct spi_imx_data *); void (*disable)(struct spi_imx_data *); + void (*disable_dma)(struct spi_imx_data *); bool has_dmamode; bool has_slavemode; unsigned int fifo_size; @@ -485,6 +486,11 @@ static void mx51_ecspi_trigger(struct spi_imx_data *spi_imx) writel(reg, spi_imx->base + MX51_ECSPI_CTRL); } +static void mx51_disable_dma(struct spi_imx_data *spi_imx) +{ + writel(0, spi_imx->base + MX51_ECSPI_DMA); +} + static void mx51_ecspi_disable(struct spi_imx_data *spi_imx) { u32 ctrl; @@ -987,6 +993,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = { .rx_available = mx51_ecspi_rx_available, .reset = mx51_ecspi_reset, .setup_wml = mx51_setup_wml, + .disable_dma = mx51_disable_dma, .fifo_size = 64, .has_dmamode = true, .dynamic_burst = true, @@ -1001,6 +1008,7 @@ static struct spi_imx_devtype_data imx53_ecspi_devtype_data = { .prepare_transfer = mx51_ecspi_prepare_transfer, .trigger = mx51_ecspi_trigger, .rx_available = mx51_ecspi_rx_available, + .disable_dma = mx51_disable_dma, .reset = mx51_ecspi_reset, .fifo_size = 64, .has_dmamode = true, @@ -1385,6 +1393,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_tx) { dmaengine_terminate_all(master->dma_tx); + dmaengine_terminate_all(master->dma_rx); return -EINVAL; } @@ -1498,6 +1507,7 @@ static int spi_imx_transfer(struct spi_device *spi, struct spi_transfer *transfer) { struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); + int ret; /* flush rxfifo before transfer */ while (spi_imx->devtype_data->rx_available(spi_imx)) @@ -1506,10 +1516,23 @@ static int spi_imx_transfer(struct spi_device *spi, if (spi_imx->slave_mode) return spi_imx_pio_transfer_slave(spi, transfer); - if (spi_imx->usedma) - return spi_imx_dma_transfer(spi_imx, transfer); - else - return spi_imx_pio_transfer(spi, transfer); + /* + * fallback PIO mode if dma setup error happen, for example sdma + * firmware may not be updated as ERR009165 required. + */ + if (spi_imx->usedma) { + ret = spi_imx_dma_transfer(spi_imx, transfer); + if (ret != -EINVAL) + return ret; + + spi_imx->devtype_data->disable_dma(spi_imx); + + spi_imx->usedma = false; + spi_imx->dynamic_burst = spi_imx->devtype_data->dynamic_burst; + dev_dbg(&spi->dev, "Fallback to PIO mode\n"); + } + + return spi_imx_pio_transfer(spi, transfer); } static int spi_imx_setup(struct spi_device *spi) |