From 0937a41974d2ab340f15da2f124493fd7164e536 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 15 Feb 2011 00:55:45 -0600 Subject: [PATCH 36/60] ASoC: McPDM: Delay McPDM shutdown to reduce pop noise commit 7dc58648dd6dbe5429202068aaadcadb29ae0247 upstream In order to reduce pop noise during stream close, McPDM shutdown is delayed so that analog companion chip can switch off first determined by ramp down time specified through ALSA SoC. McPDM shutdown work is queued in the kernel global queue to ensure proper sequencing and avoid race conditions. Change-Id: I49cdd26cbee41f6b28e2e1fd7b427caaeacf9126 Signed-off-by: Liam Girdwood Signed-off-by: Ricardo Neri Signed-off-by: Sebastien Guiriec Signed-off-by: Misael Lopez Cruz Integrated-by: Jingdong Lu --- sound/soc/omap/omap-mcpdm.c | 33 +++++++++++++++++++++++++++------ 1 files changed, 27 insertions(+), 6 deletions(-) diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index f420ad0..74be281 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -58,6 +59,7 @@ struct omap_mcpdm { void __iomem *io_base; u8 free; int irq; + struct delayed_work delayed_work; spinlock_t lock; struct omap_mcpdm_platform_data *pdata; @@ -495,6 +497,10 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "%s: active %d\n", __func__, dai->active); + /* make sure we stop any pre-existing shutdown */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + cancel_delayed_work(&mcpdm->delayed_work); + if (!dai->active && mcpdm->free) { err = omap_mcpdm_request(mcpdm); omap_mcpdm_set_offset(mcpdm); @@ -510,19 +516,32 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "%s: active %d\n", __func__, dai->active); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) mcpdm->dl_active--; - if (mcpdm->dl_active == 0) - omap_mcpdm_playback_close(mcpdm, mcpdm->downlink); - } else + else mcpdm->ul_active--; if (!dai->active) { if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) omap_mcpdm_capture_close(mcpdm, mcpdm->uplink); - if (!mcpdm->free && !mcpdm->dl_active && !mcpdm->ul_active) - omap_mcpdm_free(mcpdm); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + schedule_delayed_work(&mcpdm->delayed_work, + msecs_to_jiffies(1000)); /* TODO: pdata ? */ } + +} + +/* work to delay McPDM shutdown */ +static void playback_work(struct work_struct *work) +{ + struct omap_mcpdm *mcpdm = + container_of(work, struct omap_mcpdm, delayed_work.work); + + if (!mcpdm->dl_active) + omap_mcpdm_playback_close(mcpdm, mcpdm->downlink); + + if (!mcpdm->free && !mcpdm->dl_active && !mcpdm->ul_active) + omap_mcpdm_free(mcpdm); } static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream, @@ -690,6 +709,8 @@ static __devinit int asoc_mcpdm_probe(struct platform_device *pdev) mcpdm->dl1_offset = 0x1F; mcpdm->dl2_offset = 0x1F; + INIT_DELAYED_WORK(&mcpdm->delayed_work, playback_work); + ret = snd_soc_register_dais(&pdev->dev, omap_mcpdm_dai, ARRAY_SIZE(omap_mcpdm_dai)); if (ret == 0) -- 1.7.4.1