Skip to contentSkip to conversation

hda: Mono mux mixer support

PATCH Applied Matthew Ranostay 2 participants 5 messages Jan 21, 2008 – Jan 22, 2008

lore
Share & tools
lore
#0 lore raw

PATCH 2/2 hda: Mono mux mixer support

Add support for the mono mux on several 92HD7xxx codecs. Creates a dynamic mixer for the mux selection.

---

pci/hda/patch_sigmatel.c +82 -1
diff -r a035d5e4801c pci/hda/patch_sigmatel.c
@@ -131,6 +131,8 @@ struct sigmatel_spec {
 	hda_nid_t *pwr_nids;
 
 	/* playback */
+	struct hda_input_mux *mono_mux;
+	unsigned int cur_mmux;
 	struct hda_multi_out multiout;
 	hda_nid_t dac_nids[5];
 
@@ -144,6 +146,7 @@ struct sigmatel_spec {
 	hda_nid_t *dmux_nids;
 	unsigned int num_dmuxes;
 	hda_nid_t dig_in_nid;
+	hda_nid_t mono_nid;
 
 	/* pin widgets */
 	hda_nid_t *pin_nids;
@@ -174,6 +177,7 @@ struct sigmatel_spec {
 	struct snd_kcontrol_new *kctl_alloc;
 	struct hda_input_mux private_dimux;
 	struct hda_input_mux private_imux;
+	struct hda_input_mux private_mono_mux;
 
 	/* virtual master */
 	unsigned int vmaster_tlv[4];
@@ -399,6 +403,34 @@ static int stac92xx_mux_enum_put(struct 
 
 	return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
 				     spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
+}
+
+static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+	return snd_hda_input_mux_info(spec->mono_mux, uinfo);
+}
+
+static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+
+	ucontrol->value.enumerated.item[0] = spec->cur_mmux;
+	return 0;
+}
+
+static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+
+	return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
+				     spec->mono_nid, &spec->cur_mmux);
 }
 
 #define stac92xx_aloopback_info snd_ctl_boolean_mono_info
@@ -603,6 +635,16 @@ static struct hda_verb stac9205_core_ini
 	{}
 };
 
+#define STAC_MONO_MUX \
+	{ \
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+		.name = "Mono Mux", \
+		.count = 1, \
+		.info = stac92xx_mono_mux_enum_info, \
+		.get = stac92xx_mono_mux_enum_get, \
+		.put = stac92xx_mono_mux_enum_put, \
+	}
+
 #define STAC_INPUT_SOURCE(cnt) \
 	{ \
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
@@ -714,6 +756,7 @@ static struct snd_kcontrol_new stac92hd7
 
 static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
 	STAC_INPUT_SOURCE(2),
+	STAC_MONO_MUX,
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
@@ -733,6 +776,7 @@ static struct snd_kcontrol_new stac92hd7
 static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
 	STAC_INPUT_SOURCE(2),
 	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
+	STAC_MONO_MUX,
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
@@ -1180,7 +1224,7 @@ static struct snd_pci_quirk stac92hd73xx
 
 static unsigned int ref92hd71bxx_pin_configs[10] = {
 	0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
-	0x0181302e, 0x01114010, 0x01a19020, 0x90a000f0,
+	0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
 	0x90a000f0, 0x01452050,
 };
 
@@ -2318,6 +2362,35 @@ static int stac92xx_auto_create_hp_ctls(
 	return 0;
 }
 
+/* labels for mono mux outputs */
+static const char *stac92xx_mono_labels[3] = {
+	"DAC0", "DAC1", "Mixer"
+};
+
+/* create mono mux for mono out on capable codecs */
+static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	struct hda_input_mux *mono_mux = &spec->private_mono_mux;
+	int i, num_cons;
+	hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
+
+	num_cons = snd_hda_get_connections(codec,
+				spec->mono_nid,
+				con_lst,
+				HDA_MAX_NUM_INPUTS);
+	if (!num_cons)
+		return -EINVAL;
+
+	for (i = 0; i < num_cons; i++) {
+		mono_mux->items[mono_mux->num_items].label =
+					stac92xx_mono_labels[i];
+		mono_mux->items[mono_mux->num_items].index = i;
+		mono_mux->num_items++;
+	}
+	return 0;
+}
+
 /* labels for dmic mux inputs */
 static const char *stac92xx_dmic_labels[5] = {
 	"Analog Inputs", "Digital Mic 1", "Digital Mic 2",
@@ -2532,6 +2605,12 @@ static int stac92xx_parse_auto_config(st
 	if (err < 0)
 		return err;
 
+	if (spec->mono_nid > 0) {
+		err = stac92xx_auto_create_mono_output_ctls(codec);
+		if (err < 0)
+			return err;
+	}
+
 	if (spec->num_dmics > 0)
 		if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
 						&spec->autocfg)) < 0)
