summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorShengjiu Wang <b02247@freescale.com>2014-04-10 10:11:00 +0800
committerNitin Garg <nitin.garg@freescale.com>2015-01-15 21:17:58 -0600
commitebb41f5548c95c474be1b1893229c65558eb9568 (patch)
tree98b3efabf0ca4fcccc5fa1bf115df60a5492aa0b /sound
parent963e1bef81207531d9bac95d16607b603d750a91 (diff)
ENGR00307835-4 ASoC: fsl: implement ASRC P2P xrun handler
When ASRC P2P is working, it will check the xrun status of cpu dai in the back end bistream. then will do Whole route stop and restart. Signed-off-by: Shengjiu Wang <b02247@freescale.com> (cherry picked from commit 28d18f23fe7577f613ad8cfb4699bba26178304b)
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/fsl/fsl_asrc.c103
-rw-r--r--sound/soc/fsl/fsl_asrc.h1
-rw-r--r--sound/soc/fsl/fsl_asrc_dma.c7
3 files changed, 111 insertions, 0 deletions
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 29adf261e986..832e822d1c9f 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -537,7 +537,26 @@ static int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
+static int fsl_asrc_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(cpu_dai);
+
+ asrc_priv->substream[substream->stream] = substream;
+ return 0;
+}
+
+static void fsl_asrc_dai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(cpu_dai);
+
+ asrc_priv->substream[substream->stream] = NULL;
+}
+
static struct snd_soc_dai_ops fsl_asrc_dai_ops = {
+ .startup = fsl_asrc_dai_startup,
+ .shutdown = fsl_asrc_dai_shutdown,
.hw_params = fsl_asrc_dai_hw_params,
.hw_free = fsl_asrc_dai_hw_free,
.trigger = fsl_asrc_dai_trigger,
@@ -700,6 +719,85 @@ static struct regmap_config fsl_asrc_regmap_config = {
#include "fsl_asrc_m2m.c"
+static bool fsl_asrc_check_xrun(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_dmaengine_dai_dma_data *dma_params_be = NULL;
+ struct snd_pcm_substream *be_substream;
+ struct snd_soc_dpcm *dpcm;
+ int ret = 0;
+
+ /* find the be for this fe stream */
+ list_for_each_entry(dpcm, &rtd->dpcm[substream->stream].be_clients, list_be) {
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ struct snd_soc_dai *dai = be->cpu_dai;
+
+ if (dpcm->fe != rtd)
+ continue;
+
+ be_substream = snd_soc_dpcm_get_substream(be, substream->stream);
+ dma_params_be = snd_soc_dai_get_dma_data(dai, be_substream);
+ if (dma_params_be->check_xrun && dma_params_be->check_xrun(be_substream))
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static int stop_lock_stream(struct snd_pcm_substream *substream)
+{
+ if (substream) {
+ snd_pcm_stream_lock_irq(substream);
+ if (substream->runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+ substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);
+ }
+ return 0;
+}
+
+static int start_unlock_stream(struct snd_pcm_substream *substream)
+{
+ if (substream) {
+ if (substream->runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+ substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
+ snd_pcm_stream_unlock_irq(substream);
+ }
+ return 0;
+}
+
+static void fsl_asrc_reset(struct snd_pcm_substream *substream, bool stop)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(cpu_dai);
+ struct snd_dmaengine_dai_dma_data *dma_params_be = NULL;
+ struct snd_soc_dpcm *dpcm;
+ struct snd_pcm_substream *be_substream;
+
+ if (stop) {
+ stop_lock_stream(asrc_priv->substream[0]);
+ stop_lock_stream(asrc_priv->substream[1]);
+ }
+
+ /* find the be for this fe stream */
+ list_for_each_entry(dpcm, &rtd->dpcm[substream->stream].be_clients, list_be) {
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ struct snd_soc_dai *dai = be->cpu_dai;
+
+ if (dpcm->fe != rtd)
+ continue;
+
+ be_substream = snd_soc_dpcm_get_substream(be, substream->stream);
+ dma_params_be = snd_soc_dai_get_dma_data(dai, be_substream);
+ dma_params_be->device_reset(be_substream, 0);
+ break;
+ }
+
+ if (stop) {
+ start_unlock_stream(asrc_priv->substream[1]);
+ start_unlock_stream(asrc_priv->substream[0]);
+ }
+}
+
/**
* Initialize ASRC registers with a default configurations
*/
@@ -889,6 +987,11 @@ static int fsl_asrc_probe(struct platform_device *pdev)
return -EINVAL;
}
+ asrc_priv->dma_params_tx.check_xrun = fsl_asrc_check_xrun;
+ asrc_priv->dma_params_rx.check_xrun = fsl_asrc_check_xrun;
+ asrc_priv->dma_params_tx.device_reset = fsl_asrc_reset;
+ asrc_priv->dma_params_rx.device_reset = fsl_asrc_reset;
+
if (asrc_priv->asrc_width != 16 && asrc_priv->asrc_width != 24) {
dev_warn(&pdev->dev, "unsupported width, switching to 24bit\n");
asrc_priv->asrc_width = 24;
diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h
index 9cb1689b1b95..5bf8831089df 100644
--- a/sound/soc/fsl/fsl_asrc.h
+++ b/sound/soc/fsl/fsl_asrc.h
@@ -354,6 +354,7 @@ struct fsl_asrc {
struct clk *asrck_clk[ASRC_CLK_MAX_NUM];
spinlock_t lock;
+ struct snd_pcm_substream *substream[2];
struct fsl_asrc_pair *pair[ASRC_PAIR_MAX_NUM];
unsigned int channel_bits;
unsigned int channel_avail;
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index ffc000bc1f15..28bc57f897a4 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -50,12 +50,19 @@ static void fsl_asrc_dma_complete(void *arg)
struct snd_pcm_substream *substream = arg;
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsl_asrc_pair *pair = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_dmaengine_dai_dma_data *dma_data;
pair->pos += snd_pcm_lib_period_bytes(substream);
if (pair->pos >= snd_pcm_lib_buffer_bytes(substream))
pair->pos = 0;
snd_pcm_period_elapsed(substream);
+
+ dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+ if (dma_data->check_xrun && dma_data->check_xrun(substream))
+ dma_data->device_reset(substream, 1);
+
}
static int fsl_asrc_dma_prepare_and_submit(struct snd_pcm_substream *substream)