ASoC: twl6040: Workaround for headset DC offset caused pop noise
authorPeter Ujfalusi <peter.ujfalusi@ti.com>
Wed, 12 Oct 2011 11:46:02 +0000 (14:46 +0300)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Wed, 12 Oct 2011 12:11:54 +0000 (13:11 +0100)
Both Headset DAC need to be turned on/off at the same time before
any of the output drivers are enabled (HS Left/Right, Earpiece).
Move the HS DAC enable code to sequenced DAPM_SUPPLY, and attach
it to the DACs.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
include/linux/mfd/twl6040.h
sound/soc/codecs/twl6040.c

index 87a4778..2463c26 100644 (file)
 
 /* HSLCTL/R (0x10/0x11) fields */
 
+#define TWL6040_HSDACENA               (1 << 0)
 #define TWL6040_HSDACMODE              (1 << 1)
 #define TWL6040_HSDRVMODE              (1 << 3)
 
index 8648498..6369230 100644 (file)
@@ -654,6 +654,26 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
 static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
                        struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = w->codec;
+       u8 hslctl, hsrctl;
+
+       /*
+        * Workaround for Headset DC offset caused pop noise:
+        * Both HS DAC need to be turned on (before the HS driver) and off at
+        * the same time.
+        */
+       hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL);
+       hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL);
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               hslctl |= TWL6040_HSDACENA;
+               hsrctl |= TWL6040_HSDACENA;
+       } else {
+               hslctl &= ~TWL6040_HSDACENA;
+               hsrctl &= ~TWL6040_HSDACENA;
+       }
+       twl6040_write(codec, TWL6040_REG_HSLCTL, hslctl);
+       twl6040_write(codec, TWL6040_REG_HSRCTL, hsrctl);
+
        msleep(1);
        return 0;
 }
@@ -1103,14 +1123,8 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
                        TWL6040_REG_DMICBCTL, 4, 0),
 
        /* DACs */
-       SND_SOC_DAPM_DAC_E("HSDAC Left", "Headset Playback",
-                       TWL6040_REG_HSLCTL, 0, 0,
-                       twl6040_hs_dac_event,
-                       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_DAC_E("HSDAC Right", "Headset Playback",
-                       TWL6040_REG_HSRCTL, 0, 0,
-                       twl6040_hs_dac_event,
-                       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_DAC("HSDAC Left", "Headset Playback", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("HSDAC Right", "Headset Playback", SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_DAC_E("HFDAC Left", "Handsfree Playback",
                        TWL6040_REG_HFLCTL, 0, 0,
                        twl6040_power_mode_event,
@@ -1175,6 +1189,9 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
                            NULL, 0),
        SND_SOC_DAPM_SUPPLY("Vibra Right Control", TWL6040_REG_VIBCTLR, 2, 0,
                            NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("HSDAC Power", 1, SND_SOC_NOPM, 0, 0,
+                             twl6040_hs_dac_event,
+                             SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
        /* Analog playback PGAs */
        SND_SOC_DAPM_PGA("HF Left PGA",
@@ -1204,6 +1221,9 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"AFMAmpL", NULL, "AFML"},
        {"AFMAmpR", NULL, "AFMR"},
 
+       {"HSDAC Left", NULL, "HSDAC Power"},
+       {"HSDAC Right", NULL, "HSDAC Power"},
+
        {"Headset Left Playback", "HS DAC", "HSDAC Left"},
        {"Headset Left Playback", "Line-In amp", "AFMAmpL"},