aboutsummaryrefslogtreecommitdiffstats
path: root/bsp/pandaboard/ASoC-McPDM-Delay-McPDM-shutdown-to-reduce-pop-noise.patch
blob: ff4cf47cf3eda2203ef8dbd17545a6f13bf7100c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
From 0937a41974d2ab340f15da2f124493fd7164e536 Mon Sep 17 00:00:00 2001
From: Liam Girdwood <lrg@slimlogic.co.uk>
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 <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>
Integrated-by: Jingdong Lu <jingdong.lu@windriver.com>
---
 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 <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)
-- 
1.7.4.1