@@ -2552,6 +2631,7 @@ static int stac92xx_parse_auto_config(st
 	spec->input_mux = &spec->private_imux;
 	if (!spec->dinput_mux)
 		spec->dinput_mux = &spec->private_dimux;
+	spec->mono_mux = &spec->private_mono_mux;
 
 	return 1;
 }
@@ -3237,6 +3317,7 @@ again:
 
 	spec->gpio_mask = spec->gpio_data = 0x00000001; /* GPIO0 High = EAPD */
 
+	spec->mono_nid = 0x15;
 	spec->mux_nids = stac92hd71bxx_mux_nids;
 	spec->adc_nids = stac92hd71bxx_adc_nids;
 	spec->dmic_nids = stac92hd71bxx_dmic_nids;
#1 lore raw

At Mon, 21 Jan 2008 12:12:38 -0500,

Quoted 7 lines · Matthew Ranostay
pci/hda/patch_sigmatel.c +2 -0
@@ -2318,6 +2362,35 @@ static int stac92xx_auto_create_hp_ctls(
 	return 0;
 }
 
+/* labels for mono mux outputs */
+static const char *stac92xx_mono_labels[3] = {

pci/hda/patch_sigmatel.c static int stac92xx_auto_create_hp_ctls( · line 2376

Quoted 10 lines
pci/hda/patch_sigmatel.c +10 -0
+	"DAC0", "DAC1", "Mixer"
+};
+
+/* create mono mux for mono out on capable codecs */
+static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	struct hda_input_mux *mono_mux = &spec->private_mono_mux;
+	int i, num_cons;
+	hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];

Make this con_lst[ARRAY_SIZE(stac92xx_mono_labsl)] and

pci/hda/patch_sigmatel.c static int stac92xx_auto_create_hp_ctls( · line 2381

Quoted 5 lines
pci/hda/patch_sigmatel.c +5 -0
+
+	num_cons = snd_hda_get_connections(codec,
+				spec->mono_nid,
+				con_lst,
+				HDA_MAX_NUM_INPUTS);

Pass ARRAY_SIZE(con_lst) here. So that it won't be over the size of the label array.

thanks,

Takashi

#2 lore raw
Quoted 6 lines · Takashi Iwai

At Mon, 21 Jan 2008 12:12:38 -0500,

Quoted 4 lines · Matthew Ranostay
(quoted diff) +0 -0
@@ -2318,6 +2362,35 @@ static int stac92xx_auto_create_hp_ctls(
 	return 0;
 }
 
Quoted 14 lines

Review static int stac92xx_auto_create_hp_ctls( · line 2376

Quoted 12 lines
(quoted diff) +12 -0
+/* labels for mono mux outputs */
+static const char *stac92xx_mono_labels[3] = {
+	"DAC0", "DAC1", "Mixer"
+};
+
+/* create mono mux for mono out on capable codecs */
+static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	struct hda_input_mux *mono_mux = &spec->private_mono_mux;
+	int i, num_cons;
+	hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];

Make this con_lst[ARRAY_SIZE(stac92xx_mono_labsl)] and

Done.

Quoted 10 lines

Review static int stac92xx_auto_create_hp_ctls( · line 2381

Quoted 6 lines
(quoted diff) +5 -0
+
+	num_cons = snd_hda_get_connections(codec,
+				spec->mono_nid,
+				con_lst,
+				HDA_MAX_NUM_INPUTS);

Pass ARRAY_SIZE(con_lst) here. So that it won't be over the size of the label array.

Done. Maybe someday I'll remember of the 'ARRAY_SIZE' function without being reminded :)

Quoted 5 lines

thanks,

Takashi

Add support for the mono mux on several 92HD7xxx codecs. Creates a dynamic mixer for the mux selection.

---

pci/hda/patch_sigmatel.c +82 -1
diff -r a035d5e4801c pci/hda/patch_sigmatel.c
@@ -131,6 +131,8 @@ struct sigmatel_spec {
 	hda_nid_t *pwr_nids;
 
 	/* playback */
+	struct hda_input_mux *mono_mux;
+	unsigned int cur_mmux;
 	struct hda_multi_out multiout;
 	hda_nid_t dac_nids[5];
 
@@ -144,6 +146,7 @@ struct sigmatel_spec {
 	hda_nid_t *dmux_nids;
 	unsigned int num_dmuxes;
 	hda_nid_t dig_in_nid;
+	hda_nid_t mono_nid;
 
 	/* pin widgets */
 	hda_nid_t *pin_nids;
@@ -174,6 +177,7 @@ struct sigmatel_spec {
 	struct snd_kcontrol_new *kctl_alloc;
 	struct hda_input_mux private_dimux;
 	struct hda_input_mux private_imux;
+	struct hda_input_mux private_mono_mux;
 
 	/* virtual master */
 	unsigned int vmaster_tlv[4];
@@ -399,6 +403,34 @@ static int stac92xx_mux_enum_put(struct 
 
 	return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
 				     spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
+}
+
+static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+	return snd_hda_input_mux_info(spec->mono_mux, uinfo);
+}
+
+static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+
+	ucontrol->value.enumerated.item[0] = spec->cur_mmux;
+	return 0;
+}
+
+static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+
+	return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
+				     spec->mono_nid, &spec->cur_mmux);
 }
 
 #define stac92xx_aloopback_info snd_ctl_boolean_mono_info
@@ -603,6 +635,16 @@ static struct hda_verb stac9205_core_ini
 	{}
 };
 
