CHROMIUM: ALSA: hda: manage EAPD timing to remove audible 'pop' on Alex speakers

For systems with external amplifiers the EAPD signal can be used to
turn on/off the amp.  Depending upon the amplifier used in the system
this signal can lead to audible popping on EAPD assert/de-assert.  This
change aims to mitigate the popping by enabling (resuming) EAPD after
inputs to the amplifier have setup.  On disable (suspend) it allows
EAPD to proceed disabling of amp inputs.

BUG=chrome-os-partner:3971
TEST=manual, on CR-48 and other partner systems w/ this codec using
alex_pop.sh script posted on tracker.  Additionally played audio via
html5zombo.com across suspend / resume cycles.

Change-Id: I3c7f7b71b72c9e8540f3118119c000c572eef62c
Signed-off-by: Todd Broch <tbroch@chromium.org>
Reviewed-on: http://gerrit.chromium.org/gerrit/2487
Reviewed-by: Olof Johansson <olofj@chromium.org>
Reviewed-by: Puneet Kumar <puneetster@chromium.org>
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 0a39229..4c08075 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -17472,10 +17472,6 @@
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
-	/* always trun on EAPD */
-	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
-
 	{ }
 };
 
@@ -18996,6 +18992,37 @@
 		       "hda_codec: failed to override amp caps for NID 0x2\n");
 }
 
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static int alc272_alex_suspend(struct hda_codec *codec, pm_message_t state)
+{
+	struct alc_spec *spec = codec->spec;
+
+	set_eapd(codec, 0x14, 0);
+	set_eapd(codec, 0x15, 0);
+	msleep(300);
+
+	alc_shutup(codec);
+	if (spec && spec->power_hook)
+		spec->power_hook(codec);
+	return 0;
+}
+#endif /* CONFIG_SND_HDA_POWER_SAVE */
+#ifdef SND_HDA_NEEDS_RESUME
+static int alc272_alex_resume(struct hda_codec *codec)
+{
+	codec->patch_ops.init(codec);
+	snd_hda_codec_resume_amp(codec);
+	snd_hda_codec_resume_cache(codec);
+	if (codec->patch_ops.check_power_status)
+		codec->patch_ops.check_power_status(codec, 0x01);
+
+	msleep(25);
+	set_eapd(codec, 0x14, 1);
+	set_eapd(codec, 0x15, 1);
+	return 0;
+}
+#endif /* SND_HDA_NEEDS_RESUME */
+
 static void alc272_fixup_alex(struct hda_codec *codec,
 			       const struct alc_fixup *fix, int pre_init) {
 	if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
@@ -19005,6 +19032,12 @@
 				      (0 << AC_AMPCAP_MUTE_SHIFT)))
 		printk(KERN_WARNING
 		       "hda_codec: failed to override amp caps for NID 0x2\n");
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+	codec->patch_ops.suspend = alc272_alex_suspend;
+#endif
+#ifdef SND_HDA_NEEDS_RESUME
+	codec->patch_ops.resume = alc272_alex_resume;
+#endif
 }
 
 enum {
@@ -19049,7 +19082,6 @@
 	{}
 };
 
-
 static int patch_alc662(struct hda_codec *codec)
 {
 	struct alc_spec *spec;