mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 13:30:45 -05:00
Add devm_dma_request_chan() to simplify probe
Merge series from Bence Csókás <csokas.bence@prolan.hu>: The probe function of the atmel-quadspi driver got quite convoluted, especially since the addition of SAMA7G5 support, that was forward-ported from an older vendor kernel. To alleivate this - and similar problems in the future - an effort was made to migrate as many functions as possible, to their devm_ managed counterparts. Patch 1/2 adds the new `devm_dma_request_chan()` function. Patch 2/2 then uses this APIs to simplify the probe() function.
This commit is contained in:
@@ -926,6 +926,36 @@ void dma_release_channel(struct dma_chan *chan)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_release_channel);
|
||||
|
||||
static void dmaenginem_release_channel(void *chan)
|
||||
{
|
||||
dma_release_channel(chan);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_dma_request_chan - try to allocate an exclusive slave channel
|
||||
* @dev: pointer to client device structure
|
||||
* @name: slave channel name
|
||||
*
|
||||
* Returns pointer to appropriate DMA channel on success or an error pointer.
|
||||
*
|
||||
* The operation is managed and will be undone on driver detach.
|
||||
*/
|
||||
|
||||
struct dma_chan *devm_dma_request_chan(struct device *dev, const char *name)
|
||||
{
|
||||
struct dma_chan *chan = dma_request_chan(dev, name);
|
||||
int ret = 0;
|
||||
|
||||
if (!IS_ERR(chan))
|
||||
ret = devm_add_action_or_reset(dev, dmaenginem_release_channel, chan);
|
||||
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return chan;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_dma_request_chan);
|
||||
|
||||
/**
|
||||
* dmaengine_get - register interest in dma_channels
|
||||
*/
|
||||
|
||||
@@ -1285,18 +1285,21 @@ static int atmel_qspi_dma_init(struct spi_controller *ctrl)
|
||||
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
|
||||
int ret;
|
||||
|
||||
aq->rx_chan = dma_request_chan(&aq->pdev->dev, "rx");
|
||||
aq->rx_chan = devm_dma_request_chan(&aq->pdev->dev, "rx");
|
||||
if (IS_ERR(aq->rx_chan)) {
|
||||
ret = dev_err_probe(&aq->pdev->dev, PTR_ERR(aq->rx_chan),
|
||||
"RX DMA channel is not available\n");
|
||||
goto null_rx_chan;
|
||||
aq->rx_chan = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
aq->tx_chan = dma_request_chan(&aq->pdev->dev, "tx");
|
||||
aq->tx_chan = devm_dma_request_chan(&aq->pdev->dev, "tx");
|
||||
if (IS_ERR(aq->tx_chan)) {
|
||||
ret = dev_err_probe(&aq->pdev->dev, PTR_ERR(aq->tx_chan),
|
||||
"TX DMA channel is not available\n");
|
||||
goto release_rx_chan;
|
||||
aq->rx_chan = NULL;
|
||||
aq->tx_chan = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctrl->dma_rx = aq->rx_chan;
|
||||
@@ -1307,21 +1310,6 @@ static int atmel_qspi_dma_init(struct spi_controller *ctrl)
|
||||
dma_chan_name(aq->tx_chan), dma_chan_name(aq->rx_chan));
|
||||
|
||||
return 0;
|
||||
|
||||
release_rx_chan:
|
||||
dma_release_channel(aq->rx_chan);
|
||||
aq->tx_chan = NULL;
|
||||
null_rx_chan:
|
||||
aq->rx_chan = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void atmel_qspi_dma_release(struct atmel_qspi *aq)
|
||||
{
|
||||
if (aq->rx_chan)
|
||||
dma_release_channel(aq->rx_chan);
|
||||
if (aq->tx_chan)
|
||||
dma_release_channel(aq->tx_chan);
|
||||
}
|
||||
|
||||
static const struct atmel_qspi_ops atmel_qspi_ops = {
|
||||
@@ -1426,14 +1414,13 @@ static int atmel_qspi_probe(struct platform_device *pdev)
|
||||
|
||||
/* Request the IRQ */
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
err = irq;
|
||||
goto dma_release;
|
||||
}
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
err = devm_request_irq(&pdev->dev, irq, atmel_qspi_interrupt,
|
||||
0, dev_name(&pdev->dev), aq);
|
||||
if (err)
|
||||
goto dma_release;
|
||||
return err;
|
||||
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
@@ -1442,22 +1429,16 @@ static int atmel_qspi_probe(struct platform_device *pdev)
|
||||
|
||||
err = atmel_qspi_init(aq);
|
||||
if (err)
|
||||
goto dma_release;
|
||||
return err;
|
||||
|
||||
err = spi_register_controller(ctrl);
|
||||
if (err)
|
||||
goto dma_release;
|
||||
return err;
|
||||
|
||||
pm_runtime_mark_last_busy(&pdev->dev);
|
||||
pm_runtime_put_autosuspend(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
dma_release:
|
||||
if (aq->caps->has_dma)
|
||||
atmel_qspi_dma_release(aq);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int atmel_qspi_sama7g5_suspend(struct atmel_qspi *aq)
|
||||
@@ -1507,9 +1488,6 @@ static void atmel_qspi_remove(struct platform_device *pdev)
|
||||
|
||||
ret = pm_runtime_get_sync(&pdev->dev);
|
||||
if (ret >= 0) {
|
||||
if (aq->caps->has_dma)
|
||||
atmel_qspi_dma_release(aq);
|
||||
|
||||
if (aq->caps->has_gclk) {
|
||||
ret = atmel_qspi_sama7g5_suspend(aq);
|
||||
if (ret)
|
||||
|
||||
@@ -1524,6 +1524,7 @@ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
|
||||
|
||||
struct dma_chan *dma_request_chan(struct device *dev, const char *name);
|
||||
struct dma_chan *dma_request_chan_by_mask(const dma_cap_mask_t *mask);
|
||||
struct dma_chan *devm_dma_request_chan(struct device *dev, const char *name);
|
||||
|
||||
void dma_release_channel(struct dma_chan *chan);
|
||||
int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps);
|
||||
@@ -1560,6 +1561,12 @@ static inline struct dma_chan *dma_request_chan_by_mask(
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline struct dma_chan *devm_dma_request_chan(struct device *dev, const char *name)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline void dma_release_channel(struct dma_chan *chan)
|
||||
{
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user