+#define STAC_MONO_MUX \
+	{ \
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+		.name = "Mono Mux", \
+		.count = 1, \
+		.info = stac92xx_mono_mux_enum_info, \
+		.get = stac92xx_mono_mux_enum_get, \
+		.put = stac92xx_mono_mux_enum_put, \
+	}
+
 #define STAC_INPUT_SOURCE(cnt) \
 	{ \
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
@@ -714,6 +756,7 @@ static struct snd_kcontrol_new stac92hd7
 
 static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
 	STAC_INPUT_SOURCE(2),
+	STAC_MONO_MUX,
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
@@ -733,6 +776,7 @@ static struct snd_kcontrol_new stac92hd7
 static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
 	STAC_INPUT_SOURCE(2),
 	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
+	STAC_MONO_MUX,
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
@@ -1180,7 +1224,7 @@ static struct snd_pci_quirk stac92hd73xx
 
 static unsigned int ref92hd71bxx_pin_configs[10] = {
 	0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
-	0x0181302e, 0x01114010, 0x01a19020, 0x90a000f0,
+	0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
 	0x90a000f0, 0x01452050,
 };
 
@@ -2318,6 +2362,35 @@ static int stac92xx_auto_create_hp_ctls(
 	return 0;
 }
 
+/* labels for mono mux outputs */
+static const char *stac92xx_mono_labels[3] = {
+	"DAC0", "DAC1", "Mixer"
+};
+
+/* create mono mux for mono out on capable codecs */
+static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	struct hda_input_mux *mono_mux = &spec->private_mono_mux;
+	int i, num_cons;
+	hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
+
+	num_cons = snd_hda_get_connections(codec,
+				spec->mono_nid,
+				con_lst,
+				HDA_MAX_NUM_INPUTS);
+	if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
+		return -EINVAL;
+
+	for (i = 0; i < num_cons; i++) {
+		mono_mux->items[mono_mux->num_items].label =
+					stac92xx_mono_labels[i];
+		mono_mux->items[mono_mux->num_items].index = i;
+		mono_mux->num_items++;
+	}
+	return 0;
+}
+
 /* labels for dmic mux inputs */
 static const char *stac92xx_dmic_labels[5] = {
 	"Analog Inputs", "Digital Mic 1", "Digital Mic 2",
@@ -2532,6 +2605,12 @@ static int stac92xx_parse_auto_config(st
 	if (err < 0)
 		return err;
 
+	if (spec->mono_nid > 0) {
+		err = stac92xx_auto_create_mono_output_ctls(codec);
+		if (err < 0)
+			return err;
+	}
+
 	if (spec->num_dmics > 0)
 		if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
 						&spec->autocfg)) < 0)
