Commit 7c1c1d4a authored by Lars-Peter Clausen's avatar Lars-Peter Clausen Committed by Mark Brown

ASoC: dmaengine-pcm: Make requesting the DMA channel at PCM open optional

Refactor the dmaengine PCM library to allow the DMA channel to be requested
before opening a PCM substream. snd_dmaengine_pcm_open() now expects a DMA
channel instead of a filter function and filter parameter as its parameters.
snd_dmaengine_pcm_close() is updated to not release the DMA channel. This allows
a dmaengine based PCM driver to request its channels before the substream is
opened.

The patch also introduces two new functions, snd_dmaengine_pcm_open_request_chan()
and snd_dmaengine_pcm_close_release_chan(), which have the same signature and
behaviour of the old snd_dmaengine_pcm_{open,close}() and internally use the new
variants of these functions. All users of snd_dmaengine_pcm_{open,close}() are
updated to use snd_dmaengine_pcm_open_request_chan() and
snd_dmaengine_pcm_close_release_chan().
Signed-off-by: default avatarLars-Peter Clausen <lars@metafoo.de>
Tested-by: default avatarStephen Warren <swarren@nvidia.com>
Tested-by: default avatarShawn Guo <shawn.guo@linaro.org>
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent 69b6f196
...@@ -39,9 +39,13 @@ snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream) ...@@ -39,9 +39,13 @@ snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream); snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream);
int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
dma_filter_fn filter_fn, void *filter_data); struct dma_chan *chan);
int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream); int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream);
int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
dma_filter_fn filter_fn, void *filter_data);
int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream);
struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream); struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream);
/** /**
......
...@@ -155,7 +155,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -155,7 +155,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
if (ssc->pdev) if (ssc->pdev)
sdata = ssc->pdev->dev.platform_data; sdata = ssc->pdev->dev.platform_data;
ret = snd_dmaengine_pcm_open(substream, filter, sdata); ret = snd_dmaengine_pcm_open_request_chan(substream, filter, sdata);
if (ret) { if (ret) {
pr_err("atmel-pcm: dmaengine pcm open failed\n"); pr_err("atmel-pcm: dmaengine pcm open failed\n");
return -EINVAL; return -EINVAL;
...@@ -171,7 +171,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -171,7 +171,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
return 0; return 0;
err: err:
snd_dmaengine_pcm_close(substream); snd_dmaengine_pcm_close_release_chan(substream);
return ret; return ret;
} }
...@@ -197,7 +197,7 @@ static int atmel_pcm_open(struct snd_pcm_substream *substream) ...@@ -197,7 +197,7 @@ static int atmel_pcm_open(struct snd_pcm_substream *substream)
static struct snd_pcm_ops atmel_pcm_ops = { static struct snd_pcm_ops atmel_pcm_ops = {
.open = atmel_pcm_open, .open = atmel_pcm_open,
.close = snd_dmaengine_pcm_close, .close = snd_dmaengine_pcm_close_release_chan,
.ioctl = snd_pcm_lib_ioctl, .ioctl = snd_pcm_lib_ioctl,
.hw_params = atmel_pcm_hw_params, .hw_params = atmel_pcm_hw_params,
.prepare = atmel_pcm_dma_prepare, .prepare = atmel_pcm_dma_prepare,
......
...@@ -69,7 +69,8 @@ static int ep93xx_pcm_open(struct snd_pcm_substream *substream) ...@@ -69,7 +69,8 @@ static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware); snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
return snd_dmaengine_pcm_open(substream, ep93xx_pcm_dma_filter, return snd_dmaengine_pcm_open_request_chan(substream,
ep93xx_pcm_dma_filter,
snd_soc_dai_get_dma_data(rtd->cpu_dai, substream)); snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
} }
...@@ -100,7 +101,7 @@ static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream, ...@@ -100,7 +101,7 @@ static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,
static struct snd_pcm_ops ep93xx_pcm_ops = { static struct snd_pcm_ops ep93xx_pcm_ops = {
.open = ep93xx_pcm_open, .open = ep93xx_pcm_open,
.close = snd_dmaengine_pcm_close, .close = snd_dmaengine_pcm_close_release_chan,
.ioctl = snd_pcm_lib_ioctl, .ioctl = snd_pcm_lib_ioctl,
.hw_params = ep93xx_pcm_hw_params, .hw_params = ep93xx_pcm_hw_params,
.hw_free = ep93xx_pcm_hw_free, .hw_free = ep93xx_pcm_hw_free,
......
...@@ -100,7 +100,7 @@ static int snd_imx_open(struct snd_pcm_substream *substream) ...@@ -100,7 +100,7 @@ static int snd_imx_open(struct snd_pcm_substream *substream)
static struct snd_pcm_ops imx_pcm_ops = { static struct snd_pcm_ops imx_pcm_ops = {
.open = snd_imx_open, .open = snd_imx_open,
.close = snd_dmaengine_pcm_close, .close = snd_dmaengine_pcm_close_release_chan,
.ioctl = snd_pcm_lib_ioctl, .ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_imx_pcm_hw_params, .hw_params = snd_imx_pcm_hw_params,
.trigger = snd_dmaengine_pcm_trigger, .trigger = snd_dmaengine_pcm_trigger,
......
...@@ -87,7 +87,7 @@ static int snd_mxs_open(struct snd_pcm_substream *substream) ...@@ -87,7 +87,7 @@ static int snd_mxs_open(struct snd_pcm_substream *substream)
snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware); snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware);
return snd_dmaengine_pcm_open(substream, filter, return snd_dmaengine_pcm_open_request_chan(substream, filter,
snd_soc_dai_get_dma_data(rtd->cpu_dai, substream)); snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
} }
...@@ -104,7 +104,7 @@ static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream, ...@@ -104,7 +104,7 @@ static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream,
static struct snd_pcm_ops mxs_pcm_ops = { static struct snd_pcm_ops mxs_pcm_ops = {
.open = snd_mxs_open, .open = snd_mxs_open,
.close = snd_dmaengine_pcm_close, .close = snd_dmaengine_pcm_close_release_chan,
.ioctl = snd_pcm_lib_ioctl, .ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_mxs_pcm_hw_params, .hw_params = snd_mxs_pcm_hw_params,
.trigger = snd_dmaengine_pcm_trigger, .trigger = snd_dmaengine_pcm_trigger,
......
...@@ -118,8 +118,9 @@ static int omap_pcm_open(struct snd_pcm_substream *substream) ...@@ -118,8 +118,9 @@ static int omap_pcm_open(struct snd_pcm_substream *substream)
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
return snd_dmaengine_pcm_open(substream, omap_dma_filter_fn, return snd_dmaengine_pcm_open_request_chan(substream,
dma_data->filter_data); omap_dma_filter_fn,
dma_data->filter_data);
} }
static int omap_pcm_mmap(struct snd_pcm_substream *substream, static int omap_pcm_mmap(struct snd_pcm_substream *substream,
...@@ -135,7 +136,7 @@ static int omap_pcm_mmap(struct snd_pcm_substream *substream, ...@@ -135,7 +136,7 @@ static int omap_pcm_mmap(struct snd_pcm_substream *substream,
static struct snd_pcm_ops omap_pcm_ops = { static struct snd_pcm_ops omap_pcm_ops = {
.open = omap_pcm_open, .open = omap_pcm_open,
.close = snd_dmaengine_pcm_close, .close = snd_dmaengine_pcm_close_release_chan,
.ioctl = snd_pcm_lib_ioctl, .ioctl = snd_pcm_lib_ioctl,
.hw_params = omap_pcm_hw_params, .hw_params = omap_pcm_hw_params,
.hw_free = omap_pcm_hw_free, .hw_free = omap_pcm_hw_free,
......
...@@ -131,7 +131,8 @@ static int mmp_pcm_open(struct snd_pcm_substream *substream) ...@@ -131,7 +131,8 @@ static int mmp_pcm_open(struct snd_pcm_substream *substream)
dma_data.dma_res = r; dma_data.dma_res = r;
dma_data.ssp_id = cpu_dai->id; dma_data.ssp_id = cpu_dai->id;
return snd_dmaengine_pcm_open(substream, filter, &dma_data); return snd_dmaengine_pcm_open_request_chan(substream, filter,
&dma_data);
} }
static int mmp_pcm_mmap(struct snd_pcm_substream *substream, static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
...@@ -148,7 +149,7 @@ static int mmp_pcm_mmap(struct snd_pcm_substream *substream, ...@@ -148,7 +149,7 @@ static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
struct snd_pcm_ops mmp_pcm_ops = { struct snd_pcm_ops mmp_pcm_ops = {
.open = mmp_pcm_open, .open = mmp_pcm_open,
.close = snd_dmaengine_pcm_close, .close = snd_dmaengine_pcm_close_release_chan,
.ioctl = snd_pcm_lib_ioctl, .ioctl = snd_pcm_lib_ioctl,
.hw_params = mmp_pcm_hw_params, .hw_params = mmp_pcm_hw_params,
.trigger = snd_dmaengine_pcm_trigger, .trigger = snd_dmaengine_pcm_trigger,
......
...@@ -254,44 +254,38 @@ snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream) ...@@ -254,44 +254,38 @@ snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
} }
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer); EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer);
static int dmaengine_pcm_request_channel(struct dmaengine_pcm_runtime_data *prtd, static struct dma_chan *dmaengine_pcm_request_channel(dma_filter_fn filter_fn,
dma_filter_fn filter_fn, void *filter_data) void *filter_data)
{ {
dma_cap_mask_t mask; dma_cap_mask_t mask;
dma_cap_zero(mask); dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask);
dma_cap_set(DMA_CYCLIC, mask); dma_cap_set(DMA_CYCLIC, mask);
prtd->dma_chan = dma_request_channel(mask, filter_fn, filter_data);
if (!prtd->dma_chan)
return -ENXIO;
return 0; return dma_request_channel(mask, filter_fn, filter_data);
} }
/** /**
* snd_dmaengine_pcm_open - Open a dmaengine based PCM substream * snd_dmaengine_pcm_open - Open a dmaengine based PCM substream
* @substream: PCM substream * @substream: PCM substream
* @filter_fn: Filter function used to request the DMA channel * @chan: DMA channel to use for data transfers
* @filter_data: Data passed to the DMA filter function
* *
* Returns 0 on success, a negative error code otherwise. * Returns 0 on success, a negative error code otherwise.
* *
* This function will request a DMA channel using the passed filter function and * The function should usually be called from the pcm open callback. Note that
* data. The function should usually be called from the pcm open callback. * this function will use private_data field of the substream's runtime. So it
* * is not availabe to your pcm driver implementation.
* Note that this function will use private_data field of the substream's
* runtime. So it is not availabe to your pcm driver implementation. If you need
* to keep additional data attached to a substream use
* snd_dmaengine_pcm_{set,get}_data.
*/ */
int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
dma_filter_fn filter_fn, void *filter_data) struct dma_chan *chan)
{ {
struct dmaengine_pcm_runtime_data *prtd; struct dmaengine_pcm_runtime_data *prtd;
int ret; int ret;
if (!chan)
return -ENXIO;
ret = snd_pcm_hw_constraint_integer(substream->runtime, ret = snd_pcm_hw_constraint_integer(substream->runtime,
SNDRV_PCM_HW_PARAM_PERIODS); SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0) if (ret < 0)
...@@ -301,11 +295,7 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, ...@@ -301,11 +295,7 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
if (!prtd) if (!prtd)
return -ENOMEM; return -ENOMEM;
ret = dmaengine_pcm_request_channel(prtd, filter_fn, filter_data); prtd->dma_chan = chan;
if (ret < 0) {
kfree(prtd);
return ret;
}
substream->runtime->private_data = prtd; substream->runtime->private_data = prtd;
...@@ -313,6 +303,27 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, ...@@ -313,6 +303,27 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
} }
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open); EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open);
/**
* snd_dmaengine_pcm_open_request_chan - Open a dmaengine based PCM substream and request channel
* @substream: PCM substream
* @filter_fn: Filter function used to request the DMA channel
* @filter_data: Data passed to the DMA filter function
*
* Returns 0 on success, a negative error code otherwise.
*
* This function will request a DMA channel using the passed filter function and
* data. The function should usually be called from the pcm open callback. Note
* that this function will use private_data field of the substream's runtime. So
* it is not availabe to your pcm driver implementation.
*/
int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
dma_filter_fn filter_fn, void *filter_data)
{
return snd_dmaengine_pcm_open(substream,
dmaengine_pcm_request_channel(filter_fn, filter_data));
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan);
/** /**
* snd_dmaengine_pcm_close - Close a dmaengine based PCM substream * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream
* @substream: PCM substream * @substream: PCM substream
...@@ -321,11 +332,26 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream) ...@@ -321,11 +332,26 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
{ {
struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
dma_release_channel(prtd->dma_chan);
kfree(prtd); kfree(prtd);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close); EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close);
/**
* snd_dmaengine_pcm_release_chan_close - Close a dmaengine based PCM substream and release channel
* @substream: PCM substream
*
* Releases the DMA channel associated with the PCM substream.
*/
int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream)
{
struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
dma_release_channel(prtd->dma_chan);
return snd_dmaengine_pcm_close(substream);
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -64,7 +64,8 @@ static int spear_pcm_open(struct snd_pcm_substream *substream) ...@@ -64,7 +64,8 @@ static int spear_pcm_open(struct snd_pcm_substream *substream)
if (ret) if (ret)
return ret; return ret;
return snd_dmaengine_pcm_open(substream, dma_data->filter, dma_data) return snd_dmaengine_pcm_open_request_chan(substream, dma_data->filter,
dma_data);
} }
static int spear_pcm_mmap(struct snd_pcm_substream *substream, static int spear_pcm_mmap(struct snd_pcm_substream *substream,
...@@ -79,7 +80,7 @@ static int spear_pcm_mmap(struct snd_pcm_substream *substream, ...@@ -79,7 +80,7 @@ static int spear_pcm_mmap(struct snd_pcm_substream *substream,
static struct snd_pcm_ops spear_pcm_ops = { static struct snd_pcm_ops spear_pcm_ops = {
.open = spear_pcm_open, .open = spear_pcm_open,
.close = snd_dmaengine_pcm_close, .close = snd_dmaengine_pcm_close_release_chan,
.ioctl = snd_pcm_lib_ioctl, .ioctl = snd_pcm_lib_ioctl,
.hw_params = spear_pcm_hw_params, .hw_params = spear_pcm_hw_params,
.hw_free = spear_pcm_hw_free, .hw_free = spear_pcm_hw_free,
......
...@@ -66,7 +66,7 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream) ...@@ -66,7 +66,7 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream)
/* Set HW params now that initialization is complete */ /* Set HW params now that initialization is complete */
snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware); snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware);
ret = snd_dmaengine_pcm_open(substream, NULL, NULL); ret = snd_dmaengine_pcm_open_request_chan(substream, NULL, NULL);
if (ret) { if (ret) {
dev_err(dev, "dmaengine pcm open failed with err %d\n", ret); dev_err(dev, "dmaengine pcm open failed with err %d\n", ret);
return ret; return ret;
...@@ -144,7 +144,7 @@ static int tegra_pcm_mmap(struct snd_pcm_substream *substream, ...@@ -144,7 +144,7 @@ static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
static struct snd_pcm_ops tegra_pcm_ops = { static struct snd_pcm_ops tegra_pcm_ops = {
.open = tegra_pcm_open, .open = tegra_pcm_open,
.close = snd_dmaengine_pcm_close, .close = snd_dmaengine_pcm_close_release_chan,
.ioctl = snd_pcm_lib_ioctl, .ioctl = snd_pcm_lib_ioctl,
.hw_params = tegra_pcm_hw_params, .hw_params = tegra_pcm_hw_params,
.hw_free = tegra_pcm_hw_free, .hw_free = tegra_pcm_hw_free,
......
...@@ -125,8 +125,8 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream) ...@@ -125,8 +125,8 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream)
dma_cfg->dst_info.data_width = mem_data_width; dma_cfg->dst_info.data_width = mem_data_width;
} }
ret = snd_dmaengine_pcm_open_request_chan(substream, stedma40_filter,
ret = snd_dmaengine_pcm_open(substream, stedma40_filter, dma_cfg); dma_cfg);
if (ret) { if (ret) {
dev_dbg(dai->dev, dev_dbg(dai->dev,
"%s: ERROR: snd_dmaengine_pcm_open failed (%d)!\n", "%s: ERROR: snd_dmaengine_pcm_open failed (%d)!\n",
...@@ -211,7 +211,7 @@ static int ux500_pcm_mmap(struct snd_pcm_substream *substream, ...@@ -211,7 +211,7 @@ static int ux500_pcm_mmap(struct snd_pcm_substream *substream,
static struct snd_pcm_ops ux500_pcm_ops = { static struct snd_pcm_ops ux500_pcm_ops = {
.open = ux500_pcm_open, .open = ux500_pcm_open,
.close = snd_dmaengine_pcm_close, .close = snd_dmaengine_pcm_close_release_chan,
.ioctl = snd_pcm_lib_ioctl, .ioctl = snd_pcm_lib_ioctl,
.hw_params = ux500_pcm_hw_params, .hw_params = ux500_pcm_hw_params,
.hw_free = ux500_pcm_hw_free, .hw_free = ux500_pcm_hw_free,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment