From: Takashi Iwai <tiwai@suse.de>
Subject: Fix VT1708 jack detection on SLEPOS machines
Patch-mainline: Never
References: bnc#813922

The headphone auto-mute still doesn't work on SLEPOS machines with
VT1708 codec, and it turned out that clearing the pin control for the
speaker outputs on these machines actually turn on the speaker in
full volumes without any further volume controls.  So, there is no
other way to control the mute but disabling the amp on the pin. 

This patch adds the excpetional handling for such cases.  Since we
don't know whether it's generic to VT1708, we take here a safer path,
i.e. handling the mute via amp for all VT1708 machines.

The patch is specific to old kernel (3.8 and older), so no upstream.

Signed-off-by: Takashi Iwai <tiwai@suse.de>

---
 sound/pci/hda/patch_via.c |   44 +++++++++++++++++++++++++++++++++++++-------
 1 file changed, 37 insertions(+), 7 deletions(-)

--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -217,6 +217,7 @@ struct via_spec {
 	int hp_work_active;
 	int vt1708_jack_detect;
 	int vt1708_hp_present;
+	bool mute_via_amp;
 
 	void (*set_widgets_power_state)(struct hda_codec *codec);
 
@@ -1643,7 +1644,7 @@ static void via_free(struct hda_codec *c
 }
 
 /* mute/unmute outputs */
-static void toggle_output_mutes(struct hda_codec *codec, int num_pins,
+static void toggle_output_mutes_via_pin(struct hda_codec *codec, int num_pins,
 				hda_nid_t *pins, bool mute)
 {
 	int i;
@@ -1660,6 +1661,30 @@ static void toggle_output_mutes(struct h
 	}
 }
 
+static void toggle_output_mutes_via_amp(struct hda_codec *codec, int num_pins,
+				hda_nid_t *pins, bool mute)
+{
+	int i, ch;
+	for (i = 0; i < num_pins; i++) {
+		for (ch = 0; ch < 2; ch++) {
+			snd_hda_codec_amp_update(codec, pins[i], ch,
+						 HDA_OUTPUT, 0, 0x80,
+						 mute ? 0x80 : 0x00);
+		}
+	}
+}
+
+static void toggle_output_mutes(struct hda_codec *codec, int num_pins,
+				hda_nid_t *pins, bool mute)
+{
+	struct via_spec *spec = codec->spec;
+
+	if (spec->mute_via_amp)
+		toggle_output_mutes_via_amp(codec, num_pins, pins, mute);
+	else
+		toggle_output_mutes_via_pin(codec, num_pins, pins, mute);
+}
+
 /* mute internal speaker if line-out is plugged */
 static void via_line_automute(struct hda_codec *codec, int present)
 {
@@ -1860,7 +1885,8 @@ static int via_auto_fill_dac_nids(struct
 }
 
 static int create_ch_ctls(struct hda_codec *codec, const char *pfx,
-			  int chs, bool check_dac, struct nid_path *path)
+			  int chs, bool check_dac, struct nid_path *path,
+			  bool check_mute_via_amp)
 {
 	struct via_spec *spec = codec->spec;
 	char name[32];
@@ -1888,6 +1914,9 @@ static int create_ch_ctls(struct hda_cod
 		path->vol_ctl = nid;
 	}
 
+	if (check_mute_via_amp && spec->mute_via_amp)
+		return 0; /* no mute */
+
 	if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_MUTE))
 		nid = dac;
 	else if (check_amp_caps(codec, pin, HDA_OUTPUT, AC_AMPCAP_MUTE))
@@ -1985,10 +2014,10 @@ static int via_auto_create_multi_out_ctl
 			continue;
 		path = spec->out_path + i;
 		if (i == HDA_CLFE) {
-			err = create_ch_ctls(codec, "Center", 1, true, path);
+			err = create_ch_ctls(codec, "Center", 1, true, path, true);
 			if (err < 0)
 				return err;
-			err = create_ch_ctls(codec, "LFE", 2, true, path);
+			err = create_ch_ctls(codec, "LFE", 2, true, path, true);
 			if (err < 0)
 				return err;
 		} else {
@@ -1996,7 +2025,7 @@ static int via_auto_create_multi_out_ctl
 			if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
 			    cfg->line_outs == 1)
 				pfx = "Speaker";
-			err = create_ch_ctls(codec, pfx, 3, true, path);
+			err = create_ch_ctls(codec, pfx, 3, true, path, true);
 			if (err < 0)
 				return err;
 		}
@@ -2075,7 +2104,7 @@ static int via_auto_create_hp_ctls(struc
 		path = &spec->hp_mix_path;
 		check_dac = false;
 	}
-	err = create_ch_ctls(codec, "Headphone", 3, check_dac, path);
+	err = create_ch_ctls(codec, "Headphone", 3, check_dac, path, false);
 	if (err < 0)
 		return err;
 	if (check_dac)
@@ -2126,7 +2155,7 @@ static int via_auto_create_speaker_ctls(
 		path = &spec->speaker_mix_path;
 		check_dac = false;
 	}
-	err = create_ch_ctls(codec, "Speaker", 3, check_dac, path);
+	err = create_ch_ctls(codec, "Speaker", 3, check_dac, path, true);
 	if (err < 0)
 		return err;
 	if (check_dac)
@@ -2844,6 +2873,7 @@ static int patch_vt1708(struct hda_codec
 
 	codec->jackpoll = 1;
 	spec->vt1708_jack_detect = 1;
+	spec->mute_via_amp = 1;
 
 	/* Add HP and CD pin config connect bit re-config action */
 	vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
