summaryrefslogtreecommitdiff
path: root/sound/soc/fsl/fsl_asrc_dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/fsl/fsl_asrc_dma.c')
-rw-r--r--sound/soc/fsl/fsl_asrc_dma.c151
1 files changed, 82 insertions, 69 deletions
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index d6a3fc5f87e5..1bba48318e2d 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -8,7 +8,7 @@
#include <linux/dma-mapping.h>
#include <linux/module.h>
-#include <linux/platform_data/dma-imx.h>
+#include <linux/dma/imx-dma.h>
#include <sound/dmaengine_pcm.h>
#include <sound/pcm_params.h>
@@ -114,8 +114,8 @@ static int fsl_asrc_dma_trigger(struct snd_soc_component *component,
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- dmaengine_terminate_all(pair->dma_chan[OUT]);
- dmaengine_terminate_all(pair->dma_chan[IN]);
+ dmaengine_terminate_async(pair->dma_chan[OUT]);
+ dmaengine_terminate_async(pair->dma_chan[IN]);
break;
default:
return -EINVAL;
@@ -129,20 +129,24 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
struct snd_pcm_hw_params *params)
{
enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ enum sdma_peripheral_type be_peripheral_type = IMX_DMATYPE_SSI;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
struct snd_dmaengine_dai_dma_data *dma_params_fe = NULL;
struct snd_dmaengine_dai_dma_data *dma_params_be = NULL;
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsl_asrc_pair *pair = runtime->private_data;
+ struct dma_chan *tmp_chan = NULL, *be_chan = NULL;
+ struct snd_soc_component *component_be = NULL;
struct fsl_asrc *asrc = pair->asrc;
- struct dma_slave_config config_fe, config_be;
+ struct dma_slave_config config_fe = {}, config_be = {};
+ struct sdma_peripheral_config audio_config;
enum asrc_pair_index index = pair->index;
struct device *dev = component->dev;
+ struct device_node *of_dma_node;
int stream = substream->stream;
struct imx_dma_data *tmp_data;
struct snd_soc_dpcm *dpcm;
- struct dma_chan *tmp_chan;
struct device *dev_be;
u8 dir = tx ? OUT : IN;
dma_cap_mask_t mask;
@@ -152,11 +156,24 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
for_each_dpcm_be(rtd, stream, dpcm) {
struct snd_soc_pcm_runtime *be = dpcm->be;
struct snd_pcm_substream *substream_be;
- struct snd_soc_dai *dai = asoc_rtd_to_cpu(be, 0);
+ struct snd_soc_dai *dai_cpu = snd_soc_rtd_to_cpu(be, 0);
+ struct snd_soc_dai *dai_codec = snd_soc_rtd_to_codec(be, 0);
+ struct snd_soc_dai *dai;
if (dpcm->fe != rtd)
continue;
+ /*
+ * With audio graph card, original cpu dai is changed to codec
+ * device in backend, so if cpu dai is dummy device in backend,
+ * get the codec dai device, which is the real hardware device
+ * connected.
+ */
+ if (!snd_soc_dai_is_dummy(dai_cpu))
+ dai = dai_cpu;
+ else
+ dai = dai_codec;
+
substream_be = snd_soc_dpcm_get_substream(be, stream);
dma_params_be = snd_soc_dai_get_dma_data(dai, substream_be);
dev_be = dai->dev;
@@ -169,7 +186,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
}
/* Override dma_data of the Front-End and config its dmaengine */
- dma_params_fe = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ dma_params_fe = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
dma_params_fe->addr = asrc->paddr + asrc->get_fifo_addr(!dir, index);
dma_params_fe->maxburst = dma_params_be->maxburst;
@@ -179,7 +196,6 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
return -EINVAL;
}
- memset(&config_fe, 0, sizeof(config_fe));
ret = snd_dmaengine_pcm_prepare_slave_config(substream, params, &config_fe);
if (ret) {
dev_err(dev, "failed to prepare DMA config for Front-End\n");
@@ -198,17 +214,35 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
dma_cap_set(DMA_CYCLIC, mask);
/*
+ * The Back-End device might have already requested a DMA channel,
+ * so try to reuse it first, and then request a new one upon NULL.
+ */
+ component_be = snd_soc_lookup_component_nolocked(dev_be, SND_DMAENGINE_PCM_DRV_NAME);
+ if (component_be) {
+ be_chan = soc_component_to_pcm(component_be)->chan[substream->stream];
+ tmp_chan = be_chan;
+ }
+ if (!tmp_chan) {
+ tmp_chan = dma_request_chan(dev_be, tx ? "tx" : "rx");
+ if (IS_ERR(tmp_chan)) {
+ dev_err(dev, "failed to request DMA channel for Back-End\n");
+ return -EINVAL;
+ }
+ }
+
+ /*
* An EDMA DEV_TO_DEV channel is fixed and bound with DMA event of each
* peripheral, unlike SDMA channel that is allocated dynamically. So no
- * need to configure dma_request and dma_request2, but get dma_chan via
- * dma_request_slave_channel directly with dma name of Front-End device
+ * need to configure dma_request and dma_request2, but get dma_chan of
+ * Back-End device directly via dma_request_chan.
*/
if (!asrc->use_edma) {
/* Get DMA request of Back-End */
- tmp_chan = dma_request_slave_channel(dev_be, tx ? "tx" : "rx");
tmp_data = tmp_chan->private;
pair->dma_data.dma_request = tmp_data->dma_request;
- dma_release_channel(tmp_chan);
+ be_peripheral_type = tmp_data->peripheral_type;
+ if (!be_chan)
+ dma_release_channel(tmp_chan);
/* Get DMA request of Front-End */
tmp_chan = asrc->get_dma_channel(pair, dir);
@@ -218,11 +252,15 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
pair->dma_data.priority = tmp_data->priority;
dma_release_channel(tmp_chan);
+ of_dma_node = pair->dma_chan[!dir]->device->dev->of_node;
pair->dma_chan[dir] =
- dma_request_channel(mask, filter, &pair->dma_data);
+ __dma_request_channel(&mask, filter, &pair->dma_data,
+ of_dma_node);
+ pair->req_dma_chan = true;
} else {
- pair->dma_chan[dir] =
- asrc->get_dma_channel(pair, dir);
+ pair->dma_chan[dir] = tmp_chan;
+ /* Do not flag to release if we are reusing the Back-End one */
+ pair->req_dma_chan = !be_chan;
}
if (!pair->dma_chan[dir]) {
@@ -250,6 +288,17 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
config_be.dst_addr_width = buswidth;
config_be.dst_maxburst = dma_params_be->maxburst;
+ memset(&audio_config, 0, sizeof(audio_config));
+ config_be.peripheral_config = &audio_config;
+ config_be.peripheral_size = sizeof(audio_config);
+
+ if (tx && (be_peripheral_type == IMX_DMATYPE_SSI_DUAL ||
+ be_peripheral_type == IMX_DMATYPE_SPDIF))
+ audio_config.n_fifos_dst = 2;
+ if (!tx && (be_peripheral_type == IMX_DMATYPE_SSI_DUAL ||
+ be_peripheral_type == IMX_DMATYPE_SPDIF))
+ audio_config.n_fifos_src = 2;
+
if (tx) {
config_be.src_addr = asrc->paddr + asrc->get_fifo_addr(OUT, index);
config_be.dst_addr = dma_params_be->addr;
@@ -261,31 +310,31 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
ret = dmaengine_slave_config(pair->dma_chan[dir], &config_be);
if (ret) {
dev_err(dev, "failed to config DMA channel for Back-End\n");
- dma_release_channel(pair->dma_chan[dir]);
+ if (pair->req_dma_chan)
+ dma_release_channel(pair->dma_chan[dir]);
return ret;
}
- snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-
return 0;
}
static int fsl_asrc_dma_hw_free(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsl_asrc_pair *pair = runtime->private_data;
+ u8 dir = tx ? OUT : IN;
- snd_pcm_set_runtime_buffer(substream, NULL);
-
- if (pair->dma_chan[IN])
- dma_release_channel(pair->dma_chan[IN]);
+ if (pair->dma_chan[!dir])
+ dma_release_channel(pair->dma_chan[!dir]);
- if (pair->dma_chan[OUT])
- dma_release_channel(pair->dma_chan[OUT]);
+ /* release dev_to_dev chan if we aren't reusing the Back-End one */
+ if (pair->dma_chan[dir] && pair->req_dma_chan)
+ dma_release_channel(pair->dma_chan[dir]);
- pair->dma_chan[IN] = NULL;
- pair->dma_chan[OUT] = NULL;
+ pair->dma_chan[!dir] = NULL;
+ pair->dma_chan[dir] = NULL;
return 0;
}
@@ -294,7 +343,7 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_dmaengine_dai_dma_data *dma_data;
struct device *dev = component->dev;
@@ -339,7 +388,7 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component,
goto dma_chan_err;
}
- dma_data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ dma_data = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
/* Refine the snd_imx_hardware according to caps of DMA. */
ret = snd_dmaengine_pcm_refine_runtime_hwparams(substream,
@@ -401,9 +450,8 @@ static int fsl_asrc_dma_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
- struct snd_pcm_substream *substream;
struct snd_pcm *pcm = rtd->pcm;
- int ret, i;
+ int ret;
ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
if (ret) {
@@ -411,43 +459,8 @@ static int fsl_asrc_dma_pcm_new(struct snd_soc_component *component,
return ret;
}
- for_each_pcm_streams(i) {
- substream = pcm->streams[i].substream;
- if (!substream)
- continue;
-
- ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev,
- FSL_ASRC_DMABUF_SIZE, &substream->dma_buffer);
- if (ret) {
- dev_err(card->dev, "failed to allocate DMA buffer\n");
- goto err;
- }
- }
-
- return 0;
-
-err:
- if (--i == 0 && pcm->streams[i].substream)
- snd_dma_free_pages(&pcm->streams[i].substream->dma_buffer);
-
- return ret;
-}
-
-static void fsl_asrc_dma_pcm_free(struct snd_soc_component *component,
- struct snd_pcm *pcm)
-{
- struct snd_pcm_substream *substream;
- int i;
-
- for_each_pcm_streams(i) {
- substream = pcm->streams[i].substream;
- if (!substream)
- continue;
-
- snd_dma_free_pages(&substream->dma_buffer);
- substream->dma_buffer.area = NULL;
- substream->dma_buffer.addr = 0;
- }
+ return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
+ card->dev, FSL_ASRC_DMABUF_SIZE);
}
struct snd_soc_component_driver fsl_asrc_component = {
@@ -459,6 +472,6 @@ struct snd_soc_component_driver fsl_asrc_component = {
.close = fsl_asrc_dma_shutdown,
.pointer = fsl_asrc_dma_pcm_pointer,
.pcm_construct = fsl_asrc_dma_pcm_new,
- .pcm_destruct = fsl_asrc_dma_pcm_free,
+ .legacy_dai_naming = 1,
};
EXPORT_SYMBOL_GPL(fsl_asrc_component);