summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorLiam Girdwood <lrg@slimlogic.co.uk>2011-04-07 08:39:19 +0100
committerAndy Green <andy.green@linaro.org>2011-04-07 08:39:19 +0100
commit027617773a20ef8f7880f52cfeeab8d84d8ef3cf (patch)
tree63f75de4884cc25272d3637d9daf8d809f5f4cab /sound
parentaaab07c899f380cfeddbbb5dee5bd4126fdacfac (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.c33
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)