@@ -2552,6 +2631,7 @@ static int stac92xx_parse_auto_config(st
 	spec->input_mux = &spec->private_imux;
 	if (!spec->dinput_mux)
 		spec->dinput_mux = &spec->private_dimux;
+	spec->mono_mux = &spec->private_mono_mux;
 
 	return 1;
 }
@@ -3237,6 +3317,7 @@ again:
 
 	spec->gpio_mask = spec->gpio_data = 0x00000001; /* GPIO0 High = EAPD */
 
+	spec->mono_nid = 0x15;
 	spec->mux_nids = stac92hd71bxx_mux_nids;
 	spec->adc_nids = stac92hd71bxx_adc_nids;
 	spec->dmic_nids = stac92hd71bxx_dmic_nids;
Applied
#3 lore raw

At Mon, 21 Jan 2008 13:50:45 -0500,

Quoted 38 lines · Matthew Ranostay
Quoted 6 lines · Takashi Iwai

At Mon, 21 Jan 2008 12:12:38 -0500,

Quoted 4 lines · Matthew Ranostay
pci/hda/patch_sigmatel.c +0 -0
@@ -2318,6 +2362,35 @@ static int stac92xx_auto_create_hp_ctls(
 	return 0;
 }
 
Quoted 14 lines

pci/hda/patch_sigmatel.c static int stac92xx_auto_create_hp_ctls(

Quoted 12 lines
pci/hda/patch_sigmatel.c +12 -0
+/* labels for mono mux outputs */
+static const char *stac92xx_mono_labels[3] = {
+	"DAC0", "DAC1", "Mixer"
+};
+
+/* create mono mux for mono out on capable codecs */
+static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	struct hda_input_mux *mono_mux = &spec->private_mono_mux;
+	int i, num_cons;
+	hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];

Make this con_lst[ARRAY_SIZE(stac92xx_mono_labsl)] and

Done.

Quoted 10 lines

pci/hda/patch_sigmatel.c static int stac92xx_auto_create_hp_ctls( · line 2381

Quoted 6 lines
pci/hda/patch_sigmatel.c +5 -0
+
+	num_cons = snd_hda_get_connections(codec,
+				spec->mono_nid,
+				con_lst,
+				HDA_MAX_NUM_INPUTS);

Pass ARRAY_SIZE(con_lst) here. So that it won't be over the size of the label array.

Done. Maybe someday I'll remember of the 'ARRAY_SIZE' function without being reminded :)

Quoted 3 lines

thanks,

Quoted 7 lines
Quoted 2 lines

Takashi

Add support for the mono mux on several 92HD7xxx codecs. Creates a dynamic mixer for the mux selection.

Applied to HG tree now. Thanks.

Takashi

#4 lore raw
In reply to Matthew Ranostay

Added check to be sure that input connections does not equal more than 3(or an overflow will occur), may be possible for future codecs to have more than 3 mono mux connections.
---

Add support for the mono mux on several 92HD7xxx codecs. Creates a dynamic mixer for the mux selection.

---

pci/hda/patch_sigmatel.c +82 -1
diff -r a035d5e4801c pci/hda/patch_sigmatel.c
@@ -131,6 +131,8 @@ struct sigmatel_spec {
 	hda_nid_t *pwr_nids;
 
 	/* playback */
+	struct hda_input_mux *mono_mux;
+	unsigned int cur_mmux;
 	struct hda_multi_out multiout;
 	hda_nid_t dac_nids[5];
 
@@ -144,6 +146,7 @@ struct sigmatel_spec {
 	hda_nid_t *dmux_nids;
 	unsigned int num_dmuxes;
 	hda_nid_t dig_in_nid;
+	hda_nid_t mono_nid;
 
 	/* pin widgets */
 	hda_nid_t *pin_nids;
@@ -174,6 +177,7 @@ struct sigmatel_spec {
 	struct snd_kcontrol_new *kctl_alloc;
 	struct hda_input_mux private_dimux;
 	struct hda_input_mux private_imux;
+	struct hda_input_mux private_mono_mux;
 
 	/* virtual master */
 	unsigned int vmaster_tlv[4];
@@ -399,6 +403,34 @@ static int stac92xx_mux_enum_put(struct 
 
 	return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
 				     spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
+}
+
+static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+	return snd_hda_input_mux_info(spec->mono_mux, uinfo);
+}
+
+static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+
+	ucontrol->value.enumerated.item[0] = spec->cur_mmux;
+	return 0;
+}
+
+static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+
+	return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
+				     spec->mono_nid, &spec->cur_mmux);
 }
 
 #define stac92xx_aloopback_info snd_ctl_boolean_mono_info
