[alsa-devel] [PATCH 10/30] ALSA: HDA VIA: Add smart5.1 function.

Logan Li loganli at viatech.com.cn
Sat Oct 10 13:07:52 CEST 2009


From: Lydia Wang <lydiawang at viatech.com.cn>
Subject: ALSA: HDA VIA: Add smart5.1 function.

Smart 5.1 is for 3-jacks model, to reuse input pins as outputs.
While off, they act as "line out" / "line in" / "mic in".
While on, they acts as "line out" / "back left/right" / "center/lfe".

Signed-off-by: Lydia Wang <lydiawang at viatech.com.cn>
Signed-off-by: Logan Li <loganli at viatech.com.cn>

---
 sound/pci/hda/patch_via.c |  177 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 173 insertions(+), 4 deletions(-)

--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -211,7 +211,7 @@
 
 struct via_spec {
 	/* codec parameterization */
-	struct snd_kcontrol_new *mixers[3];
+	struct snd_kcontrol_new *mixers[4];
 	unsigned int num_mixers;
 
 	struct hda_verb *init_verbs[5];
@@ -253,6 +253,7 @@
 	const struct hda_input_mux *hp_mux;
 	unsigned int hp_independent_mode;
 	unsigned int hp_independent_mode_index;
+	unsigned int smart51_enabled;
 
 	enum VIA_HDA_CODEC codec_type;
 
@@ -390,6 +391,8 @@
 	}
 }
 
