[ALSA] hda-codec - Fix Gateway laptops with STAC9200

Fix the output of Gateway laptops with STAC9200 codec chip.
They require the EAPD control for some pins.  These pins shouldn't be
powered down.
To enable EAPD control, a new model 'gateway' was added to STAC9200.
The known PCI SSIDs are included in the quirk list.
The fix was originally suggested by Brian Hinz, in ALSA bug#2948.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 9268925..a035eb6 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -972,6 +972,7 @@
 	  dell-m25	Dell Inspiron E1505n
 	  dell-m26	Dell Inspiron 1501
 	  dell-m27	Dell Inspiron E1705/9400
+	  gateway	Gateway laptops with EAPD control
 
 	STAC9205/9254
 	  ref		Reference board
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 239cdd8..187533e 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1630,10 +1630,24 @@
 
 	nid = codec->start_nid;
 	for (i = 0; i < codec->num_nodes; i++, nid++) {
-		if (get_wcaps(codec, nid) & AC_WCAP_POWER)
+		if (get_wcaps(codec, nid) & AC_WCAP_POWER) {
+			unsigned int pincap;
+			/*
+			 * don't power down the widget if it controls eapd
+			 * and EAPD_BTLENABLE is set.
+			 */
+			pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+			if (pincap & AC_PINCAP_EAPD) {
+				int eapd = snd_hda_codec_read(codec, nid,
+					0, AC_VERB_GET_EAPD_BTLENABLE, 0);
+				eapd &= 0x02;
+				if (power_state == AC_PWRST_D3 && eapd)
+					continue;
+			}
 			snd_hda_codec_write(codec, nid, 0,
 					    AC_VERB_SET_POWER_STATE,
 					    power_state);
+		}
 	}
 
 	if (power_state == AC_PWRST_D0) {
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 27360d2..fe91b9b 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -49,6 +49,7 @@
 	STAC_9200_DELL_M25,
 	STAC_9200_DELL_M26,
 	STAC_9200_DELL_M27,
+	STAC_9200_GATEWAY,
 	STAC_9200_MODELS
 };
 
@@ -378,6 +379,13 @@
 	{}
 };
 
+static struct hda_verb stac9200_eapd_init[] = {
+	/* set dac0mux for dac converter */
+	{0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+	{}
+};
+
 static struct hda_verb stac925x_core_init[] = {
 	/* set dac0mux for dac converter */
 	{ 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -693,6 +701,7 @@
 	[STAC_9200_DELL_M25] = "dell-m25",
 	[STAC_9200_DELL_M26] = "dell-m26",
 	[STAC_9200_DELL_M27] = "dell-m27",
+	[STAC_9200_GATEWAY] = "gateway",
 };
 
 static struct snd_pci_quirk stac9200_cfg_tbl[] = {
@@ -760,7 +769,12 @@
 		      "unknown Dell", STAC_9200_DELL_M26),
 	/* Panasonic */
 	SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF),
-
+	/* Gateway machines needs EAPD to be set on resume */
+	SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
+	SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
+		      STAC_9200_GATEWAY),
+	SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
+		      STAC_9200_GATEWAY),
 	{} /* terminator */
 };
 
@@ -2492,7 +2506,10 @@
 	spec->num_dmics = 0;
 	spec->num_adcs = 1;
 
-	spec->init = stac9200_core_init;
+	if (spec->board_config == STAC_9200_GATEWAY)
+		spec->init = stac9200_eapd_init;
+	else
+		spec->init = stac9200_core_init;
 	spec->mixer = stac9200_mixer;
 
 	err = stac9200_parse_auto_config(codec);