Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7fa9742b authored by Takashi Iwai's avatar Takashi Iwai
Browse files

Merge branch 'fix/hda' into for-linus

parents a1cb9cd6 7085ec12
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -209,6 +209,7 @@ AD1884A / AD1883 / AD1984A / AD1984B
  laptop	laptop with HP jack sensing
  mobile	mobile devices with HP jack sensing
  thinkpad	Lenovo Thinkpad X300
  touchsmart	HP Touchsmart

AD1884
======
+1 −0
Original line number Diff line number Diff line
@@ -2303,6 +2303,7 @@ static void __devinit check_probe_mask(struct azx *chip, int dev)
 * white-list for enable_msi
 */
static struct snd_pci_quirk msi_white_list[] __devinitdata = {
	SND_PCI_QUIRK(0x103c, 0x30f7, "HP Pavilion dv4t-1300", 1),
	SND_PCI_QUIRK(0x103c, 0x3607, "HP Compa CQ40", 1),
	{}
};
+139 −0
Original line number Diff line number Diff line
@@ -4031,6 +4031,127 @@ static int ad1984a_thinkpad_init(struct hda_codec *codec)
	return 0;
}

/*
 * HP Touchsmart
 * port-A (0x11)      - front hp-out
 * port-B (0x14)      - unused
 * port-C (0x15)      - unused
 * port-D (0x12)      - rear line out
 * port-E (0x1c)      - front mic-in
 * port-F (0x16)      - Internal speakers
 * digital-mic (0x17) - Internal mic
 */

static struct hda_verb ad1984a_touchsmart_verbs[] = {
	/* DACs; unmute as default */
	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
	/* Port-A (HP) mixer - route only from analog mixer */
	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
	/* Port-A pin */
	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
	/* Port-A (HP) pin - always unmuted */
	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
	/* Port-E (int speaker) mixer - route only from analog mixer */
	{0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03},
	/* Port-E pin */
	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
	/* Port-F (int speaker) mixer - route only from analog mixer */
	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
	/* Port-F pin */
	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
	/* Analog mixer; mute as default */
	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
	/* Analog Mix output amp */
	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
	/* capture sources */
	/* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
	/* unsolicited event for pin-sense */
	{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
	{0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
	/* allow to touch GPIO1 (for mute control) */
	{0x01, AC_VERB_SET_GPIO_MASK, 0x02},
	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
	{0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
	/* internal mic - dmic */
	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
	/* set magic COEFs for dmic */
	{0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
	{0x01, AC_VERB_SET_PROC_COEF, 0x08},
	{ } /* end */
};

static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
/*	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
	{
		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
		.name = "Master Playback Switch",
		.info = snd_hda_mixer_amp_switch_info,
		.get = snd_hda_mixer_amp_switch_get,
		.put = ad1884a_mobile_master_sw_put,
		.private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
	},
	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
	HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
	HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
	HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
	{ } /* end */
};

/* switch to external mic if plugged */
static void ad1984a_touchsmart_automic(struct hda_codec *codec)
{
	if (snd_hda_codec_read(codec, 0x1c, 0,
				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000) {
		snd_hda_codec_write(codec, 0x0c, 0,
				     AC_VERB_SET_CONNECT_SEL, 0x4);
	} else {
		snd_hda_codec_write(codec, 0x0c, 0,
				     AC_VERB_SET_CONNECT_SEL, 0x5);
	}
}


/* unsolicited event for HP jack sensing */
static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec,
	unsigned int res)
{
	switch (res >> 26) {
	case AD1884A_HP_EVENT:
		ad1884a_hp_automute(codec);
		break;
	case AD1884A_MIC_EVENT:
		ad1984a_touchsmart_automic(codec);
		break;
	}
}

/* initialize jack-sensing, too */
static int ad1984a_touchsmart_init(struct hda_codec *codec)
{
	ad198x_init(codec);
	ad1884a_hp_automute(codec);
	ad1984a_touchsmart_automic(codec);
	return 0;
}


/*
 */

@@ -4039,6 +4160,7 @@ enum {
	AD1884A_LAPTOP,
	AD1884A_MOBILE,
	AD1884A_THINKPAD,
	AD1984A_TOUCHSMART,
	AD1884A_MODELS
};

@@ -4047,6 +4169,7 @@ static const char *ad1884a_models[AD1884A_MODELS] = {
	[AD1884A_LAPTOP]	= "laptop",
	[AD1884A_MOBILE]	= "mobile",
	[AD1884A_THINKPAD]	= "thinkpad",
	[AD1984A_TOUCHSMART]	= "touchsmart",
};

static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
@@ -4059,6 +4182,7 @@ static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
	SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
	SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE),
	SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
	SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART),
	{}
};

@@ -4142,6 +4266,21 @@ static int patch_ad1884a(struct hda_codec *codec)
		codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event;
		codec->patch_ops.init = ad1984a_thinkpad_init;
		break;
	case AD1984A_TOUCHSMART:
		spec->mixers[0] = ad1984a_touchsmart_mixers;
		spec->init_verbs[0] = ad1984a_touchsmart_verbs;
		spec->multiout.dig_out_nid = 0;
		codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event;
		codec->patch_ops.init = ad1984a_touchsmart_init;
		/* set the upper-limit for mixer amp to 0dB for avoiding the
		 * possible damage by overloading
		 */
		snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
					  (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
					  (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
					  (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
					  (1 << AC_AMPCAP_MUTE_SHIFT));
		break;
	}

	return 0;
+11 −1
Original line number Diff line number Diff line
@@ -682,11 +682,13 @@ static struct hda_input_mux cxt5045_capture_source = {
};

static struct hda_input_mux cxt5045_capture_source_benq = {
	.num_items = 3,
	.num_items = 5,
	.items = {
		{ "IntMic", 0x1 },
		{ "ExtMic", 0x2 },
		{ "LineIn", 0x3 },
		{ "CD",     0x4 },
		{ "Mixer",  0x0 },
	}
};

@@ -811,11 +813,19 @@ static struct snd_kcontrol_new cxt5045_mixers[] = {
};

static struct snd_kcontrol_new cxt5045_benq_mixers[] = {
	HDA_CODEC_VOLUME("CD Capture Volume", 0x1a, 0x04, HDA_INPUT),
	HDA_CODEC_MUTE("CD Capture Switch", 0x1a, 0x04, HDA_INPUT),
	HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x4, HDA_INPUT),
	HDA_CODEC_MUTE("CD Playback Switch", 0x17, 0x4, HDA_INPUT),

	HDA_CODEC_VOLUME("Line In Capture Volume", 0x1a, 0x03, HDA_INPUT),
	HDA_CODEC_MUTE("Line In Capture Switch", 0x1a, 0x03, HDA_INPUT),
	HDA_CODEC_VOLUME("Line In Playback Volume", 0x17, 0x3, HDA_INPUT),
	HDA_CODEC_MUTE("Line In Playback Switch", 0x17, 0x3, HDA_INPUT),

	HDA_CODEC_VOLUME("Mixer Capture Volume", 0x1a, 0x0, HDA_INPUT),
	HDA_CODEC_MUTE("Mixer Capture Switch", 0x1a, 0x0, HDA_INPUT),

	{}
};

+157 −87
Original line number Diff line number Diff line
@@ -12660,7 +12660,7 @@ static struct alc_config_preset alc268_presets[] = {
		.init_hook = alc268_toshiba_automute,
	},
	[ALC268_ACER] = {
		.mixers = { alc268_acer_mixer, alc268_capture_nosrc_mixer,
		.mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
			    alc268_beep_mixer },
		.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
				alc268_acer_verbs },
@@ -16852,6 +16852,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = {
	SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
	SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
		      ALC662_3ST_6ch_DIG),
	SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB200", ALC663_ASUS_MODE4),
	SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
	SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
		      ALC662_3ST_6ch_DIG),