+static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
+
 static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
 				unsigned int *affected_parm)
 {
@@ -400,9 +403,10 @@
 		& AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */
 	unsigned present = snd_hda_codec_read(codec, nid, 0,
 					      AC_VERB_GET_PIN_SENSE, 0) >> 31;
-
-	if ((no_presence || present) && get_defcfg_connect(def_conf)
-	    != AC_JACK_PORT_NONE) {
+	struct via_spec *spec = codec->spec;
+	if ((spec->smart51_enabled && is_smart51_pins(spec, nid))
+	    || ((no_presence || present)
+		&& get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) {
 		*affected_parm = AC_PWRST_D0; /* if it's connected */
 		parm = AC_PWRST_D0;
 	} else
@@ -657,6 +661,167 @@
 	{ } /* end */
 };
 
+static void notify_aa_path_ctls(struct hda_codec *codec)
+{
+	int i;
+	struct snd_ctl_elem_id id;
+	const char *labels[] = {"Mic", "Front Mic", "Line"};
+
+	memset(&id, 0, sizeof(id));
+	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	for (i = 0; i < ARRAY_SIZE(labels); i++) {
+		sprintf(id.name, "%s Playback Volume", labels[i]);
+		snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
+			       &id);
+	}
+}
+
+static void mute_aa_path(struct hda_codec *codec, int mute)
+{
+	struct via_spec *spec = codec->spec;
+	hda_nid_t  nid_mixer;
+	int start_idx;
+	int end_idx;
+	int i;
+	/* get nid of MW0 and start & end index */
+	switch (spec->codec_type) {
+	case VT1708:
+		nid_mixer = 0x17;
+		start_idx = 2;
+		end_idx = 4;
+		break;
+	case VT1709_10CH:
+	case VT1709_6CH:
+		nid_mixer = 0x18;
+		start_idx = 2;
+		end_idx = 4;
+		break;
+	case VT1708B_8CH:
+	case VT1708B_4CH:
+	case VT1708S:
+		nid_mixer = 0x16;
+		start_idx = 2;
+		end_idx = 4;
+		break;
+	default:
+		return;
+	}
+	/* check AA path's mute status */
+	for (i = start_idx; i <= end_idx; i++) {
+		int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE;
+		snd_hda_codec_amp_stereo(codec, nid_mixer, HDA_INPUT, i,
+					 HDA_AMP_MUTE, val);
+	}
+}
+static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin)
+{
+	int res = 0;
+	int index;
+	for (index = AUTO_PIN_MIC; index < AUTO_PIN_FRONT_LINE; index++) {
+		if (pin == spec->autocfg.input_pins[index]) {
+			res = 1;
+			break;
+		}
+	}
+	return res;
+}
+
+static int via_smart51_info(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int via_smart51_get(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct via_spec *spec = codec->spec;
+	int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
+	int on = 1;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(index); i++) {
+		hda_nid_t nid = spec->autocfg.input_pins[index[i]];
+		if (nid) {
+			int ctl =
+			    snd_hda_codec_read(codec, nid, 0,
+					       AC_VERB_GET_PIN_WIDGET_CONTROL,
+					       0);
+			if (i == AUTO_PIN_FRONT_MIC
+			    && spec->hp_independent_mode)
+				continue; /* ignore FMic for independent HP */
+			if (ctl & AC_PINCTL_IN_EN
+			    && !(ctl & AC_PINCTL_OUT_EN))
+				on = 0;
+		}
+	}
+	*ucontrol->value.integer.value = on;
+	return 0;
+}
+
+static int via_smart51_put(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct via_spec *spec = codec->spec;
+	int out_in = *ucontrol->value.integer.value
+		? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN;
+	int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(index); i++) {
+		hda_nid_t nid = spec->autocfg.input_pins[index[i]];
+		if (i == AUTO_PIN_FRONT_MIC
+		    && spec->hp_independent_mode)
+			continue; /* don't retask FMic for independent HP */
+		if (nid) {
+			unsigned int parm = snd_hda_codec_read(
+				codec, nid, 0,
+				AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+			parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
+			parm |= out_in;
+			snd_hda_codec_write(codec, nid, 0,
+					    AC_VERB_SET_PIN_WIDGET_CONTROL,
+					    parm);
+			if (out_in == AC_PINCTL_OUT_EN) {
+				mute_aa_path(codec, 1);
+				notify_aa_path_ctls(codec);
+			}
+		}
+		if (i == AUTO_PIN_FRONT_MIC) {
+			if (spec->codec_type == VT1708S) {
+				/* input = index 1 (AOW3) */
+				snd_hda_codec_write(
+					codec, nid, 0,
+					AC_VERB_SET_CONNECT_SEL, 1);
+				snd_hda_codec_amp_stereo(
+					codec, nid, HDA_OUTPUT,
+					0, HDA_AMP_MUTE, HDA_AMP_UNMUTE);
+			}
+		}
+	}
+	spec->smart51_enabled = *ucontrol->value.integer.value;
+	set_jack_power_state(codec);
+	return 1;
+}
+
+static struct snd_kcontrol_new via_smart51_mixer[] = {
+	{
+	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	 .name = "Smart 5.1",
+	 .count = 1,
+	 .info = via_smart51_info,
+	 .get = via_smart51_get,
+	 .put = via_smart51_put,
+	 },
+	{}			/* end */
+};
+
 /* capture mixer elements */
 static struct snd_kcontrol_new vt1708_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
@@ -1587,6 +1752,7 @@
 	if (spec->hp_mux)
 		spec->mixers[spec->num_mixers++] = via_hp_mixer;
 
+	spec->mixers[spec->num_mixers++] = via_smart51_mixer;
 	return 1;
 }
 
@@ -2087,6 +2253,7 @@
 	if (spec->hp_mux)
 		spec->mixers[spec->num_mixers++] = via_hp_mixer;
 
+	spec->mixers[spec->num_mixers++] = via_smart51_mixer;
 	return 1;
 }
 
@@ -2649,6 +2816,7 @@
 	if (spec->hp_mux)
 		spec->mixers[spec->num_mixers++] = via_hp_mixer;
 
+	spec->mixers[spec->num_mixers++] = via_smart51_mixer;
 	return 1;
 }
 
@@ -3142,6 +3310,7 @@
 	if (spec->hp_mux)
 		spec->mixers[spec->num_mixers++] = via_hp_mixer;
 
+	spec->mixers[spec->num_mixers++] = via_smart51_mixer;
 	return 1;
 }
 





More information about the Alsa-devel mailing list