diff options
author | Liam Girdwood <lrg@slimlogic.co.uk> | 2011-04-07 08:39:19 +0100 |
---|---|---|
committer | Andy Green <andy.green@linaro.org> | 2011-04-07 08:39:19 +0100 |
commit | 027617773a20ef8f7880f52cfeeab8d84d8ef3cf (patch) | |
tree | 63f75de4884cc25272d3637d9daf8d809f5f4cab /sound | |
parent | aaab07c899f380cfeddbbb5dee5bd4126fdacfac (diff) |
ASoC: McPDM: Delay McPDM shutdown to reduce pop noise
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 <lrg@slimlogic.co.uk>
Signed-off-by: Ricardo Neri <ricardo.neri@ti.com>
Signed-off-by: Sebastien Guiriec <s-guiriec@ti.com>
Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
Diffstat (limited to 'sound')
-rw-r--r-- | 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 f420ad001e3..74be28126d5 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -34,6 +34,7 @@ #include <linux/irq.h> #include <linux/slab.h> #include <linux/pm_runtime.h> +#include <linux/workqueue.h> #include <sound/core.h> #include <sound/pcm.h> @@ -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) |