summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@ti.com>2011-10-12 14:46:02 +0300
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-10-12 13:11:54 +0100
commit33b6816ca3a4027a1b5444c83c1c24c0b1991262 (patch)
treec14a30ad5b0d70023887f6de96889678409b8c2b
parent67c341302f5a401a405be758250bada39746c96b (diff)
downloadop-kernel-dev-33b6816ca3a4027a1b5444c83c1c24c0b1991262.zip
op-kernel-dev-33b6816ca3a4027a1b5444c83c1c24c0b1991262.tar.gz
ASoC: twl6040: Workaround for headset DC offset caused pop noise
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>
-rw-r--r--include/linux/mfd/twl6040.h1
-rw-r--r--sound/soc/codecs/twl6040.c36
2 files changed, 29 insertions, 8 deletions
diff --git a/include/linux/mfd/twl6040.h b/include/linux/mfd/twl6040.h
index 87a4778..2463c261 100644
--- a/include/linux/mfd/twl6040.h
+++ b/include/linux/mfd/twl6040.h
@@ -122,6 +122,7 @@
/* HSLCTL/R (0x10/0x11) fields */
+#define TWL6040_HSDACENA (1 << 0)
#define TWL6040_HSDACMODE (1 << 1)
#define TWL6040_HSDRVMODE (1 << 3)
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 8648498..6369230 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -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"},
OpenPOWER on IntegriCloud