Browse Source

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 28d18f23fe)
isee-imx_3.14.28.y
Shengjiu Wang 7 years ago
committed by Nitin Garg
parent
commit
ebb41f5548
3 changed files with 111 additions and 0 deletions
  1. +103
    -0
      sound/soc/fsl/fsl_asrc.c
  2. +1
    -0
      sound/soc/fsl/fsl_asrc.h
  3. +7
    -0
      sound/soc/fsl/fsl_asrc_dma.c

+ 103
- 0
sound/soc/fsl/fsl_asrc.c View File

@ -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;


+ 1
- 0
sound/soc/fsl/fsl_asrc.h View File

@ -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;


+ 7
- 0
sound/soc/fsl/fsl_asrc_dma.c View File

@ -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)


Loading…
Cancel
Save