@@ -17145,70 +17146,145 @@ static struct alc_config_preset alc662_presets[] = {
 * BIOS auto configuration
 */
/* add playback controls from the parsed DAC table */
static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
/* convert from MIX nid to DAC */
static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
{
	if (nid == 0x0f)
		return 0x02;
	else if (nid >= 0x0c && nid <= 0x0e)
		return nid - 0x0c + 0x02;
	else
		return 0;
}
/* get MIX nid connected to the given pin targeted to DAC */
static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
				   hda_nid_t dac)
{
	hda_nid_t mix[4];
	int i, num;
	num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
	for (i = 0; i < num; i++) {
		if (alc662_mix_to_dac(mix[i]) == dac)
			return mix[i];
	}
	return 0;
}
/* look for an empty DAC slot */
static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
{
	struct alc_spec *spec = codec->spec;
	hda_nid_t srcs[5];
	int i, j, num;
	num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
	if (num < 0)
		return 0;
	for (i = 0; i < num; i++) {
		hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
		if (!nid)
			continue;
		for (j = 0; j < spec->multiout.num_dacs; j++)
			if (spec->multiout.dac_nids[j] == nid)
				break;
		if (j >= spec->multiout.num_dacs)
			return nid;
	}
	return 0;
}
/* fill in the dac_nids table from the parsed pin configuration */
static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
				     const struct auto_pin_cfg *cfg)
{
	struct alc_spec *spec = codec->spec;
	int i;
	hda_nid_t dac;
	spec->multiout.dac_nids = spec->private_dac_nids;
	for (i = 0; i < cfg->line_outs; i++) {
		dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
		if (!dac)
			continue;
		spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
	}
	return 0;
}
static int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
			      hda_nid_t nid, unsigned int chs)
{
	char name[32];
	sprintf(name, "%s Playback Volume", pfx);
	return add_control(spec, ALC_CTL_WIDGET_VOL, name,
			   HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
}
static int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
			     hda_nid_t nid, unsigned int chs)
{
	char name[32];
	sprintf(name, "%s Playback Switch", pfx);
	return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
			   HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
}
#define alc662_add_stereo_vol(spec, pfx, nid) \
	alc662_add_vol_ctl(spec, pfx, nid, 3)
#define alc662_add_stereo_sw(spec, pfx, nid) \
	alc662_add_sw_ctl(spec, pfx, nid, 3)
/* add playback controls from the parsed DAC table */
static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
					     const struct auto_pin_cfg *cfg)
{
	struct alc_spec *spec = codec->spec;
	static const char *chname[4] = {
		"Front", "Surround", NULL /*CLFE*/, "Side"
	};
	hda_nid_t nid;
	hda_nid_t nid, mix;
	int i, err;
	for (i = 0; i < cfg->line_outs; i++) {
		if (!spec->multiout.dac_nids[i])
		nid = spec->multiout.dac_nids[i];
		if (!nid)
			continue;
		mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
		if (!mix)
			continue;
		nid = alc880_idx_to_dac(i);
		if (i == 2) {
			/* Center/LFE */
			err = add_control(spec, ALC_CTL_WIDGET_VOL,
					  "Center Playback Volume",
					  HDA_COMPOSE_AMP_VAL(nid, 1, 0,
							      HDA_OUTPUT));
			err = alc662_add_vol_ctl(spec, "Center", nid, 1);
			if (err < 0)
				return err;
			err = add_control(spec, ALC_CTL_WIDGET_VOL,
					  "LFE Playback Volume",
					  HDA_COMPOSE_AMP_VAL(nid, 2, 0,
							      HDA_OUTPUT));
			err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
			if (err < 0)
				return err;
			err = add_control(spec, ALC_CTL_WIDGET_MUTE,
					  "Center Playback Switch",
					  HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
							      HDA_INPUT));
			err = alc662_add_sw_ctl(spec, "Center", mix, 1);
			if (err < 0)
				return err;
			err = add_control(spec, ALC_CTL_WIDGET_MUTE,
					  "LFE Playback Switch",
					  HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
							      HDA_INPUT));
			err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
			if (err < 0)
				return err;
		} else {
			const char *pfx;
			if (cfg->line_outs == 1 &&
			    cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
				if (!cfg->hp_pins)
				if (cfg->hp_outs)
					pfx = "Speaker";
				else
					pfx = "PCM";
			} else
				pfx = chname[i];
			sprintf(name, "%s Playback Volume", pfx);
			err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
					  HDA_COMPOSE_AMP_VAL(nid, 3, 0,
							      HDA_OUTPUT));
			err = alc662_add_vol_ctl(spec, pfx, nid, 3);
			if (err < 0)
				return err;
			if (cfg->line_outs == 1 &&
			    cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
				pfx = "Speaker";
			sprintf(name, "%s Playback Switch", pfx);
			err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
				HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
						    3, 0, HDA_INPUT));
			err = alc662_add_sw_ctl(spec, pfx, mix, 3);
			if (err < 0)
				return err;
		}
