Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

spi: dw: Add deferred DMA-channels setup support

Currently if the source DMA device isn't ready to provide the channels
capable of the SPI DMA transfers, the DW SSI controller will be registered
with no DMA support. It isn't right since all what the driver needs to do
is to postpone the probe procedure until the DMA device is ready. Let's
fix that in the framework of the DWC SSI generic DMA implementation. First
we need to use the dma_request_chan() method instead of the
dma_request_slave_channel() function, because the later one is deprecated
and most importantly doesn't return the failure cause but the
NULL-pointer. Second we need to stop the DW SSI controller probe procedure
if the -EPROBE_DEFER error is returned on the DMA initialization. The
procedure will resume later when the channels are ready to be requested.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Link: https://lore.kernel.org/r/20220624210623.6383-1-Sergey.Semin@baikalelectronics.ru
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Serge Semin and committed by
Mark Brown
e95a1cd2 a813c47d

+22 -8
+4 -1
drivers/spi/spi-dw-core.c
··· 942 942 943 943 if (dws->dma_ops && dws->dma_ops->dma_init) { 944 944 ret = dws->dma_ops->dma_init(dev, dws); 945 - if (ret) { 945 + if (ret == -EPROBE_DEFER) { 946 + goto err_free_irq; 947 + } else if (ret) { 946 948 dev_warn(dev, "DMA init failed\n"); 947 949 } else { 948 950 master->can_dma = dws->dma_ops->can_dma; ··· 965 963 if (dws->dma_ops && dws->dma_ops->dma_exit) 966 964 dws->dma_ops->dma_exit(dws); 967 965 dw_spi_enable_chip(dws, 0); 966 + err_free_irq: 968 967 free_irq(dws->irq, master); 969 968 err_free_master: 970 969 spi_controller_put(master);
+18 -7
drivers/spi/spi-dw-dma.c
··· 139 139 140 140 static int dw_spi_dma_init_generic(struct device *dev, struct dw_spi *dws) 141 141 { 142 - dws->rxchan = dma_request_slave_channel(dev, "rx"); 143 - if (!dws->rxchan) 144 - return -ENODEV; 142 + int ret; 145 143 146 - dws->txchan = dma_request_slave_channel(dev, "tx"); 147 - if (!dws->txchan) { 148 - dma_release_channel(dws->rxchan); 144 + dws->rxchan = dma_request_chan(dev, "rx"); 145 + if (IS_ERR(dws->rxchan)) { 146 + ret = PTR_ERR(dws->rxchan); 149 147 dws->rxchan = NULL; 150 - return -ENODEV; 148 + goto err_exit; 149 + } 150 + 151 + dws->txchan = dma_request_chan(dev, "tx"); 152 + if (IS_ERR(dws->txchan)) { 153 + ret = PTR_ERR(dws->txchan); 154 + dws->txchan = NULL; 155 + goto free_rxchan; 151 156 } 152 157 153 158 dws->master->dma_rx = dws->rxchan; ··· 165 160 dw_spi_dma_sg_burst_init(dws); 166 161 167 162 return 0; 163 + 164 + free_rxchan: 165 + dma_release_channel(dws->rxchan); 166 + dws->rxchan = NULL; 167 + err_exit: 168 + return ret; 168 169 } 169 170 170 171 static void dw_spi_dma_exit(struct dw_spi *dws)