Add option to request reorder update power on codecs. Certain codecs can generate pop noise, when for example enabling the bypass path. The route cause in these codecs are the DAPM update power and register write sequence: 1. User enable the bypass 2. DAPM power up sequence takes place 2.1 codec DAPM widgets got powered on, codec is enabled 2.2 External speaker enabled 3. The bit enabling the bypass got changed.
Step 3 can cause audible pop on the speaker.
By introducing new flag for the DAPM (dapm_reorder_pupdate), codecs can request for reordered power up sequence, which will look like this:
1. User enable the bypass 2. The bit enabling the bypass got changed. 3. DAPM power up sequence takes place 3.1 codec DAPM widgets got powered on, codec is enabled 3.2 External speaker enabled
The pop noise going to be filtered out, since the speaker going to be enabled after the bit change taken place.
The default (current) sequence is not changed, since codec drivers must request for reordered sequence.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@nokia.com --- include/sound/soc-dapm.h | 1 + sound/soc/soc-dapm.c | 27 +++++++++++++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 041e98b..38f8aad 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -474,6 +474,7 @@ struct snd_soc_dapm_context { enum snd_soc_bias_level suspend_bias_level; struct delayed_work delayed_work; unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */ + unsigned int dapm_reorder_pupdate:1; /* Reordered pupdate in widgets */
struct device *dev; /* from parent - for debug */ struct snd_soc_codec *codec; /* parent codec */ diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 6a29d59..432ecf5 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1626,6 +1626,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; unsigned int val, val2, val_mask; + unsigned int change, dapm_pupdate_first = 1; int connect; int ret;
@@ -1646,16 +1647,21 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, mutex_lock(&widget->codec->mutex); widget->value = val;
- if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) { - if (val) - /* new connection */ - connect = invert ? 0:1; - else - /* old connection must be powered down */ - connect = invert ? 1:0; + change = snd_soc_test_bits(widget->codec, reg, val_mask, val); + if (val) + /* new connection */ + connect = invert ? 0 : 1; + else + /* old connection must be powered down */ + connect = invert ? 1 : 0;
- dapm_mixer_update_power(widget, kcontrol, connect); + if (widget->dapm->dapm_reorder_pupdate) { + /* reodered DAPM change requested */ + if (connect) + dapm_pupdate_first = 0; } + if (change && dapm_pupdate_first) + dapm_mixer_update_power(widget, kcontrol, connect);
if (widget->event) { if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { @@ -1673,6 +1679,11 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, } else ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
+ if (ret < 0) + goto out; + + if (change && !dapm_pupdate_first) + dapm_mixer_update_power(widget, kcontrol, connect); out: mutex_unlock(&widget->codec->mutex); return ret;