@@ -17217,54 +17293,38 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
}
/* add playback controls for speaker and HP outputs */
static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
/* return DAC nid if any new DAC is assigned */
static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
					const char *pfx)
{
	hda_nid_t nid;
	struct alc_spec *spec = codec->spec;
	hda_nid_t nid, mix;
	int err;
	char name[32];
	if (!pin)
		return 0;
	if (pin == 0x17) {
		/* ALC663 has a mono output pin on 0x17 */
	nid = alc662_look_for_dac(codec, pin);
	if (!nid) {
		char name[32];
		/* the corresponding DAC is already occupied */
		if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
			return 0; /* no way */
		/* create a switch only */
		sprintf(name, "%s Playback Switch", pfx);
		err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
				  HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT));
		return err;
		return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
				   HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
	}
	if (alc880_is_fixed_pin(pin)) {
		nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
		/* printk(KERN_DEBUG "DAC nid=%x\n",nid); */
		/* specify the DAC as the extra output */
		if (!spec->multiout.hp_nid)
			spec->multiout.hp_nid = nid;
		else
			spec->multiout.extra_out_nid[0] = nid;
		/* control HP volume/switch on the output mixer amp */
		nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
		sprintf(name, "%s Playback Volume", pfx);
		err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
				  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
		if (err < 0)
			return err;
		sprintf(name, "%s Playback Switch", pfx);
		err = add_control(spec, ALC_CTL_BIND_MUTE, name,
				  HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
	mix = alc662_dac_to_mix(codec, pin, nid);
	if (!mix)
		return 0;
	err = alc662_add_vol_ctl(spec, pfx, nid, 3);
	if (err < 0)
		return err;
	} else if (alc880_is_multi_pin(pin)) {
		/* set manual connection */
		/* we have only a switch on HP-out PIN */
		sprintf(name, "%s Playback Switch", pfx);
		err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
				  HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
	err = alc662_add_sw_ctl(spec, pfx, mix, 3);
	if (err < 0)
		return err;
	}
	return 0;
	return nid;
}
/* create playback/capture controls for input pins */
@@ -17273,30 +17333,35 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
					      hda_nid_t nid, int pin_type,
					      int dac_idx)
					      hda_nid_t dac)
{
	int i, num;
	hda_nid_t srcs[4];
	alc_set_pin_output(codec, nid, pin_type);
	/* need the manual connection? */
	if (alc880_is_multi_pin(nid)) {
		struct alc_spec *spec = codec->spec;
		int idx = alc880_multi_pin_idx(nid);
		snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
				    AC_VERB_SET_CONNECT_SEL,
				    alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
	num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
	if (num <= 1)
		return;
	for (i = 0; i < num; i++) {
		if (alc662_mix_to_dac(srcs[i]) != dac)
			continue;
		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
		return;
	}
}
static void alc662_auto_init_multi_out(struct hda_codec *codec)
{
	struct alc_spec *spec = codec->spec;
	int pin_type = get_pin_type(spec->autocfg.line_out_type);
	int i;
	for (i = 0; i <= HDA_SIDE; i++) {
		hda_nid_t nid = spec->autocfg.line_out_pins[i];
		int pin_type = get_pin_type(spec->autocfg.line_out_type);
		if (nid)
			alc662_auto_set_output_and_unmute(codec, nid, pin_type,
							  i);
					spec->multiout.dac_nids[i]);
	}
}
@@ -17306,12 +17371,13 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec)
	hda_nid_t pin;
	pin = spec->autocfg.hp_pins[0];
	if (pin) /* connect to front */
		/* use dac 0 */
		alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
	if (pin)
		alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
						  spec->multiout.hp_nid);
	pin = spec->autocfg.speaker_pins[0];
	if (pin)
		alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
		alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
					spec->multiout.extra_out_nid[0]);
}
#define ALC662_PIN_CD_NID		ALC880_PIN_CD_NID
@@ -17349,21 +17415,25 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
	if (!spec->autocfg.line_outs)
		return 0; /* can't find valid BIOS pin config */
	err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
	err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
	if (err < 0)
		return err;
	err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
	err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
	if (err < 0)
		return err;
	err = alc662_auto_create_extra_out(spec,
	err = alc662_auto_create_extra_out(codec,
					   spec->autocfg.speaker_pins[0],
					   "Speaker");
	if (err < 0)
		return err;
	err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
	if (err)
		spec->multiout.extra_out_nid[0] = err;
	err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
					   "Headphone");
	if (err < 0)
		return err;
	if (err)
		spec->multiout.hp_nid = err;
	err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
	if (err < 0)
		return err;
Loading