diff options
author | Nicolin Chen <b42378@freescale.com> | 2013-10-08 16:39:39 +0800 |
---|---|---|
committer | Jason Liu <r64343@freescale.com> | 2013-10-30 09:55:52 +0800 |
commit | 0c7a25933a30ed812fe91ba28ca0ae5d3b76dac8 (patch) | |
tree | 68640af80bfeb53012d01735763051ec0f0ec5a5 /sound | |
parent | 9d531128378a75e927f9f1f24a2b2af502d4bdec (diff) |
ENGR00281859-3 ASoC: fsl: Prepare dmaengine before submit it
ASRC and HDMI audio might meet unexpected stop, 'ctrl+z' for example,
and then disable its sdma channel. But after 'fg' resume, because sdma
channel's status has already been set into DMA_ERROR, we need to prepare
dmaengine again to clear its error state, otherwise sdma driver would
bypass its channel enabling and 'Input/Output error' would happen to
ALSA lib.
The combined prepare and submit are also being used in soc-dmaengine,
the common ASoC dmaengine driver.
And since we already use a proper way to handle sdma channel status,
there's no need to make an exception for HDMI any more, so drop it.
Signed-off-by: Nicolin Chen <b42378@freescale.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/fsl/fsl_asrc.c | 31 | ||||
-rw-r--r-- | sound/soc/fsl/imx-hdmi-dma.c | 35 |
2 files changed, 47 insertions, 19 deletions
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index dc230ffee9dd..d91484f236c9 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -133,13 +133,6 @@ static int asrc_p2p_request_channel(struct snd_pcm_substream *substream) dev_err(rtd->card->dev, "can not config dma channel\n"); goto error; } - asrc_p2p->asrc_p2p_desc = dmaengine_prep_dma_cyclic(chan, 0xffff, 64, - 64, DMA_DEV_TO_DEV, 0); - if (!asrc_p2p->asrc_p2p_desc) { - dev_err(&chan->dev->device, - "cannot prepare slave dma\n"); - goto error; - } return 0; error: @@ -274,16 +267,38 @@ static int fsl_asrc_p2p_hw_free(struct snd_pcm_substream *substream, return 0; } +static int fsl_asrc_dma_prepare_and_submit(struct snd_pcm_substream *substream, + struct fsl_asrc_p2p *asrc_p2p) +{ + struct dma_async_tx_descriptor *desc = asrc_p2p->asrc_p2p_desc; + struct dma_chan *chan = asrc_p2p->asrc_p2p_dma_chan; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct device *dev = rtd->platform->dev; + + desc = dmaengine_prep_dma_cyclic(chan, 0xffff, 64, 64, DMA_DEV_TO_DEV, 0); + if (!desc) { + dev_err(dev, "failed to prepare slave dma\n"); + return -EINVAL; + } + + dmaengine_submit(desc); + + return 0; +} + static int fsl_asrc_p2p_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *cpu_dai) { struct fsl_asrc_p2p *asrc_p2p = snd_soc_dai_get_drvdata(cpu_dai); + int ret; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - dmaengine_submit(asrc_p2p->asrc_p2p_desc); + ret = fsl_asrc_dma_prepare_and_submit(substream, asrc_p2p); + if (ret) + return ret; dma_async_issue_pending(asrc_p2p->asrc_p2p_dma_chan); asrc_p2p->asrc_ops.asrc_p2p_start_conv(asrc_p2p->asrc_index); break; diff --git a/sound/soc/fsl/imx-hdmi-dma.c b/sound/soc/fsl/imx-hdmi-dma.c index 0dc32dcf98b5..4155122f8d0e 100644 --- a/sound/soc/fsl/imx-hdmi-dma.c +++ b/sound/soc/fsl/imx-hdmi-dma.c @@ -697,16 +697,6 @@ static int hdmi_sdma_config(struct snd_pcm_substream *substream, return -EINVAL; } - priv->desc = dmaengine_prep_dma_cyclic(priv->dma_channel, 0, 0, 0, - DMA_TRANS_NONE, 0); - if (!priv->desc) { - dev_err(dev, "failed to prepare slave dma\n"); - return -EINVAL; - } - - priv->desc->callback = hdmi_sdma_callback; - priv->desc->callback_param = (void *)priv; - return 0; } @@ -810,12 +800,33 @@ static void hdmi_dma_trigger_init(struct snd_pcm_substream *substream, hdmi_writeb(status, HDMI_IH_AHBDMAAUD_STAT0); } +static int hdmi_dma_prepare_and_submit(struct snd_pcm_substream *substream, + struct hdmi_dma_priv *priv) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct device *dev = rtd->platform->dev; + + priv->desc = dmaengine_prep_dma_cyclic(priv->dma_channel, 0, 0, 0, + DMA_TRANS_NONE, 0); + if (!priv->desc) { + dev_err(dev, "failed to prepare slave dma\n"); + return -EINVAL; + } + + priv->desc->callback = hdmi_sdma_callback; + priv->desc->callback_param = (void *)priv; + dmaengine_submit(priv->desc); + + return 0; +} + static int hdmi_dma_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct hdmi_dma_priv *priv = runtime->private_data; struct device *dev = rtd->platform->dev; + int ret; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -831,7 +842,9 @@ static int hdmi_dma_trigger(struct snd_pcm_substream *substream, int cmd) hdmi_audio_writeb(AHB_DMA_START, START, 0x1); hdmi_dma_irq_set(false); hdmi_set_dma_mode(1); - dmaengine_submit(priv->desc); + ret = hdmi_dma_prepare_and_submit(substream, priv); + if (ret) + return ret; dma_async_issue_pending(priv->desc->chan); break; case SNDRV_PCM_TRIGGER_STOP: |