@@ -603,6 +635,16 @@ static struct hda_verb stac9205_core_ini
 	{}
 };
 
+#define STAC_MONO_MUX \
+	{ \
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+		.name = "Mono Mux", \
+		.count = 1, \
+		.info = stac92xx_mono_mux_enum_info, \
+		.get = stac92xx_mono_mux_enum_get, \
+		.put = stac92xx_mono_mux_enum_put, \
+	}
+
 #define STAC_INPUT_SOURCE(cnt) \
 	{ \
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
@@ -714,6 +756,7 @@ static struct snd_kcontrol_new stac92hd7
 
 static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
 	STAC_INPUT_SOURCE(2),
+	STAC_MONO_MUX,
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
@@ -733,6 +776,7 @@ static struct snd_kcontrol_new stac92hd7
 static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
 	STAC_INPUT_SOURCE(2),
 	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
+	STAC_MONO_MUX,
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
@@ -1180,7 +1224,7 @@ static struct snd_pci_quirk stac92hd73xx
 
 static unsigned int ref92hd71bxx_pin_configs[10] = {
 	0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
-	0x0181302e, 0x01114010, 0x01a19020, 0x90a000f0,
+	0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
 	0x90a000f0, 0x01452050,
 };
 
@@ -2318,6 +2362,35 @@ static int stac92xx_auto_create_hp_ctls(
 	return 0;
 }
 
+/* labels for mono mux outputs */
+static const char *stac92xx_mono_labels[3] = {
+	"DAC0", "DAC1", "Mixer"
+};
+
+/* create mono mux for mono out on capable codecs */
+static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	struct hda_input_mux *mono_mux = &spec->private_mono_mux;
+	int i, num_cons;
+	hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
+
+	num_cons = snd_hda_get_connections(codec,
+				spec->mono_nid,
+				con_lst,
+				HDA_MAX_NUM_INPUTS);
+	if (!num_cons || num_cons > 3)
+		return -EINVAL;
+
+	for (i = 0; i < num_cons; i++) {
+		mono_mux->items[mono_mux->num_items].label =
+					stac92xx_mono_labels[i];
+		mono_mux->items[mono_mux->num_items].index = i;
+		mono_mux->num_items++;
+	}
+	return 0;
+}
+
 /* labels for dmic mux inputs */
 static const char *stac92xx_dmic_labels[5] = {
 	"Analog Inputs", "Digital Mic 1", "Digital Mic 2",
@@ -2532,6 +2605,12 @@ static int stac92xx_parse_auto_config(st
 	if (err < 0)
 		return err;
 
+	if (spec->mono_nid > 0) {
+		err = stac92xx_auto_create_mono_output_ctls(codec);
+		if (err < 0)
+			return err;
+	}
+
 	if (spec->num_dmics > 0)
 		if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
 						&spec->autocfg)) < 0)
@@ -2552,6 +2631,7 @@ static int stac92xx_parse_auto_config(st
 	spec->input_mux = &spec->private_imux;
 	if (!spec->dinput_mux)
 		spec->dinput_mux = &spec->private_dimux;
+	spec->mono_mux = &spec->private_mono_mux;
 
 	return 1;
 }
@@ -3237,6 +3317,7 @@ again:
 
 	spec->gpio_mask = spec->gpio_data = 0x00000001; /* GPIO0 High = EAPD */
 
+	spec->mono_nid = 0x15;
 	spec->mux_nids = stac92hd71bxx_mux_nids;
 	spec->adc_nids = stac92hd71bxx_adc_nids;
 	spec->dmic_nids = stac92hd71bxx_dmic_nids;