xref: /openbmc/linux/sound/pci/hda/patch_via.c (revision 24088a58d694ca5acc31ba67f966f60385789235)
1c577b8a1SJoseph Chan /*
2c577b8a1SJoseph Chan  * Universal Interface for Intel High Definition Audio Codec
3c577b8a1SJoseph Chan  *
48e86597fSLydia Wang  * HD audio interface patch for VIA VT17xx/VT18xx/VT20xx codec
5c577b8a1SJoseph Chan  *
68e86597fSLydia Wang  *  (C) 2006-2009 VIA Technology, Inc.
78e86597fSLydia Wang  *  (C) 2006-2008 Takashi Iwai <tiwai@suse.de>
8c577b8a1SJoseph Chan  *
9c577b8a1SJoseph Chan  *  This driver is free software; you can redistribute it and/or modify
10c577b8a1SJoseph Chan  *  it under the terms of the GNU General Public License as published by
11c577b8a1SJoseph Chan  *  the Free Software Foundation; either version 2 of the License, or
12c577b8a1SJoseph Chan  *  (at your option) any later version.
13c577b8a1SJoseph Chan  *
14c577b8a1SJoseph Chan  *  This driver is distributed in the hope that it will be useful,
15c577b8a1SJoseph Chan  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16c577b8a1SJoseph Chan  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17c577b8a1SJoseph Chan  *  GNU General Public License for more details.
18c577b8a1SJoseph Chan  *
19c577b8a1SJoseph Chan  *  You should have received a copy of the GNU General Public License
20c577b8a1SJoseph Chan  *  along with this program; if not, write to the Free Software
21c577b8a1SJoseph Chan  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
22c577b8a1SJoseph Chan  */
23c577b8a1SJoseph Chan 
24c577b8a1SJoseph Chan /* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */
25c577b8a1SJoseph Chan /*									     */
26c577b8a1SJoseph Chan /* 2006-03-03  Lydia Wang  Create the basic patch to support VT1708 codec    */
27c577b8a1SJoseph Chan /* 2006-03-14  Lydia Wang  Modify hard code for some pin widget nid	     */
28c577b8a1SJoseph Chan /* 2006-08-02  Lydia Wang  Add support to VT1709 codec			     */
29c577b8a1SJoseph Chan /* 2006-09-08  Lydia Wang  Fix internal loopback recording source select bug */
30f7278fd0SJosepch Chan /* 2007-09-12  Lydia Wang  Add EAPD enable during driver initialization	     */
31f7278fd0SJosepch Chan /* 2007-09-17  Lydia Wang  Add VT1708B codec support			    */
3276d9b0ddSHarald Welte /* 2007-11-14  Lydia Wang  Add VT1708A codec HP and CD pin connect config    */
33fb4cb772SHarald Welte /* 2008-02-03  Lydia Wang  Fix Rear channels and Back channels inverse issue */
34d949cac1SHarald Welte /* 2008-03-06  Lydia Wang  Add VT1702 codec and VT1708S codec support	     */
3569e52a80SHarald Welte /* 2008-04-09  Lydia Wang  Add mute front speaker when HP plugin	     */
360aa62aefSHarald Welte /* 2008-04-09  Lydia Wang  Add Independent HP feature			     */
3798aa34c0SHarald Welte /* 2008-05-28  Lydia Wang  Add second S/PDIF Out support for VT1702	     */
38d7426329SHarald Welte /* 2008-09-15  Logan Li	   Add VT1708S Mic Boost workaround/backdoor	     */
398e86597fSLydia Wang /* 2009-02-16  Logan Li	   Add support for VT1718S			     */
408e86597fSLydia Wang /* 2009-03-13  Logan Li	   Add support for VT1716S			     */
418e86597fSLydia Wang /* 2009-04-14  Lydai Wang  Add support for VT1828S and VT2020		     */
428e86597fSLydia Wang /* 2009-07-08  Lydia Wang  Add support for VT2002P			     */
438e86597fSLydia Wang /* 2009-07-21  Lydia Wang  Add support for VT1812			     */
4436dd5c4aSLydia Wang /* 2009-09-19  Lydia Wang  Add support for VT1818S			     */
45c577b8a1SJoseph Chan /*									     */
46c577b8a1SJoseph Chan /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
47c577b8a1SJoseph Chan 
48c577b8a1SJoseph Chan 
49c577b8a1SJoseph Chan #include <linux/init.h>
50c577b8a1SJoseph Chan #include <linux/delay.h>
51c577b8a1SJoseph Chan #include <linux/slab.h>
52c577b8a1SJoseph Chan #include <sound/core.h>
530aa62aefSHarald Welte #include <sound/asoundef.h>
54c577b8a1SJoseph Chan #include "hda_codec.h"
55c577b8a1SJoseph Chan #include "hda_local.h"
56c577b8a1SJoseph Chan 
575b0cb1d8SJaroslav Kysela #define NID_MAPPING		(-1)
585b0cb1d8SJaroslav Kysela 
59c577b8a1SJoseph Chan /* amp values */
60c577b8a1SJoseph Chan #define AMP_VAL_IDX_SHIFT	19
61c577b8a1SJoseph Chan #define AMP_VAL_IDX_MASK	(0x0f<<19)
62c577b8a1SJoseph Chan 
63c577b8a1SJoseph Chan /* Pin Widget NID */
64c577b8a1SJoseph Chan #define VT1708_HP_NID		0x13
65c577b8a1SJoseph Chan #define VT1708_DIGOUT_NID	0x14
66c577b8a1SJoseph Chan #define VT1708_DIGIN_NID	0x16
67f7278fd0SJosepch Chan #define VT1708_DIGIN_PIN	0x26
6876d9b0ddSHarald Welte #define VT1708_HP_PIN_NID	0x20
6976d9b0ddSHarald Welte #define VT1708_CD_PIN_NID	0x24
70c577b8a1SJoseph Chan 
71c577b8a1SJoseph Chan #define VT1709_HP_DAC_NID	0x28
72c577b8a1SJoseph Chan #define VT1709_DIGOUT_NID	0x13
73c577b8a1SJoseph Chan #define VT1709_DIGIN_NID	0x17
74f7278fd0SJosepch Chan #define VT1709_DIGIN_PIN	0x25
75f7278fd0SJosepch Chan 
76f7278fd0SJosepch Chan #define VT1708B_HP_NID		0x25
77f7278fd0SJosepch Chan #define VT1708B_DIGOUT_NID	0x12
78f7278fd0SJosepch Chan #define VT1708B_DIGIN_NID	0x15
79f7278fd0SJosepch Chan #define VT1708B_DIGIN_PIN	0x21
80c577b8a1SJoseph Chan 
81d949cac1SHarald Welte #define VT1708S_HP_NID		0x25
82d949cac1SHarald Welte #define VT1708S_DIGOUT_NID	0x12
83d949cac1SHarald Welte 
84d949cac1SHarald Welte #define VT1702_HP_NID		0x17
85d949cac1SHarald Welte #define VT1702_DIGOUT_NID	0x11
86d949cac1SHarald Welte 
87d7426329SHarald Welte enum VIA_HDA_CODEC {
88d7426329SHarald Welte 	UNKNOWN = -1,
89d7426329SHarald Welte 	VT1708,
90d7426329SHarald Welte 	VT1709_10CH,
91d7426329SHarald Welte 	VT1709_6CH,
92d7426329SHarald Welte 	VT1708B_8CH,
93d7426329SHarald Welte 	VT1708B_4CH,
94d7426329SHarald Welte 	VT1708S,
95518bf3baSLydia Wang 	VT1708BCE,
96d7426329SHarald Welte 	VT1702,
97eb7188caSLydia Wang 	VT1718S,
98f3db423dSLydia Wang 	VT1716S,
9925eaba2fSLydia Wang 	VT2002P,
100ab6734e7SLydia Wang 	VT1812,
10111890956SLydia Wang 	VT1802,
102d7426329SHarald Welte 	CODEC_TYPES,
103d7426329SHarald Welte };
104d7426329SHarald Welte 
10511890956SLydia Wang #define VT2002P_COMPATIBLE(spec) \
10611890956SLydia Wang 	((spec)->codec_type == VT2002P ||\
10711890956SLydia Wang 	 (spec)->codec_type == VT1812 ||\
10811890956SLydia Wang 	 (spec)->codec_type == VT1802)
10911890956SLydia Wang 
1101f2e99feSLydia Wang struct via_spec {
1111f2e99feSLydia Wang 	/* codec parameterization */
11290dd48a1STakashi Iwai 	const struct snd_kcontrol_new *mixers[6];
1131f2e99feSLydia Wang 	unsigned int num_mixers;
1141f2e99feSLydia Wang 
11590dd48a1STakashi Iwai 	const struct hda_verb *init_verbs[5];
1161f2e99feSLydia Wang 	unsigned int num_iverbs;
1171f2e99feSLydia Wang 
1181f2e99feSLydia Wang 	char *stream_name_analog;
11990dd48a1STakashi Iwai 	const struct hda_pcm_stream *stream_analog_playback;
12090dd48a1STakashi Iwai 	const struct hda_pcm_stream *stream_analog_capture;
1211f2e99feSLydia Wang 
1221f2e99feSLydia Wang 	char *stream_name_digital;
12390dd48a1STakashi Iwai 	const struct hda_pcm_stream *stream_digital_playback;
12490dd48a1STakashi Iwai 	const struct hda_pcm_stream *stream_digital_capture;
1251f2e99feSLydia Wang 
1261f2e99feSLydia Wang 	/* playback */
1271f2e99feSLydia Wang 	struct hda_multi_out multiout;
1281f2e99feSLydia Wang 	hda_nid_t slave_dig_outs[2];
1291f2e99feSLydia Wang 
1301f2e99feSLydia Wang 	/* capture */
1311f2e99feSLydia Wang 	unsigned int num_adc_nids;
13290dd48a1STakashi Iwai 	const hda_nid_t *adc_nids;
1331f2e99feSLydia Wang 	hda_nid_t mux_nids[3];
1341f2e99feSLydia Wang 	hda_nid_t dig_in_nid;
1351f2e99feSLydia Wang 	hda_nid_t dig_in_pin;
1361f2e99feSLydia Wang 
1371f2e99feSLydia Wang 	/* capture source */
1381f2e99feSLydia Wang 	const struct hda_input_mux *input_mux;
1391f2e99feSLydia Wang 	unsigned int cur_mux[3];
1401f2e99feSLydia Wang 
1411f2e99feSLydia Wang 	/* PCM information */
1421f2e99feSLydia Wang 	struct hda_pcm pcm_rec[3];
1431f2e99feSLydia Wang 
1441f2e99feSLydia Wang 	/* dynamic controls, init_verbs and input_mux */
1451f2e99feSLydia Wang 	struct auto_pin_cfg autocfg;
1461f2e99feSLydia Wang 	struct snd_array kctls;
1471f2e99feSLydia Wang 	struct hda_input_mux private_imux[2];
1481f2e99feSLydia Wang 	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
1491f2e99feSLydia Wang 
1501f2e99feSLydia Wang 	/* HP mode source */
1511f2e99feSLydia Wang 	const struct hda_input_mux *hp_mux;
1521f2e99feSLydia Wang 	unsigned int hp_independent_mode;
1531f2e99feSLydia Wang 	unsigned int hp_independent_mode_index;
1541f2e99feSLydia Wang 	unsigned int smart51_enabled;
155f3db423dSLydia Wang 	unsigned int dmic_enabled;
156*24088a58STakashi Iwai 	unsigned int no_pin_power_ctl;
1571f2e99feSLydia Wang 	enum VIA_HDA_CODEC codec_type;
1581f2e99feSLydia Wang 
1591f2e99feSLydia Wang 	/* work to check hp jack state */
1601f2e99feSLydia Wang 	struct hda_codec *codec;
1611f2e99feSLydia Wang 	struct delayed_work vt1708_hp_work;
1621f2e99feSLydia Wang 	int vt1708_jack_detectect;
1631f2e99feSLydia Wang 	int vt1708_hp_present;
1643e95b9abSLydia Wang 
1653e95b9abSLydia Wang 	void (*set_widgets_power_state)(struct hda_codec *codec);
1663e95b9abSLydia Wang 
1671f2e99feSLydia Wang #ifdef CONFIG_SND_HDA_POWER_SAVE
1681f2e99feSLydia Wang 	struct hda_loopback_check loopback;
1691f2e99feSLydia Wang #endif
1701f2e99feSLydia Wang };
1711f2e99feSLydia Wang 
1720341ccd7SLydia Wang static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec);
1735b0cb1d8SJaroslav Kysela static struct via_spec * via_new_spec(struct hda_codec *codec)
1745b0cb1d8SJaroslav Kysela {
1755b0cb1d8SJaroslav Kysela 	struct via_spec *spec;
1765b0cb1d8SJaroslav Kysela 
1775b0cb1d8SJaroslav Kysela 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1785b0cb1d8SJaroslav Kysela 	if (spec == NULL)
1795b0cb1d8SJaroslav Kysela 		return NULL;
1805b0cb1d8SJaroslav Kysela 
1815b0cb1d8SJaroslav Kysela 	codec->spec = spec;
1825b0cb1d8SJaroslav Kysela 	spec->codec = codec;
1830341ccd7SLydia Wang 	spec->codec_type = get_codec_type(codec);
1840341ccd7SLydia Wang 	/* VT1708BCE & VT1708S are almost same */
1850341ccd7SLydia Wang 	if (spec->codec_type == VT1708BCE)
1860341ccd7SLydia Wang 		spec->codec_type = VT1708S;
1875b0cb1d8SJaroslav Kysela 	return spec;
1885b0cb1d8SJaroslav Kysela }
1895b0cb1d8SJaroslav Kysela 
190744ff5f4SLydia Wang static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
191d7426329SHarald Welte {
192744ff5f4SLydia Wang 	u32 vendor_id = codec->vendor_id;
193d7426329SHarald Welte 	u16 ven_id = vendor_id >> 16;
194d7426329SHarald Welte 	u16 dev_id = vendor_id & 0xffff;
195d7426329SHarald Welte 	enum VIA_HDA_CODEC codec_type;
196d7426329SHarald Welte 
197d7426329SHarald Welte 	/* get codec type */
198d7426329SHarald Welte 	if (ven_id != 0x1106)
199d7426329SHarald Welte 		codec_type = UNKNOWN;
200d7426329SHarald Welte 	else if (dev_id >= 0x1708 && dev_id <= 0x170b)
201d7426329SHarald Welte 		codec_type = VT1708;
202d7426329SHarald Welte 	else if (dev_id >= 0xe710 && dev_id <= 0xe713)
203d7426329SHarald Welte 		codec_type = VT1709_10CH;
204d7426329SHarald Welte 	else if (dev_id >= 0xe714 && dev_id <= 0xe717)
205d7426329SHarald Welte 		codec_type = VT1709_6CH;
206518bf3baSLydia Wang 	else if (dev_id >= 0xe720 && dev_id <= 0xe723) {
207d7426329SHarald Welte 		codec_type = VT1708B_8CH;
208518bf3baSLydia Wang 		if (snd_hda_param_read(codec, 0x16, AC_PAR_CONNLIST_LEN) == 0x7)
209518bf3baSLydia Wang 			codec_type = VT1708BCE;
210518bf3baSLydia Wang 	} else if (dev_id >= 0xe724 && dev_id <= 0xe727)
211d7426329SHarald Welte 		codec_type = VT1708B_4CH;
212d7426329SHarald Welte 	else if ((dev_id & 0xfff) == 0x397
213d7426329SHarald Welte 		 && (dev_id >> 12) < 8)
214d7426329SHarald Welte 		codec_type = VT1708S;
215d7426329SHarald Welte 	else if ((dev_id & 0xfff) == 0x398
216d7426329SHarald Welte 		 && (dev_id >> 12) < 8)
217d7426329SHarald Welte 		codec_type = VT1702;
218eb7188caSLydia Wang 	else if ((dev_id & 0xfff) == 0x428
219eb7188caSLydia Wang 		 && (dev_id >> 12) < 8)
220eb7188caSLydia Wang 		codec_type = VT1718S;
221f3db423dSLydia Wang 	else if (dev_id == 0x0433 || dev_id == 0xa721)
222f3db423dSLydia Wang 		codec_type = VT1716S;
223bb3c6bfcSLydia Wang 	else if (dev_id == 0x0441 || dev_id == 0x4441)
224bb3c6bfcSLydia Wang 		codec_type = VT1718S;
22525eaba2fSLydia Wang 	else if (dev_id == 0x0438 || dev_id == 0x4438)
22625eaba2fSLydia Wang 		codec_type = VT2002P;
227ab6734e7SLydia Wang 	else if (dev_id == 0x0448)
228ab6734e7SLydia Wang 		codec_type = VT1812;
22936dd5c4aSLydia Wang 	else if (dev_id == 0x0440)
23036dd5c4aSLydia Wang 		codec_type = VT1708S;
23111890956SLydia Wang 	else if ((dev_id & 0xfff) == 0x446)
23211890956SLydia Wang 		codec_type = VT1802;
233d7426329SHarald Welte 	else
234d7426329SHarald Welte 		codec_type = UNKNOWN;
235d7426329SHarald Welte 	return codec_type;
236d7426329SHarald Welte };
237d7426329SHarald Welte 
238ec7e7e42SLydia Wang #define VIA_JACK_EVENT		0x20
23969e52a80SHarald Welte #define VIA_HP_EVENT		0x01
24069e52a80SHarald Welte #define VIA_GPIO_EVENT		0x02
241ec7e7e42SLydia Wang #define VIA_MONO_EVENT		0x03
242ec7e7e42SLydia Wang #define VIA_SPEAKER_EVENT	0x04
243ec7e7e42SLydia Wang #define VIA_BIND_HP_EVENT	0x05
24469e52a80SHarald Welte 
245c577b8a1SJoseph Chan enum {
246c577b8a1SJoseph Chan 	VIA_CTL_WIDGET_VOL,
247c577b8a1SJoseph Chan 	VIA_CTL_WIDGET_MUTE,
248f5271101SLydia Wang 	VIA_CTL_WIDGET_ANALOG_MUTE,
24925eaba2fSLydia Wang 	VIA_CTL_WIDGET_BIND_PIN_MUTE,
250c577b8a1SJoseph Chan };
251c577b8a1SJoseph Chan 
252c577b8a1SJoseph Chan enum {
253eb14a46cSHarald Welte 	AUTO_SEQ_FRONT = 0,
254c577b8a1SJoseph Chan 	AUTO_SEQ_SURROUND,
255c577b8a1SJoseph Chan 	AUTO_SEQ_CENLFE,
256c577b8a1SJoseph Chan 	AUTO_SEQ_SIDE
257c577b8a1SJoseph Chan };
258c577b8a1SJoseph Chan 
259f5271101SLydia Wang static void analog_low_current_mode(struct hda_codec *codec, int stream_idle);
2601f2e99feSLydia Wang static int is_aa_path_mute(struct hda_codec *codec);
2611f2e99feSLydia Wang 
2621f2e99feSLydia Wang static void vt1708_start_hp_work(struct via_spec *spec)
2631f2e99feSLydia Wang {
2641f2e99feSLydia Wang 	if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
2651f2e99feSLydia Wang 		return;
2661f2e99feSLydia Wang 	snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
2671f2e99feSLydia Wang 			    !spec->vt1708_jack_detectect);
2681f2e99feSLydia Wang 	if (!delayed_work_pending(&spec->vt1708_hp_work))
2691f2e99feSLydia Wang 		schedule_delayed_work(&spec->vt1708_hp_work,
2701f2e99feSLydia Wang 				      msecs_to_jiffies(100));
2711f2e99feSLydia Wang }
2721f2e99feSLydia Wang 
2731f2e99feSLydia Wang static void vt1708_stop_hp_work(struct via_spec *spec)
2741f2e99feSLydia Wang {
2751f2e99feSLydia Wang 	if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
2761f2e99feSLydia Wang 		return;
2771f2e99feSLydia Wang 	if (snd_hda_get_bool_hint(spec->codec, "analog_loopback_hp_detect") == 1
2781f2e99feSLydia Wang 	    && !is_aa_path_mute(spec->codec))
2791f2e99feSLydia Wang 		return;
2801f2e99feSLydia Wang 	snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
2811f2e99feSLydia Wang 			    !spec->vt1708_jack_detectect);
2825b84ba26STejun Heo 	cancel_delayed_work_sync(&spec->vt1708_hp_work);
2831f2e99feSLydia Wang }
284f5271101SLydia Wang 
2853e95b9abSLydia Wang static void set_widgets_power_state(struct hda_codec *codec)
2863e95b9abSLydia Wang {
2873e95b9abSLydia Wang 	struct via_spec *spec = codec->spec;
2883e95b9abSLydia Wang 	if (spec->set_widgets_power_state)
2893e95b9abSLydia Wang 		spec->set_widgets_power_state(codec);
2903e95b9abSLydia Wang }
29125eaba2fSLydia Wang 
292f5271101SLydia Wang static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
293f5271101SLydia Wang 				   struct snd_ctl_elem_value *ucontrol)
294f5271101SLydia Wang {
295f5271101SLydia Wang 	int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
296f5271101SLydia Wang 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
297f5271101SLydia Wang 
2983e95b9abSLydia Wang 	set_widgets_power_state(codec);
299f5271101SLydia Wang 	analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1);
3001f2e99feSLydia Wang 	if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) {
3011f2e99feSLydia Wang 		if (is_aa_path_mute(codec))
3021f2e99feSLydia Wang 			vt1708_start_hp_work(codec->spec);
3031f2e99feSLydia Wang 		else
3041f2e99feSLydia Wang 			vt1708_stop_hp_work(codec->spec);
3051f2e99feSLydia Wang 	}
306f5271101SLydia Wang 	return change;
307f5271101SLydia Wang }
308f5271101SLydia Wang 
309f5271101SLydia Wang /* modify .put = snd_hda_mixer_amp_switch_put */
310f5271101SLydia Wang #define ANALOG_INPUT_MUTE						\
311f5271101SLydia Wang 	{		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		\
312f5271101SLydia Wang 			.name = NULL,					\
313f5271101SLydia Wang 			.index = 0,					\
314f5271101SLydia Wang 			.info = snd_hda_mixer_amp_switch_info,		\
315f5271101SLydia Wang 			.get = snd_hda_mixer_amp_switch_get,		\
316f5271101SLydia Wang 			.put = analog_input_switch_put,			\
317f5271101SLydia Wang 			.private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
318f5271101SLydia Wang 
31925eaba2fSLydia Wang static void via_hp_bind_automute(struct hda_codec *codec);
32025eaba2fSLydia Wang 
32125eaba2fSLydia Wang static int bind_pin_switch_put(struct snd_kcontrol *kcontrol,
32225eaba2fSLydia Wang 			       struct snd_ctl_elem_value *ucontrol)
32325eaba2fSLydia Wang {
32425eaba2fSLydia Wang 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
32525eaba2fSLydia Wang 	struct via_spec *spec = codec->spec;
32625eaba2fSLydia Wang 	int i;
32725eaba2fSLydia Wang 	int change = 0;
32825eaba2fSLydia Wang 
32925eaba2fSLydia Wang 	long *valp = ucontrol->value.integer.value;
33025eaba2fSLydia Wang 	int lmute, rmute;
33125eaba2fSLydia Wang 	if (strstr(kcontrol->id.name, "Switch") == NULL) {
33225eaba2fSLydia Wang 		snd_printd("Invalid control!\n");
33325eaba2fSLydia Wang 		return change;
33425eaba2fSLydia Wang 	}
33525eaba2fSLydia Wang 	change = snd_hda_mixer_amp_switch_put(kcontrol,
33625eaba2fSLydia Wang 					      ucontrol);
33725eaba2fSLydia Wang 	/* Get mute value */
33825eaba2fSLydia Wang 	lmute = *valp ? 0 : HDA_AMP_MUTE;
33925eaba2fSLydia Wang 	valp++;
34025eaba2fSLydia Wang 	rmute = *valp ? 0 : HDA_AMP_MUTE;
34125eaba2fSLydia Wang 
34225eaba2fSLydia Wang 	/* Set hp pins */
34325eaba2fSLydia Wang 	if (!spec->hp_independent_mode) {
34425eaba2fSLydia Wang 		for (i = 0; i < spec->autocfg.hp_outs; i++) {
34525eaba2fSLydia Wang 			snd_hda_codec_amp_update(
34625eaba2fSLydia Wang 				codec, spec->autocfg.hp_pins[i],
34725eaba2fSLydia Wang 				0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
34825eaba2fSLydia Wang 				lmute);
34925eaba2fSLydia Wang 			snd_hda_codec_amp_update(
35025eaba2fSLydia Wang 				codec, spec->autocfg.hp_pins[i],
35125eaba2fSLydia Wang 				1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
35225eaba2fSLydia Wang 				rmute);
35325eaba2fSLydia Wang 		}
35425eaba2fSLydia Wang 	}
35525eaba2fSLydia Wang 
35625eaba2fSLydia Wang 	if (!lmute && !rmute) {
35725eaba2fSLydia Wang 		/* Line Outs */
35825eaba2fSLydia Wang 		for (i = 0; i < spec->autocfg.line_outs; i++)
35925eaba2fSLydia Wang 			snd_hda_codec_amp_stereo(
36025eaba2fSLydia Wang 				codec, spec->autocfg.line_out_pins[i],
36125eaba2fSLydia Wang 				HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
36225eaba2fSLydia Wang 		/* Speakers */
36325eaba2fSLydia Wang 		for (i = 0; i < spec->autocfg.speaker_outs; i++)
36425eaba2fSLydia Wang 			snd_hda_codec_amp_stereo(
36525eaba2fSLydia Wang 				codec, spec->autocfg.speaker_pins[i],
36625eaba2fSLydia Wang 				HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
36725eaba2fSLydia Wang 		/* unmute */
36825eaba2fSLydia Wang 		via_hp_bind_automute(codec);
36925eaba2fSLydia Wang 
37025eaba2fSLydia Wang 	} else {
37125eaba2fSLydia Wang 		if (lmute) {
37225eaba2fSLydia Wang 			/* Mute all left channels */
37325eaba2fSLydia Wang 			for (i = 1; i < spec->autocfg.line_outs; i++)
37425eaba2fSLydia Wang 				snd_hda_codec_amp_update(
37525eaba2fSLydia Wang 					codec,
37625eaba2fSLydia Wang 					spec->autocfg.line_out_pins[i],
37725eaba2fSLydia Wang 					0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
37825eaba2fSLydia Wang 					lmute);
37925eaba2fSLydia Wang 			for (i = 0; i < spec->autocfg.speaker_outs; i++)
38025eaba2fSLydia Wang 				snd_hda_codec_amp_update(
38125eaba2fSLydia Wang 					codec,
38225eaba2fSLydia Wang 					spec->autocfg.speaker_pins[i],
38325eaba2fSLydia Wang 					0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
38425eaba2fSLydia Wang 					lmute);
38525eaba2fSLydia Wang 		}
38625eaba2fSLydia Wang 		if (rmute) {
38725eaba2fSLydia Wang 			/* mute all right channels */
38825eaba2fSLydia Wang 			for (i = 1; i < spec->autocfg.line_outs; i++)
38925eaba2fSLydia Wang 				snd_hda_codec_amp_update(
39025eaba2fSLydia Wang 					codec,
39125eaba2fSLydia Wang 					spec->autocfg.line_out_pins[i],
39225eaba2fSLydia Wang 					1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
39325eaba2fSLydia Wang 					rmute);
39425eaba2fSLydia Wang 			for (i = 0; i < spec->autocfg.speaker_outs; i++)
39525eaba2fSLydia Wang 				snd_hda_codec_amp_update(
39625eaba2fSLydia Wang 					codec,
39725eaba2fSLydia Wang 					spec->autocfg.speaker_pins[i],
39825eaba2fSLydia Wang 					1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
39925eaba2fSLydia Wang 					rmute);
40025eaba2fSLydia Wang 		}
40125eaba2fSLydia Wang 	}
40225eaba2fSLydia Wang 	return change;
40325eaba2fSLydia Wang }
40425eaba2fSLydia Wang 
40525eaba2fSLydia Wang #define BIND_PIN_MUTE							\
40625eaba2fSLydia Wang 	{		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		\
40725eaba2fSLydia Wang 			.name = NULL,					\
40825eaba2fSLydia Wang 			.index = 0,					\
40925eaba2fSLydia Wang 			.info = snd_hda_mixer_amp_switch_info,		\
41025eaba2fSLydia Wang 			.get = snd_hda_mixer_amp_switch_get,		\
41125eaba2fSLydia Wang 			.put = bind_pin_switch_put,			\
41225eaba2fSLydia Wang 			.private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
41325eaba2fSLydia Wang 
41490dd48a1STakashi Iwai static const struct snd_kcontrol_new via_control_templates[] = {
415c577b8a1SJoseph Chan 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
416c577b8a1SJoseph Chan 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
417f5271101SLydia Wang 	ANALOG_INPUT_MUTE,
41825eaba2fSLydia Wang 	BIND_PIN_MUTE,
419c577b8a1SJoseph Chan };
420c577b8a1SJoseph Chan 
42190dd48a1STakashi Iwai static const hda_nid_t vt1708_adc_nids[2] = {
422c577b8a1SJoseph Chan 	/* ADC1-2 */
423c577b8a1SJoseph Chan 	0x15, 0x27
424c577b8a1SJoseph Chan };
425c577b8a1SJoseph Chan 
42690dd48a1STakashi Iwai static const hda_nid_t vt1709_adc_nids[3] = {
427c577b8a1SJoseph Chan 	/* ADC1-2 */
428c577b8a1SJoseph Chan 	0x14, 0x15, 0x16
429c577b8a1SJoseph Chan };
430c577b8a1SJoseph Chan 
43190dd48a1STakashi Iwai static const hda_nid_t vt1708B_adc_nids[2] = {
432f7278fd0SJosepch Chan 	/* ADC1-2 */
433f7278fd0SJosepch Chan 	0x13, 0x14
434f7278fd0SJosepch Chan };
435f7278fd0SJosepch Chan 
43690dd48a1STakashi Iwai static const hda_nid_t vt1708S_adc_nids[2] = {
437d949cac1SHarald Welte 	/* ADC1-2 */
438d949cac1SHarald Welte 	0x13, 0x14
439d949cac1SHarald Welte };
440d949cac1SHarald Welte 
44190dd48a1STakashi Iwai static const hda_nid_t vt1702_adc_nids[3] = {
442d949cac1SHarald Welte 	/* ADC1-2 */
443d949cac1SHarald Welte 	0x12, 0x20, 0x1F
444d949cac1SHarald Welte };
445d949cac1SHarald Welte 
44690dd48a1STakashi Iwai static const hda_nid_t vt1718S_adc_nids[2] = {
447eb7188caSLydia Wang 	/* ADC1-2 */
448eb7188caSLydia Wang 	0x10, 0x11
449eb7188caSLydia Wang };
450eb7188caSLydia Wang 
45190dd48a1STakashi Iwai static const hda_nid_t vt1716S_adc_nids[2] = {
452f3db423dSLydia Wang 	/* ADC1-2 */
453f3db423dSLydia Wang 	0x13, 0x14
454f3db423dSLydia Wang };
455f3db423dSLydia Wang 
45690dd48a1STakashi Iwai static const hda_nid_t vt2002P_adc_nids[2] = {
45725eaba2fSLydia Wang 	/* ADC1-2 */
45825eaba2fSLydia Wang 	0x10, 0x11
45925eaba2fSLydia Wang };
46025eaba2fSLydia Wang 
46190dd48a1STakashi Iwai static const hda_nid_t vt1812_adc_nids[2] = {
462ab6734e7SLydia Wang 	/* ADC1-2 */
463ab6734e7SLydia Wang 	0x10, 0x11
464ab6734e7SLydia Wang };
465ab6734e7SLydia Wang 
466ab6734e7SLydia Wang 
467c577b8a1SJoseph Chan /* add dynamic controls */
4687b315bb4STakashi Iwai static int __via_add_control(struct via_spec *spec, int type, const char *name,
4697b315bb4STakashi Iwai 			     int idx, unsigned long val)
470c577b8a1SJoseph Chan {
471c577b8a1SJoseph Chan 	struct snd_kcontrol_new *knew;
472c577b8a1SJoseph Chan 
473603c4019STakashi Iwai 	snd_array_init(&spec->kctls, sizeof(*knew), 32);
474603c4019STakashi Iwai 	knew = snd_array_new(&spec->kctls);
475c577b8a1SJoseph Chan 	if (!knew)
476c577b8a1SJoseph Chan 		return -ENOMEM;
47771eb7dccSLydia Wang 	*knew = via_control_templates[type];
478c577b8a1SJoseph Chan 	knew->name = kstrdup(name, GFP_KERNEL);
479c577b8a1SJoseph Chan 	if (!knew->name)
480c577b8a1SJoseph Chan 		return -ENOMEM;
4814d02d1b6SJaroslav Kysela 	if (get_amp_nid_(val))
4825e26dfd0SJaroslav Kysela 		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
483c577b8a1SJoseph Chan 	knew->private_value = val;
484c577b8a1SJoseph Chan 	return 0;
485c577b8a1SJoseph Chan }
486c577b8a1SJoseph Chan 
4877b315bb4STakashi Iwai #define via_add_control(spec, type, name, val) \
4887b315bb4STakashi Iwai 	__via_add_control(spec, type, name, 0, val)
4897b315bb4STakashi Iwai 
4905b0cb1d8SJaroslav Kysela static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec,
49190dd48a1STakashi Iwai 				const struct snd_kcontrol_new *tmpl)
4925b0cb1d8SJaroslav Kysela {
4935b0cb1d8SJaroslav Kysela 	struct snd_kcontrol_new *knew;
4945b0cb1d8SJaroslav Kysela 
4955b0cb1d8SJaroslav Kysela 	snd_array_init(&spec->kctls, sizeof(*knew), 32);
4965b0cb1d8SJaroslav Kysela 	knew = snd_array_new(&spec->kctls);
4975b0cb1d8SJaroslav Kysela 	if (!knew)
4985b0cb1d8SJaroslav Kysela 		return NULL;
4995b0cb1d8SJaroslav Kysela 	*knew = *tmpl;
5005b0cb1d8SJaroslav Kysela 	knew->name = kstrdup(tmpl->name, GFP_KERNEL);
5015b0cb1d8SJaroslav Kysela 	if (!knew->name)
5025b0cb1d8SJaroslav Kysela 		return NULL;
503b331439dSTakashi Iwai 	return knew;
5045b0cb1d8SJaroslav Kysela }
5055b0cb1d8SJaroslav Kysela 
506603c4019STakashi Iwai static void via_free_kctls(struct hda_codec *codec)
507603c4019STakashi Iwai {
508603c4019STakashi Iwai 	struct via_spec *spec = codec->spec;
509603c4019STakashi Iwai 
510603c4019STakashi Iwai 	if (spec->kctls.list) {
511603c4019STakashi Iwai 		struct snd_kcontrol_new *kctl = spec->kctls.list;
512603c4019STakashi Iwai 		int i;
513603c4019STakashi Iwai 		for (i = 0; i < spec->kctls.used; i++)
514603c4019STakashi Iwai 			kfree(kctl[i].name);
515603c4019STakashi Iwai 	}
516603c4019STakashi Iwai 	snd_array_free(&spec->kctls);
517603c4019STakashi Iwai }
518603c4019STakashi Iwai 
519c577b8a1SJoseph Chan /* create input playback/capture controls for the given pin */
5209510e8ddSLydia Wang static int via_new_analog_input(struct via_spec *spec, const char *ctlname,
5217b315bb4STakashi Iwai 				int type_idx, int idx, int mix_nid)
522c577b8a1SJoseph Chan {
523c577b8a1SJoseph Chan 	char name[32];
524c577b8a1SJoseph Chan 	int err;
525c577b8a1SJoseph Chan 
526c577b8a1SJoseph Chan 	sprintf(name, "%s Playback Volume", ctlname);
5277b315bb4STakashi Iwai 	err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, name, type_idx,
528c577b8a1SJoseph Chan 			      HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
529c577b8a1SJoseph Chan 	if (err < 0)
530c577b8a1SJoseph Chan 		return err;
531c577b8a1SJoseph Chan 	sprintf(name, "%s Playback Switch", ctlname);
5327b315bb4STakashi Iwai 	err = __via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name, type_idx,
533c577b8a1SJoseph Chan 			      HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
534c577b8a1SJoseph Chan 	if (err < 0)
535c577b8a1SJoseph Chan 		return err;
536c577b8a1SJoseph Chan 	return 0;
537c577b8a1SJoseph Chan }
538c577b8a1SJoseph Chan 
539c577b8a1SJoseph Chan static void via_auto_set_output_and_unmute(struct hda_codec *codec,
540c577b8a1SJoseph Chan 					   hda_nid_t nid, int pin_type,
541c577b8a1SJoseph Chan 					   int dac_idx)
542c577b8a1SJoseph Chan {
543c577b8a1SJoseph Chan 	/* set as output */
544c577b8a1SJoseph Chan 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
545c577b8a1SJoseph Chan 			    pin_type);
546c577b8a1SJoseph Chan 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
547c577b8a1SJoseph Chan 			    AMP_OUT_UNMUTE);
548d3a11e60STakashi Iwai 	if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
549d3a11e60STakashi Iwai 		snd_hda_codec_write(codec, nid, 0,
550d3a11e60STakashi Iwai 				    AC_VERB_SET_EAPD_BTLENABLE, 0x02);
551c577b8a1SJoseph Chan }
552c577b8a1SJoseph Chan 
553c577b8a1SJoseph Chan 
554c577b8a1SJoseph Chan static void via_auto_init_multi_out(struct hda_codec *codec)
555c577b8a1SJoseph Chan {
556c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
557c577b8a1SJoseph Chan 	int i;
558c577b8a1SJoseph Chan 
559c577b8a1SJoseph Chan 	for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
560c577b8a1SJoseph Chan 		hda_nid_t nid = spec->autocfg.line_out_pins[i];
561c577b8a1SJoseph Chan 		if (nid)
562c577b8a1SJoseph Chan 			via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
563c577b8a1SJoseph Chan 	}
564c577b8a1SJoseph Chan }
565c577b8a1SJoseph Chan 
566c577b8a1SJoseph Chan static void via_auto_init_hp_out(struct hda_codec *codec)
567c577b8a1SJoseph Chan {
568c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
569c577b8a1SJoseph Chan 	hda_nid_t pin;
57025eaba2fSLydia Wang 	int i;
571c577b8a1SJoseph Chan 
57225eaba2fSLydia Wang 	for (i = 0; i < spec->autocfg.hp_outs; i++) {
57325eaba2fSLydia Wang 		pin = spec->autocfg.hp_pins[i];
574c577b8a1SJoseph Chan 		if (pin) /* connect to front */
575c577b8a1SJoseph Chan 			via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
576c577b8a1SJoseph Chan 	}
57725eaba2fSLydia Wang }
578c577b8a1SJoseph Chan 
57932e0191dSClemens Ladisch static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
58032e0191dSClemens Ladisch 
581c577b8a1SJoseph Chan static void via_auto_init_analog_input(struct hda_codec *codec)
582c577b8a1SJoseph Chan {
583c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
5847b315bb4STakashi Iwai 	const struct auto_pin_cfg *cfg = &spec->autocfg;
58532e0191dSClemens Ladisch 	unsigned int ctl;
586c577b8a1SJoseph Chan 	int i;
587c577b8a1SJoseph Chan 
5887b315bb4STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
5897b315bb4STakashi Iwai 		hda_nid_t nid = cfg->inputs[i].pin;
59032e0191dSClemens Ladisch 		if (spec->smart51_enabled && is_smart51_pins(spec, nid))
59132e0191dSClemens Ladisch 			ctl = PIN_OUT;
59230649676SDavid Henningsson 		else if (cfg->inputs[i].type == AUTO_PIN_MIC)
59332e0191dSClemens Ladisch 			ctl = PIN_VREF50;
59432e0191dSClemens Ladisch 		else
59532e0191dSClemens Ladisch 			ctl = PIN_IN;
596c577b8a1SJoseph Chan 		snd_hda_codec_write(codec, nid, 0,
59732e0191dSClemens Ladisch 				    AC_VERB_SET_PIN_WIDGET_CONTROL, ctl);
598c577b8a1SJoseph Chan 	}
599c577b8a1SJoseph Chan }
600f5271101SLydia Wang 
601f5271101SLydia Wang static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
602f5271101SLydia Wang 				unsigned int *affected_parm)
603f5271101SLydia Wang {
604f5271101SLydia Wang 	unsigned parm;
605f5271101SLydia Wang 	unsigned def_conf = snd_hda_codec_get_pincfg(codec, nid);
606f5271101SLydia Wang 	unsigned no_presence = (def_conf & AC_DEFCFG_MISC)
607f5271101SLydia Wang 		>> AC_DEFCFG_MISC_SHIFT
608f5271101SLydia Wang 		& AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */
6091564b287SLydia Wang 	struct via_spec *spec = codec->spec;
610*24088a58STakashi Iwai 	unsigned present = 0;
611*24088a58STakashi Iwai 
612*24088a58STakashi Iwai 	no_presence |= spec->no_pin_power_ctl;
613*24088a58STakashi Iwai 	if (!no_presence)
614*24088a58STakashi Iwai 		present = snd_hda_jack_detect(codec, nid);
6151564b287SLydia Wang 	if ((spec->smart51_enabled && is_smart51_pins(spec, nid))
6161564b287SLydia Wang 	    || ((no_presence || present)
6171564b287SLydia Wang 		&& get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) {
618f5271101SLydia Wang 		*affected_parm = AC_PWRST_D0; /* if it's connected */
619f5271101SLydia Wang 		parm = AC_PWRST_D0;
620f5271101SLydia Wang 	} else
621f5271101SLydia Wang 		parm = AC_PWRST_D3;
622f5271101SLydia Wang 
623f5271101SLydia Wang 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
624f5271101SLydia Wang }
625f5271101SLydia Wang 
626*24088a58STakashi Iwai static int via_pin_power_ctl_info(struct snd_kcontrol *kcontrol,
627*24088a58STakashi Iwai 				  struct snd_ctl_elem_info *uinfo)
628*24088a58STakashi Iwai {
629*24088a58STakashi Iwai 	static const char * const texts[] = {
630*24088a58STakashi Iwai 		"Disabled", "Enabled"
631*24088a58STakashi Iwai 	};
632*24088a58STakashi Iwai 
633*24088a58STakashi Iwai 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
634*24088a58STakashi Iwai 	uinfo->count = 1;
635*24088a58STakashi Iwai 	uinfo->value.enumerated.items = 2;
636*24088a58STakashi Iwai 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
637*24088a58STakashi Iwai 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
638*24088a58STakashi Iwai 	strcpy(uinfo->value.enumerated.name,
639*24088a58STakashi Iwai 	       texts[uinfo->value.enumerated.item]);
640*24088a58STakashi Iwai 	return 0;
641*24088a58STakashi Iwai }
642*24088a58STakashi Iwai 
643*24088a58STakashi Iwai static int via_pin_power_ctl_get(struct snd_kcontrol *kcontrol,
644*24088a58STakashi Iwai 				 struct snd_ctl_elem_value *ucontrol)
645*24088a58STakashi Iwai {
646*24088a58STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
647*24088a58STakashi Iwai 	struct via_spec *spec = codec->spec;
648*24088a58STakashi Iwai 	ucontrol->value.enumerated.item[0] = !spec->no_pin_power_ctl;
649*24088a58STakashi Iwai 	return 0;
650*24088a58STakashi Iwai }
651*24088a58STakashi Iwai 
652*24088a58STakashi Iwai static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol,
653*24088a58STakashi Iwai 				 struct snd_ctl_elem_value *ucontrol)
654*24088a58STakashi Iwai {
655*24088a58STakashi Iwai 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
656*24088a58STakashi Iwai 	struct via_spec *spec = codec->spec;
657*24088a58STakashi Iwai 	unsigned int val = !ucontrol->value.enumerated.item[0];
658*24088a58STakashi Iwai 
659*24088a58STakashi Iwai 	if (val == spec->no_pin_power_ctl)
660*24088a58STakashi Iwai 		return 0;
661*24088a58STakashi Iwai 	spec->no_pin_power_ctl = val;
662*24088a58STakashi Iwai 	set_widgets_power_state(codec);
663*24088a58STakashi Iwai 	return 1;
664*24088a58STakashi Iwai }
665*24088a58STakashi Iwai 
666*24088a58STakashi Iwai static const struct snd_kcontrol_new via_pin_power_ctl_enum = {
667*24088a58STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
668*24088a58STakashi Iwai 	.name = "Dynamic Power-Control",
669*24088a58STakashi Iwai 	.info = via_pin_power_ctl_info,
670*24088a58STakashi Iwai 	.get = via_pin_power_ctl_get,
671*24088a58STakashi Iwai 	.put = via_pin_power_ctl_put,
672*24088a58STakashi Iwai };
673*24088a58STakashi Iwai 
674*24088a58STakashi Iwai 
675c577b8a1SJoseph Chan /*
676c577b8a1SJoseph Chan  * input MUX handling
677c577b8a1SJoseph Chan  */
678c577b8a1SJoseph Chan static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
679c577b8a1SJoseph Chan 			     struct snd_ctl_elem_info *uinfo)
680c577b8a1SJoseph Chan {
681c577b8a1SJoseph Chan 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
682c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
683c577b8a1SJoseph Chan 	return snd_hda_input_mux_info(spec->input_mux, uinfo);
684c577b8a1SJoseph Chan }
685c577b8a1SJoseph Chan 
686c577b8a1SJoseph Chan static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
687c577b8a1SJoseph Chan 			    struct snd_ctl_elem_value *ucontrol)
688c577b8a1SJoseph Chan {
689c577b8a1SJoseph Chan 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
690c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
691c577b8a1SJoseph Chan 	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
692c577b8a1SJoseph Chan 
693c577b8a1SJoseph Chan 	ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
694c577b8a1SJoseph Chan 	return 0;
695c577b8a1SJoseph Chan }
696c577b8a1SJoseph Chan 
697c577b8a1SJoseph Chan static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
698c577b8a1SJoseph Chan 			    struct snd_ctl_elem_value *ucontrol)
699c577b8a1SJoseph Chan {
700c577b8a1SJoseph Chan 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
701c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
702c577b8a1SJoseph Chan 	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
703bff5fbf5SLydia Wang 	int ret;
704c577b8a1SJoseph Chan 
705337b9d02STakashi Iwai 	if (!spec->mux_nids[adc_idx])
706337b9d02STakashi Iwai 		return -EINVAL;
707a80e6e3cSLydia Wang 	/* switch to D0 beofre change index */
708a80e6e3cSLydia Wang 	if (snd_hda_codec_read(codec, spec->mux_nids[adc_idx], 0,
709a80e6e3cSLydia Wang 			       AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0)
710a80e6e3cSLydia Wang 		snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0,
711a80e6e3cSLydia Wang 				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
712bff5fbf5SLydia Wang 
713bff5fbf5SLydia Wang 	ret = snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
714bff5fbf5SLydia Wang 				     spec->mux_nids[adc_idx],
715bff5fbf5SLydia Wang 				     &spec->cur_mux[adc_idx]);
716a80e6e3cSLydia Wang 	/* update jack power state */
7173e95b9abSLydia Wang 	set_widgets_power_state(codec);
718a80e6e3cSLydia Wang 
719bff5fbf5SLydia Wang 	return ret;
720c577b8a1SJoseph Chan }
721c577b8a1SJoseph Chan 
7220aa62aefSHarald Welte static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
7230aa62aefSHarald Welte 				   struct snd_ctl_elem_info *uinfo)
7240aa62aefSHarald Welte {
7250aa62aefSHarald Welte 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
7260aa62aefSHarald Welte 	struct via_spec *spec = codec->spec;
7270aa62aefSHarald Welte 	return snd_hda_input_mux_info(spec->hp_mux, uinfo);
7280aa62aefSHarald Welte }
7290aa62aefSHarald Welte 
7300aa62aefSHarald Welte static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
7310aa62aefSHarald Welte 				  struct snd_ctl_elem_value *ucontrol)
7320aa62aefSHarald Welte {
7330aa62aefSHarald Welte 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
7345b0cb1d8SJaroslav Kysela 	hda_nid_t nid = kcontrol->private_value;
735eb7188caSLydia Wang 	unsigned int pinsel;
736eb7188caSLydia Wang 
737eb7188caSLydia Wang 	/* use !! to translate conn sel 2 for VT1718S */
738eb7188caSLydia Wang 	pinsel = !!snd_hda_codec_read(codec, nid, 0,
7390aa62aefSHarald Welte 				      AC_VERB_GET_CONNECT_SEL,
7400aa62aefSHarald Welte 				      0x00);
7410aa62aefSHarald Welte 	ucontrol->value.enumerated.item[0] = pinsel;
7420aa62aefSHarald Welte 
7430aa62aefSHarald Welte 	return 0;
7440aa62aefSHarald Welte }
7450aa62aefSHarald Welte 
7460713efebSLydia Wang static void activate_ctl(struct hda_codec *codec, const char *name, int active)
7470713efebSLydia Wang {
7480713efebSLydia Wang 	struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name);
7490713efebSLydia Wang 	if (ctl) {
7500713efebSLydia Wang 		ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
7510713efebSLydia Wang 		ctl->vd[0].access |= active
7520713efebSLydia Wang 			? 0 : SNDRV_CTL_ELEM_ACCESS_INACTIVE;
7530713efebSLydia Wang 		snd_ctl_notify(codec->bus->card,
7540713efebSLydia Wang 			       SNDRV_CTL_EVENT_MASK_VALUE, &ctl->id);
7550713efebSLydia Wang 	}
7560713efebSLydia Wang }
7570713efebSLydia Wang 
7585b0cb1d8SJaroslav Kysela static hda_nid_t side_mute_channel(struct via_spec *spec)
7595b0cb1d8SJaroslav Kysela {
7605b0cb1d8SJaroslav Kysela 	switch (spec->codec_type) {
7615b0cb1d8SJaroslav Kysela 	case VT1708:		return 0x1b;
7625b0cb1d8SJaroslav Kysela 	case VT1709_10CH:	return 0x29;
7635b0cb1d8SJaroslav Kysela 	case VT1708B_8CH:	/* fall thru */
7645b0cb1d8SJaroslav Kysela 	case VT1708S:		return 0x27;
765e87885feSLydia Wang 	case VT2002P:		return 0x19;
766e87885feSLydia Wang 	case VT1802:		return 0x15;
767e87885feSLydia Wang 	case VT1812:		return 0x15;
7685b0cb1d8SJaroslav Kysela 	default:		return 0;
7695b0cb1d8SJaroslav Kysela 	}
7705b0cb1d8SJaroslav Kysela }
7715b0cb1d8SJaroslav Kysela 
772cdc1784dSLydia Wang static int update_side_mute_status(struct hda_codec *codec)
773cdc1784dSLydia Wang {
774cdc1784dSLydia Wang 	/* mute side channel */
775cdc1784dSLydia Wang 	struct via_spec *spec = codec->spec;
776e87885feSLydia Wang 	unsigned int parm;
7775b0cb1d8SJaroslav Kysela 	hda_nid_t sw3 = side_mute_channel(spec);
778cdc1784dSLydia Wang 
779e87885feSLydia Wang 	if (sw3) {
780e87885feSLydia Wang 		if (VT2002P_COMPATIBLE(spec))
781e87885feSLydia Wang 			parm = spec->hp_independent_mode ?
782e87885feSLydia Wang 			       AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1);
783e87885feSLydia Wang 		else
784e87885feSLydia Wang 			parm = spec->hp_independent_mode ?
785e87885feSLydia Wang 			       AMP_OUT_MUTE : AMP_OUT_UNMUTE;
786e87885feSLydia Wang 		snd_hda_codec_write(codec, sw3, 0,
787e87885feSLydia Wang 				    AC_VERB_SET_AMP_GAIN_MUTE, parm);
788e87885feSLydia Wang 		if (spec->codec_type == VT1812)
789e87885feSLydia Wang 			snd_hda_codec_write(codec, 0x1d, 0,
790e87885feSLydia Wang 					    AC_VERB_SET_AMP_GAIN_MUTE, parm);
791e87885feSLydia Wang 	}
792cdc1784dSLydia Wang 	return 0;
793cdc1784dSLydia Wang }
794cdc1784dSLydia Wang 
7950aa62aefSHarald Welte static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
7960aa62aefSHarald Welte 				  struct snd_ctl_elem_value *ucontrol)
7970aa62aefSHarald Welte {
7980aa62aefSHarald Welte 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
7990aa62aefSHarald Welte 	struct via_spec *spec = codec->spec;
8005b0cb1d8SJaroslav Kysela 	hda_nid_t nid = kcontrol->private_value;
8010aa62aefSHarald Welte 	unsigned int pinsel = ucontrol->value.enumerated.item[0];
802cdc1784dSLydia Wang 	/* Get Independent Mode index of headphone pin widget */
803cdc1784dSLydia Wang 	spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel
804cdc1784dSLydia Wang 		? 1 : 0;
805ce0e5a9eSLydia Wang 	if (spec->codec_type == VT1718S)
806ce0e5a9eSLydia Wang 		snd_hda_codec_write(codec, nid, 0,
807ce0e5a9eSLydia Wang 				    AC_VERB_SET_CONNECT_SEL, pinsel ? 2 : 0);
808ce0e5a9eSLydia Wang 	else
809ce0e5a9eSLydia Wang 		snd_hda_codec_write(codec, nid, 0,
810ce0e5a9eSLydia Wang 				    AC_VERB_SET_CONNECT_SEL, pinsel);
8110aa62aefSHarald Welte 
812ce0e5a9eSLydia Wang 	if (spec->codec_type == VT1812)
813ce0e5a9eSLydia Wang 		snd_hda_codec_write(codec, 0x35, 0,
814ce0e5a9eSLydia Wang 				    AC_VERB_SET_CONNECT_SEL, pinsel);
815cdc1784dSLydia Wang 	if (spec->multiout.hp_nid && spec->multiout.hp_nid
816cdc1784dSLydia Wang 	    != spec->multiout.dac_nids[HDA_FRONT])
817cdc1784dSLydia Wang 		snd_hda_codec_setup_stream(codec, spec->multiout.hp_nid,
8180aa62aefSHarald Welte 					   0, 0, 0);
8190aa62aefSHarald Welte 
820cdc1784dSLydia Wang 	update_side_mute_status(codec);
8210713efebSLydia Wang 	/* update HP volume/swtich active state */
8220713efebSLydia Wang 	if (spec->codec_type == VT1708S
823eb7188caSLydia Wang 	    || spec->codec_type == VT1702
824f3db423dSLydia Wang 	    || spec->codec_type == VT1718S
82525eaba2fSLydia Wang 	    || spec->codec_type == VT1716S
82611890956SLydia Wang 	    || VT2002P_COMPATIBLE(spec)) {
8270713efebSLydia Wang 		activate_ctl(codec, "Headphone Playback Volume",
8280713efebSLydia Wang 			     spec->hp_independent_mode);
8290713efebSLydia Wang 		activate_ctl(codec, "Headphone Playback Switch",
8300713efebSLydia Wang 			     spec->hp_independent_mode);
8310713efebSLydia Wang 	}
832ce0e5a9eSLydia Wang 	/* update jack power state */
8333e95b9abSLydia Wang 	set_widgets_power_state(codec);
8340aa62aefSHarald Welte 	return 0;
8350aa62aefSHarald Welte }
8360aa62aefSHarald Welte 
83790dd48a1STakashi Iwai static const struct snd_kcontrol_new via_hp_mixer[2] = {
8380aa62aefSHarald Welte 	{
8390aa62aefSHarald Welte 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8400aa62aefSHarald Welte 		.name = "Independent HP",
8410aa62aefSHarald Welte 		.info = via_independent_hp_info,
8420aa62aefSHarald Welte 		.get = via_independent_hp_get,
8430aa62aefSHarald Welte 		.put = via_independent_hp_put,
8440aa62aefSHarald Welte 	},
8455b0cb1d8SJaroslav Kysela 	{
8465b0cb1d8SJaroslav Kysela 		.iface = NID_MAPPING,
8475b0cb1d8SJaroslav Kysela 		.name = "Independent HP",
8485b0cb1d8SJaroslav Kysela 	},
8490aa62aefSHarald Welte };
8500aa62aefSHarald Welte 
8513d83e577STakashi Iwai static int via_hp_build(struct hda_codec *codec)
8525b0cb1d8SJaroslav Kysela {
8533d83e577STakashi Iwai 	struct via_spec *spec = codec->spec;
8545b0cb1d8SJaroslav Kysela 	struct snd_kcontrol_new *knew;
8555b0cb1d8SJaroslav Kysela 	hda_nid_t nid;
8563d83e577STakashi Iwai 	int nums;
8573d83e577STakashi Iwai 	hda_nid_t conn[HDA_MAX_CONNECTIONS];
8585b0cb1d8SJaroslav Kysela 
8595b0cb1d8SJaroslav Kysela 	switch (spec->codec_type) {
8605b0cb1d8SJaroslav Kysela 	case VT1718S:
8615b0cb1d8SJaroslav Kysela 		nid = 0x34;
8625b0cb1d8SJaroslav Kysela 		break;
8635b0cb1d8SJaroslav Kysela 	case VT2002P:
86411890956SLydia Wang 	case VT1802:
8655b0cb1d8SJaroslav Kysela 		nid = 0x35;
8665b0cb1d8SJaroslav Kysela 		break;
8675b0cb1d8SJaroslav Kysela 	case VT1812:
8685b0cb1d8SJaroslav Kysela 		nid = 0x3d;
8695b0cb1d8SJaroslav Kysela 		break;
8705b0cb1d8SJaroslav Kysela 	default:
8715b0cb1d8SJaroslav Kysela 		nid = spec->autocfg.hp_pins[0];
8725b0cb1d8SJaroslav Kysela 		break;
8735b0cb1d8SJaroslav Kysela 	}
8745b0cb1d8SJaroslav Kysela 
875ee3c35c0SLydia Wang 	if (spec->codec_type != VT1708) {
876ee3c35c0SLydia Wang 		nums = snd_hda_get_connections(codec, nid,
877ee3c35c0SLydia Wang 					       conn, HDA_MAX_CONNECTIONS);
8783d83e577STakashi Iwai 		if (nums <= 1)
8793d83e577STakashi Iwai 			return 0;
880ee3c35c0SLydia Wang 	}
8813d83e577STakashi Iwai 
8823d83e577STakashi Iwai 	knew = via_clone_control(spec, &via_hp_mixer[0]);
8833d83e577STakashi Iwai 	if (knew == NULL)
8843d83e577STakashi Iwai 		return -ENOMEM;
8853d83e577STakashi Iwai 
8865b0cb1d8SJaroslav Kysela 	knew->subdevice = HDA_SUBDEV_NID_FLAG | nid;
8875b0cb1d8SJaroslav Kysela 	knew->private_value = nid;
8885b0cb1d8SJaroslav Kysela 
8895b0cb1d8SJaroslav Kysela 	knew = via_clone_control(spec, &via_hp_mixer[1]);
8905b0cb1d8SJaroslav Kysela 	if (knew == NULL)
8915b0cb1d8SJaroslav Kysela 		return -ENOMEM;
8925b0cb1d8SJaroslav Kysela 	knew->subdevice = side_mute_channel(spec);
8935b0cb1d8SJaroslav Kysela 
8945b0cb1d8SJaroslav Kysela 	return 0;
8955b0cb1d8SJaroslav Kysela }
8965b0cb1d8SJaroslav Kysela 
8971564b287SLydia Wang static void notify_aa_path_ctls(struct hda_codec *codec)
8981564b287SLydia Wang {
8991564b287SLydia Wang 	int i;
9001564b287SLydia Wang 	struct snd_ctl_elem_id id;
901525566cbSLydia Wang 	const char *labels[] = {"Mic", "Front Mic", "Line", "Rear Mic"};
902525566cbSLydia Wang 	struct snd_kcontrol *ctl;
9031564b287SLydia Wang 
9041564b287SLydia Wang 	memset(&id, 0, sizeof(id));
9051564b287SLydia Wang 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
9061564b287SLydia Wang 	for (i = 0; i < ARRAY_SIZE(labels); i++) {
9071564b287SLydia Wang 		sprintf(id.name, "%s Playback Volume", labels[i]);
908525566cbSLydia Wang 		ctl = snd_hda_find_mixer_ctl(codec, id.name);
909525566cbSLydia Wang 		if (ctl)
910525566cbSLydia Wang 			snd_ctl_notify(codec->bus->card,
911525566cbSLydia Wang 					SNDRV_CTL_EVENT_MASK_VALUE,
912525566cbSLydia Wang 					&ctl->id);
9131564b287SLydia Wang 	}
9141564b287SLydia Wang }
9151564b287SLydia Wang 
9161564b287SLydia Wang static void mute_aa_path(struct hda_codec *codec, int mute)
9171564b287SLydia Wang {
9181564b287SLydia Wang 	struct via_spec *spec = codec->spec;
9191564b287SLydia Wang 	hda_nid_t  nid_mixer;
9201564b287SLydia Wang 	int start_idx;
9211564b287SLydia Wang 	int end_idx;
9221564b287SLydia Wang 	int i;
9231564b287SLydia Wang 	/* get nid of MW0 and start & end index */
9241564b287SLydia Wang 	switch (spec->codec_type) {
9251564b287SLydia Wang 	case VT1708:
9261564b287SLydia Wang 		nid_mixer = 0x17;
9271564b287SLydia Wang 		start_idx = 2;
9281564b287SLydia Wang 		end_idx = 4;
9291564b287SLydia Wang 		break;
9301564b287SLydia Wang 	case VT1709_10CH:
9311564b287SLydia Wang 	case VT1709_6CH:
9321564b287SLydia Wang 		nid_mixer = 0x18;
9331564b287SLydia Wang 		start_idx = 2;
9341564b287SLydia Wang 		end_idx = 4;
9351564b287SLydia Wang 		break;
9361564b287SLydia Wang 	case VT1708B_8CH:
9371564b287SLydia Wang 	case VT1708B_4CH:
9381564b287SLydia Wang 	case VT1708S:
939f3db423dSLydia Wang 	case VT1716S:
9401564b287SLydia Wang 		nid_mixer = 0x16;
9411564b287SLydia Wang 		start_idx = 2;
9421564b287SLydia Wang 		end_idx = 4;
9431564b287SLydia Wang 		break;
944ab657e0cSLydia Wang 	case VT1718S:
945ab657e0cSLydia Wang 		nid_mixer = 0x21;
946ab657e0cSLydia Wang 		start_idx = 1;
947ab657e0cSLydia Wang 		end_idx = 3;
948ab657e0cSLydia Wang 		break;
9491564b287SLydia Wang 	default:
9501564b287SLydia Wang 		return;
9511564b287SLydia Wang 	}
9521564b287SLydia Wang 	/* check AA path's mute status */
9531564b287SLydia Wang 	for (i = start_idx; i <= end_idx; i++) {
9541564b287SLydia Wang 		int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE;
9551564b287SLydia Wang 		snd_hda_codec_amp_stereo(codec, nid_mixer, HDA_INPUT, i,
9561564b287SLydia Wang 					 HDA_AMP_MUTE, val);
9571564b287SLydia Wang 	}
9581564b287SLydia Wang }
9591564b287SLydia Wang static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin)
9601564b287SLydia Wang {
9617b315bb4STakashi Iwai 	const struct auto_pin_cfg *cfg = &spec->autocfg;
9627b315bb4STakashi Iwai 	int i;
9637b315bb4STakashi Iwai 
9647b315bb4STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
9657b315bb4STakashi Iwai 		if (pin == cfg->inputs[i].pin)
96686e2959aSTakashi Iwai 			return cfg->inputs[i].type <= AUTO_PIN_LINE_IN;
9671564b287SLydia Wang 	}
9687b315bb4STakashi Iwai 	return 0;
9691564b287SLydia Wang }
9701564b287SLydia Wang 
9711564b287SLydia Wang static int via_smart51_info(struct snd_kcontrol *kcontrol,
9721564b287SLydia Wang 			    struct snd_ctl_elem_info *uinfo)
9731564b287SLydia Wang {
9741564b287SLydia Wang 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
9751564b287SLydia Wang 	uinfo->count = 1;
9761564b287SLydia Wang 	uinfo->value.integer.min = 0;
9771564b287SLydia Wang 	uinfo->value.integer.max = 1;
9781564b287SLydia Wang 	return 0;
9791564b287SLydia Wang }
9801564b287SLydia Wang 
9811564b287SLydia Wang static int via_smart51_get(struct snd_kcontrol *kcontrol,
9821564b287SLydia Wang 			   struct snd_ctl_elem_value *ucontrol)
9831564b287SLydia Wang {
9841564b287SLydia Wang 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9851564b287SLydia Wang 	struct via_spec *spec = codec->spec;
9867b315bb4STakashi Iwai 	const struct auto_pin_cfg *cfg = &spec->autocfg;
9871564b287SLydia Wang 	int on = 1;
9881564b287SLydia Wang 	int i;
9891564b287SLydia Wang 
9907b315bb4STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
9917b315bb4STakashi Iwai 		hda_nid_t nid = cfg->inputs[i].pin;
9927b315bb4STakashi Iwai 		int ctl = snd_hda_codec_read(codec, nid, 0,
9937b315bb4STakashi Iwai 					     AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
99486e2959aSTakashi Iwai 		if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
9957b315bb4STakashi Iwai 			continue;
99686e2959aSTakashi Iwai 		if (cfg->inputs[i].type == AUTO_PIN_MIC &&
9977b315bb4STakashi Iwai 		    spec->hp_independent_mode && spec->codec_type != VT1718S)
9981564b287SLydia Wang 			continue; /* ignore FMic for independent HP */
9997b315bb4STakashi Iwai 		if ((ctl & AC_PINCTL_IN_EN) && !(ctl & AC_PINCTL_OUT_EN))
10001564b287SLydia Wang 			on = 0;
10011564b287SLydia Wang 	}
10021564b287SLydia Wang 	*ucontrol->value.integer.value = on;
10031564b287SLydia Wang 	return 0;
10041564b287SLydia Wang }
10051564b287SLydia Wang 
10061564b287SLydia Wang static int via_smart51_put(struct snd_kcontrol *kcontrol,
10071564b287SLydia Wang 			   struct snd_ctl_elem_value *ucontrol)
10081564b287SLydia Wang {
10091564b287SLydia Wang 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10101564b287SLydia Wang 	struct via_spec *spec = codec->spec;
10117b315bb4STakashi Iwai 	const struct auto_pin_cfg *cfg = &spec->autocfg;
10121564b287SLydia Wang 	int out_in = *ucontrol->value.integer.value
10131564b287SLydia Wang 		? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN;
10141564b287SLydia Wang 	int i;
10151564b287SLydia Wang 
10167b315bb4STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
10177b315bb4STakashi Iwai 		hda_nid_t nid = cfg->inputs[i].pin;
10187b315bb4STakashi Iwai 		unsigned int parm;
10197b315bb4STakashi Iwai 
102086e2959aSTakashi Iwai 		if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
10217b315bb4STakashi Iwai 			continue;
102286e2959aSTakashi Iwai 		if (cfg->inputs[i].type == AUTO_PIN_MIC &&
10237b315bb4STakashi Iwai 		    spec->hp_independent_mode && spec->codec_type != VT1718S)
10241564b287SLydia Wang 			continue; /* don't retask FMic for independent HP */
10257b315bb4STakashi Iwai 
10267b315bb4STakashi Iwai 		parm = snd_hda_codec_read(codec, nid, 0,
10271564b287SLydia Wang 					  AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
10281564b287SLydia Wang 		parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
10291564b287SLydia Wang 		parm |= out_in;
10301564b287SLydia Wang 		snd_hda_codec_write(codec, nid, 0,
10311564b287SLydia Wang 				    AC_VERB_SET_PIN_WIDGET_CONTROL,
10321564b287SLydia Wang 				    parm);
10331564b287SLydia Wang 		if (out_in == AC_PINCTL_OUT_EN) {
10341564b287SLydia Wang 			mute_aa_path(codec, 1);
10351564b287SLydia Wang 			notify_aa_path_ctls(codec);
10361564b287SLydia Wang 		}
10377b315bb4STakashi Iwai 		if (spec->codec_type == VT1718S) {
1038eb7188caSLydia Wang 			snd_hda_codec_amp_stereo(
1039eb7188caSLydia Wang 					codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE,
1040eb7188caSLydia Wang 					HDA_AMP_UNMUTE);
10411564b287SLydia Wang 		}
104286e2959aSTakashi Iwai 		if (cfg->inputs[i].type == AUTO_PIN_MIC) {
1043f3db423dSLydia Wang 			if (spec->codec_type == VT1708S
1044f3db423dSLydia Wang 			    || spec->codec_type == VT1716S) {
10451564b287SLydia Wang 				/* input = index 1 (AOW3) */
10461564b287SLydia Wang 				snd_hda_codec_write(
10471564b287SLydia Wang 					codec, nid, 0,
10481564b287SLydia Wang 					AC_VERB_SET_CONNECT_SEL, 1);
10491564b287SLydia Wang 				snd_hda_codec_amp_stereo(
10501564b287SLydia Wang 					codec, nid, HDA_OUTPUT,
10511564b287SLydia Wang 					0, HDA_AMP_MUTE, HDA_AMP_UNMUTE);
10521564b287SLydia Wang 			}
10531564b287SLydia Wang 		}
10541564b287SLydia Wang 	}
10551564b287SLydia Wang 	spec->smart51_enabled = *ucontrol->value.integer.value;
10563e95b9abSLydia Wang 	set_widgets_power_state(codec);
10571564b287SLydia Wang 	return 1;
10581564b287SLydia Wang }
10591564b287SLydia Wang 
10605f4b36d6STakashi Iwai static const struct snd_kcontrol_new via_smart51_mixer = {
10611564b287SLydia Wang 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10621564b287SLydia Wang 	.name = "Smart 5.1",
10631564b287SLydia Wang 	.count = 1,
10641564b287SLydia Wang 	.info = via_smart51_info,
10651564b287SLydia Wang 	.get = via_smart51_get,
10661564b287SLydia Wang 	.put = via_smart51_put,
10671564b287SLydia Wang };
10681564b287SLydia Wang 
10695b0cb1d8SJaroslav Kysela static int via_smart51_build(struct via_spec *spec)
10705b0cb1d8SJaroslav Kysela {
10715b0cb1d8SJaroslav Kysela 	struct snd_kcontrol_new *knew;
10727b315bb4STakashi Iwai 	const struct auto_pin_cfg *cfg = &spec->autocfg;
10735b0cb1d8SJaroslav Kysela 	hda_nid_t nid;
10745b0cb1d8SJaroslav Kysela 	int i;
10755b0cb1d8SJaroslav Kysela 
1076cb34c207SLydia Wang 	if (!cfg)
1077cb34c207SLydia Wang 		return 0;
1078cb34c207SLydia Wang 	if (cfg->line_outs > 2)
1079cb34c207SLydia Wang 		return 0;
1080cb34c207SLydia Wang 
10815f4b36d6STakashi Iwai 	knew = via_clone_control(spec, &via_smart51_mixer);
10825b0cb1d8SJaroslav Kysela 	if (knew == NULL)
10835b0cb1d8SJaroslav Kysela 		return -ENOMEM;
10845b0cb1d8SJaroslav Kysela 
10857b315bb4STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
10867b315bb4STakashi Iwai 		nid = cfg->inputs[i].pin;
108786e2959aSTakashi Iwai 		if (cfg->inputs[i].type <= AUTO_PIN_LINE_IN) {
10885f4b36d6STakashi Iwai 			knew->subdevice = HDA_SUBDEV_NID_FLAG | nid;
10897b315bb4STakashi Iwai 			break;
10905b0cb1d8SJaroslav Kysela 		}
10915b0cb1d8SJaroslav Kysela 	}
10925b0cb1d8SJaroslav Kysela 
10935b0cb1d8SJaroslav Kysela 	return 0;
10945b0cb1d8SJaroslav Kysela }
10955b0cb1d8SJaroslav Kysela 
1096c577b8a1SJoseph Chan /* capture mixer elements */
109790dd48a1STakashi Iwai static const struct snd_kcontrol_new vt1708_capture_mixer[] = {
1098c577b8a1SJoseph Chan 	HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
1099c577b8a1SJoseph Chan 	HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
1100c577b8a1SJoseph Chan 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
1101c577b8a1SJoseph Chan 	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
1102c577b8a1SJoseph Chan 	{
1103c577b8a1SJoseph Chan 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1104c577b8a1SJoseph Chan 		/* The multiple "Capture Source" controls confuse alsamixer
1105c577b8a1SJoseph Chan 		 * So call somewhat different..
1106c577b8a1SJoseph Chan 		 */
1107c577b8a1SJoseph Chan 		/* .name = "Capture Source", */
1108c577b8a1SJoseph Chan 		.name = "Input Source",
1109c577b8a1SJoseph Chan 		.count = 1,
1110c577b8a1SJoseph Chan 		.info = via_mux_enum_info,
1111c577b8a1SJoseph Chan 		.get = via_mux_enum_get,
1112c577b8a1SJoseph Chan 		.put = via_mux_enum_put,
1113c577b8a1SJoseph Chan 	},
1114c577b8a1SJoseph Chan 	{ } /* end */
1115c577b8a1SJoseph Chan };
1116f5271101SLydia Wang 
1117f5271101SLydia Wang /* check AA path's mute statue */
1118f5271101SLydia Wang static int is_aa_path_mute(struct hda_codec *codec)
1119f5271101SLydia Wang {
1120f5271101SLydia Wang 	int mute = 1;
1121f5271101SLydia Wang 	hda_nid_t  nid_mixer;
1122f5271101SLydia Wang 	int start_idx;
1123f5271101SLydia Wang 	int end_idx;
1124f5271101SLydia Wang 	int i;
1125f5271101SLydia Wang 	struct via_spec *spec = codec->spec;
1126f5271101SLydia Wang 	/* get nid of MW0 and start & end index */
1127f5271101SLydia Wang 	switch (spec->codec_type) {
1128f5271101SLydia Wang 	case VT1708B_8CH:
1129f5271101SLydia Wang 	case VT1708B_4CH:
1130f5271101SLydia Wang 	case VT1708S:
1131f3db423dSLydia Wang 	case VT1716S:
1132f5271101SLydia Wang 		nid_mixer = 0x16;
1133f5271101SLydia Wang 		start_idx = 2;
1134f5271101SLydia Wang 		end_idx = 4;
1135f5271101SLydia Wang 		break;
1136f5271101SLydia Wang 	case VT1702:
1137f5271101SLydia Wang 		nid_mixer = 0x1a;
1138f5271101SLydia Wang 		start_idx = 1;
1139f5271101SLydia Wang 		end_idx = 3;
1140f5271101SLydia Wang 		break;
1141eb7188caSLydia Wang 	case VT1718S:
1142eb7188caSLydia Wang 		nid_mixer = 0x21;
1143eb7188caSLydia Wang 		start_idx = 1;
1144eb7188caSLydia Wang 		end_idx = 3;
1145eb7188caSLydia Wang 		break;
114625eaba2fSLydia Wang 	case VT2002P:
1147ab6734e7SLydia Wang 	case VT1812:
114811890956SLydia Wang 	case VT1802:
114925eaba2fSLydia Wang 		nid_mixer = 0x21;
115025eaba2fSLydia Wang 		start_idx = 0;
115125eaba2fSLydia Wang 		end_idx = 2;
115225eaba2fSLydia Wang 		break;
1153f5271101SLydia Wang 	default:
1154f5271101SLydia Wang 		return 0;
1155f5271101SLydia Wang 	}
1156f5271101SLydia Wang 	/* check AA path's mute status */
1157f5271101SLydia Wang 	for (i = start_idx; i <= end_idx; i++) {
1158f5271101SLydia Wang 		unsigned int con_list = snd_hda_codec_read(
1159f5271101SLydia Wang 			codec, nid_mixer, 0, AC_VERB_GET_CONNECT_LIST, i/4*4);
1160f5271101SLydia Wang 		int shift = 8 * (i % 4);
1161f5271101SLydia Wang 		hda_nid_t nid_pin = (con_list & (0xff << shift)) >> shift;
1162f5271101SLydia Wang 		unsigned int defconf = snd_hda_codec_get_pincfg(codec, nid_pin);
1163f5271101SLydia Wang 		if (get_defcfg_connect(defconf) == AC_JACK_PORT_COMPLEX) {
1164f5271101SLydia Wang 			/* check mute status while the pin is connected */
1165f5271101SLydia Wang 			int mute_l = snd_hda_codec_amp_read(codec, nid_mixer, 0,
1166f5271101SLydia Wang 							    HDA_INPUT, i) >> 7;
1167f5271101SLydia Wang 			int mute_r = snd_hda_codec_amp_read(codec, nid_mixer, 1,
1168f5271101SLydia Wang 							    HDA_INPUT, i) >> 7;
1169f5271101SLydia Wang 			if (!mute_l || !mute_r) {
1170f5271101SLydia Wang 				mute = 0;
1171f5271101SLydia Wang 				break;
1172f5271101SLydia Wang 			}
1173f5271101SLydia Wang 		}
1174f5271101SLydia Wang 	}
1175f5271101SLydia Wang 	return mute;
1176f5271101SLydia Wang }
1177f5271101SLydia Wang 
1178f5271101SLydia Wang /* enter/exit analog low-current mode */
1179f5271101SLydia Wang static void analog_low_current_mode(struct hda_codec *codec, int stream_idle)
1180f5271101SLydia Wang {
1181f5271101SLydia Wang 	struct via_spec *spec = codec->spec;
1182f5271101SLydia Wang 	static int saved_stream_idle = 1; /* saved stream idle status */
1183f5271101SLydia Wang 	int enable = is_aa_path_mute(codec);
1184f5271101SLydia Wang 	unsigned int verb = 0;
1185f5271101SLydia Wang 	unsigned int parm = 0;
1186f5271101SLydia Wang 
1187f5271101SLydia Wang 	if (stream_idle == -1)	/* stream status did not change */
1188f5271101SLydia Wang 		enable = enable && saved_stream_idle;
1189f5271101SLydia Wang 	else {
1190f5271101SLydia Wang 		enable = enable && stream_idle;
1191f5271101SLydia Wang 		saved_stream_idle = stream_idle;
1192f5271101SLydia Wang 	}
1193f5271101SLydia Wang 
1194f5271101SLydia Wang 	/* decide low current mode's verb & parameter */
1195f5271101SLydia Wang 	switch (spec->codec_type) {
1196f5271101SLydia Wang 	case VT1708B_8CH:
1197f5271101SLydia Wang 	case VT1708B_4CH:
1198f5271101SLydia Wang 		verb = 0xf70;
1199f5271101SLydia Wang 		parm = enable ? 0x02 : 0x00; /* 0x02: 2/3x, 0x00: 1x */
1200f5271101SLydia Wang 		break;
1201f5271101SLydia Wang 	case VT1708S:
1202eb7188caSLydia Wang 	case VT1718S:
1203f3db423dSLydia Wang 	case VT1716S:
1204f5271101SLydia Wang 		verb = 0xf73;
1205f5271101SLydia Wang 		parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */
1206f5271101SLydia Wang 		break;
1207f5271101SLydia Wang 	case VT1702:
1208f5271101SLydia Wang 		verb = 0xf73;
1209f5271101SLydia Wang 		parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */
1210f5271101SLydia Wang 		break;
121125eaba2fSLydia Wang 	case VT2002P:
1212ab6734e7SLydia Wang 	case VT1812:
121311890956SLydia Wang 	case VT1802:
121425eaba2fSLydia Wang 		verb = 0xf93;
121525eaba2fSLydia Wang 		parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */
121625eaba2fSLydia Wang 		break;
1217f5271101SLydia Wang 	default:
1218f5271101SLydia Wang 		return;		/* other codecs are not supported */
1219f5271101SLydia Wang 	}
1220f5271101SLydia Wang 	/* send verb */
1221f5271101SLydia Wang 	snd_hda_codec_write(codec, codec->afg, 0, verb, parm);
1222f5271101SLydia Wang }
1223f5271101SLydia Wang 
1224c577b8a1SJoseph Chan /*
1225c577b8a1SJoseph Chan  * generic initialization of ADC, input mixers and output mixers
1226c577b8a1SJoseph Chan  */
122790dd48a1STakashi Iwai static const struct hda_verb vt1708_volume_init_verbs[] = {
1228c577b8a1SJoseph Chan 	/*
1229c577b8a1SJoseph Chan 	 * Unmute ADC0-1 and set the default input to mic-in
1230c577b8a1SJoseph Chan 	 */
1231c577b8a1SJoseph Chan 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1232c577b8a1SJoseph Chan 	{0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1233c577b8a1SJoseph Chan 
1234c577b8a1SJoseph Chan 
1235f7278fd0SJosepch Chan 	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1236c577b8a1SJoseph Chan 	 * mixer widget
1237c577b8a1SJoseph Chan 	 */
1238c577b8a1SJoseph Chan 	/* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1239f7278fd0SJosepch Chan 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1240f7278fd0SJosepch Chan 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1241f7278fd0SJosepch Chan 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1242f7278fd0SJosepch Chan 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1243f7278fd0SJosepch Chan 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1244c577b8a1SJoseph Chan 
1245c577b8a1SJoseph Chan 	/*
1246c577b8a1SJoseph Chan 	 * Set up output mixers (0x19 - 0x1b)
1247c577b8a1SJoseph Chan 	 */
1248c577b8a1SJoseph Chan 	/* set vol=0 to output mixers */
1249c577b8a1SJoseph Chan 	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1250c577b8a1SJoseph Chan 	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1251c577b8a1SJoseph Chan 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1252c577b8a1SJoseph Chan 
1253bfdc675aSLydia Wang 	/* Setup default input MW0 to PW4 */
1254bfdc675aSLydia Wang 	{0x20, AC_VERB_SET_CONNECT_SEL, 0},
1255c577b8a1SJoseph Chan 	/* PW9 Output enable */
1256c577b8a1SJoseph Chan 	{0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1257aa266fccSLydia Wang 	/* power down jack detect function */
1258aa266fccSLydia Wang 	{0x1, 0xf81, 0x1},
1259f7278fd0SJosepch Chan 	{ }
1260c577b8a1SJoseph Chan };
1261c577b8a1SJoseph Chan 
1262c577b8a1SJoseph Chan static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
1263c577b8a1SJoseph Chan 				 struct hda_codec *codec,
1264c577b8a1SJoseph Chan 				 struct snd_pcm_substream *substream)
1265c577b8a1SJoseph Chan {
1266c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
126717314379SLydia Wang 	int idle = substream->pstr->substream_opened == 1
126817314379SLydia Wang 		&& substream->ref_count == 0;
126917314379SLydia Wang 	analog_low_current_mode(codec, idle);
12709a08160bSTakashi Iwai 	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
12719a08160bSTakashi Iwai 					     hinfo);
1272c577b8a1SJoseph Chan }
1273c577b8a1SJoseph Chan 
12740aa62aefSHarald Welte static void playback_multi_pcm_prep_0(struct hda_codec *codec,
12750aa62aefSHarald Welte 				      unsigned int stream_tag,
12760aa62aefSHarald Welte 				      unsigned int format,
12770aa62aefSHarald Welte 				      struct snd_pcm_substream *substream)
12780aa62aefSHarald Welte {
12790aa62aefSHarald Welte 	struct via_spec *spec = codec->spec;
12800aa62aefSHarald Welte 	struct hda_multi_out *mout = &spec->multiout;
1281dda14410STakashi Iwai 	const hda_nid_t *nids = mout->dac_nids;
12820aa62aefSHarald Welte 	int chs = substream->runtime->channels;
12830aa62aefSHarald Welte 	int i;
12847c935976SStephen Warren 	struct hda_spdif_out *spdif =
12857c935976SStephen Warren 		snd_hda_spdif_out_of_nid(codec, spec->multiout.dig_out_nid);
12860aa62aefSHarald Welte 
12870aa62aefSHarald Welte 	mutex_lock(&codec->spdif_mutex);
12880aa62aefSHarald Welte 	if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
12890aa62aefSHarald Welte 		if (chs == 2 &&
12900aa62aefSHarald Welte 		    snd_hda_is_supported_format(codec, mout->dig_out_nid,
12910aa62aefSHarald Welte 						format) &&
12927c935976SStephen Warren 		    !(spdif->status & IEC958_AES0_NONAUDIO)) {
12930aa62aefSHarald Welte 			mout->dig_out_used = HDA_DIG_ANALOG_DUP;
12940aa62aefSHarald Welte 			/* turn off SPDIF once; otherwise the IEC958 bits won't
12950aa62aefSHarald Welte 			 * be updated */
12967c935976SStephen Warren 			if (spdif->ctls & AC_DIG1_ENABLE)
12970aa62aefSHarald Welte 				snd_hda_codec_write(codec, mout->dig_out_nid, 0,
12980aa62aefSHarald Welte 						    AC_VERB_SET_DIGI_CONVERT_1,
12997c935976SStephen Warren 						    spdif->ctls &
13000aa62aefSHarald Welte 							~AC_DIG1_ENABLE & 0xff);
13010aa62aefSHarald Welte 			snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
13020aa62aefSHarald Welte 						   stream_tag, 0, format);
13030aa62aefSHarald Welte 			/* turn on again (if needed) */
13047c935976SStephen Warren 			if (spdif->ctls & AC_DIG1_ENABLE)
13050aa62aefSHarald Welte 				snd_hda_codec_write(codec, mout->dig_out_nid, 0,
13060aa62aefSHarald Welte 						    AC_VERB_SET_DIGI_CONVERT_1,
13077c935976SStephen Warren 						    spdif->ctls & 0xff);
13080aa62aefSHarald Welte 		} else {
13090aa62aefSHarald Welte 			mout->dig_out_used = 0;
13100aa62aefSHarald Welte 			snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
13110aa62aefSHarald Welte 						   0, 0, 0);
13120aa62aefSHarald Welte 		}
13130aa62aefSHarald Welte 	}
13140aa62aefSHarald Welte 	mutex_unlock(&codec->spdif_mutex);
13150aa62aefSHarald Welte 
13160aa62aefSHarald Welte 	/* front */
13170aa62aefSHarald Welte 	snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag,
13180aa62aefSHarald Welte 				   0, format);
13190aa62aefSHarald Welte 
1320eb7188caSLydia Wang 	if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT]
1321eb7188caSLydia Wang 	    && !spec->hp_independent_mode)
13220aa62aefSHarald Welte 		/* headphone out will just decode front left/right (stereo) */
13230aa62aefSHarald Welte 		snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag,
13240aa62aefSHarald Welte 					   0, format);
13250aa62aefSHarald Welte 
13260aa62aefSHarald Welte 	/* extra outputs copied from front */
13270aa62aefSHarald Welte 	for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
13280aa62aefSHarald Welte 		if (mout->extra_out_nid[i])
13290aa62aefSHarald Welte 			snd_hda_codec_setup_stream(codec,
13300aa62aefSHarald Welte 						   mout->extra_out_nid[i],
13310aa62aefSHarald Welte 						   stream_tag, 0, format);
13320aa62aefSHarald Welte 
13330aa62aefSHarald Welte 	/* surrounds */
13340aa62aefSHarald Welte 	for (i = 1; i < mout->num_dacs; i++) {
13350aa62aefSHarald Welte 		if (chs >= (i + 1) * 2) /* independent out */
13360aa62aefSHarald Welte 			snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
13370aa62aefSHarald Welte 						   i * 2, format);
13380aa62aefSHarald Welte 		else /* copy front */
13390aa62aefSHarald Welte 			snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
13400aa62aefSHarald Welte 						   0, format);
13410aa62aefSHarald Welte 	}
13420aa62aefSHarald Welte }
13430aa62aefSHarald Welte 
13440aa62aefSHarald Welte static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
13450aa62aefSHarald Welte 					  struct hda_codec *codec,
13460aa62aefSHarald Welte 					  unsigned int stream_tag,
13470aa62aefSHarald Welte 					  unsigned int format,
13480aa62aefSHarald Welte 					  struct snd_pcm_substream *substream)
13490aa62aefSHarald Welte {
13500aa62aefSHarald Welte 	struct via_spec *spec = codec->spec;
13510aa62aefSHarald Welte 	struct hda_multi_out *mout = &spec->multiout;
1352dda14410STakashi Iwai 	const hda_nid_t *nids = mout->dac_nids;
13530aa62aefSHarald Welte 
13540aa62aefSHarald Welte 	if (substream->number == 0)
13550aa62aefSHarald Welte 		playback_multi_pcm_prep_0(codec, stream_tag, format,
13560aa62aefSHarald Welte 					  substream);
13570aa62aefSHarald Welte 	else {
13580aa62aefSHarald Welte 		if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
13590aa62aefSHarald Welte 		    spec->hp_independent_mode)
13600aa62aefSHarald Welte 			snd_hda_codec_setup_stream(codec, mout->hp_nid,
13610aa62aefSHarald Welte 						   stream_tag, 0, format);
13620aa62aefSHarald Welte 	}
13631f2e99feSLydia Wang 	vt1708_start_hp_work(spec);
13640aa62aefSHarald Welte 	return 0;
13650aa62aefSHarald Welte }
13660aa62aefSHarald Welte 
13670aa62aefSHarald Welte static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
13680aa62aefSHarald Welte 				    struct hda_codec *codec,
13690aa62aefSHarald Welte 				    struct snd_pcm_substream *substream)
13700aa62aefSHarald Welte {
13710aa62aefSHarald Welte 	struct via_spec *spec = codec->spec;
13720aa62aefSHarald Welte 	struct hda_multi_out *mout = &spec->multiout;
1373dda14410STakashi Iwai 	const hda_nid_t *nids = mout->dac_nids;
13740aa62aefSHarald Welte 	int i;
13750aa62aefSHarald Welte 
13760aa62aefSHarald Welte 	if (substream->number == 0) {
13770aa62aefSHarald Welte 		for (i = 0; i < mout->num_dacs; i++)
13780aa62aefSHarald Welte 			snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
13790aa62aefSHarald Welte 
13800aa62aefSHarald Welte 		if (mout->hp_nid && !spec->hp_independent_mode)
13810aa62aefSHarald Welte 			snd_hda_codec_setup_stream(codec, mout->hp_nid,
13820aa62aefSHarald Welte 						   0, 0, 0);
13830aa62aefSHarald Welte 
13840aa62aefSHarald Welte 		for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
13850aa62aefSHarald Welte 			if (mout->extra_out_nid[i])
13860aa62aefSHarald Welte 				snd_hda_codec_setup_stream(codec,
13870aa62aefSHarald Welte 							mout->extra_out_nid[i],
13880aa62aefSHarald Welte 							0, 0, 0);
13890aa62aefSHarald Welte 		mutex_lock(&codec->spdif_mutex);
13900aa62aefSHarald Welte 		if (mout->dig_out_nid &&
13910aa62aefSHarald Welte 		    mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
13920aa62aefSHarald Welte 			snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
13930aa62aefSHarald Welte 						   0, 0, 0);
13940aa62aefSHarald Welte 			mout->dig_out_used = 0;
13950aa62aefSHarald Welte 		}
13960aa62aefSHarald Welte 		mutex_unlock(&codec->spdif_mutex);
13970aa62aefSHarald Welte 	} else {
13980aa62aefSHarald Welte 		if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
13990aa62aefSHarald Welte 		    spec->hp_independent_mode)
14000aa62aefSHarald Welte 			snd_hda_codec_setup_stream(codec, mout->hp_nid,
14010aa62aefSHarald Welte 						   0, 0, 0);
14020aa62aefSHarald Welte 	}
14031f2e99feSLydia Wang 	vt1708_stop_hp_work(spec);
14040aa62aefSHarald Welte 	return 0;
14050aa62aefSHarald Welte }
14060aa62aefSHarald Welte 
1407c577b8a1SJoseph Chan /*
1408c577b8a1SJoseph Chan  * Digital out
1409c577b8a1SJoseph Chan  */
1410c577b8a1SJoseph Chan static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1411c577b8a1SJoseph Chan 				     struct hda_codec *codec,
1412c577b8a1SJoseph Chan 				     struct snd_pcm_substream *substream)
1413c577b8a1SJoseph Chan {
1414c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
1415c577b8a1SJoseph Chan 	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1416c577b8a1SJoseph Chan }
1417c577b8a1SJoseph Chan 
1418c577b8a1SJoseph Chan static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1419c577b8a1SJoseph Chan 				      struct hda_codec *codec,
1420c577b8a1SJoseph Chan 				      struct snd_pcm_substream *substream)
1421c577b8a1SJoseph Chan {
1422c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
1423c577b8a1SJoseph Chan 	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1424c577b8a1SJoseph Chan }
1425c577b8a1SJoseph Chan 
14265691ec7fSHarald Welte static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
142798aa34c0SHarald Welte 					struct hda_codec *codec,
142898aa34c0SHarald Welte 					unsigned int stream_tag,
142998aa34c0SHarald Welte 					unsigned int format,
143098aa34c0SHarald Welte 					struct snd_pcm_substream *substream)
143198aa34c0SHarald Welte {
143298aa34c0SHarald Welte 	struct via_spec *spec = codec->spec;
14339da29271STakashi Iwai 	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
14349da29271STakashi Iwai 					     stream_tag, format, substream);
14359da29271STakashi Iwai }
14365691ec7fSHarald Welte 
14379da29271STakashi Iwai static int via_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
14389da29271STakashi Iwai 					struct hda_codec *codec,
14399da29271STakashi Iwai 					struct snd_pcm_substream *substream)
14409da29271STakashi Iwai {
14419da29271STakashi Iwai 	struct via_spec *spec = codec->spec;
14429da29271STakashi Iwai 	snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
144398aa34c0SHarald Welte 	return 0;
144498aa34c0SHarald Welte }
144598aa34c0SHarald Welte 
1446c577b8a1SJoseph Chan /*
1447c577b8a1SJoseph Chan  * Analog capture
1448c577b8a1SJoseph Chan  */
1449c577b8a1SJoseph Chan static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1450c577b8a1SJoseph Chan 				   struct hda_codec *codec,
1451c577b8a1SJoseph Chan 				   unsigned int stream_tag,
1452c577b8a1SJoseph Chan 				   unsigned int format,
1453c577b8a1SJoseph Chan 				   struct snd_pcm_substream *substream)
1454c577b8a1SJoseph Chan {
1455c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
1456c577b8a1SJoseph Chan 
1457c577b8a1SJoseph Chan 	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1458c577b8a1SJoseph Chan 				   stream_tag, 0, format);
1459c577b8a1SJoseph Chan 	return 0;
1460c577b8a1SJoseph Chan }
1461c577b8a1SJoseph Chan 
1462c577b8a1SJoseph Chan static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1463c577b8a1SJoseph Chan 				   struct hda_codec *codec,
1464c577b8a1SJoseph Chan 				   struct snd_pcm_substream *substream)
1465c577b8a1SJoseph Chan {
1466c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
1467888afa15STakashi Iwai 	snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
1468c577b8a1SJoseph Chan 	return 0;
1469c577b8a1SJoseph Chan }
1470c577b8a1SJoseph Chan 
147190dd48a1STakashi Iwai static const struct hda_pcm_stream vt1708_pcm_analog_playback = {
14720aa62aefSHarald Welte 	.substreams = 2,
1473c577b8a1SJoseph Chan 	.channels_min = 2,
1474c577b8a1SJoseph Chan 	.channels_max = 8,
1475c577b8a1SJoseph Chan 	.nid = 0x10, /* NID to query formats and rates */
1476c577b8a1SJoseph Chan 	.ops = {
1477c577b8a1SJoseph Chan 		.open = via_playback_pcm_open,
14780aa62aefSHarald Welte 		.prepare = via_playback_multi_pcm_prepare,
14790aa62aefSHarald Welte 		.cleanup = via_playback_multi_pcm_cleanup
1480c577b8a1SJoseph Chan 	},
1481c577b8a1SJoseph Chan };
1482c577b8a1SJoseph Chan 
148390dd48a1STakashi Iwai static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
1484c873cc25SLydia Wang 	.substreams = 2,
1485bc9b5623STakashi Iwai 	.channels_min = 2,
1486bc9b5623STakashi Iwai 	.channels_max = 8,
1487bc9b5623STakashi Iwai 	.nid = 0x10, /* NID to query formats and rates */
1488bc9b5623STakashi Iwai 	/* We got noisy outputs on the right channel on VT1708 when
1489bc9b5623STakashi Iwai 	 * 24bit samples are used.  Until any workaround is found,
1490bc9b5623STakashi Iwai 	 * disable the 24bit format, so far.
1491bc9b5623STakashi Iwai 	 */
1492bc9b5623STakashi Iwai 	.formats = SNDRV_PCM_FMTBIT_S16_LE,
1493bc9b5623STakashi Iwai 	.ops = {
1494bc9b5623STakashi Iwai 		.open = via_playback_pcm_open,
1495c873cc25SLydia Wang 		.prepare = via_playback_multi_pcm_prepare,
1496c873cc25SLydia Wang 		.cleanup = via_playback_multi_pcm_cleanup
1497bc9b5623STakashi Iwai 	},
1498bc9b5623STakashi Iwai };
1499bc9b5623STakashi Iwai 
150090dd48a1STakashi Iwai static const struct hda_pcm_stream vt1708_pcm_analog_capture = {
1501c577b8a1SJoseph Chan 	.substreams = 2,
1502c577b8a1SJoseph Chan 	.channels_min = 2,
1503c577b8a1SJoseph Chan 	.channels_max = 2,
1504c577b8a1SJoseph Chan 	.nid = 0x15, /* NID to query formats and rates */
1505c577b8a1SJoseph Chan 	.ops = {
1506c577b8a1SJoseph Chan 		.prepare = via_capture_pcm_prepare,
1507c577b8a1SJoseph Chan 		.cleanup = via_capture_pcm_cleanup
1508c577b8a1SJoseph Chan 	},
1509c577b8a1SJoseph Chan };
1510c577b8a1SJoseph Chan 
151190dd48a1STakashi Iwai static const struct hda_pcm_stream vt1708_pcm_digital_playback = {
1512c577b8a1SJoseph Chan 	.substreams = 1,
1513c577b8a1SJoseph Chan 	.channels_min = 2,
1514c577b8a1SJoseph Chan 	.channels_max = 2,
1515c577b8a1SJoseph Chan 	/* NID is set in via_build_pcms */
1516c577b8a1SJoseph Chan 	.ops = {
1517c577b8a1SJoseph Chan 		.open = via_dig_playback_pcm_open,
15186b97eb45STakashi Iwai 		.close = via_dig_playback_pcm_close,
15199da29271STakashi Iwai 		.prepare = via_dig_playback_pcm_prepare,
15209da29271STakashi Iwai 		.cleanup = via_dig_playback_pcm_cleanup
1521c577b8a1SJoseph Chan 	},
1522c577b8a1SJoseph Chan };
1523c577b8a1SJoseph Chan 
152490dd48a1STakashi Iwai static const struct hda_pcm_stream vt1708_pcm_digital_capture = {
1525c577b8a1SJoseph Chan 	.substreams = 1,
1526c577b8a1SJoseph Chan 	.channels_min = 2,
1527c577b8a1SJoseph Chan 	.channels_max = 2,
1528c577b8a1SJoseph Chan };
1529c577b8a1SJoseph Chan 
1530c577b8a1SJoseph Chan static int via_build_controls(struct hda_codec *codec)
1531c577b8a1SJoseph Chan {
1532c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
15335b0cb1d8SJaroslav Kysela 	struct snd_kcontrol *kctl;
153490dd48a1STakashi Iwai 	const struct snd_kcontrol_new *knew;
15355b0cb1d8SJaroslav Kysela 	int err, i;
1536c577b8a1SJoseph Chan 
1537*24088a58STakashi Iwai 	if (spec->set_widgets_power_state)
1538*24088a58STakashi Iwai 		if (!via_clone_control(spec, &via_pin_power_ctl_enum))
1539*24088a58STakashi Iwai 			return -ENOMEM;
1540*24088a58STakashi Iwai 
1541c577b8a1SJoseph Chan 	for (i = 0; i < spec->num_mixers; i++) {
1542c577b8a1SJoseph Chan 		err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1543c577b8a1SJoseph Chan 		if (err < 0)
1544c577b8a1SJoseph Chan 			return err;
1545c577b8a1SJoseph Chan 	}
1546c577b8a1SJoseph Chan 
1547c577b8a1SJoseph Chan 	if (spec->multiout.dig_out_nid) {
1548c577b8a1SJoseph Chan 		err = snd_hda_create_spdif_out_ctls(codec,
154974b654c9SStephen Warren 						    spec->multiout.dig_out_nid,
1550c577b8a1SJoseph Chan 						    spec->multiout.dig_out_nid);
1551c577b8a1SJoseph Chan 		if (err < 0)
1552c577b8a1SJoseph Chan 			return err;
15539a08160bSTakashi Iwai 		err = snd_hda_create_spdif_share_sw(codec,
15549a08160bSTakashi Iwai 						    &spec->multiout);
15559a08160bSTakashi Iwai 		if (err < 0)
15569a08160bSTakashi Iwai 			return err;
15579a08160bSTakashi Iwai 		spec->multiout.share_spdif = 1;
1558c577b8a1SJoseph Chan 	}
1559c577b8a1SJoseph Chan 	if (spec->dig_in_nid) {
1560c577b8a1SJoseph Chan 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1561c577b8a1SJoseph Chan 		if (err < 0)
1562c577b8a1SJoseph Chan 			return err;
1563c577b8a1SJoseph Chan 	}
156417314379SLydia Wang 
15655b0cb1d8SJaroslav Kysela 	/* assign Capture Source enums to NID */
15665b0cb1d8SJaroslav Kysela 	kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
15675b0cb1d8SJaroslav Kysela 	for (i = 0; kctl && i < kctl->count; i++) {
156821949f00STakashi Iwai 		err = snd_hda_add_nid(codec, kctl, i, spec->mux_nids[i]);
15695b0cb1d8SJaroslav Kysela 		if (err < 0)
15705b0cb1d8SJaroslav Kysela 			return err;
15715b0cb1d8SJaroslav Kysela 	}
15725b0cb1d8SJaroslav Kysela 
15735b0cb1d8SJaroslav Kysela 	/* other nid->control mapping */
15745b0cb1d8SJaroslav Kysela 	for (i = 0; i < spec->num_mixers; i++) {
15755b0cb1d8SJaroslav Kysela 		for (knew = spec->mixers[i]; knew->name; knew++) {
15765b0cb1d8SJaroslav Kysela 			if (knew->iface != NID_MAPPING)
15775b0cb1d8SJaroslav Kysela 				continue;
15785b0cb1d8SJaroslav Kysela 			kctl = snd_hda_find_mixer_ctl(codec, knew->name);
15795b0cb1d8SJaroslav Kysela 			if (kctl == NULL)
15805b0cb1d8SJaroslav Kysela 				continue;
15815b0cb1d8SJaroslav Kysela 			err = snd_hda_add_nid(codec, kctl, 0,
15825b0cb1d8SJaroslav Kysela 					      knew->subdevice);
15835b0cb1d8SJaroslav Kysela 		}
15845b0cb1d8SJaroslav Kysela 	}
15855b0cb1d8SJaroslav Kysela 
158617314379SLydia Wang 	/* init power states */
15873e95b9abSLydia Wang 	set_widgets_power_state(codec);
158817314379SLydia Wang 	analog_low_current_mode(codec, 1);
158917314379SLydia Wang 
1590603c4019STakashi Iwai 	via_free_kctls(codec); /* no longer needed */
1591c577b8a1SJoseph Chan 	return 0;
1592c577b8a1SJoseph Chan }
1593c577b8a1SJoseph Chan 
1594c577b8a1SJoseph Chan static int via_build_pcms(struct hda_codec *codec)
1595c577b8a1SJoseph Chan {
1596c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
1597c577b8a1SJoseph Chan 	struct hda_pcm *info = spec->pcm_rec;
1598c577b8a1SJoseph Chan 
1599c577b8a1SJoseph Chan 	codec->num_pcms = 1;
1600c577b8a1SJoseph Chan 	codec->pcm_info = info;
1601c577b8a1SJoseph Chan 
1602c577b8a1SJoseph Chan 	info->name = spec->stream_name_analog;
1603377ff31aSLydia Wang 	info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
1604377ff31aSLydia Wang 		*(spec->stream_analog_playback);
1605377ff31aSLydia Wang 	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
1606377ff31aSLydia Wang 		spec->multiout.dac_nids[0];
1607c577b8a1SJoseph Chan 	info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
1608c577b8a1SJoseph Chan 	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
1609c577b8a1SJoseph Chan 
1610c577b8a1SJoseph Chan 	info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
1611c577b8a1SJoseph Chan 		spec->multiout.max_channels;
1612c577b8a1SJoseph Chan 
1613c577b8a1SJoseph Chan 	if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1614c577b8a1SJoseph Chan 		codec->num_pcms++;
1615c577b8a1SJoseph Chan 		info++;
1616c577b8a1SJoseph Chan 		info->name = spec->stream_name_digital;
16177ba72ba1STakashi Iwai 		info->pcm_type = HDA_PCM_TYPE_SPDIF;
1618c577b8a1SJoseph Chan 		if (spec->multiout.dig_out_nid) {
1619c577b8a1SJoseph Chan 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
1620c577b8a1SJoseph Chan 				*(spec->stream_digital_playback);
1621c577b8a1SJoseph Chan 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
1622c577b8a1SJoseph Chan 				spec->multiout.dig_out_nid;
1623c577b8a1SJoseph Chan 		}
1624c577b8a1SJoseph Chan 		if (spec->dig_in_nid) {
1625c577b8a1SJoseph Chan 			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
1626c577b8a1SJoseph Chan 				*(spec->stream_digital_capture);
1627c577b8a1SJoseph Chan 			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
1628c577b8a1SJoseph Chan 				spec->dig_in_nid;
1629c577b8a1SJoseph Chan 		}
1630c577b8a1SJoseph Chan 	}
1631c577b8a1SJoseph Chan 
1632c577b8a1SJoseph Chan 	return 0;
1633c577b8a1SJoseph Chan }
1634c577b8a1SJoseph Chan 
1635c577b8a1SJoseph Chan static void via_free(struct hda_codec *codec)
1636c577b8a1SJoseph Chan {
1637c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
1638c577b8a1SJoseph Chan 
1639c577b8a1SJoseph Chan 	if (!spec)
1640c577b8a1SJoseph Chan 		return;
1641c577b8a1SJoseph Chan 
1642603c4019STakashi Iwai 	via_free_kctls(codec);
16431f2e99feSLydia Wang 	vt1708_stop_hp_work(spec);
1644c577b8a1SJoseph Chan 	kfree(codec->spec);
1645c577b8a1SJoseph Chan }
1646c577b8a1SJoseph Chan 
164769e52a80SHarald Welte /* mute internal speaker if HP is plugged */
164869e52a80SHarald Welte static void via_hp_automute(struct hda_codec *codec)
164969e52a80SHarald Welte {
1650dcf34c8cSLydia Wang 	unsigned int present = 0;
165169e52a80SHarald Welte 	struct via_spec *spec = codec->spec;
165269e52a80SHarald Welte 
1653d56757abSTakashi Iwai 	present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
1654dcf34c8cSLydia Wang 
1655dcf34c8cSLydia Wang 	if (!spec->hp_independent_mode) {
1656dcf34c8cSLydia Wang 		struct snd_ctl_elem_id id;
1657dcf34c8cSLydia Wang 		/* auto mute */
1658dcf34c8cSLydia Wang 		snd_hda_codec_amp_stereo(
1659dcf34c8cSLydia Wang 			codec, spec->autocfg.line_out_pins[0], HDA_OUTPUT, 0,
1660dcf34c8cSLydia Wang 			HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
1661dcf34c8cSLydia Wang 		/* notify change */
1662dcf34c8cSLydia Wang 		memset(&id, 0, sizeof(id));
1663dcf34c8cSLydia Wang 		id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1664dcf34c8cSLydia Wang 		strcpy(id.name, "Front Playback Switch");
1665dcf34c8cSLydia Wang 		snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
1666dcf34c8cSLydia Wang 			       &id);
1667dcf34c8cSLydia Wang 	}
166869e52a80SHarald Welte }
166969e52a80SHarald Welte 
1670f3db423dSLydia Wang /* mute mono out if HP or Line out is plugged */
1671f3db423dSLydia Wang static void via_mono_automute(struct hda_codec *codec)
1672f3db423dSLydia Wang {
1673f3db423dSLydia Wang 	unsigned int hp_present, lineout_present;
1674f3db423dSLydia Wang 	struct via_spec *spec = codec->spec;
1675f3db423dSLydia Wang 
1676f3db423dSLydia Wang 	if (spec->codec_type != VT1716S)
1677f3db423dSLydia Wang 		return;
1678f3db423dSLydia Wang 
1679d56757abSTakashi Iwai 	lineout_present = snd_hda_jack_detect(codec,
1680d56757abSTakashi Iwai 					      spec->autocfg.line_out_pins[0]);
1681f3db423dSLydia Wang 
1682f3db423dSLydia Wang 	/* Mute Mono Out if Line Out is plugged */
1683f3db423dSLydia Wang 	if (lineout_present) {
1684f3db423dSLydia Wang 		snd_hda_codec_amp_stereo(
1685f3db423dSLydia Wang 			codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE, HDA_AMP_MUTE);
1686f3db423dSLydia Wang 		return;
1687f3db423dSLydia Wang 	}
1688f3db423dSLydia Wang 
1689d56757abSTakashi Iwai 	hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
1690f3db423dSLydia Wang 
1691f3db423dSLydia Wang 	if (!spec->hp_independent_mode)
1692f3db423dSLydia Wang 		snd_hda_codec_amp_stereo(
1693f3db423dSLydia Wang 			codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE,
1694f3db423dSLydia Wang 			hp_present ? HDA_AMP_MUTE : 0);
1695f3db423dSLydia Wang }
1696f3db423dSLydia Wang 
169769e52a80SHarald Welte static void via_gpio_control(struct hda_codec *codec)
169869e52a80SHarald Welte {
169969e52a80SHarald Welte 	unsigned int gpio_data;
170069e52a80SHarald Welte 	unsigned int vol_counter;
170169e52a80SHarald Welte 	unsigned int vol;
170269e52a80SHarald Welte 	unsigned int master_vol;
170369e52a80SHarald Welte 
170469e52a80SHarald Welte 	struct via_spec *spec = codec->spec;
170569e52a80SHarald Welte 
170669e52a80SHarald Welte 	gpio_data = snd_hda_codec_read(codec, codec->afg, 0,
170769e52a80SHarald Welte 				       AC_VERB_GET_GPIO_DATA, 0) & 0x03;
170869e52a80SHarald Welte 
170969e52a80SHarald Welte 	vol_counter = (snd_hda_codec_read(codec, codec->afg, 0,
171069e52a80SHarald Welte 					  0xF84, 0) & 0x3F0000) >> 16;
171169e52a80SHarald Welte 
171269e52a80SHarald Welte 	vol = vol_counter & 0x1F;
171369e52a80SHarald Welte 	master_vol = snd_hda_codec_read(codec, 0x1A, 0,
171469e52a80SHarald Welte 					AC_VERB_GET_AMP_GAIN_MUTE,
171569e52a80SHarald Welte 					AC_AMP_GET_INPUT);
171669e52a80SHarald Welte 
171769e52a80SHarald Welte 	if (gpio_data == 0x02) {
171869e52a80SHarald Welte 		/* unmute line out */
171969e52a80SHarald Welte 		snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
172069e52a80SHarald Welte 					 HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
172169e52a80SHarald Welte 
172269e52a80SHarald Welte 		if (vol_counter & 0x20) {
172369e52a80SHarald Welte 			/* decrease volume */
172469e52a80SHarald Welte 			if (vol > master_vol)
172569e52a80SHarald Welte 				vol = master_vol;
172669e52a80SHarald Welte 			snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT,
172769e52a80SHarald Welte 						 0, HDA_AMP_VOLMASK,
172869e52a80SHarald Welte 						 master_vol-vol);
172969e52a80SHarald Welte 		} else {
173069e52a80SHarald Welte 			/* increase volume */
173169e52a80SHarald Welte 			snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, 0,
173269e52a80SHarald Welte 					 HDA_AMP_VOLMASK,
173369e52a80SHarald Welte 					 ((master_vol+vol) > 0x2A) ? 0x2A :
173469e52a80SHarald Welte 					  (master_vol+vol));
173569e52a80SHarald Welte 		}
173669e52a80SHarald Welte 	} else if (!(gpio_data & 0x02)) {
173769e52a80SHarald Welte 		/* mute line out */
173869e52a80SHarald Welte 		snd_hda_codec_amp_stereo(codec,
173969e52a80SHarald Welte 					 spec->autocfg.line_out_pins[0],
174069e52a80SHarald Welte 					 HDA_OUTPUT, 0, HDA_AMP_MUTE,
174169e52a80SHarald Welte 					 HDA_AMP_MUTE);
174269e52a80SHarald Welte 	}
174369e52a80SHarald Welte }
174469e52a80SHarald Welte 
174525eaba2fSLydia Wang /* mute Internal-Speaker if HP is plugged */
174625eaba2fSLydia Wang static void via_speaker_automute(struct hda_codec *codec)
174725eaba2fSLydia Wang {
174825eaba2fSLydia Wang 	unsigned int hp_present;
174925eaba2fSLydia Wang 	struct via_spec *spec = codec->spec;
175025eaba2fSLydia Wang 
175127439ce7SLydia Wang 	if (!VT2002P_COMPATIBLE(spec))
175225eaba2fSLydia Wang 		return;
175325eaba2fSLydia Wang 
1754d56757abSTakashi Iwai 	hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
175525eaba2fSLydia Wang 
175625eaba2fSLydia Wang 	if (!spec->hp_independent_mode) {
175725eaba2fSLydia Wang 		struct snd_ctl_elem_id id;
175825eaba2fSLydia Wang 		snd_hda_codec_amp_stereo(
175925eaba2fSLydia Wang 			codec, spec->autocfg.speaker_pins[0], HDA_OUTPUT, 0,
176025eaba2fSLydia Wang 			HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0);
176125eaba2fSLydia Wang 		/* notify change */
176225eaba2fSLydia Wang 		memset(&id, 0, sizeof(id));
176325eaba2fSLydia Wang 		id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
176425eaba2fSLydia Wang 		strcpy(id.name, "Speaker Playback Switch");
176525eaba2fSLydia Wang 		snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
176625eaba2fSLydia Wang 			       &id);
176725eaba2fSLydia Wang 	}
176825eaba2fSLydia Wang }
176925eaba2fSLydia Wang 
177025eaba2fSLydia Wang /* mute line-out and internal speaker if HP is plugged */
177125eaba2fSLydia Wang static void via_hp_bind_automute(struct hda_codec *codec)
177225eaba2fSLydia Wang {
177301a1796bSakpm@linux-foundation.org 	/* use long instead of int below just to avoid an internal compiler
177401a1796bSakpm@linux-foundation.org 	 * error with gcc 4.0.x
177501a1796bSakpm@linux-foundation.org 	 */
177601a1796bSakpm@linux-foundation.org 	unsigned long hp_present, present = 0;
177725eaba2fSLydia Wang 	struct via_spec *spec = codec->spec;
177825eaba2fSLydia Wang 	int i;
177925eaba2fSLydia Wang 
178025eaba2fSLydia Wang 	if (!spec->autocfg.hp_pins[0] || !spec->autocfg.line_out_pins[0])
178125eaba2fSLydia Wang 		return;
178225eaba2fSLydia Wang 
1783d56757abSTakashi Iwai 	hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
178425eaba2fSLydia Wang 
1785d56757abSTakashi Iwai 	present = snd_hda_jack_detect(codec, spec->autocfg.line_out_pins[0]);
178625eaba2fSLydia Wang 
178725eaba2fSLydia Wang 	if (!spec->hp_independent_mode) {
178825eaba2fSLydia Wang 		/* Mute Line-Outs */
178925eaba2fSLydia Wang 		for (i = 0; i < spec->autocfg.line_outs; i++)
179025eaba2fSLydia Wang 			snd_hda_codec_amp_stereo(
179125eaba2fSLydia Wang 				codec, spec->autocfg.line_out_pins[i],
179225eaba2fSLydia Wang 				HDA_OUTPUT, 0,
179325eaba2fSLydia Wang 				HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0);
179425eaba2fSLydia Wang 		if (hp_present)
179525eaba2fSLydia Wang 			present = hp_present;
179625eaba2fSLydia Wang 	}
179725eaba2fSLydia Wang 	/* Speakers */
179825eaba2fSLydia Wang 	for (i = 0; i < spec->autocfg.speaker_outs; i++)
179925eaba2fSLydia Wang 		snd_hda_codec_amp_stereo(
180025eaba2fSLydia Wang 			codec, spec->autocfg.speaker_pins[i], HDA_OUTPUT, 0,
180125eaba2fSLydia Wang 			HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
180225eaba2fSLydia Wang }
180325eaba2fSLydia Wang 
180425eaba2fSLydia Wang 
180569e52a80SHarald Welte /* unsolicited event for jack sensing */
180669e52a80SHarald Welte static void via_unsol_event(struct hda_codec *codec,
180769e52a80SHarald Welte 				  unsigned int res)
180869e52a80SHarald Welte {
180969e52a80SHarald Welte 	res >>= 26;
1810ec7e7e42SLydia Wang 
1811a34df19aSLydia Wang 	if (res & VIA_JACK_EVENT)
18123e95b9abSLydia Wang 		set_widgets_power_state(codec);
1813ec7e7e42SLydia Wang 
1814ec7e7e42SLydia Wang 	res &= ~VIA_JACK_EVENT;
1815ec7e7e42SLydia Wang 
1816ec7e7e42SLydia Wang 	if (res == VIA_HP_EVENT)
1817ec7e7e42SLydia Wang 		via_hp_automute(codec);
1818ec7e7e42SLydia Wang 	else if (res == VIA_GPIO_EVENT)
1819ec7e7e42SLydia Wang 		via_gpio_control(codec);
1820ec7e7e42SLydia Wang 	else if (res == VIA_MONO_EVENT)
1821f3db423dSLydia Wang 		via_mono_automute(codec);
1822ec7e7e42SLydia Wang 	else if (res == VIA_SPEAKER_EVENT)
182325eaba2fSLydia Wang 		via_speaker_automute(codec);
1824ec7e7e42SLydia Wang 	else if (res == VIA_BIND_HP_EVENT)
182525eaba2fSLydia Wang 		via_hp_bind_automute(codec);
182669e52a80SHarald Welte }
182769e52a80SHarald Welte 
1828c577b8a1SJoseph Chan static int via_init(struct hda_codec *codec)
1829c577b8a1SJoseph Chan {
1830c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
183169e52a80SHarald Welte 	int i;
183269e52a80SHarald Welte 	for (i = 0; i < spec->num_iverbs; i++)
183369e52a80SHarald Welte 		snd_hda_sequence_write(codec, spec->init_verbs[i]);
183469e52a80SHarald Welte 
1835f7278fd0SJosepch Chan 	/* Lydia Add for EAPD enable */
1836f7278fd0SJosepch Chan 	if (!spec->dig_in_nid) { /* No Digital In connection */
183755d1d6c1STakashi Iwai 		if (spec->dig_in_pin) {
183855d1d6c1STakashi Iwai 			snd_hda_codec_write(codec, spec->dig_in_pin, 0,
1839f7278fd0SJosepch Chan 					    AC_VERB_SET_PIN_WIDGET_CONTROL,
184012b74c80STakashi Iwai 					    PIN_OUT);
184155d1d6c1STakashi Iwai 			snd_hda_codec_write(codec, spec->dig_in_pin, 0,
1842f7278fd0SJosepch Chan 					    AC_VERB_SET_EAPD_BTLENABLE, 0x02);
1843f7278fd0SJosepch Chan 		}
184412b74c80STakashi Iwai 	} else /* enable SPDIF-input pin */
184512b74c80STakashi Iwai 		snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
184612b74c80STakashi Iwai 				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
1847f7278fd0SJosepch Chan 
18489da29271STakashi Iwai 	/* assign slave outs */
18499da29271STakashi Iwai 	if (spec->slave_dig_outs[0])
18509da29271STakashi Iwai 		codec->slave_dig_outs = spec->slave_dig_outs;
18515691ec7fSHarald Welte 
1852c577b8a1SJoseph Chan 	return 0;
1853c577b8a1SJoseph Chan }
1854c577b8a1SJoseph Chan 
18551f2e99feSLydia Wang #ifdef SND_HDA_NEEDS_RESUME
18561f2e99feSLydia Wang static int via_suspend(struct hda_codec *codec, pm_message_t state)
18571f2e99feSLydia Wang {
18581f2e99feSLydia Wang 	struct via_spec *spec = codec->spec;
18591f2e99feSLydia Wang 	vt1708_stop_hp_work(spec);
18601f2e99feSLydia Wang 	return 0;
18611f2e99feSLydia Wang }
18621f2e99feSLydia Wang #endif
18631f2e99feSLydia Wang 
1864cb53c626STakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE
1865cb53c626STakashi Iwai static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
1866cb53c626STakashi Iwai {
1867cb53c626STakashi Iwai 	struct via_spec *spec = codec->spec;
1868cb53c626STakashi Iwai 	return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
1869cb53c626STakashi Iwai }
1870cb53c626STakashi Iwai #endif
1871cb53c626STakashi Iwai 
1872c577b8a1SJoseph Chan /*
1873c577b8a1SJoseph Chan  */
187490dd48a1STakashi Iwai static const struct hda_codec_ops via_patch_ops = {
1875c577b8a1SJoseph Chan 	.build_controls = via_build_controls,
1876c577b8a1SJoseph Chan 	.build_pcms = via_build_pcms,
1877c577b8a1SJoseph Chan 	.init = via_init,
1878c577b8a1SJoseph Chan 	.free = via_free,
18791f2e99feSLydia Wang #ifdef SND_HDA_NEEDS_RESUME
18801f2e99feSLydia Wang 	.suspend = via_suspend,
18811f2e99feSLydia Wang #endif
1882cb53c626STakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE
1883cb53c626STakashi Iwai 	.check_power_status = via_check_power_status,
1884cb53c626STakashi Iwai #endif
1885c577b8a1SJoseph Chan };
1886c577b8a1SJoseph Chan 
1887c577b8a1SJoseph Chan /* fill in the dac_nids table from the parsed pin configuration */
1888c577b8a1SJoseph Chan static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
1889c577b8a1SJoseph Chan 				     const struct auto_pin_cfg *cfg)
1890c577b8a1SJoseph Chan {
1891c577b8a1SJoseph Chan 	int i;
1892c577b8a1SJoseph Chan 	hda_nid_t nid;
1893c577b8a1SJoseph Chan 
1894c577b8a1SJoseph Chan 	spec->multiout.num_dacs = cfg->line_outs;
1895c577b8a1SJoseph Chan 
1896c577b8a1SJoseph Chan 	spec->multiout.dac_nids = spec->private_dac_nids;
1897c577b8a1SJoseph Chan 
1898c577b8a1SJoseph Chan 	for (i = 0; i < 4; i++) {
1899c577b8a1SJoseph Chan 		nid = cfg->line_out_pins[i];
1900c577b8a1SJoseph Chan 		if (nid) {
1901c577b8a1SJoseph Chan 			/* config dac list */
1902c577b8a1SJoseph Chan 			switch (i) {
1903c577b8a1SJoseph Chan 			case AUTO_SEQ_FRONT:
1904dda14410STakashi Iwai 				spec->private_dac_nids[i] = 0x10;
1905c577b8a1SJoseph Chan 				break;
1906c577b8a1SJoseph Chan 			case AUTO_SEQ_CENLFE:
1907dda14410STakashi Iwai 				spec->private_dac_nids[i] = 0x12;
1908c577b8a1SJoseph Chan 				break;
1909c577b8a1SJoseph Chan 			case AUTO_SEQ_SURROUND:
1910dda14410STakashi Iwai 				spec->private_dac_nids[i] = 0x11;
1911c577b8a1SJoseph Chan 				break;
1912c577b8a1SJoseph Chan 			case AUTO_SEQ_SIDE:
1913dda14410STakashi Iwai 				spec->private_dac_nids[i] = 0x13;
1914c577b8a1SJoseph Chan 				break;
1915c577b8a1SJoseph Chan 			}
1916c577b8a1SJoseph Chan 		}
1917c577b8a1SJoseph Chan 	}
1918c577b8a1SJoseph Chan 
1919c577b8a1SJoseph Chan 	return 0;
1920c577b8a1SJoseph Chan }
1921c577b8a1SJoseph Chan 
1922c577b8a1SJoseph Chan /* add playback controls from the parsed DAC table */
1923c577b8a1SJoseph Chan static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
1924c577b8a1SJoseph Chan 					     const struct auto_pin_cfg *cfg)
1925c577b8a1SJoseph Chan {
1926c577b8a1SJoseph Chan 	char name[32];
1927ea734963STakashi Iwai 	static const char * const chname[4] = {
1928ea734963STakashi Iwai 		"Front", "Surround", "C/LFE", "Side"
1929ea734963STakashi Iwai 	};
19309645c203SLydia Wang 	hda_nid_t nid, nid_vol, nid_vols[] = {0x17, 0x19, 0x1a, 0x1b};
1931c577b8a1SJoseph Chan 	int i, err;
1932c577b8a1SJoseph Chan 
1933c577b8a1SJoseph Chan 	for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1934c577b8a1SJoseph Chan 		nid = cfg->line_out_pins[i];
1935c577b8a1SJoseph Chan 
1936c577b8a1SJoseph Chan 		if (!nid)
1937c577b8a1SJoseph Chan 			continue;
1938c577b8a1SJoseph Chan 
19399645c203SLydia Wang 		nid_vol = nid_vols[i];
1940c577b8a1SJoseph Chan 
1941c577b8a1SJoseph Chan 		if (i == AUTO_SEQ_CENLFE) {
1942c577b8a1SJoseph Chan 			/* Center/LFE */
1943c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1944c577b8a1SJoseph Chan 					"Center Playback Volume",
1945f7278fd0SJosepch Chan 					HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1946f7278fd0SJosepch Chan 							    HDA_OUTPUT));
1947c577b8a1SJoseph Chan 			if (err < 0)
1948c577b8a1SJoseph Chan 				return err;
1949c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1950c577b8a1SJoseph Chan 					      "LFE Playback Volume",
1951f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1952f7278fd0SJosepch Chan 								  HDA_OUTPUT));
1953c577b8a1SJoseph Chan 			if (err < 0)
1954c577b8a1SJoseph Chan 				return err;
1955c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1956c577b8a1SJoseph Chan 					      "Center Playback Switch",
1957f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1958f7278fd0SJosepch Chan 								  HDA_OUTPUT));
1959c577b8a1SJoseph Chan 			if (err < 0)
1960c577b8a1SJoseph Chan 				return err;
1961c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1962c577b8a1SJoseph Chan 					      "LFE Playback Switch",
1963f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1964f7278fd0SJosepch Chan 								  HDA_OUTPUT));
1965c577b8a1SJoseph Chan 			if (err < 0)
1966c577b8a1SJoseph Chan 				return err;
1967c577b8a1SJoseph Chan 		} else if (i == AUTO_SEQ_FRONT) {
1968c577b8a1SJoseph Chan 			/* add control to mixer index 0 */
1969c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1970c577b8a1SJoseph Chan 					      "Master Front Playback Volume",
19719645c203SLydia Wang 					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1972f7278fd0SJosepch Chan 								  HDA_INPUT));
1973c577b8a1SJoseph Chan 			if (err < 0)
1974c577b8a1SJoseph Chan 				return err;
1975c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1976c577b8a1SJoseph Chan 					      "Master Front Playback Switch",
19779645c203SLydia Wang 					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1978f7278fd0SJosepch Chan 								  HDA_INPUT));
1979c577b8a1SJoseph Chan 			if (err < 0)
1980c577b8a1SJoseph Chan 				return err;
1981c577b8a1SJoseph Chan 
1982c577b8a1SJoseph Chan 			/* add control to PW3 */
1983c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Volume", chname[i]);
1984c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1985f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1986f7278fd0SJosepch Chan 								  HDA_OUTPUT));
1987c577b8a1SJoseph Chan 			if (err < 0)
1988c577b8a1SJoseph Chan 				return err;
1989c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Switch", chname[i]);
1990c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1991f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1992f7278fd0SJosepch Chan 								  HDA_OUTPUT));
1993c577b8a1SJoseph Chan 			if (err < 0)
1994c577b8a1SJoseph Chan 				return err;
1995c577b8a1SJoseph Chan 		} else {
1996c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Volume", chname[i]);
1997c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1998f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1999f7278fd0SJosepch Chan 								  HDA_OUTPUT));
2000c577b8a1SJoseph Chan 			if (err < 0)
2001c577b8a1SJoseph Chan 				return err;
2002c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Switch", chname[i]);
2003c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2004f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2005f7278fd0SJosepch Chan 								  HDA_OUTPUT));
2006c577b8a1SJoseph Chan 			if (err < 0)
2007c577b8a1SJoseph Chan 				return err;
2008c577b8a1SJoseph Chan 		}
2009c577b8a1SJoseph Chan 	}
2010c577b8a1SJoseph Chan 
2011c577b8a1SJoseph Chan 	return 0;
2012c577b8a1SJoseph Chan }
2013c577b8a1SJoseph Chan 
20140aa62aefSHarald Welte static void create_hp_imux(struct via_spec *spec)
20150aa62aefSHarald Welte {
20160aa62aefSHarald Welte 	int i;
20170aa62aefSHarald Welte 	struct hda_input_mux *imux = &spec->private_imux[1];
2018ea734963STakashi Iwai 	static const char * const texts[] = { "OFF", "ON", NULL};
20190aa62aefSHarald Welte 
20200aa62aefSHarald Welte 	/* for hp mode select */
202110a20af7STakashi Iwai 	for (i = 0; texts[i]; i++)
202210a20af7STakashi Iwai 		snd_hda_add_imux_item(imux, texts[i], i, NULL);
20230aa62aefSHarald Welte 
20240aa62aefSHarald Welte 	spec->hp_mux = &spec->private_imux[1];
20250aa62aefSHarald Welte }
20260aa62aefSHarald Welte 
2027c577b8a1SJoseph Chan static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2028c577b8a1SJoseph Chan {
2029c577b8a1SJoseph Chan 	int err;
2030c577b8a1SJoseph Chan 
2031c577b8a1SJoseph Chan 	if (!pin)
2032c577b8a1SJoseph Chan 		return 0;
2033c577b8a1SJoseph Chan 
2034c577b8a1SJoseph Chan 	spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
2035cdc1784dSLydia Wang 	spec->hp_independent_mode_index = 1;
2036c577b8a1SJoseph Chan 
2037c577b8a1SJoseph Chan 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2038c577b8a1SJoseph Chan 			      "Headphone Playback Volume",
2039c577b8a1SJoseph Chan 			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2040c577b8a1SJoseph Chan 	if (err < 0)
2041c577b8a1SJoseph Chan 		return err;
2042c577b8a1SJoseph Chan 	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2043c577b8a1SJoseph Chan 			      "Headphone Playback Switch",
2044c577b8a1SJoseph Chan 			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2045c577b8a1SJoseph Chan 	if (err < 0)
2046c577b8a1SJoseph Chan 		return err;
2047c577b8a1SJoseph Chan 
20480aa62aefSHarald Welte 	create_hp_imux(spec);
20490aa62aefSHarald Welte 
2050c577b8a1SJoseph Chan 	return 0;
2051c577b8a1SJoseph Chan }
2052c577b8a1SJoseph Chan 
2053c577b8a1SJoseph Chan /* create playback/capture controls for input pins */
205410a20af7STakashi Iwai static int vt_auto_create_analog_input_ctls(struct hda_codec *codec,
2055f3268512STakashi Iwai 					    const struct auto_pin_cfg *cfg,
2056f3268512STakashi Iwai 					    hda_nid_t cap_nid,
205790dd48a1STakashi Iwai 					    const hda_nid_t pin_idxs[],
205890dd48a1STakashi Iwai 					    int num_idxs)
2059c577b8a1SJoseph Chan {
206010a20af7STakashi Iwai 	struct via_spec *spec = codec->spec;
20610aa62aefSHarald Welte 	struct hda_input_mux *imux = &spec->private_imux[0];
20627b315bb4STakashi Iwai 	int i, err, idx, type, type_idx = 0;
2063c577b8a1SJoseph Chan 
2064c577b8a1SJoseph Chan 	/* for internal loopback recording select */
2065f3268512STakashi Iwai 	for (idx = 0; idx < num_idxs; idx++) {
2066f3268512STakashi Iwai 		if (pin_idxs[idx] == 0xff) {
206710a20af7STakashi Iwai 			snd_hda_add_imux_item(imux, "Stereo Mixer", idx, NULL);
2068f3268512STakashi Iwai 			break;
2069f3268512STakashi Iwai 		}
2070f3268512STakashi Iwai 	}
2071c577b8a1SJoseph Chan 
20727b315bb4STakashi Iwai 	for (i = 0; i < cfg->num_inputs; i++) {
207310a20af7STakashi Iwai 		const char *label;
20747b315bb4STakashi Iwai 		type = cfg->inputs[i].type;
2075f3268512STakashi Iwai 		for (idx = 0; idx < num_idxs; idx++)
20767b315bb4STakashi Iwai 			if (pin_idxs[idx] == cfg->inputs[i].pin)
2077c577b8a1SJoseph Chan 				break;
2078f3268512STakashi Iwai 		if (idx >= num_idxs)
2079f3268512STakashi Iwai 			continue;
20807b315bb4STakashi Iwai 		if (i > 0 && type == cfg->inputs[i - 1].type)
20817b315bb4STakashi Iwai 			type_idx++;
20827b315bb4STakashi Iwai 		else
20837b315bb4STakashi Iwai 			type_idx = 0;
208410a20af7STakashi Iwai 		label = hda_get_autocfg_input_label(codec, cfg, i);
208516922281SLydia Wang 		if (spec->codec_type == VT1708S ||
208616922281SLydia Wang 		    spec->codec_type == VT1702 ||
208716922281SLydia Wang 		    spec->codec_type == VT1716S)
208816922281SLydia Wang 			err = via_new_analog_input(spec, label, type_idx,
208916922281SLydia Wang 						   idx+1, cap_nid);
209016922281SLydia Wang 		else
209116922281SLydia Wang 			err = via_new_analog_input(spec, label, type_idx,
209216922281SLydia Wang 						   idx, cap_nid);
2093c577b8a1SJoseph Chan 		if (err < 0)
2094c577b8a1SJoseph Chan 			return err;
209510a20af7STakashi Iwai 		snd_hda_add_imux_item(imux, label, idx, NULL);
2096c577b8a1SJoseph Chan 	}
2097c577b8a1SJoseph Chan 	return 0;
2098c577b8a1SJoseph Chan }
2099c577b8a1SJoseph Chan 
2100f3268512STakashi Iwai /* create playback/capture controls for input pins */
210110a20af7STakashi Iwai static int vt1708_auto_create_analog_input_ctls(struct hda_codec *codec,
2102f3268512STakashi Iwai 						const struct auto_pin_cfg *cfg)
2103f3268512STakashi Iwai {
210490dd48a1STakashi Iwai 	static const hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 };
210510a20af7STakashi Iwai 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x17, pin_idxs,
2106f3268512STakashi Iwai 						ARRAY_SIZE(pin_idxs));
2107f3268512STakashi Iwai }
2108f3268512STakashi Iwai 
2109cb53c626STakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE
211090dd48a1STakashi Iwai static const struct hda_amp_list vt1708_loopbacks[] = {
2111cb53c626STakashi Iwai 	{ 0x17, HDA_INPUT, 1 },
2112cb53c626STakashi Iwai 	{ 0x17, HDA_INPUT, 2 },
2113cb53c626STakashi Iwai 	{ 0x17, HDA_INPUT, 3 },
2114cb53c626STakashi Iwai 	{ 0x17, HDA_INPUT, 4 },
2115cb53c626STakashi Iwai 	{ } /* end */
2116cb53c626STakashi Iwai };
2117cb53c626STakashi Iwai #endif
2118cb53c626STakashi Iwai 
211976d9b0ddSHarald Welte static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
212076d9b0ddSHarald Welte {
212176d9b0ddSHarald Welte 	unsigned int def_conf;
212276d9b0ddSHarald Welte 	unsigned char seqassoc;
212376d9b0ddSHarald Welte 
21242f334f92STakashi Iwai 	def_conf = snd_hda_codec_get_pincfg(codec, nid);
212576d9b0ddSHarald Welte 	seqassoc = (unsigned char) get_defcfg_association(def_conf);
212676d9b0ddSHarald Welte 	seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
212782ef9e45SLydia Wang 	if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE
212882ef9e45SLydia Wang 	    && (seqassoc == 0xf0 || seqassoc == 0xff)) {
212976d9b0ddSHarald Welte 		def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
21302f334f92STakashi Iwai 		snd_hda_codec_set_pincfg(codec, nid, def_conf);
213176d9b0ddSHarald Welte 	}
213276d9b0ddSHarald Welte 
213376d9b0ddSHarald Welte 	return;
213476d9b0ddSHarald Welte }
213576d9b0ddSHarald Welte 
21361f2e99feSLydia Wang static int vt1708_jack_detectect_get(struct snd_kcontrol *kcontrol,
21371f2e99feSLydia Wang 				     struct snd_ctl_elem_value *ucontrol)
21381f2e99feSLydia Wang {
21391f2e99feSLydia Wang 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
21401f2e99feSLydia Wang 	struct via_spec *spec = codec->spec;
21411f2e99feSLydia Wang 
21421f2e99feSLydia Wang 	if (spec->codec_type != VT1708)
21431f2e99feSLydia Wang 		return 0;
21441f2e99feSLydia Wang 	spec->vt1708_jack_detectect =
21451f2e99feSLydia Wang 		!((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1);
21461f2e99feSLydia Wang 	ucontrol->value.integer.value[0] = spec->vt1708_jack_detectect;
21471f2e99feSLydia Wang 	return 0;
21481f2e99feSLydia Wang }
21491f2e99feSLydia Wang 
21501f2e99feSLydia Wang static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol,
21511f2e99feSLydia Wang 				     struct snd_ctl_elem_value *ucontrol)
21521f2e99feSLydia Wang {
21531f2e99feSLydia Wang 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
21541f2e99feSLydia Wang 	struct via_spec *spec = codec->spec;
21551f2e99feSLydia Wang 	int change;
21561f2e99feSLydia Wang 
21571f2e99feSLydia Wang 	if (spec->codec_type != VT1708)
21581f2e99feSLydia Wang 		return 0;
21591f2e99feSLydia Wang 	spec->vt1708_jack_detectect = ucontrol->value.integer.value[0];
21601f2e99feSLydia Wang 	change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8))
21611f2e99feSLydia Wang 		== !spec->vt1708_jack_detectect;
21621f2e99feSLydia Wang 	if (spec->vt1708_jack_detectect) {
21631f2e99feSLydia Wang 		mute_aa_path(codec, 1);
21641f2e99feSLydia Wang 		notify_aa_path_ctls(codec);
21651f2e99feSLydia Wang 	}
21661f2e99feSLydia Wang 	return change;
21671f2e99feSLydia Wang }
21681f2e99feSLydia Wang 
216990dd48a1STakashi Iwai static const struct snd_kcontrol_new vt1708_jack_detectect[] = {
21701f2e99feSLydia Wang 	{
21711f2e99feSLydia Wang 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
21721f2e99feSLydia Wang 		.name = "Jack Detect",
21731f2e99feSLydia Wang 		.count = 1,
21741f2e99feSLydia Wang 		.info = snd_ctl_boolean_mono_info,
21751f2e99feSLydia Wang 		.get = vt1708_jack_detectect_get,
21761f2e99feSLydia Wang 		.put = vt1708_jack_detectect_put,
21771f2e99feSLydia Wang 	},
21781f2e99feSLydia Wang 	{} /* end */
21791f2e99feSLydia Wang };
21801f2e99feSLydia Wang 
2181c577b8a1SJoseph Chan static int vt1708_parse_auto_config(struct hda_codec *codec)
2182c577b8a1SJoseph Chan {
2183c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
2184c577b8a1SJoseph Chan 	int err;
2185c577b8a1SJoseph Chan 
218676d9b0ddSHarald Welte 	/* Add HP and CD pin config connect bit re-config action */
218776d9b0ddSHarald Welte 	vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
218876d9b0ddSHarald Welte 	vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
218976d9b0ddSHarald Welte 
2190c577b8a1SJoseph Chan 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
2191c577b8a1SJoseph Chan 	if (err < 0)
2192c577b8a1SJoseph Chan 		return err;
2193c577b8a1SJoseph Chan 	err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
2194c577b8a1SJoseph Chan 	if (err < 0)
2195c577b8a1SJoseph Chan 		return err;
2196c577b8a1SJoseph Chan 	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2197c577b8a1SJoseph Chan 		return 0; /* can't find valid BIOS pin config */
2198c577b8a1SJoseph Chan 
2199c577b8a1SJoseph Chan 	err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
2200c577b8a1SJoseph Chan 	if (err < 0)
2201c577b8a1SJoseph Chan 		return err;
2202c577b8a1SJoseph Chan 	err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2203c577b8a1SJoseph Chan 	if (err < 0)
2204c577b8a1SJoseph Chan 		return err;
220510a20af7STakashi Iwai 	err = vt1708_auto_create_analog_input_ctls(codec, &spec->autocfg);
2206c577b8a1SJoseph Chan 	if (err < 0)
2207c577b8a1SJoseph Chan 		return err;
22081f2e99feSLydia Wang 	/* add jack detect on/off control */
22091f2e99feSLydia Wang 	err = snd_hda_add_new_ctls(codec, vt1708_jack_detectect);
22101f2e99feSLydia Wang 	if (err < 0)
22111f2e99feSLydia Wang 		return err;
2212c577b8a1SJoseph Chan 
2213c577b8a1SJoseph Chan 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2214c577b8a1SJoseph Chan 
22150852d7a6STakashi Iwai 	if (spec->autocfg.dig_outs)
2216c577b8a1SJoseph Chan 		spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
221755d1d6c1STakashi Iwai 	spec->dig_in_pin = VT1708_DIGIN_PIN;
2218c577b8a1SJoseph Chan 	if (spec->autocfg.dig_in_pin)
2219c577b8a1SJoseph Chan 		spec->dig_in_nid = VT1708_DIGIN_NID;
2220c577b8a1SJoseph Chan 
2221603c4019STakashi Iwai 	if (spec->kctls.list)
2222603c4019STakashi Iwai 		spec->mixers[spec->num_mixers++] = spec->kctls.list;
2223c577b8a1SJoseph Chan 
222469e52a80SHarald Welte 	spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
2225c577b8a1SJoseph Chan 
22260aa62aefSHarald Welte 	spec->input_mux = &spec->private_imux[0];
22270aa62aefSHarald Welte 
2228f8fdd495SHarald Welte 	if (spec->hp_mux)
22293d83e577STakashi Iwai 		via_hp_build(codec);
2230c577b8a1SJoseph Chan 
22315b0cb1d8SJaroslav Kysela 	via_smart51_build(spec);
2232c577b8a1SJoseph Chan 	return 1;
2233c577b8a1SJoseph Chan }
2234c577b8a1SJoseph Chan 
2235c577b8a1SJoseph Chan /* init callback for auto-configuration model -- overriding the default init */
2236c577b8a1SJoseph Chan static int via_auto_init(struct hda_codec *codec)
2237c577b8a1SJoseph Chan {
223825eaba2fSLydia Wang 	struct via_spec *spec = codec->spec;
223925eaba2fSLydia Wang 
2240c577b8a1SJoseph Chan 	via_init(codec);
2241c577b8a1SJoseph Chan 	via_auto_init_multi_out(codec);
2242c577b8a1SJoseph Chan 	via_auto_init_hp_out(codec);
2243c577b8a1SJoseph Chan 	via_auto_init_analog_input(codec);
224411890956SLydia Wang 
224511890956SLydia Wang 	if (VT2002P_COMPATIBLE(spec)) {
224625eaba2fSLydia Wang 		via_hp_bind_automute(codec);
224725eaba2fSLydia Wang 	} else {
224825eaba2fSLydia Wang 		via_hp_automute(codec);
224925eaba2fSLydia Wang 		via_speaker_automute(codec);
225025eaba2fSLydia Wang 	}
225125eaba2fSLydia Wang 
2252c577b8a1SJoseph Chan 	return 0;
2253c577b8a1SJoseph Chan }
2254c577b8a1SJoseph Chan 
22551f2e99feSLydia Wang static void vt1708_update_hp_jack_state(struct work_struct *work)
22561f2e99feSLydia Wang {
22571f2e99feSLydia Wang 	struct via_spec *spec = container_of(work, struct via_spec,
22581f2e99feSLydia Wang 					     vt1708_hp_work.work);
22591f2e99feSLydia Wang 	if (spec->codec_type != VT1708)
22601f2e99feSLydia Wang 		return;
22611f2e99feSLydia Wang 	/* if jack state toggled */
22621f2e99feSLydia Wang 	if (spec->vt1708_hp_present
2263d56757abSTakashi Iwai 	    != snd_hda_jack_detect(spec->codec, spec->autocfg.hp_pins[0])) {
22641f2e99feSLydia Wang 		spec->vt1708_hp_present ^= 1;
22651f2e99feSLydia Wang 		via_hp_automute(spec->codec);
22661f2e99feSLydia Wang 	}
22671f2e99feSLydia Wang 	vt1708_start_hp_work(spec);
22681f2e99feSLydia Wang }
22691f2e99feSLydia Wang 
2270337b9d02STakashi Iwai static int get_mux_nids(struct hda_codec *codec)
2271337b9d02STakashi Iwai {
2272337b9d02STakashi Iwai 	struct via_spec *spec = codec->spec;
2273337b9d02STakashi Iwai 	hda_nid_t nid, conn[8];
2274337b9d02STakashi Iwai 	unsigned int type;
2275337b9d02STakashi Iwai 	int i, n;
2276337b9d02STakashi Iwai 
2277337b9d02STakashi Iwai 	for (i = 0; i < spec->num_adc_nids; i++) {
2278337b9d02STakashi Iwai 		nid = spec->adc_nids[i];
2279337b9d02STakashi Iwai 		while (nid) {
2280a22d543aSTakashi Iwai 			type = get_wcaps_type(get_wcaps(codec, nid));
22811c55d521STakashi Iwai 			if (type == AC_WID_PIN)
22821c55d521STakashi Iwai 				break;
2283337b9d02STakashi Iwai 			n = snd_hda_get_connections(codec, nid, conn,
2284337b9d02STakashi Iwai 						    ARRAY_SIZE(conn));
2285337b9d02STakashi Iwai 			if (n <= 0)
2286337b9d02STakashi Iwai 				break;
2287337b9d02STakashi Iwai 			if (n > 1) {
2288337b9d02STakashi Iwai 				spec->mux_nids[i] = nid;
2289337b9d02STakashi Iwai 				break;
2290337b9d02STakashi Iwai 			}
2291337b9d02STakashi Iwai 			nid = conn[0];
2292337b9d02STakashi Iwai 		}
2293337b9d02STakashi Iwai 	}
22941c55d521STakashi Iwai 	return 0;
2295337b9d02STakashi Iwai }
2296337b9d02STakashi Iwai 
2297c577b8a1SJoseph Chan static int patch_vt1708(struct hda_codec *codec)
2298c577b8a1SJoseph Chan {
2299c577b8a1SJoseph Chan 	struct via_spec *spec;
2300c577b8a1SJoseph Chan 	int err;
2301c577b8a1SJoseph Chan 
2302c577b8a1SJoseph Chan 	/* create a codec specific record */
23035b0cb1d8SJaroslav Kysela 	spec = via_new_spec(codec);
2304c577b8a1SJoseph Chan 	if (spec == NULL)
2305c577b8a1SJoseph Chan 		return -ENOMEM;
2306c577b8a1SJoseph Chan 
2307c577b8a1SJoseph Chan 	/* automatic parse from the BIOS config */
2308c577b8a1SJoseph Chan 	err = vt1708_parse_auto_config(codec);
2309c577b8a1SJoseph Chan 	if (err < 0) {
2310c577b8a1SJoseph Chan 		via_free(codec);
2311c577b8a1SJoseph Chan 		return err;
2312c577b8a1SJoseph Chan 	} else if (!err) {
2313c577b8a1SJoseph Chan 		printk(KERN_INFO "hda_codec: Cannot set up configuration "
2314c577b8a1SJoseph Chan 		       "from BIOS.  Using genenic mode...\n");
2315c577b8a1SJoseph Chan 	}
2316c577b8a1SJoseph Chan 
2317c577b8a1SJoseph Chan 
2318c577b8a1SJoseph Chan 	spec->stream_name_analog = "VT1708 Analog";
2319c577b8a1SJoseph Chan 	spec->stream_analog_playback = &vt1708_pcm_analog_playback;
2320bc9b5623STakashi Iwai 	/* disable 32bit format on VT1708 */
2321bc9b5623STakashi Iwai 	if (codec->vendor_id == 0x11061708)
2322bc9b5623STakashi Iwai 		spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback;
2323c577b8a1SJoseph Chan 	spec->stream_analog_capture = &vt1708_pcm_analog_capture;
2324c577b8a1SJoseph Chan 
2325c577b8a1SJoseph Chan 	spec->stream_name_digital = "VT1708 Digital";
2326c577b8a1SJoseph Chan 	spec->stream_digital_playback = &vt1708_pcm_digital_playback;
2327c577b8a1SJoseph Chan 	spec->stream_digital_capture = &vt1708_pcm_digital_capture;
2328c577b8a1SJoseph Chan 
2329c577b8a1SJoseph Chan 
2330c577b8a1SJoseph Chan 	if (!spec->adc_nids && spec->input_mux) {
2331c577b8a1SJoseph Chan 		spec->adc_nids = vt1708_adc_nids;
2332c577b8a1SJoseph Chan 		spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
23330f67a611STakashi Iwai 		get_mux_nids(codec);
2334c577b8a1SJoseph Chan 		spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
2335c577b8a1SJoseph Chan 		spec->num_mixers++;
2336c577b8a1SJoseph Chan 	}
2337c577b8a1SJoseph Chan 
2338c577b8a1SJoseph Chan 	codec->patch_ops = via_patch_ops;
2339c577b8a1SJoseph Chan 
2340c577b8a1SJoseph Chan 	codec->patch_ops.init = via_auto_init;
2341cb53c626STakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE
2342cb53c626STakashi Iwai 	spec->loopback.amplist = vt1708_loopbacks;
2343cb53c626STakashi Iwai #endif
23441f2e99feSLydia Wang 	INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state);
2345c577b8a1SJoseph Chan 	return 0;
2346c577b8a1SJoseph Chan }
2347c577b8a1SJoseph Chan 
2348c577b8a1SJoseph Chan /* capture mixer elements */
234990dd48a1STakashi Iwai static const struct snd_kcontrol_new vt1709_capture_mixer[] = {
2350c577b8a1SJoseph Chan 	HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
2351c577b8a1SJoseph Chan 	HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
2352c577b8a1SJoseph Chan 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
2353c577b8a1SJoseph Chan 	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
2354c577b8a1SJoseph Chan 	HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
2355c577b8a1SJoseph Chan 	HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
2356c577b8a1SJoseph Chan 	{
2357c577b8a1SJoseph Chan 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2358c577b8a1SJoseph Chan 		/* The multiple "Capture Source" controls confuse alsamixer
2359c577b8a1SJoseph Chan 		 * So call somewhat different..
2360c577b8a1SJoseph Chan 		 */
2361c577b8a1SJoseph Chan 		/* .name = "Capture Source", */
2362c577b8a1SJoseph Chan 		.name = "Input Source",
2363c577b8a1SJoseph Chan 		.count = 1,
2364c577b8a1SJoseph Chan 		.info = via_mux_enum_info,
2365c577b8a1SJoseph Chan 		.get = via_mux_enum_get,
2366c577b8a1SJoseph Chan 		.put = via_mux_enum_put,
2367c577b8a1SJoseph Chan 	},
2368c577b8a1SJoseph Chan 	{ } /* end */
2369c577b8a1SJoseph Chan };
2370c577b8a1SJoseph Chan 
237190dd48a1STakashi Iwai static const struct hda_verb vt1709_uniwill_init_verbs[] = {
2372a34df19aSLydia Wang 	{0x20, AC_VERB_SET_UNSOLICITED_ENABLE,
2373a34df19aSLydia Wang 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
237469e52a80SHarald Welte 	{ }
237569e52a80SHarald Welte };
237669e52a80SHarald Welte 
2377c577b8a1SJoseph Chan /*
2378c577b8a1SJoseph Chan  * generic initialization of ADC, input mixers and output mixers
2379c577b8a1SJoseph Chan  */
238090dd48a1STakashi Iwai static const struct hda_verb vt1709_10ch_volume_init_verbs[] = {
2381c577b8a1SJoseph Chan 	/*
2382c577b8a1SJoseph Chan 	 * Unmute ADC0-2 and set the default input to mic-in
2383c577b8a1SJoseph Chan 	 */
2384c577b8a1SJoseph Chan 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2385c577b8a1SJoseph Chan 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2386c577b8a1SJoseph Chan 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2387c577b8a1SJoseph Chan 
2388c577b8a1SJoseph Chan 
2389f7278fd0SJosepch Chan 	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2390c577b8a1SJoseph Chan 	 * mixer widget
2391c577b8a1SJoseph Chan 	 */
2392c577b8a1SJoseph Chan 	/* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2393f7278fd0SJosepch Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2394f7278fd0SJosepch Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2395f7278fd0SJosepch Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2396f7278fd0SJosepch Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2397f7278fd0SJosepch Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2398c577b8a1SJoseph Chan 
2399c577b8a1SJoseph Chan 	/*
2400c577b8a1SJoseph Chan 	 * Set up output selector (0x1a, 0x1b, 0x29)
2401c577b8a1SJoseph Chan 	 */
2402c577b8a1SJoseph Chan 	/* set vol=0 to output mixers */
2403c577b8a1SJoseph Chan 	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2404c577b8a1SJoseph Chan 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2405c577b8a1SJoseph Chan 	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2406c577b8a1SJoseph Chan 
2407c577b8a1SJoseph Chan 	/*
2408c577b8a1SJoseph Chan 	 *  Unmute PW3 and PW4
2409c577b8a1SJoseph Chan 	 */
2410c577b8a1SJoseph Chan 	{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2411c577b8a1SJoseph Chan 	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2412c577b8a1SJoseph Chan 
2413bfdc675aSLydia Wang 	/* Set input of PW4 as MW0 */
2414bfdc675aSLydia Wang 	{0x20, AC_VERB_SET_CONNECT_SEL, 0},
2415c577b8a1SJoseph Chan 	/* PW9 Output enable */
2416c577b8a1SJoseph Chan 	{0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2417c577b8a1SJoseph Chan 	{ }
2418c577b8a1SJoseph Chan };
2419c577b8a1SJoseph Chan 
242090dd48a1STakashi Iwai static const struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
2421c577b8a1SJoseph Chan 	.substreams = 1,
2422c577b8a1SJoseph Chan 	.channels_min = 2,
2423c577b8a1SJoseph Chan 	.channels_max = 10,
2424c577b8a1SJoseph Chan 	.nid = 0x10, /* NID to query formats and rates */
2425c577b8a1SJoseph Chan 	.ops = {
2426c577b8a1SJoseph Chan 		.open = via_playback_pcm_open,
2427c873cc25SLydia Wang 		.prepare = via_playback_multi_pcm_prepare,
2428c873cc25SLydia Wang 		.cleanup = via_playback_multi_pcm_cleanup,
2429c577b8a1SJoseph Chan 	},
2430c577b8a1SJoseph Chan };
2431c577b8a1SJoseph Chan 
243290dd48a1STakashi Iwai static const struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
2433c577b8a1SJoseph Chan 	.substreams = 1,
2434c577b8a1SJoseph Chan 	.channels_min = 2,
2435c577b8a1SJoseph Chan 	.channels_max = 6,
2436c577b8a1SJoseph Chan 	.nid = 0x10, /* NID to query formats and rates */
2437c577b8a1SJoseph Chan 	.ops = {
2438c577b8a1SJoseph Chan 		.open = via_playback_pcm_open,
2439c873cc25SLydia Wang 		.prepare = via_playback_multi_pcm_prepare,
2440c873cc25SLydia Wang 		.cleanup = via_playback_multi_pcm_cleanup,
2441c577b8a1SJoseph Chan 	},
2442c577b8a1SJoseph Chan };
2443c577b8a1SJoseph Chan 
244490dd48a1STakashi Iwai static const struct hda_pcm_stream vt1709_pcm_analog_capture = {
2445c577b8a1SJoseph Chan 	.substreams = 2,
2446c577b8a1SJoseph Chan 	.channels_min = 2,
2447c577b8a1SJoseph Chan 	.channels_max = 2,
2448c577b8a1SJoseph Chan 	.nid = 0x14, /* NID to query formats and rates */
2449c577b8a1SJoseph Chan 	.ops = {
2450c577b8a1SJoseph Chan 		.prepare = via_capture_pcm_prepare,
2451c577b8a1SJoseph Chan 		.cleanup = via_capture_pcm_cleanup
2452c577b8a1SJoseph Chan 	},
2453c577b8a1SJoseph Chan };
2454c577b8a1SJoseph Chan 
245590dd48a1STakashi Iwai static const struct hda_pcm_stream vt1709_pcm_digital_playback = {
2456c577b8a1SJoseph Chan 	.substreams = 1,
2457c577b8a1SJoseph Chan 	.channels_min = 2,
2458c577b8a1SJoseph Chan 	.channels_max = 2,
2459c577b8a1SJoseph Chan 	/* NID is set in via_build_pcms */
2460c577b8a1SJoseph Chan 	.ops = {
2461c577b8a1SJoseph Chan 		.open = via_dig_playback_pcm_open,
2462c577b8a1SJoseph Chan 		.close = via_dig_playback_pcm_close
2463c577b8a1SJoseph Chan 	},
2464c577b8a1SJoseph Chan };
2465c577b8a1SJoseph Chan 
246690dd48a1STakashi Iwai static const struct hda_pcm_stream vt1709_pcm_digital_capture = {
2467c577b8a1SJoseph Chan 	.substreams = 1,
2468c577b8a1SJoseph Chan 	.channels_min = 2,
2469c577b8a1SJoseph Chan 	.channels_max = 2,
2470c577b8a1SJoseph Chan };
2471c577b8a1SJoseph Chan 
2472c577b8a1SJoseph Chan static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
2473c577b8a1SJoseph Chan 				     const struct auto_pin_cfg *cfg)
2474c577b8a1SJoseph Chan {
2475c577b8a1SJoseph Chan 	int i;
2476c577b8a1SJoseph Chan 	hda_nid_t nid;
2477c577b8a1SJoseph Chan 
2478c577b8a1SJoseph Chan 	if (cfg->line_outs == 4)  /* 10 channels */
2479c577b8a1SJoseph Chan 		spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
2480c577b8a1SJoseph Chan 	else if (cfg->line_outs == 3) /* 6 channels */
2481c577b8a1SJoseph Chan 		spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
2482c577b8a1SJoseph Chan 
2483c577b8a1SJoseph Chan 	spec->multiout.dac_nids = spec->private_dac_nids;
2484c577b8a1SJoseph Chan 
2485c577b8a1SJoseph Chan 	if (cfg->line_outs == 4) { /* 10 channels */
2486c577b8a1SJoseph Chan 		for (i = 0; i < cfg->line_outs; i++) {
2487c577b8a1SJoseph Chan 			nid = cfg->line_out_pins[i];
2488c577b8a1SJoseph Chan 			if (nid) {
2489c577b8a1SJoseph Chan 				/* config dac list */
2490c577b8a1SJoseph Chan 				switch (i) {
2491c577b8a1SJoseph Chan 				case AUTO_SEQ_FRONT:
2492c577b8a1SJoseph Chan 					/* AOW0 */
2493dda14410STakashi Iwai 					spec->private_dac_nids[i] = 0x10;
2494c577b8a1SJoseph Chan 					break;
2495c577b8a1SJoseph Chan 				case AUTO_SEQ_CENLFE:
2496c577b8a1SJoseph Chan 					/* AOW2 */
2497dda14410STakashi Iwai 					spec->private_dac_nids[i] = 0x12;
2498c577b8a1SJoseph Chan 					break;
2499c577b8a1SJoseph Chan 				case AUTO_SEQ_SURROUND:
2500c577b8a1SJoseph Chan 					/* AOW3 */
2501dda14410STakashi Iwai 					spec->private_dac_nids[i] = 0x11;
2502c577b8a1SJoseph Chan 					break;
2503c577b8a1SJoseph Chan 				case AUTO_SEQ_SIDE:
2504c577b8a1SJoseph Chan 					/* AOW1 */
2505dda14410STakashi Iwai 					spec->private_dac_nids[i] = 0x27;
2506c577b8a1SJoseph Chan 					break;
2507c577b8a1SJoseph Chan 				default:
2508c577b8a1SJoseph Chan 					break;
2509c577b8a1SJoseph Chan 				}
2510c577b8a1SJoseph Chan 			}
2511c577b8a1SJoseph Chan 		}
2512dda14410STakashi Iwai 		spec->private_dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
2513c577b8a1SJoseph Chan 
2514c577b8a1SJoseph Chan 	} else if (cfg->line_outs == 3) { /* 6 channels */
2515c577b8a1SJoseph Chan 		for (i = 0; i < cfg->line_outs; i++) {
2516c577b8a1SJoseph Chan 			nid = cfg->line_out_pins[i];
2517c577b8a1SJoseph Chan 			if (nid) {
2518c577b8a1SJoseph Chan 				/* config dac list */
2519c577b8a1SJoseph Chan 				switch (i) {
2520c577b8a1SJoseph Chan 				case AUTO_SEQ_FRONT:
2521c577b8a1SJoseph Chan 					/* AOW0 */
2522dda14410STakashi Iwai 					spec->private_dac_nids[i] = 0x10;
2523c577b8a1SJoseph Chan 					break;
2524c577b8a1SJoseph Chan 				case AUTO_SEQ_CENLFE:
2525c577b8a1SJoseph Chan 					/* AOW2 */
2526dda14410STakashi Iwai 					spec->private_dac_nids[i] = 0x12;
2527c577b8a1SJoseph Chan 					break;
2528c577b8a1SJoseph Chan 				case AUTO_SEQ_SURROUND:
2529c577b8a1SJoseph Chan 					/* AOW1 */
2530dda14410STakashi Iwai 					spec->private_dac_nids[i] = 0x11;
2531c577b8a1SJoseph Chan 					break;
2532c577b8a1SJoseph Chan 				default:
2533c577b8a1SJoseph Chan 					break;
2534c577b8a1SJoseph Chan 				}
2535c577b8a1SJoseph Chan 			}
2536c577b8a1SJoseph Chan 		}
2537c577b8a1SJoseph Chan 	}
2538c577b8a1SJoseph Chan 
2539c577b8a1SJoseph Chan 	return 0;
2540c577b8a1SJoseph Chan }
2541c577b8a1SJoseph Chan 
2542c577b8a1SJoseph Chan /* add playback controls from the parsed DAC table */
2543c577b8a1SJoseph Chan static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
2544c577b8a1SJoseph Chan 					     const struct auto_pin_cfg *cfg)
2545c577b8a1SJoseph Chan {
2546c577b8a1SJoseph Chan 	char name[32];
2547ea734963STakashi Iwai 	static const char * const chname[4] = {
2548ea734963STakashi Iwai 		"Front", "Surround", "C/LFE", "Side"
2549ea734963STakashi Iwai 	};
25504483a2f5SLydia Wang 	hda_nid_t nid, nid_vol, nid_vols[] = {0x18, 0x1a, 0x1b, 0x29};
2551c577b8a1SJoseph Chan 	int i, err;
2552c577b8a1SJoseph Chan 
2553c577b8a1SJoseph Chan 	for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2554c577b8a1SJoseph Chan 		nid = cfg->line_out_pins[i];
2555c577b8a1SJoseph Chan 
2556c577b8a1SJoseph Chan 		if (!nid)
2557c577b8a1SJoseph Chan 			continue;
2558c577b8a1SJoseph Chan 
25594483a2f5SLydia Wang 		nid_vol = nid_vols[i];
25604483a2f5SLydia Wang 
2561c577b8a1SJoseph Chan 		if (i == AUTO_SEQ_CENLFE) {
2562c577b8a1SJoseph Chan 			/* Center/LFE */
2563c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2564c577b8a1SJoseph Chan 					      "Center Playback Volume",
25654483a2f5SLydia Wang 					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2566f7278fd0SJosepch Chan 								  HDA_OUTPUT));
2567c577b8a1SJoseph Chan 			if (err < 0)
2568c577b8a1SJoseph Chan 				return err;
2569c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2570c577b8a1SJoseph Chan 					      "LFE Playback Volume",
25714483a2f5SLydia Wang 					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2572f7278fd0SJosepch Chan 								  HDA_OUTPUT));
2573c577b8a1SJoseph Chan 			if (err < 0)
2574c577b8a1SJoseph Chan 				return err;
2575c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2576c577b8a1SJoseph Chan 					      "Center Playback Switch",
25774483a2f5SLydia Wang 					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2578f7278fd0SJosepch Chan 								  HDA_OUTPUT));
2579c577b8a1SJoseph Chan 			if (err < 0)
2580c577b8a1SJoseph Chan 				return err;
2581c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2582c577b8a1SJoseph Chan 					      "LFE Playback Switch",
25834483a2f5SLydia Wang 					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2584f7278fd0SJosepch Chan 								  HDA_OUTPUT));
2585c577b8a1SJoseph Chan 			if (err < 0)
2586c577b8a1SJoseph Chan 				return err;
2587c577b8a1SJoseph Chan 		} else if (i == AUTO_SEQ_FRONT) {
25884483a2f5SLydia Wang 			/* ADD control to mixer index 0 */
2589c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2590c577b8a1SJoseph Chan 					      "Master Front Playback Volume",
25914483a2f5SLydia Wang 					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2592f7278fd0SJosepch Chan 								  HDA_INPUT));
2593c577b8a1SJoseph Chan 			if (err < 0)
2594c577b8a1SJoseph Chan 				return err;
2595c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2596c577b8a1SJoseph Chan 					      "Master Front Playback Switch",
25974483a2f5SLydia Wang 					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2598f7278fd0SJosepch Chan 								  HDA_INPUT));
2599c577b8a1SJoseph Chan 			if (err < 0)
2600c577b8a1SJoseph Chan 				return err;
2601c577b8a1SJoseph Chan 
2602c577b8a1SJoseph Chan 			/* add control to PW3 */
2603c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Volume", chname[i]);
2604c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2605f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2606f7278fd0SJosepch Chan 								  HDA_OUTPUT));
2607c577b8a1SJoseph Chan 			if (err < 0)
2608c577b8a1SJoseph Chan 				return err;
2609c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Switch", chname[i]);
2610c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2611f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2612f7278fd0SJosepch Chan 								  HDA_OUTPUT));
2613c577b8a1SJoseph Chan 			if (err < 0)
2614c577b8a1SJoseph Chan 				return err;
2615c577b8a1SJoseph Chan 		} else if (i == AUTO_SEQ_SURROUND) {
2616c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Volume", chname[i]);
2617c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
26184483a2f5SLydia Wang 					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2619f7278fd0SJosepch Chan 								  HDA_OUTPUT));
2620c577b8a1SJoseph Chan 			if (err < 0)
2621c577b8a1SJoseph Chan 				return err;
2622c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Switch", chname[i]);
2623c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
26244483a2f5SLydia Wang 					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2625f7278fd0SJosepch Chan 								  HDA_OUTPUT));
2626c577b8a1SJoseph Chan 			if (err < 0)
2627c577b8a1SJoseph Chan 				return err;
2628c577b8a1SJoseph Chan 		} else if (i == AUTO_SEQ_SIDE) {
2629c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Volume", chname[i]);
2630c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
26314483a2f5SLydia Wang 					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2632f7278fd0SJosepch Chan 								  HDA_OUTPUT));
2633c577b8a1SJoseph Chan 			if (err < 0)
2634c577b8a1SJoseph Chan 				return err;
2635c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Switch", chname[i]);
2636c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
26374483a2f5SLydia Wang 					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2638f7278fd0SJosepch Chan 								  HDA_OUTPUT));
2639c577b8a1SJoseph Chan 			if (err < 0)
2640c577b8a1SJoseph Chan 				return err;
2641c577b8a1SJoseph Chan 		}
2642c577b8a1SJoseph Chan 	}
2643c577b8a1SJoseph Chan 
2644c577b8a1SJoseph Chan 	return 0;
2645c577b8a1SJoseph Chan }
2646c577b8a1SJoseph Chan 
2647c577b8a1SJoseph Chan static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2648c577b8a1SJoseph Chan {
2649c577b8a1SJoseph Chan 	int err;
2650c577b8a1SJoseph Chan 
2651c577b8a1SJoseph Chan 	if (!pin)
2652c577b8a1SJoseph Chan 		return 0;
2653c577b8a1SJoseph Chan 
2654c577b8a1SJoseph Chan 	if (spec->multiout.num_dacs == 5) /* 10 channels */
2655c577b8a1SJoseph Chan 		spec->multiout.hp_nid = VT1709_HP_DAC_NID;
2656c577b8a1SJoseph Chan 	else if (spec->multiout.num_dacs == 3) /* 6 channels */
2657c577b8a1SJoseph Chan 		spec->multiout.hp_nid = 0;
2658cdc1784dSLydia Wang 	spec->hp_independent_mode_index = 1;
2659c577b8a1SJoseph Chan 
2660c577b8a1SJoseph Chan 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2661c577b8a1SJoseph Chan 			      "Headphone Playback Volume",
2662c577b8a1SJoseph Chan 			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2663c577b8a1SJoseph Chan 	if (err < 0)
2664c577b8a1SJoseph Chan 		return err;
2665c577b8a1SJoseph Chan 	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2666c577b8a1SJoseph Chan 			      "Headphone Playback Switch",
2667c577b8a1SJoseph Chan 			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2668c577b8a1SJoseph Chan 	if (err < 0)
2669c577b8a1SJoseph Chan 		return err;
2670c577b8a1SJoseph Chan 
2671c577b8a1SJoseph Chan 	return 0;
2672c577b8a1SJoseph Chan }
2673c577b8a1SJoseph Chan 
2674c577b8a1SJoseph Chan /* create playback/capture controls for input pins */
267510a20af7STakashi Iwai static int vt1709_auto_create_analog_input_ctls(struct hda_codec *codec,
2676c577b8a1SJoseph Chan 						const struct auto_pin_cfg *cfg)
2677c577b8a1SJoseph Chan {
267890dd48a1STakashi Iwai 	static const hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 };
267910a20af7STakashi Iwai 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x18, pin_idxs,
2680f3268512STakashi Iwai 						ARRAY_SIZE(pin_idxs));
2681c577b8a1SJoseph Chan }
2682c577b8a1SJoseph Chan 
2683c577b8a1SJoseph Chan static int vt1709_parse_auto_config(struct hda_codec *codec)
2684c577b8a1SJoseph Chan {
2685c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
2686c577b8a1SJoseph Chan 	int err;
2687c577b8a1SJoseph Chan 
2688c577b8a1SJoseph Chan 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
2689c577b8a1SJoseph Chan 	if (err < 0)
2690c577b8a1SJoseph Chan 		return err;
2691c577b8a1SJoseph Chan 	err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
2692c577b8a1SJoseph Chan 	if (err < 0)
2693c577b8a1SJoseph Chan 		return err;
2694c577b8a1SJoseph Chan 	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2695c577b8a1SJoseph Chan 		return 0; /* can't find valid BIOS pin config */
2696c577b8a1SJoseph Chan 
2697c577b8a1SJoseph Chan 	err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
2698c577b8a1SJoseph Chan 	if (err < 0)
2699c577b8a1SJoseph Chan 		return err;
2700c577b8a1SJoseph Chan 	err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2701c577b8a1SJoseph Chan 	if (err < 0)
2702c577b8a1SJoseph Chan 		return err;
270310a20af7STakashi Iwai 	err = vt1709_auto_create_analog_input_ctls(codec, &spec->autocfg);
2704c577b8a1SJoseph Chan 	if (err < 0)
2705c577b8a1SJoseph Chan 		return err;
2706c577b8a1SJoseph Chan 
2707c577b8a1SJoseph Chan 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2708c577b8a1SJoseph Chan 
27090852d7a6STakashi Iwai 	if (spec->autocfg.dig_outs)
2710c577b8a1SJoseph Chan 		spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
271155d1d6c1STakashi Iwai 	spec->dig_in_pin = VT1709_DIGIN_PIN;
2712c577b8a1SJoseph Chan 	if (spec->autocfg.dig_in_pin)
2713c577b8a1SJoseph Chan 		spec->dig_in_nid = VT1709_DIGIN_NID;
2714c577b8a1SJoseph Chan 
2715603c4019STakashi Iwai 	if (spec->kctls.list)
2716603c4019STakashi Iwai 		spec->mixers[spec->num_mixers++] = spec->kctls.list;
2717c577b8a1SJoseph Chan 
27180aa62aefSHarald Welte 	spec->input_mux = &spec->private_imux[0];
2719c577b8a1SJoseph Chan 
2720f8fdd495SHarald Welte 	if (spec->hp_mux)
27213d83e577STakashi Iwai 		via_hp_build(codec);
2722f8fdd495SHarald Welte 
27235b0cb1d8SJaroslav Kysela 	via_smart51_build(spec);
2724c577b8a1SJoseph Chan 	return 1;
2725c577b8a1SJoseph Chan }
2726c577b8a1SJoseph Chan 
2727cb53c626STakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE
272890dd48a1STakashi Iwai static const struct hda_amp_list vt1709_loopbacks[] = {
2729cb53c626STakashi Iwai 	{ 0x18, HDA_INPUT, 1 },
2730cb53c626STakashi Iwai 	{ 0x18, HDA_INPUT, 2 },
2731cb53c626STakashi Iwai 	{ 0x18, HDA_INPUT, 3 },
2732cb53c626STakashi Iwai 	{ 0x18, HDA_INPUT, 4 },
2733cb53c626STakashi Iwai 	{ } /* end */
2734cb53c626STakashi Iwai };
2735cb53c626STakashi Iwai #endif
2736cb53c626STakashi Iwai 
2737c577b8a1SJoseph Chan static int patch_vt1709_10ch(struct hda_codec *codec)
2738c577b8a1SJoseph Chan {
2739c577b8a1SJoseph Chan 	struct via_spec *spec;
2740c577b8a1SJoseph Chan 	int err;
2741c577b8a1SJoseph Chan 
2742c577b8a1SJoseph Chan 	/* create a codec specific record */
27435b0cb1d8SJaroslav Kysela 	spec = via_new_spec(codec);
2744c577b8a1SJoseph Chan 	if (spec == NULL)
2745c577b8a1SJoseph Chan 		return -ENOMEM;
2746c577b8a1SJoseph Chan 
2747c577b8a1SJoseph Chan 	err = vt1709_parse_auto_config(codec);
2748c577b8a1SJoseph Chan 	if (err < 0) {
2749c577b8a1SJoseph Chan 		via_free(codec);
2750c577b8a1SJoseph Chan 		return err;
2751c577b8a1SJoseph Chan 	} else if (!err) {
2752c577b8a1SJoseph Chan 		printk(KERN_INFO "hda_codec: Cannot set up configuration.  "
2753c577b8a1SJoseph Chan 		       "Using genenic mode...\n");
2754c577b8a1SJoseph Chan 	}
2755c577b8a1SJoseph Chan 
275669e52a80SHarald Welte 	spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs;
275769e52a80SHarald Welte 	spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
2758c577b8a1SJoseph Chan 
2759c577b8a1SJoseph Chan 	spec->stream_name_analog = "VT1709 Analog";
2760c577b8a1SJoseph Chan 	spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
2761c577b8a1SJoseph Chan 	spec->stream_analog_capture = &vt1709_pcm_analog_capture;
2762c577b8a1SJoseph Chan 
2763c577b8a1SJoseph Chan 	spec->stream_name_digital = "VT1709 Digital";
2764c577b8a1SJoseph Chan 	spec->stream_digital_playback = &vt1709_pcm_digital_playback;
2765c577b8a1SJoseph Chan 	spec->stream_digital_capture = &vt1709_pcm_digital_capture;
2766c577b8a1SJoseph Chan 
2767c577b8a1SJoseph Chan 
2768c577b8a1SJoseph Chan 	if (!spec->adc_nids && spec->input_mux) {
2769c577b8a1SJoseph Chan 		spec->adc_nids = vt1709_adc_nids;
2770c577b8a1SJoseph Chan 		spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
2771337b9d02STakashi Iwai 		get_mux_nids(codec);
2772c577b8a1SJoseph Chan 		spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
2773c577b8a1SJoseph Chan 		spec->num_mixers++;
2774c577b8a1SJoseph Chan 	}
2775c577b8a1SJoseph Chan 
2776c577b8a1SJoseph Chan 	codec->patch_ops = via_patch_ops;
2777c577b8a1SJoseph Chan 
2778c577b8a1SJoseph Chan 	codec->patch_ops.init = via_auto_init;
277969e52a80SHarald Welte 	codec->patch_ops.unsol_event = via_unsol_event;
2780cb53c626STakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE
2781cb53c626STakashi Iwai 	spec->loopback.amplist = vt1709_loopbacks;
2782cb53c626STakashi Iwai #endif
2783c577b8a1SJoseph Chan 
2784c577b8a1SJoseph Chan 	return 0;
2785c577b8a1SJoseph Chan }
2786c577b8a1SJoseph Chan /*
2787c577b8a1SJoseph Chan  * generic initialization of ADC, input mixers and output mixers
2788c577b8a1SJoseph Chan  */
278990dd48a1STakashi Iwai static const struct hda_verb vt1709_6ch_volume_init_verbs[] = {
2790c577b8a1SJoseph Chan 	/*
2791c577b8a1SJoseph Chan 	 * Unmute ADC0-2 and set the default input to mic-in
2792c577b8a1SJoseph Chan 	 */
2793c577b8a1SJoseph Chan 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2794c577b8a1SJoseph Chan 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2795c577b8a1SJoseph Chan 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2796c577b8a1SJoseph Chan 
2797c577b8a1SJoseph Chan 
2798c577b8a1SJoseph Chan 	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2799c577b8a1SJoseph Chan 	 * mixer widget
2800c577b8a1SJoseph Chan 	 */
2801c577b8a1SJoseph Chan 	/* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2802c577b8a1SJoseph Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2803c577b8a1SJoseph Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2804c577b8a1SJoseph Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2805c577b8a1SJoseph Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2806c577b8a1SJoseph Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2807c577b8a1SJoseph Chan 
2808c577b8a1SJoseph Chan 	/*
2809c577b8a1SJoseph Chan 	 * Set up output selector (0x1a, 0x1b, 0x29)
2810c577b8a1SJoseph Chan 	 */
2811c577b8a1SJoseph Chan 	/* set vol=0 to output mixers */
2812c577b8a1SJoseph Chan 	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2813c577b8a1SJoseph Chan 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2814c577b8a1SJoseph Chan 	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2815c577b8a1SJoseph Chan 
2816c577b8a1SJoseph Chan 	/*
2817c577b8a1SJoseph Chan 	 *  Unmute PW3 and PW4
2818c577b8a1SJoseph Chan 	 */
2819c577b8a1SJoseph Chan 	{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2820c577b8a1SJoseph Chan 	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2821c577b8a1SJoseph Chan 
2822c577b8a1SJoseph Chan 	/* Set input of PW4 as MW0 */
2823c577b8a1SJoseph Chan 	{0x20, AC_VERB_SET_CONNECT_SEL, 0},
2824c577b8a1SJoseph Chan 	/* PW9 Output enable */
2825c577b8a1SJoseph Chan 	{0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2826c577b8a1SJoseph Chan 	{ }
2827c577b8a1SJoseph Chan };
2828c577b8a1SJoseph Chan 
2829c577b8a1SJoseph Chan static int patch_vt1709_6ch(struct hda_codec *codec)
2830c577b8a1SJoseph Chan {
2831c577b8a1SJoseph Chan 	struct via_spec *spec;
2832c577b8a1SJoseph Chan 	int err;
2833c577b8a1SJoseph Chan 
2834c577b8a1SJoseph Chan 	/* create a codec specific record */
28355b0cb1d8SJaroslav Kysela 	spec = via_new_spec(codec);
2836c577b8a1SJoseph Chan 	if (spec == NULL)
2837c577b8a1SJoseph Chan 		return -ENOMEM;
2838c577b8a1SJoseph Chan 
2839c577b8a1SJoseph Chan 	err = vt1709_parse_auto_config(codec);
2840c577b8a1SJoseph Chan 	if (err < 0) {
2841c577b8a1SJoseph Chan 		via_free(codec);
2842c577b8a1SJoseph Chan 		return err;
2843c577b8a1SJoseph Chan 	} else if (!err) {
2844c577b8a1SJoseph Chan 		printk(KERN_INFO "hda_codec: Cannot set up configuration.  "
2845c577b8a1SJoseph Chan 		       "Using genenic mode...\n");
2846c577b8a1SJoseph Chan 	}
2847c577b8a1SJoseph Chan 
284869e52a80SHarald Welte 	spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs;
284969e52a80SHarald Welte 	spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
2850c577b8a1SJoseph Chan 
2851c577b8a1SJoseph Chan 	spec->stream_name_analog = "VT1709 Analog";
2852c577b8a1SJoseph Chan 	spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
2853c577b8a1SJoseph Chan 	spec->stream_analog_capture = &vt1709_pcm_analog_capture;
2854c577b8a1SJoseph Chan 
2855c577b8a1SJoseph Chan 	spec->stream_name_digital = "VT1709 Digital";
2856c577b8a1SJoseph Chan 	spec->stream_digital_playback = &vt1709_pcm_digital_playback;
2857c577b8a1SJoseph Chan 	spec->stream_digital_capture = &vt1709_pcm_digital_capture;
2858c577b8a1SJoseph Chan 
2859c577b8a1SJoseph Chan 
2860c577b8a1SJoseph Chan 	if (!spec->adc_nids && spec->input_mux) {
2861c577b8a1SJoseph Chan 		spec->adc_nids = vt1709_adc_nids;
2862c577b8a1SJoseph Chan 		spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
2863337b9d02STakashi Iwai 		get_mux_nids(codec);
2864c577b8a1SJoseph Chan 		spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
2865c577b8a1SJoseph Chan 		spec->num_mixers++;
2866c577b8a1SJoseph Chan 	}
2867c577b8a1SJoseph Chan 
2868c577b8a1SJoseph Chan 	codec->patch_ops = via_patch_ops;
2869c577b8a1SJoseph Chan 
2870c577b8a1SJoseph Chan 	codec->patch_ops.init = via_auto_init;
287169e52a80SHarald Welte 	codec->patch_ops.unsol_event = via_unsol_event;
2872cb53c626STakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE
2873cb53c626STakashi Iwai 	spec->loopback.amplist = vt1709_loopbacks;
2874cb53c626STakashi Iwai #endif
2875f7278fd0SJosepch Chan 	return 0;
2876f7278fd0SJosepch Chan }
2877f7278fd0SJosepch Chan 
2878f7278fd0SJosepch Chan /* capture mixer elements */
287990dd48a1STakashi Iwai static const struct snd_kcontrol_new vt1708B_capture_mixer[] = {
2880f7278fd0SJosepch Chan 	HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
2881f7278fd0SJosepch Chan 	HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
2882f7278fd0SJosepch Chan 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
2883f7278fd0SJosepch Chan 	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
2884f7278fd0SJosepch Chan 	{
2885f7278fd0SJosepch Chan 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2886f7278fd0SJosepch Chan 		/* The multiple "Capture Source" controls confuse alsamixer
2887f7278fd0SJosepch Chan 		 * So call somewhat different..
2888f7278fd0SJosepch Chan 		 */
2889f7278fd0SJosepch Chan 		/* .name = "Capture Source", */
2890f7278fd0SJosepch Chan 		.name = "Input Source",
2891f7278fd0SJosepch Chan 		.count = 1,
2892f7278fd0SJosepch Chan 		.info = via_mux_enum_info,
2893f7278fd0SJosepch Chan 		.get = via_mux_enum_get,
2894f7278fd0SJosepch Chan 		.put = via_mux_enum_put,
2895f7278fd0SJosepch Chan 	},
2896f7278fd0SJosepch Chan 	{ } /* end */
2897f7278fd0SJosepch Chan };
2898f7278fd0SJosepch Chan /*
2899f7278fd0SJosepch Chan  * generic initialization of ADC, input mixers and output mixers
2900f7278fd0SJosepch Chan  */
290190dd48a1STakashi Iwai static const struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
2902f7278fd0SJosepch Chan 	/*
2903f7278fd0SJosepch Chan 	 * Unmute ADC0-1 and set the default input to mic-in
2904f7278fd0SJosepch Chan 	 */
2905f7278fd0SJosepch Chan 	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2906f7278fd0SJosepch Chan 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2907f7278fd0SJosepch Chan 
2908f7278fd0SJosepch Chan 
2909f7278fd0SJosepch Chan 	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2910f7278fd0SJosepch Chan 	 * mixer widget
2911f7278fd0SJosepch Chan 	 */
2912f7278fd0SJosepch Chan 	/* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2913f7278fd0SJosepch Chan 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2914f7278fd0SJosepch Chan 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2915f7278fd0SJosepch Chan 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2916f7278fd0SJosepch Chan 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2917f7278fd0SJosepch Chan 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2918f7278fd0SJosepch Chan 
2919f7278fd0SJosepch Chan 	/*
2920f7278fd0SJosepch Chan 	 * Set up output mixers
2921f7278fd0SJosepch Chan 	 */
2922f7278fd0SJosepch Chan 	/* set vol=0 to output mixers */
2923f7278fd0SJosepch Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2924f7278fd0SJosepch Chan 	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2925f7278fd0SJosepch Chan 	{0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2926f7278fd0SJosepch Chan 
2927f7278fd0SJosepch Chan 	/* Setup default input to PW4 */
2928bfdc675aSLydia Wang 	{0x1d, AC_VERB_SET_CONNECT_SEL, 0},
2929f7278fd0SJosepch Chan 	/* PW9 Output enable */
2930f7278fd0SJosepch Chan 	{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2931f7278fd0SJosepch Chan 	/* PW10 Input enable */
2932f7278fd0SJosepch Chan 	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
2933f7278fd0SJosepch Chan 	{ }
2934f7278fd0SJosepch Chan };
2935f7278fd0SJosepch Chan 
293690dd48a1STakashi Iwai static const struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
2937f7278fd0SJosepch Chan 	/*
2938f7278fd0SJosepch Chan 	 * Unmute ADC0-1 and set the default input to mic-in
2939f7278fd0SJosepch Chan 	 */
2940f7278fd0SJosepch Chan 	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2941f7278fd0SJosepch Chan 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2942f7278fd0SJosepch Chan 
2943f7278fd0SJosepch Chan 
2944f7278fd0SJosepch Chan 	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2945f7278fd0SJosepch Chan 	 * mixer widget
2946f7278fd0SJosepch Chan 	 */
2947f7278fd0SJosepch Chan 	/* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2948f7278fd0SJosepch Chan 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2949f7278fd0SJosepch Chan 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2950f7278fd0SJosepch Chan 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2951f7278fd0SJosepch Chan 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2952f7278fd0SJosepch Chan 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2953f7278fd0SJosepch Chan 
2954f7278fd0SJosepch Chan 	/*
2955f7278fd0SJosepch Chan 	 * Set up output mixers
2956f7278fd0SJosepch Chan 	 */
2957f7278fd0SJosepch Chan 	/* set vol=0 to output mixers */
2958f7278fd0SJosepch Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2959f7278fd0SJosepch Chan 	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2960f7278fd0SJosepch Chan 	{0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2961f7278fd0SJosepch Chan 
2962f7278fd0SJosepch Chan 	/* Setup default input of PW4 to MW0 */
2963f7278fd0SJosepch Chan 	{0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
2964f7278fd0SJosepch Chan 	/* PW9 Output enable */
2965f7278fd0SJosepch Chan 	{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2966f7278fd0SJosepch Chan 	/* PW10 Input enable */
2967f7278fd0SJosepch Chan 	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
2968f7278fd0SJosepch Chan 	{ }
2969f7278fd0SJosepch Chan };
2970f7278fd0SJosepch Chan 
297190dd48a1STakashi Iwai static const struct hda_verb vt1708B_uniwill_init_verbs[] = {
2972a34df19aSLydia Wang 	{0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
2973a34df19aSLydia Wang 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
2974a34df19aSLydia Wang 	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
2975a34df19aSLydia Wang 	{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
2976a34df19aSLydia Wang 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
2977a34df19aSLydia Wang 	{0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
2978a34df19aSLydia Wang 	{0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
2979a34df19aSLydia Wang 	{0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
2980a34df19aSLydia Wang 	{0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
298169e52a80SHarald Welte 	{ }
298269e52a80SHarald Welte };
298369e52a80SHarald Welte 
298417314379SLydia Wang static int via_pcm_open_close(struct hda_pcm_stream *hinfo,
298517314379SLydia Wang 			      struct hda_codec *codec,
298617314379SLydia Wang 			      struct snd_pcm_substream *substream)
298717314379SLydia Wang {
298817314379SLydia Wang 	int idle = substream->pstr->substream_opened == 1
298917314379SLydia Wang 		&& substream->ref_count == 0;
299017314379SLydia Wang 
299117314379SLydia Wang 	analog_low_current_mode(codec, idle);
299217314379SLydia Wang 	return 0;
299317314379SLydia Wang }
299417314379SLydia Wang 
299590dd48a1STakashi Iwai static const struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
29960aa62aefSHarald Welte 	.substreams = 2,
2997f7278fd0SJosepch Chan 	.channels_min = 2,
2998f7278fd0SJosepch Chan 	.channels_max = 8,
2999f7278fd0SJosepch Chan 	.nid = 0x10, /* NID to query formats and rates */
3000f7278fd0SJosepch Chan 	.ops = {
3001f7278fd0SJosepch Chan 		.open = via_playback_pcm_open,
30020aa62aefSHarald Welte 		.prepare = via_playback_multi_pcm_prepare,
300317314379SLydia Wang 		.cleanup = via_playback_multi_pcm_cleanup,
300417314379SLydia Wang 		.close = via_pcm_open_close
3005f7278fd0SJosepch Chan 	},
3006f7278fd0SJosepch Chan };
3007f7278fd0SJosepch Chan 
300890dd48a1STakashi Iwai static const struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
30090aa62aefSHarald Welte 	.substreams = 2,
3010f7278fd0SJosepch Chan 	.channels_min = 2,
3011f7278fd0SJosepch Chan 	.channels_max = 4,
3012f7278fd0SJosepch Chan 	.nid = 0x10, /* NID to query formats and rates */
3013f7278fd0SJosepch Chan 	.ops = {
3014f7278fd0SJosepch Chan 		.open = via_playback_pcm_open,
30150aa62aefSHarald Welte 		.prepare = via_playback_multi_pcm_prepare,
30160aa62aefSHarald Welte 		.cleanup = via_playback_multi_pcm_cleanup
3017f7278fd0SJosepch Chan 	},
3018f7278fd0SJosepch Chan };
3019f7278fd0SJosepch Chan 
302090dd48a1STakashi Iwai static const struct hda_pcm_stream vt1708B_pcm_analog_capture = {
3021f7278fd0SJosepch Chan 	.substreams = 2,
3022f7278fd0SJosepch Chan 	.channels_min = 2,
3023f7278fd0SJosepch Chan 	.channels_max = 2,
3024f7278fd0SJosepch Chan 	.nid = 0x13, /* NID to query formats and rates */
3025f7278fd0SJosepch Chan 	.ops = {
302617314379SLydia Wang 		.open = via_pcm_open_close,
3027f7278fd0SJosepch Chan 		.prepare = via_capture_pcm_prepare,
302817314379SLydia Wang 		.cleanup = via_capture_pcm_cleanup,
302917314379SLydia Wang 		.close = via_pcm_open_close
3030f7278fd0SJosepch Chan 	},
3031f7278fd0SJosepch Chan };
3032f7278fd0SJosepch Chan 
303390dd48a1STakashi Iwai static const struct hda_pcm_stream vt1708B_pcm_digital_playback = {
3034f7278fd0SJosepch Chan 	.substreams = 1,
3035f7278fd0SJosepch Chan 	.channels_min = 2,
3036f7278fd0SJosepch Chan 	.channels_max = 2,
3037f7278fd0SJosepch Chan 	/* NID is set in via_build_pcms */
3038f7278fd0SJosepch Chan 	.ops = {
3039f7278fd0SJosepch Chan 		.open = via_dig_playback_pcm_open,
3040f7278fd0SJosepch Chan 		.close = via_dig_playback_pcm_close,
30419da29271STakashi Iwai 		.prepare = via_dig_playback_pcm_prepare,
30429da29271STakashi Iwai 		.cleanup = via_dig_playback_pcm_cleanup
3043f7278fd0SJosepch Chan 	},
3044f7278fd0SJosepch Chan };
3045f7278fd0SJosepch Chan 
304690dd48a1STakashi Iwai static const struct hda_pcm_stream vt1708B_pcm_digital_capture = {
3047f7278fd0SJosepch Chan 	.substreams = 1,
3048f7278fd0SJosepch Chan 	.channels_min = 2,
3049f7278fd0SJosepch Chan 	.channels_max = 2,
3050f7278fd0SJosepch Chan };
3051f7278fd0SJosepch Chan 
3052f7278fd0SJosepch Chan /* fill in the dac_nids table from the parsed pin configuration */
3053f7278fd0SJosepch Chan static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
3054f7278fd0SJosepch Chan 				     const struct auto_pin_cfg *cfg)
3055f7278fd0SJosepch Chan {
3056f7278fd0SJosepch Chan 	int i;
3057f7278fd0SJosepch Chan 	hda_nid_t nid;
3058f7278fd0SJosepch Chan 
3059f7278fd0SJosepch Chan 	spec->multiout.num_dacs = cfg->line_outs;
3060f7278fd0SJosepch Chan 
3061f7278fd0SJosepch Chan 	spec->multiout.dac_nids = spec->private_dac_nids;
3062f7278fd0SJosepch Chan 
3063f7278fd0SJosepch Chan 	for (i = 0; i < 4; i++) {
3064f7278fd0SJosepch Chan 		nid = cfg->line_out_pins[i];
3065f7278fd0SJosepch Chan 		if (nid) {
3066f7278fd0SJosepch Chan 			/* config dac list */
3067f7278fd0SJosepch Chan 			switch (i) {
3068f7278fd0SJosepch Chan 			case AUTO_SEQ_FRONT:
3069dda14410STakashi Iwai 				spec->private_dac_nids[i] = 0x10;
3070f7278fd0SJosepch Chan 				break;
3071f7278fd0SJosepch Chan 			case AUTO_SEQ_CENLFE:
3072dda14410STakashi Iwai 				spec->private_dac_nids[i] = 0x24;
3073f7278fd0SJosepch Chan 				break;
3074f7278fd0SJosepch Chan 			case AUTO_SEQ_SURROUND:
3075dda14410STakashi Iwai 				spec->private_dac_nids[i] = 0x11;
3076f7278fd0SJosepch Chan 				break;
3077f7278fd0SJosepch Chan 			case AUTO_SEQ_SIDE:
3078dda14410STakashi Iwai 				spec->private_dac_nids[i] = 0x25;
3079f7278fd0SJosepch Chan 				break;
3080f7278fd0SJosepch Chan 			}
3081f7278fd0SJosepch Chan 		}
3082f7278fd0SJosepch Chan 	}
3083f7278fd0SJosepch Chan 
3084f7278fd0SJosepch Chan 	return 0;
3085f7278fd0SJosepch Chan }
3086f7278fd0SJosepch Chan 
3087f7278fd0SJosepch Chan /* add playback controls from the parsed DAC table */
3088f7278fd0SJosepch Chan static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
3089f7278fd0SJosepch Chan 					     const struct auto_pin_cfg *cfg)
3090f7278fd0SJosepch Chan {
3091f7278fd0SJosepch Chan 	char name[32];
3092ea734963STakashi Iwai 	static const char * const chname[4] = {
3093ea734963STakashi Iwai 		"Front", "Surround", "C/LFE", "Side"
3094ea734963STakashi Iwai 	};
3095fb4cb772SHarald Welte 	hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27};
3096f7278fd0SJosepch Chan 	hda_nid_t nid, nid_vol = 0;
3097f7278fd0SJosepch Chan 	int i, err;
3098f7278fd0SJosepch Chan 
3099f7278fd0SJosepch Chan 	for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
3100f7278fd0SJosepch Chan 		nid = cfg->line_out_pins[i];
3101f7278fd0SJosepch Chan 
3102f7278fd0SJosepch Chan 		if (!nid)
3103f7278fd0SJosepch Chan 			continue;
3104f7278fd0SJosepch Chan 
3105f7278fd0SJosepch Chan 		nid_vol = nid_vols[i];
3106f7278fd0SJosepch Chan 
3107f7278fd0SJosepch Chan 		if (i == AUTO_SEQ_CENLFE) {
3108f7278fd0SJosepch Chan 			/* Center/LFE */
3109f7278fd0SJosepch Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3110f7278fd0SJosepch Chan 					      "Center Playback Volume",
3111f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
3112f7278fd0SJosepch Chan 								  HDA_OUTPUT));
3113f7278fd0SJosepch Chan 			if (err < 0)
3114f7278fd0SJosepch Chan 				return err;
3115f7278fd0SJosepch Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3116f7278fd0SJosepch Chan 					      "LFE Playback Volume",
3117f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
3118f7278fd0SJosepch Chan 								  HDA_OUTPUT));
3119f7278fd0SJosepch Chan 			if (err < 0)
3120f7278fd0SJosepch Chan 				return err;
3121f7278fd0SJosepch Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3122f7278fd0SJosepch Chan 					      "Center Playback Switch",
3123f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
3124f7278fd0SJosepch Chan 								  HDA_OUTPUT));
3125f7278fd0SJosepch Chan 			if (err < 0)
3126f7278fd0SJosepch Chan 				return err;
3127f7278fd0SJosepch Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3128f7278fd0SJosepch Chan 					      "LFE Playback Switch",
3129f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
3130f7278fd0SJosepch Chan 								  HDA_OUTPUT));
3131f7278fd0SJosepch Chan 			if (err < 0)
3132f7278fd0SJosepch Chan 				return err;
3133f7278fd0SJosepch Chan 		} else if (i == AUTO_SEQ_FRONT) {
3134f7278fd0SJosepch Chan 			/* add control to mixer index 0 */
3135f7278fd0SJosepch Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3136f7278fd0SJosepch Chan 					      "Master Front Playback Volume",
3137f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3138f7278fd0SJosepch Chan 								  HDA_INPUT));
3139f7278fd0SJosepch Chan 			if (err < 0)
3140f7278fd0SJosepch Chan 				return err;
3141f7278fd0SJosepch Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3142f7278fd0SJosepch Chan 					      "Master Front Playback Switch",
3143f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3144f7278fd0SJosepch Chan 								  HDA_INPUT));
3145f7278fd0SJosepch Chan 			if (err < 0)
3146f7278fd0SJosepch Chan 				return err;
3147f7278fd0SJosepch Chan 
3148f7278fd0SJosepch Chan 			/* add control to PW3 */
3149f7278fd0SJosepch Chan 			sprintf(name, "%s Playback Volume", chname[i]);
3150f7278fd0SJosepch Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3151f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3152f7278fd0SJosepch Chan 								  HDA_OUTPUT));
3153f7278fd0SJosepch Chan 			if (err < 0)
3154f7278fd0SJosepch Chan 				return err;
3155f7278fd0SJosepch Chan 			sprintf(name, "%s Playback Switch", chname[i]);
3156f7278fd0SJosepch Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3157f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3158f7278fd0SJosepch Chan 								  HDA_OUTPUT));
3159f7278fd0SJosepch Chan 			if (err < 0)
3160f7278fd0SJosepch Chan 				return err;
3161f7278fd0SJosepch Chan 		} else {
3162f7278fd0SJosepch Chan 			sprintf(name, "%s Playback Volume", chname[i]);
3163f7278fd0SJosepch Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3164f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3165f7278fd0SJosepch Chan 								  HDA_OUTPUT));
3166f7278fd0SJosepch Chan 			if (err < 0)
3167f7278fd0SJosepch Chan 				return err;
3168f7278fd0SJosepch Chan 			sprintf(name, "%s Playback Switch", chname[i]);
3169f7278fd0SJosepch Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3170f7278fd0SJosepch Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3171f7278fd0SJosepch Chan 								  HDA_OUTPUT));
3172f7278fd0SJosepch Chan 			if (err < 0)
3173f7278fd0SJosepch Chan 				return err;
3174f7278fd0SJosepch Chan 		}
3175f7278fd0SJosepch Chan 	}
3176f7278fd0SJosepch Chan 
3177f7278fd0SJosepch Chan 	return 0;
3178f7278fd0SJosepch Chan }
3179f7278fd0SJosepch Chan 
3180f7278fd0SJosepch Chan static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
3181f7278fd0SJosepch Chan {
3182f7278fd0SJosepch Chan 	int err;
3183f7278fd0SJosepch Chan 
3184f7278fd0SJosepch Chan 	if (!pin)
3185f7278fd0SJosepch Chan 		return 0;
3186f7278fd0SJosepch Chan 
3187f7278fd0SJosepch Chan 	spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
3188cdc1784dSLydia Wang 	spec->hp_independent_mode_index = 1;
3189f7278fd0SJosepch Chan 
3190f7278fd0SJosepch Chan 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3191f7278fd0SJosepch Chan 			      "Headphone Playback Volume",
3192f7278fd0SJosepch Chan 			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3193f7278fd0SJosepch Chan 	if (err < 0)
3194f7278fd0SJosepch Chan 		return err;
3195f7278fd0SJosepch Chan 	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3196f7278fd0SJosepch Chan 			      "Headphone Playback Switch",
3197f7278fd0SJosepch Chan 			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3198f7278fd0SJosepch Chan 	if (err < 0)
3199f7278fd0SJosepch Chan 		return err;
3200f7278fd0SJosepch Chan 
32010aa62aefSHarald Welte 	create_hp_imux(spec);
32020aa62aefSHarald Welte 
3203f7278fd0SJosepch Chan 	return 0;
3204f7278fd0SJosepch Chan }
3205f7278fd0SJosepch Chan 
3206f7278fd0SJosepch Chan /* create playback/capture controls for input pins */
320710a20af7STakashi Iwai static int vt1708B_auto_create_analog_input_ctls(struct hda_codec *codec,
3208f7278fd0SJosepch Chan 						const struct auto_pin_cfg *cfg)
3209f7278fd0SJosepch Chan {
321090dd48a1STakashi Iwai 	static const hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e };
321110a20af7STakashi Iwai 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
3212f3268512STakashi Iwai 						ARRAY_SIZE(pin_idxs));
3213f7278fd0SJosepch Chan }
3214f7278fd0SJosepch Chan 
3215f7278fd0SJosepch Chan static int vt1708B_parse_auto_config(struct hda_codec *codec)
3216f7278fd0SJosepch Chan {
3217f7278fd0SJosepch Chan 	struct via_spec *spec = codec->spec;
3218f7278fd0SJosepch Chan 	int err;
3219f7278fd0SJosepch Chan 
3220f7278fd0SJosepch Chan 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
3221f7278fd0SJosepch Chan 	if (err < 0)
3222f7278fd0SJosepch Chan 		return err;
3223f7278fd0SJosepch Chan 	err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg);
3224f7278fd0SJosepch Chan 	if (err < 0)
3225f7278fd0SJosepch Chan 		return err;
3226f7278fd0SJosepch Chan 	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
3227f7278fd0SJosepch Chan 		return 0; /* can't find valid BIOS pin config */
3228f7278fd0SJosepch Chan 
3229f7278fd0SJosepch Chan 	err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg);
3230f7278fd0SJosepch Chan 	if (err < 0)
3231f7278fd0SJosepch Chan 		return err;
3232f7278fd0SJosepch Chan 	err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
3233f7278fd0SJosepch Chan 	if (err < 0)
3234f7278fd0SJosepch Chan 		return err;
323510a20af7STakashi Iwai 	err = vt1708B_auto_create_analog_input_ctls(codec, &spec->autocfg);
3236f7278fd0SJosepch Chan 	if (err < 0)
3237f7278fd0SJosepch Chan 		return err;
3238f7278fd0SJosepch Chan 
3239f7278fd0SJosepch Chan 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3240f7278fd0SJosepch Chan 
32410852d7a6STakashi Iwai 	if (spec->autocfg.dig_outs)
3242f7278fd0SJosepch Chan 		spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
324355d1d6c1STakashi Iwai 	spec->dig_in_pin = VT1708B_DIGIN_PIN;
3244f7278fd0SJosepch Chan 	if (spec->autocfg.dig_in_pin)
3245f7278fd0SJosepch Chan 		spec->dig_in_nid = VT1708B_DIGIN_NID;
3246f7278fd0SJosepch Chan 
3247603c4019STakashi Iwai 	if (spec->kctls.list)
3248603c4019STakashi Iwai 		spec->mixers[spec->num_mixers++] = spec->kctls.list;
3249f7278fd0SJosepch Chan 
32500aa62aefSHarald Welte 	spec->input_mux = &spec->private_imux[0];
32510aa62aefSHarald Welte 
3252f8fdd495SHarald Welte 	if (spec->hp_mux)
32533d83e577STakashi Iwai 		via_hp_build(codec);
3254f7278fd0SJosepch Chan 
32555b0cb1d8SJaroslav Kysela 	via_smart51_build(spec);
3256f7278fd0SJosepch Chan 	return 1;
3257f7278fd0SJosepch Chan }
3258f7278fd0SJosepch Chan 
3259f7278fd0SJosepch Chan #ifdef CONFIG_SND_HDA_POWER_SAVE
326090dd48a1STakashi Iwai static const struct hda_amp_list vt1708B_loopbacks[] = {
3261f7278fd0SJosepch Chan 	{ 0x16, HDA_INPUT, 1 },
3262f7278fd0SJosepch Chan 	{ 0x16, HDA_INPUT, 2 },
3263f7278fd0SJosepch Chan 	{ 0x16, HDA_INPUT, 3 },
3264f7278fd0SJosepch Chan 	{ 0x16, HDA_INPUT, 4 },
3265f7278fd0SJosepch Chan 	{ } /* end */
3266f7278fd0SJosepch Chan };
3267f7278fd0SJosepch Chan #endif
32683e95b9abSLydia Wang 
32693e95b9abSLydia Wang static void set_widgets_power_state_vt1708B(struct hda_codec *codec)
32703e95b9abSLydia Wang {
32713e95b9abSLydia Wang 	struct via_spec *spec = codec->spec;
32723e95b9abSLydia Wang 	int imux_is_smixer;
32733e95b9abSLydia Wang 	unsigned int parm;
32743e95b9abSLydia Wang 	int is_8ch = 0;
3275bc92df7fSLydia Wang 	if ((spec->codec_type != VT1708B_4CH) &&
3276bc92df7fSLydia Wang 	    (codec->vendor_id != 0x11064397))
32773e95b9abSLydia Wang 		is_8ch = 1;
32783e95b9abSLydia Wang 
32793e95b9abSLydia Wang 	/* SW0 (17h) = stereo mixer */
32803e95b9abSLydia Wang 	imux_is_smixer =
32813e95b9abSLydia Wang 	(snd_hda_codec_read(codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
32823e95b9abSLydia Wang 	 == ((spec->codec_type == VT1708S) ? 5 : 0));
32833e95b9abSLydia Wang 	/* inputs */
32843e95b9abSLydia Wang 	/* PW 1/2/5 (1ah/1bh/1eh) */
32853e95b9abSLydia Wang 	parm = AC_PWRST_D3;
32863e95b9abSLydia Wang 	set_pin_power_state(codec, 0x1a, &parm);
32873e95b9abSLydia Wang 	set_pin_power_state(codec, 0x1b, &parm);
32883e95b9abSLydia Wang 	set_pin_power_state(codec, 0x1e, &parm);
32893e95b9abSLydia Wang 	if (imux_is_smixer)
32903e95b9abSLydia Wang 		parm = AC_PWRST_D0;
32913e95b9abSLydia Wang 	/* SW0 (17h), AIW 0/1 (13h/14h) */
32923e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm);
32933e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm);
32943e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm);
32953e95b9abSLydia Wang 
32963e95b9abSLydia Wang 	/* outputs */
32973e95b9abSLydia Wang 	/* PW0 (19h), SW1 (18h), AOW1 (11h) */
32983e95b9abSLydia Wang 	parm = AC_PWRST_D3;
32993e95b9abSLydia Wang 	set_pin_power_state(codec, 0x19, &parm);
33003e95b9abSLydia Wang 	if (spec->smart51_enabled)
33013e95b9abSLydia Wang 		set_pin_power_state(codec, 0x1b, &parm);
33023e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm);
33033e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
33043e95b9abSLydia Wang 
33053e95b9abSLydia Wang 	/* PW6 (22h), SW2 (26h), AOW2 (24h) */
33063e95b9abSLydia Wang 	if (is_8ch) {
33073e95b9abSLydia Wang 		parm = AC_PWRST_D3;
33083e95b9abSLydia Wang 		set_pin_power_state(codec, 0x22, &parm);
33093e95b9abSLydia Wang 		if (spec->smart51_enabled)
33103e95b9abSLydia Wang 			set_pin_power_state(codec, 0x1a, &parm);
33113e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x26, 0,
33123e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
33133e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x24, 0,
33143e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
3315bc92df7fSLydia Wang 	} else if (codec->vendor_id == 0x11064397) {
3316bc92df7fSLydia Wang 		/* PW7(23h), SW2(27h), AOW2(25h) */
3317bc92df7fSLydia Wang 		parm = AC_PWRST_D3;
3318bc92df7fSLydia Wang 		set_pin_power_state(codec, 0x23, &parm);
3319bc92df7fSLydia Wang 		if (spec->smart51_enabled)
3320bc92df7fSLydia Wang 			set_pin_power_state(codec, 0x1a, &parm);
3321bc92df7fSLydia Wang 		snd_hda_codec_write(codec, 0x27, 0,
3322bc92df7fSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
3323bc92df7fSLydia Wang 		snd_hda_codec_write(codec, 0x25, 0,
3324bc92df7fSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
33253e95b9abSLydia Wang 	}
33263e95b9abSLydia Wang 
33273e95b9abSLydia Wang 	/* PW 3/4/7 (1ch/1dh/23h) */
33283e95b9abSLydia Wang 	parm = AC_PWRST_D3;
33293e95b9abSLydia Wang 	/* force to D0 for internal Speaker */
33303e95b9abSLydia Wang 	set_pin_power_state(codec, 0x1c, &parm);
33313e95b9abSLydia Wang 	set_pin_power_state(codec, 0x1d, &parm);
33323e95b9abSLydia Wang 	if (is_8ch)
33333e95b9abSLydia Wang 		set_pin_power_state(codec, 0x23, &parm);
33343e95b9abSLydia Wang 
33353e95b9abSLydia Wang 	/* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
33363e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
33373e95b9abSLydia Wang 			    imux_is_smixer ? AC_PWRST_D0 : parm);
33383e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
33393e95b9abSLydia Wang 	if (is_8ch) {
33403e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x25, 0,
33413e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
33423e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x27, 0,
33433e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
3344bc92df7fSLydia Wang 	} else if (codec->vendor_id == 0x11064397 && spec->hp_independent_mode)
3345bc92df7fSLydia Wang 		snd_hda_codec_write(codec, 0x25, 0,
3346bc92df7fSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
33473e95b9abSLydia Wang }
33483e95b9abSLydia Wang 
3349518bf3baSLydia Wang static int patch_vt1708S(struct hda_codec *codec);
3350f7278fd0SJosepch Chan static int patch_vt1708B_8ch(struct hda_codec *codec)
3351f7278fd0SJosepch Chan {
3352f7278fd0SJosepch Chan 	struct via_spec *spec;
3353f7278fd0SJosepch Chan 	int err;
3354f7278fd0SJosepch Chan 
3355518bf3baSLydia Wang 	if (get_codec_type(codec) == VT1708BCE)
3356518bf3baSLydia Wang 		return patch_vt1708S(codec);
3357f7278fd0SJosepch Chan 	/* create a codec specific record */
33585b0cb1d8SJaroslav Kysela 	spec = via_new_spec(codec);
3359f7278fd0SJosepch Chan 	if (spec == NULL)
3360f7278fd0SJosepch Chan 		return -ENOMEM;
3361f7278fd0SJosepch Chan 
3362f7278fd0SJosepch Chan 	/* automatic parse from the BIOS config */
3363f7278fd0SJosepch Chan 	err = vt1708B_parse_auto_config(codec);
3364f7278fd0SJosepch Chan 	if (err < 0) {
3365f7278fd0SJosepch Chan 		via_free(codec);
3366f7278fd0SJosepch Chan 		return err;
3367f7278fd0SJosepch Chan 	} else if (!err) {
3368f7278fd0SJosepch Chan 		printk(KERN_INFO "hda_codec: Cannot set up configuration "
3369f7278fd0SJosepch Chan 		       "from BIOS.  Using genenic mode...\n");
3370f7278fd0SJosepch Chan 	}
3371f7278fd0SJosepch Chan 
337269e52a80SHarald Welte 	spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs;
337369e52a80SHarald Welte 	spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
3374f7278fd0SJosepch Chan 
3375f7278fd0SJosepch Chan 	spec->stream_name_analog = "VT1708B Analog";
3376f7278fd0SJosepch Chan 	spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
3377f7278fd0SJosepch Chan 	spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
3378f7278fd0SJosepch Chan 
3379f7278fd0SJosepch Chan 	spec->stream_name_digital = "VT1708B Digital";
3380f7278fd0SJosepch Chan 	spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
3381f7278fd0SJosepch Chan 	spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
3382f7278fd0SJosepch Chan 
3383f7278fd0SJosepch Chan 	if (!spec->adc_nids && spec->input_mux) {
3384f7278fd0SJosepch Chan 		spec->adc_nids = vt1708B_adc_nids;
3385f7278fd0SJosepch Chan 		spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
3386337b9d02STakashi Iwai 		get_mux_nids(codec);
3387f7278fd0SJosepch Chan 		spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
3388f7278fd0SJosepch Chan 		spec->num_mixers++;
3389f7278fd0SJosepch Chan 	}
3390f7278fd0SJosepch Chan 
3391f7278fd0SJosepch Chan 	codec->patch_ops = via_patch_ops;
3392f7278fd0SJosepch Chan 
3393f7278fd0SJosepch Chan 	codec->patch_ops.init = via_auto_init;
339469e52a80SHarald Welte 	codec->patch_ops.unsol_event = via_unsol_event;
3395f7278fd0SJosepch Chan #ifdef CONFIG_SND_HDA_POWER_SAVE
3396f7278fd0SJosepch Chan 	spec->loopback.amplist = vt1708B_loopbacks;
3397f7278fd0SJosepch Chan #endif
3398f7278fd0SJosepch Chan 
33993e95b9abSLydia Wang 	spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
34003e95b9abSLydia Wang 
3401f7278fd0SJosepch Chan 	return 0;
3402f7278fd0SJosepch Chan }
3403f7278fd0SJosepch Chan 
3404f7278fd0SJosepch Chan static int patch_vt1708B_4ch(struct hda_codec *codec)
3405f7278fd0SJosepch Chan {
3406f7278fd0SJosepch Chan 	struct via_spec *spec;
3407f7278fd0SJosepch Chan 	int err;
3408f7278fd0SJosepch Chan 
3409f7278fd0SJosepch Chan 	/* create a codec specific record */
34105b0cb1d8SJaroslav Kysela 	spec = via_new_spec(codec);
3411f7278fd0SJosepch Chan 	if (spec == NULL)
3412f7278fd0SJosepch Chan 		return -ENOMEM;
3413f7278fd0SJosepch Chan 
3414f7278fd0SJosepch Chan 	/* automatic parse from the BIOS config */
3415f7278fd0SJosepch Chan 	err = vt1708B_parse_auto_config(codec);
3416f7278fd0SJosepch Chan 	if (err < 0) {
3417f7278fd0SJosepch Chan 		via_free(codec);
3418f7278fd0SJosepch Chan 		return err;
3419f7278fd0SJosepch Chan 	} else if (!err) {
3420f7278fd0SJosepch Chan 		printk(KERN_INFO "hda_codec: Cannot set up configuration "
3421f7278fd0SJosepch Chan 		       "from BIOS.  Using genenic mode...\n");
3422f7278fd0SJosepch Chan 	}
3423f7278fd0SJosepch Chan 
342469e52a80SHarald Welte 	spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs;
342569e52a80SHarald Welte 	spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
3426f7278fd0SJosepch Chan 
3427f7278fd0SJosepch Chan 	spec->stream_name_analog = "VT1708B Analog";
3428f7278fd0SJosepch Chan 	spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
3429f7278fd0SJosepch Chan 	spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
3430f7278fd0SJosepch Chan 
3431f7278fd0SJosepch Chan 	spec->stream_name_digital = "VT1708B Digital";
3432f7278fd0SJosepch Chan 	spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
3433f7278fd0SJosepch Chan 	spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
3434f7278fd0SJosepch Chan 
3435f7278fd0SJosepch Chan 	if (!spec->adc_nids && spec->input_mux) {
3436f7278fd0SJosepch Chan 		spec->adc_nids = vt1708B_adc_nids;
3437f7278fd0SJosepch Chan 		spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
3438337b9d02STakashi Iwai 		get_mux_nids(codec);
3439f7278fd0SJosepch Chan 		spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
3440f7278fd0SJosepch Chan 		spec->num_mixers++;
3441f7278fd0SJosepch Chan 	}
3442f7278fd0SJosepch Chan 
3443f7278fd0SJosepch Chan 	codec->patch_ops = via_patch_ops;
3444f7278fd0SJosepch Chan 
3445f7278fd0SJosepch Chan 	codec->patch_ops.init = via_auto_init;
344669e52a80SHarald Welte 	codec->patch_ops.unsol_event = via_unsol_event;
3447f7278fd0SJosepch Chan #ifdef CONFIG_SND_HDA_POWER_SAVE
3448f7278fd0SJosepch Chan 	spec->loopback.amplist = vt1708B_loopbacks;
3449f7278fd0SJosepch Chan #endif
3450c577b8a1SJoseph Chan 
34513e95b9abSLydia Wang 	spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
34523e95b9abSLydia Wang 
3453c577b8a1SJoseph Chan 	return 0;
3454c577b8a1SJoseph Chan }
3455c577b8a1SJoseph Chan 
3456d949cac1SHarald Welte /* Patch for VT1708S */
3457d949cac1SHarald Welte 
3458d949cac1SHarald Welte /* capture mixer elements */
345990dd48a1STakashi Iwai static const struct snd_kcontrol_new vt1708S_capture_mixer[] = {
3460d949cac1SHarald Welte 	HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
3461d949cac1SHarald Welte 	HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
3462d949cac1SHarald Welte 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
3463d949cac1SHarald Welte 	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
34646369bcfcSLydia Wang 	HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT),
34656369bcfcSLydia Wang 	HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0,
34666369bcfcSLydia Wang 			 HDA_INPUT),
3467d949cac1SHarald Welte 	{
3468d949cac1SHarald Welte 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3469d949cac1SHarald Welte 		/* The multiple "Capture Source" controls confuse alsamixer
3470d949cac1SHarald Welte 		 * So call somewhat different..
3471d949cac1SHarald Welte 		 */
3472d949cac1SHarald Welte 		/* .name = "Capture Source", */
3473d949cac1SHarald Welte 		.name = "Input Source",
3474d949cac1SHarald Welte 		.count = 1,
3475d949cac1SHarald Welte 		.info = via_mux_enum_info,
3476d949cac1SHarald Welte 		.get = via_mux_enum_get,
3477d949cac1SHarald Welte 		.put = via_mux_enum_put,
3478d949cac1SHarald Welte 	},
3479d949cac1SHarald Welte 	{ } /* end */
3480d949cac1SHarald Welte };
3481d949cac1SHarald Welte 
348290dd48a1STakashi Iwai static const struct hda_verb vt1708S_volume_init_verbs[] = {
3483d949cac1SHarald Welte 	/* Unmute ADC0-1 and set the default input to mic-in */
3484d949cac1SHarald Welte 	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3485d949cac1SHarald Welte 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3486d949cac1SHarald Welte 
3487d949cac1SHarald Welte 	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the
3488d949cac1SHarald Welte 	 * analog-loopback mixer widget */
3489d949cac1SHarald Welte 	/* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
3490d949cac1SHarald Welte 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3491d949cac1SHarald Welte 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3492d949cac1SHarald Welte 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3493d949cac1SHarald Welte 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3494d949cac1SHarald Welte 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
3495d949cac1SHarald Welte 
3496d949cac1SHarald Welte 	/* Setup default input of PW4 to MW0 */
3497d949cac1SHarald Welte 	{0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
34985691ec7fSHarald Welte 	/* PW9, PW10  Output enable */
3499d949cac1SHarald Welte 	{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
35005691ec7fSHarald Welte 	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
3501d7426329SHarald Welte 	/* Enable Mic Boost Volume backdoor */
3502d7426329SHarald Welte 	{0x1, 0xf98, 0x1},
3503bc7e7e5cSLydia Wang 	/* don't bybass mixer */
3504bc7e7e5cSLydia Wang 	{0x1, 0xf88, 0xc0},
3505d949cac1SHarald Welte 	{ }
3506d949cac1SHarald Welte };
3507d949cac1SHarald Welte 
350890dd48a1STakashi Iwai static const struct hda_verb vt1708S_uniwill_init_verbs[] = {
3509a34df19aSLydia Wang 	{0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
3510a34df19aSLydia Wang 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
3511a34df19aSLydia Wang 	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3512a34df19aSLydia Wang 	{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3513a34df19aSLydia Wang 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3514a34df19aSLydia Wang 	{0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3515a34df19aSLydia Wang 	{0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3516a34df19aSLydia Wang 	{0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3517a34df19aSLydia Wang 	{0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
351869e52a80SHarald Welte 	{ }
351969e52a80SHarald Welte };
352069e52a80SHarald Welte 
352190dd48a1STakashi Iwai static const struct hda_verb vt1705_uniwill_init_verbs[] = {
3522bc92df7fSLydia Wang 	{0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
3523bc92df7fSLydia Wang 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
3524bc92df7fSLydia Wang 	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3525bc92df7fSLydia Wang 	{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3526bc92df7fSLydia Wang 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3527bc92df7fSLydia Wang 	{0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3528bc92df7fSLydia Wang 	{0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3529bc92df7fSLydia Wang 	{0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3530bc92df7fSLydia Wang 	{ }
3531bc92df7fSLydia Wang };
3532bc92df7fSLydia Wang 
353390dd48a1STakashi Iwai static const struct hda_pcm_stream vt1708S_pcm_analog_playback = {
3534d949cac1SHarald Welte 	.substreams = 2,
3535d949cac1SHarald Welte 	.channels_min = 2,
3536d949cac1SHarald Welte 	.channels_max = 8,
3537d949cac1SHarald Welte 	.nid = 0x10, /* NID to query formats and rates */
3538d949cac1SHarald Welte 	.ops = {
3539d949cac1SHarald Welte 		.open = via_playback_pcm_open,
3540c873cc25SLydia Wang 		.prepare = via_playback_multi_pcm_prepare,
3541c873cc25SLydia Wang 		.cleanup = via_playback_multi_pcm_cleanup,
354217314379SLydia Wang 		.close = via_pcm_open_close
3543d949cac1SHarald Welte 	},
3544d949cac1SHarald Welte };
3545d949cac1SHarald Welte 
354690dd48a1STakashi Iwai static const struct hda_pcm_stream vt1705_pcm_analog_playback = {
3547bc92df7fSLydia Wang 	.substreams = 2,
3548bc92df7fSLydia Wang 	.channels_min = 2,
3549bc92df7fSLydia Wang 	.channels_max = 6,
3550bc92df7fSLydia Wang 	.nid = 0x10, /* NID to query formats and rates */
3551bc92df7fSLydia Wang 	.ops = {
3552bc92df7fSLydia Wang 		.open = via_playback_pcm_open,
3553bc92df7fSLydia Wang 		.prepare = via_playback_multi_pcm_prepare,
3554bc92df7fSLydia Wang 		.cleanup = via_playback_multi_pcm_cleanup,
3555bc92df7fSLydia Wang 		.close = via_pcm_open_close
3556bc92df7fSLydia Wang 	},
3557bc92df7fSLydia Wang };
3558bc92df7fSLydia Wang 
355990dd48a1STakashi Iwai static const struct hda_pcm_stream vt1708S_pcm_analog_capture = {
3560d949cac1SHarald Welte 	.substreams = 2,
3561d949cac1SHarald Welte 	.channels_min = 2,
3562d949cac1SHarald Welte 	.channels_max = 2,
3563d949cac1SHarald Welte 	.nid = 0x13, /* NID to query formats and rates */
3564d949cac1SHarald Welte 	.ops = {
356517314379SLydia Wang 		.open = via_pcm_open_close,
3566d949cac1SHarald Welte 		.prepare = via_capture_pcm_prepare,
356717314379SLydia Wang 		.cleanup = via_capture_pcm_cleanup,
356817314379SLydia Wang 		.close = via_pcm_open_close
3569d949cac1SHarald Welte 	},
3570d949cac1SHarald Welte };
3571d949cac1SHarald Welte 
357290dd48a1STakashi Iwai static const struct hda_pcm_stream vt1708S_pcm_digital_playback = {
35739da29271STakashi Iwai 	.substreams = 1,
3574d949cac1SHarald Welte 	.channels_min = 2,
3575d949cac1SHarald Welte 	.channels_max = 2,
3576d949cac1SHarald Welte 	/* NID is set in via_build_pcms */
3577d949cac1SHarald Welte 	.ops = {
3578d949cac1SHarald Welte 		.open = via_dig_playback_pcm_open,
3579d949cac1SHarald Welte 		.close = via_dig_playback_pcm_close,
35809da29271STakashi Iwai 		.prepare = via_dig_playback_pcm_prepare,
35819da29271STakashi Iwai 		.cleanup = via_dig_playback_pcm_cleanup
3582d949cac1SHarald Welte 	},
3583d949cac1SHarald Welte };
3584d949cac1SHarald Welte 
3585d949cac1SHarald Welte /* fill in the dac_nids table from the parsed pin configuration */
3586d949cac1SHarald Welte static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
3587d949cac1SHarald Welte 				     const struct auto_pin_cfg *cfg)
3588d949cac1SHarald Welte {
3589d949cac1SHarald Welte 	int i;
3590d949cac1SHarald Welte 	hda_nid_t nid;
3591d949cac1SHarald Welte 
3592d949cac1SHarald Welte 	spec->multiout.num_dacs = cfg->line_outs;
3593d949cac1SHarald Welte 
3594d949cac1SHarald Welte 	spec->multiout.dac_nids = spec->private_dac_nids;
3595d949cac1SHarald Welte 
3596d949cac1SHarald Welte 	for (i = 0; i < 4; i++) {
3597d949cac1SHarald Welte 		nid = cfg->line_out_pins[i];
3598d949cac1SHarald Welte 		if (nid) {
3599d949cac1SHarald Welte 			/* config dac list */
3600d949cac1SHarald Welte 			switch (i) {
3601d949cac1SHarald Welte 			case AUTO_SEQ_FRONT:
3602dda14410STakashi Iwai 				spec->private_dac_nids[i] = 0x10;
3603d949cac1SHarald Welte 				break;
3604d949cac1SHarald Welte 			case AUTO_SEQ_CENLFE:
3605bc92df7fSLydia Wang 				if (spec->codec->vendor_id == 0x11064397)
3606dda14410STakashi Iwai 					spec->private_dac_nids[i] = 0x25;
3607bc92df7fSLydia Wang 				else
3608dda14410STakashi Iwai 					spec->private_dac_nids[i] = 0x24;
3609d949cac1SHarald Welte 				break;
3610d949cac1SHarald Welte 			case AUTO_SEQ_SURROUND:
3611dda14410STakashi Iwai 				spec->private_dac_nids[i] = 0x11;
3612d949cac1SHarald Welte 				break;
3613d949cac1SHarald Welte 			case AUTO_SEQ_SIDE:
3614dda14410STakashi Iwai 				spec->private_dac_nids[i] = 0x25;
3615d949cac1SHarald Welte 				break;
3616d949cac1SHarald Welte 			}
3617d949cac1SHarald Welte 		}
3618d949cac1SHarald Welte 	}
3619d949cac1SHarald Welte 
362032e0191dSClemens Ladisch 	/* for Smart 5.1, line/mic inputs double as output pins */
362132e0191dSClemens Ladisch 	if (cfg->line_outs == 1) {
362232e0191dSClemens Ladisch 		spec->multiout.num_dacs = 3;
3623dda14410STakashi Iwai 		spec->private_dac_nids[AUTO_SEQ_SURROUND] = 0x11;
3624bc92df7fSLydia Wang 		if (spec->codec->vendor_id == 0x11064397)
3625dda14410STakashi Iwai 			spec->private_dac_nids[AUTO_SEQ_CENLFE] = 0x25;
3626bc92df7fSLydia Wang 		else
3627dda14410STakashi Iwai 			spec->private_dac_nids[AUTO_SEQ_CENLFE] = 0x24;
362832e0191dSClemens Ladisch 	}
362932e0191dSClemens Ladisch 
3630d949cac1SHarald Welte 	return 0;
3631d949cac1SHarald Welte }
3632d949cac1SHarald Welte 
3633d949cac1SHarald Welte /* add playback controls from the parsed DAC table */
3634bc92df7fSLydia Wang static int vt1708S_auto_create_multi_out_ctls(struct hda_codec *codec,
3635d949cac1SHarald Welte 					     const struct auto_pin_cfg *cfg)
3636d949cac1SHarald Welte {
3637bc92df7fSLydia Wang 	struct via_spec *spec = codec->spec;
3638d949cac1SHarald Welte 	char name[32];
3639ea734963STakashi Iwai 	static const char * const chname[4] = {
3640ea734963STakashi Iwai 		"Front", "Surround", "C/LFE", "Side"
3641ea734963STakashi Iwai 	};
3642bc92df7fSLydia Wang 	hda_nid_t nid_vols[2][4] = { {0x10, 0x11, 0x24, 0x25},
3643bc92df7fSLydia Wang 				     {0x10, 0x11, 0x25, 0} };
3644bc92df7fSLydia Wang 	hda_nid_t nid_mutes[2][4] = { {0x1C, 0x18, 0x26, 0x27},
3645bc92df7fSLydia Wang 				      {0x1C, 0x18, 0x27, 0} };
3646d949cac1SHarald Welte 	hda_nid_t nid, nid_vol, nid_mute;
3647d949cac1SHarald Welte 	int i, err;
3648d949cac1SHarald Welte 
3649d949cac1SHarald Welte 	for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
3650d949cac1SHarald Welte 		nid = cfg->line_out_pins[i];
3651d949cac1SHarald Welte 
365232e0191dSClemens Ladisch 		/* for Smart 5.1, there are always at least six channels */
365332e0191dSClemens Ladisch 		if (!nid && i > AUTO_SEQ_CENLFE)
3654d949cac1SHarald Welte 			continue;
3655d949cac1SHarald Welte 
3656bc92df7fSLydia Wang 		if (codec->vendor_id == 0x11064397) {
3657bc92df7fSLydia Wang 			nid_vol = nid_vols[1][i];
3658bc92df7fSLydia Wang 			nid_mute = nid_mutes[1][i];
3659bc92df7fSLydia Wang 		} else {
3660bc92df7fSLydia Wang 			nid_vol = nid_vols[0][i];
3661bc92df7fSLydia Wang 			nid_mute = nid_mutes[0][i];
3662bc92df7fSLydia Wang 		}
3663bc92df7fSLydia Wang 		if (!nid_vol && !nid_mute)
3664bc92df7fSLydia Wang 			continue;
3665d949cac1SHarald Welte 
3666d949cac1SHarald Welte 		if (i == AUTO_SEQ_CENLFE) {
3667d949cac1SHarald Welte 			/* Center/LFE */
3668d949cac1SHarald Welte 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3669d949cac1SHarald Welte 					      "Center Playback Volume",
3670d949cac1SHarald Welte 					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
3671d949cac1SHarald Welte 								  HDA_OUTPUT));
3672d949cac1SHarald Welte 			if (err < 0)
3673d949cac1SHarald Welte 				return err;
3674d949cac1SHarald Welte 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3675d949cac1SHarald Welte 					      "LFE Playback Volume",
3676d949cac1SHarald Welte 					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
3677d949cac1SHarald Welte 								  HDA_OUTPUT));
3678d949cac1SHarald Welte 			if (err < 0)
3679d949cac1SHarald Welte 				return err;
3680d949cac1SHarald Welte 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3681d949cac1SHarald Welte 					      "Center Playback Switch",
3682d949cac1SHarald Welte 					      HDA_COMPOSE_AMP_VAL(nid_mute,
3683d949cac1SHarald Welte 								  1, 0,
3684d949cac1SHarald Welte 								  HDA_OUTPUT));
3685d949cac1SHarald Welte 			if (err < 0)
3686d949cac1SHarald Welte 				return err;
3687d949cac1SHarald Welte 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3688d949cac1SHarald Welte 					      "LFE Playback Switch",
3689d949cac1SHarald Welte 					      HDA_COMPOSE_AMP_VAL(nid_mute,
3690d949cac1SHarald Welte 								  2, 0,
3691d949cac1SHarald Welte 								  HDA_OUTPUT));
3692d949cac1SHarald Welte 			if (err < 0)
3693d949cac1SHarald Welte 				return err;
3694d949cac1SHarald Welte 		} else if (i == AUTO_SEQ_FRONT) {
3695d949cac1SHarald Welte 			/* add control to mixer index 0 */
3696d949cac1SHarald Welte 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3697d949cac1SHarald Welte 					      "Master Front Playback Volume",
3698d949cac1SHarald Welte 					      HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
3699d949cac1SHarald Welte 								  HDA_INPUT));
3700d949cac1SHarald Welte 			if (err < 0)
3701d949cac1SHarald Welte 				return err;
3702d949cac1SHarald Welte 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3703d949cac1SHarald Welte 					      "Master Front Playback Switch",
3704d949cac1SHarald Welte 					      HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
3705d949cac1SHarald Welte 								  HDA_INPUT));
3706d949cac1SHarald Welte 			if (err < 0)
3707d949cac1SHarald Welte 				return err;
3708d949cac1SHarald Welte 
3709d949cac1SHarald Welte 			/* Front */
3710d949cac1SHarald Welte 			sprintf(name, "%s Playback Volume", chname[i]);
3711d949cac1SHarald Welte 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3712d949cac1SHarald Welte 					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3713d949cac1SHarald Welte 								  HDA_OUTPUT));
3714d949cac1SHarald Welte 			if (err < 0)
3715d949cac1SHarald Welte 				return err;
3716d949cac1SHarald Welte 			sprintf(name, "%s Playback Switch", chname[i]);
3717d949cac1SHarald Welte 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3718d949cac1SHarald Welte 					      HDA_COMPOSE_AMP_VAL(nid_mute,
3719d949cac1SHarald Welte 								  3, 0,
3720d949cac1SHarald Welte 								  HDA_OUTPUT));
3721d949cac1SHarald Welte 			if (err < 0)
3722d949cac1SHarald Welte 				return err;
3723d949cac1SHarald Welte 		} else {
3724d949cac1SHarald Welte 			sprintf(name, "%s Playback Volume", chname[i]);
3725d949cac1SHarald Welte 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3726d949cac1SHarald Welte 					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3727d949cac1SHarald Welte 								  HDA_OUTPUT));
3728d949cac1SHarald Welte 			if (err < 0)
3729d949cac1SHarald Welte 				return err;
3730d949cac1SHarald Welte 			sprintf(name, "%s Playback Switch", chname[i]);
3731d949cac1SHarald Welte 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3732d949cac1SHarald Welte 					      HDA_COMPOSE_AMP_VAL(nid_mute,
3733d949cac1SHarald Welte 								  3, 0,
3734d949cac1SHarald Welte 								  HDA_OUTPUT));
3735d949cac1SHarald Welte 			if (err < 0)
3736d949cac1SHarald Welte 				return err;
3737d949cac1SHarald Welte 		}
3738d949cac1SHarald Welte 	}
3739d949cac1SHarald Welte 
3740d949cac1SHarald Welte 	return 0;
3741d949cac1SHarald Welte }
3742d949cac1SHarald Welte 
3743d949cac1SHarald Welte static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
3744d949cac1SHarald Welte {
3745d949cac1SHarald Welte 	int err;
3746d949cac1SHarald Welte 
3747d949cac1SHarald Welte 	if (!pin)
3748d949cac1SHarald Welte 		return 0;
3749d949cac1SHarald Welte 
3750d949cac1SHarald Welte 	spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */
3751cdc1784dSLydia Wang 	spec->hp_independent_mode_index = 1;
3752d949cac1SHarald Welte 
3753d949cac1SHarald Welte 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3754d949cac1SHarald Welte 			      "Headphone Playback Volume",
3755d949cac1SHarald Welte 			      HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
3756d949cac1SHarald Welte 	if (err < 0)
3757d949cac1SHarald Welte 		return err;
3758d949cac1SHarald Welte 
3759d949cac1SHarald Welte 	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3760d949cac1SHarald Welte 			      "Headphone Playback Switch",
3761d949cac1SHarald Welte 			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3762d949cac1SHarald Welte 	if (err < 0)
3763d949cac1SHarald Welte 		return err;
3764d949cac1SHarald Welte 
37650aa62aefSHarald Welte 	create_hp_imux(spec);
37660aa62aefSHarald Welte 
3767d949cac1SHarald Welte 	return 0;
3768d949cac1SHarald Welte }
3769d949cac1SHarald Welte 
3770d949cac1SHarald Welte /* create playback/capture controls for input pins */
377110a20af7STakashi Iwai static int vt1708S_auto_create_analog_input_ctls(struct hda_codec *codec,
3772d949cac1SHarald Welte 						const struct auto_pin_cfg *cfg)
3773d949cac1SHarald Welte {
377490dd48a1STakashi Iwai 	static const hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
377510a20af7STakashi Iwai 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
3776f3268512STakashi Iwai 						ARRAY_SIZE(pin_idxs));
3777d949cac1SHarald Welte }
3778d949cac1SHarald Welte 
37799da29271STakashi Iwai /* fill out digital output widgets; one for master and one for slave outputs */
37809da29271STakashi Iwai static void fill_dig_outs(struct hda_codec *codec)
37819da29271STakashi Iwai {
37829da29271STakashi Iwai 	struct via_spec *spec = codec->spec;
37839da29271STakashi Iwai 	int i;
37849da29271STakashi Iwai 
37859da29271STakashi Iwai 	for (i = 0; i < spec->autocfg.dig_outs; i++) {
37869da29271STakashi Iwai 		hda_nid_t nid;
37879da29271STakashi Iwai 		int conn;
37889da29271STakashi Iwai 
37899da29271STakashi Iwai 		nid = spec->autocfg.dig_out_pins[i];
37909da29271STakashi Iwai 		if (!nid)
37919da29271STakashi Iwai 			continue;
37929da29271STakashi Iwai 		conn = snd_hda_get_connections(codec, nid, &nid, 1);
37939da29271STakashi Iwai 		if (conn < 1)
37949da29271STakashi Iwai 			continue;
37959da29271STakashi Iwai 		if (!spec->multiout.dig_out_nid)
37969da29271STakashi Iwai 			spec->multiout.dig_out_nid = nid;
37979da29271STakashi Iwai 		else {
37989da29271STakashi Iwai 			spec->slave_dig_outs[0] = nid;
37999da29271STakashi Iwai 			break; /* at most two dig outs */
38009da29271STakashi Iwai 		}
38019da29271STakashi Iwai 	}
38029da29271STakashi Iwai }
38039da29271STakashi Iwai 
3804d949cac1SHarald Welte static int vt1708S_parse_auto_config(struct hda_codec *codec)
3805d949cac1SHarald Welte {
3806d949cac1SHarald Welte 	struct via_spec *spec = codec->spec;
3807d949cac1SHarald Welte 	int err;
3808d949cac1SHarald Welte 
38099da29271STakashi Iwai 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
3810d949cac1SHarald Welte 	if (err < 0)
3811d949cac1SHarald Welte 		return err;
3812d949cac1SHarald Welte 	err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg);
3813d949cac1SHarald Welte 	if (err < 0)
3814d949cac1SHarald Welte 		return err;
3815d949cac1SHarald Welte 	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
3816d949cac1SHarald Welte 		return 0; /* can't find valid BIOS pin config */
3817d949cac1SHarald Welte 
3818bc92df7fSLydia Wang 	err = vt1708S_auto_create_multi_out_ctls(codec, &spec->autocfg);
3819d949cac1SHarald Welte 	if (err < 0)
3820d949cac1SHarald Welte 		return err;
3821d949cac1SHarald Welte 	err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
3822d949cac1SHarald Welte 	if (err < 0)
3823d949cac1SHarald Welte 		return err;
382410a20af7STakashi Iwai 	err = vt1708S_auto_create_analog_input_ctls(codec, &spec->autocfg);
3825d949cac1SHarald Welte 	if (err < 0)
3826d949cac1SHarald Welte 		return err;
3827d949cac1SHarald Welte 
3828d949cac1SHarald Welte 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3829d949cac1SHarald Welte 
38309da29271STakashi Iwai 	fill_dig_outs(codec);
383198aa34c0SHarald Welte 
3832603c4019STakashi Iwai 	if (spec->kctls.list)
3833603c4019STakashi Iwai 		spec->mixers[spec->num_mixers++] = spec->kctls.list;
3834d949cac1SHarald Welte 
38350aa62aefSHarald Welte 	spec->input_mux = &spec->private_imux[0];
38360aa62aefSHarald Welte 
3837f8fdd495SHarald Welte 	if (spec->hp_mux)
38383d83e577STakashi Iwai 		via_hp_build(codec);
3839d949cac1SHarald Welte 
38405b0cb1d8SJaroslav Kysela 	via_smart51_build(spec);
3841d949cac1SHarald Welte 	return 1;
3842d949cac1SHarald Welte }
3843d949cac1SHarald Welte 
3844d949cac1SHarald Welte #ifdef CONFIG_SND_HDA_POWER_SAVE
384590dd48a1STakashi Iwai static const struct hda_amp_list vt1708S_loopbacks[] = {
3846d949cac1SHarald Welte 	{ 0x16, HDA_INPUT, 1 },
3847d949cac1SHarald Welte 	{ 0x16, HDA_INPUT, 2 },
3848d949cac1SHarald Welte 	{ 0x16, HDA_INPUT, 3 },
3849d949cac1SHarald Welte 	{ 0x16, HDA_INPUT, 4 },
3850d949cac1SHarald Welte 	{ } /* end */
3851d949cac1SHarald Welte };
3852d949cac1SHarald Welte #endif
3853d949cac1SHarald Welte 
38546369bcfcSLydia Wang static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin,
38556369bcfcSLydia Wang 			       int offset, int num_steps, int step_size)
38566369bcfcSLydia Wang {
38576369bcfcSLydia Wang 	snd_hda_override_amp_caps(codec, pin, HDA_INPUT,
38586369bcfcSLydia Wang 				  (offset << AC_AMPCAP_OFFSET_SHIFT) |
38596369bcfcSLydia Wang 				  (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) |
38606369bcfcSLydia Wang 				  (step_size << AC_AMPCAP_STEP_SIZE_SHIFT) |
38616369bcfcSLydia Wang 				  (0 << AC_AMPCAP_MUTE_SHIFT));
38626369bcfcSLydia Wang }
38636369bcfcSLydia Wang 
3864d949cac1SHarald Welte static int patch_vt1708S(struct hda_codec *codec)
3865d949cac1SHarald Welte {
3866d949cac1SHarald Welte 	struct via_spec *spec;
3867d949cac1SHarald Welte 	int err;
3868d949cac1SHarald Welte 
3869d949cac1SHarald Welte 	/* create a codec specific record */
38705b0cb1d8SJaroslav Kysela 	spec = via_new_spec(codec);
3871d949cac1SHarald Welte 	if (spec == NULL)
3872d949cac1SHarald Welte 		return -ENOMEM;
3873d949cac1SHarald Welte 
3874d949cac1SHarald Welte 	/* automatic parse from the BIOS config */
3875d949cac1SHarald Welte 	err = vt1708S_parse_auto_config(codec);
3876d949cac1SHarald Welte 	if (err < 0) {
3877d949cac1SHarald Welte 		via_free(codec);
3878d949cac1SHarald Welte 		return err;
3879d949cac1SHarald Welte 	} else if (!err) {
3880d949cac1SHarald Welte 		printk(KERN_INFO "hda_codec: Cannot set up configuration "
3881d949cac1SHarald Welte 		       "from BIOS.  Using genenic mode...\n");
3882d949cac1SHarald Welte 	}
3883d949cac1SHarald Welte 
388469e52a80SHarald Welte 	spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
3885bc92df7fSLydia Wang 	if (codec->vendor_id == 0x11064397)
3886bc92df7fSLydia Wang 		spec->init_verbs[spec->num_iverbs++] =
3887bc92df7fSLydia Wang 			vt1705_uniwill_init_verbs;
3888bc92df7fSLydia Wang 	else
3889bc92df7fSLydia Wang 		spec->init_verbs[spec->num_iverbs++] =
3890bc92df7fSLydia Wang 			vt1708S_uniwill_init_verbs;
3891d949cac1SHarald Welte 
389236dd5c4aSLydia Wang 	if (codec->vendor_id == 0x11060440)
389336dd5c4aSLydia Wang 		spec->stream_name_analog = "VT1818S Analog";
3894bc92df7fSLydia Wang 	else if (codec->vendor_id == 0x11064397)
3895bc92df7fSLydia Wang 		spec->stream_name_analog = "VT1705 Analog";
389636dd5c4aSLydia Wang 	else
3897d949cac1SHarald Welte 		spec->stream_name_analog = "VT1708S Analog";
3898bc92df7fSLydia Wang 	if (codec->vendor_id == 0x11064397)
3899bc92df7fSLydia Wang 		spec->stream_analog_playback = &vt1705_pcm_analog_playback;
3900bc92df7fSLydia Wang 	else
3901d949cac1SHarald Welte 		spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
3902d949cac1SHarald Welte 	spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
3903d949cac1SHarald Welte 
390436dd5c4aSLydia Wang 	if (codec->vendor_id == 0x11060440)
390536dd5c4aSLydia Wang 		spec->stream_name_digital = "VT1818S Digital";
3906bc92df7fSLydia Wang 	else if (codec->vendor_id == 0x11064397)
3907bc92df7fSLydia Wang 		spec->stream_name_digital = "VT1705 Digital";
390836dd5c4aSLydia Wang 	else
3909d949cac1SHarald Welte 		spec->stream_name_digital = "VT1708S Digital";
3910d949cac1SHarald Welte 	spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
3911d949cac1SHarald Welte 
3912d949cac1SHarald Welte 	if (!spec->adc_nids && spec->input_mux) {
3913d949cac1SHarald Welte 		spec->adc_nids = vt1708S_adc_nids;
3914d949cac1SHarald Welte 		spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
3915337b9d02STakashi Iwai 		get_mux_nids(codec);
39166369bcfcSLydia Wang 		override_mic_boost(codec, 0x1a, 0, 3, 40);
39176369bcfcSLydia Wang 		override_mic_boost(codec, 0x1e, 0, 3, 40);
3918d949cac1SHarald Welte 		spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
3919d949cac1SHarald Welte 		spec->num_mixers++;
3920d949cac1SHarald Welte 	}
3921d949cac1SHarald Welte 
3922d949cac1SHarald Welte 	codec->patch_ops = via_patch_ops;
3923d949cac1SHarald Welte 
3924d949cac1SHarald Welte 	codec->patch_ops.init = via_auto_init;
392569e52a80SHarald Welte 	codec->patch_ops.unsol_event = via_unsol_event;
3926d949cac1SHarald Welte #ifdef CONFIG_SND_HDA_POWER_SAVE
3927d949cac1SHarald Welte 	spec->loopback.amplist = vt1708S_loopbacks;
3928d949cac1SHarald Welte #endif
3929d949cac1SHarald Welte 
3930518bf3baSLydia Wang 	/* correct names for VT1708BCE */
3931518bf3baSLydia Wang 	if (get_codec_type(codec) == VT1708BCE)	{
3932518bf3baSLydia Wang 		kfree(codec->chip_name);
3933518bf3baSLydia Wang 		codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
3934518bf3baSLydia Wang 		snprintf(codec->bus->card->mixername,
3935518bf3baSLydia Wang 			 sizeof(codec->bus->card->mixername),
3936518bf3baSLydia Wang 			 "%s %s", codec->vendor_name, codec->chip_name);
3937518bf3baSLydia Wang 		spec->stream_name_analog = "VT1708BCE Analog";
3938518bf3baSLydia Wang 		spec->stream_name_digital = "VT1708BCE Digital";
3939518bf3baSLydia Wang 	}
3940970f630fSLydia Wang 	/* correct names for VT1818S */
3941970f630fSLydia Wang 	if (codec->vendor_id == 0x11060440) {
3942970f630fSLydia Wang 		spec->stream_name_analog = "VT1818S Analog";
3943970f630fSLydia Wang 		spec->stream_name_digital = "VT1818S Digital";
3944970f630fSLydia Wang 	}
3945bc92df7fSLydia Wang 	/* correct names for VT1705 */
3946bc92df7fSLydia Wang 	if (codec->vendor_id == 0x11064397)	{
3947bc92df7fSLydia Wang 		kfree(codec->chip_name);
3948bc92df7fSLydia Wang 		codec->chip_name = kstrdup("VT1705", GFP_KERNEL);
3949bc92df7fSLydia Wang 		snprintf(codec->bus->card->mixername,
3950bc92df7fSLydia Wang 			 sizeof(codec->bus->card->mixername),
3951bc92df7fSLydia Wang 			 "%s %s", codec->vendor_name, codec->chip_name);
3952bc92df7fSLydia Wang 	}
39533e95b9abSLydia Wang 	spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
3954d949cac1SHarald Welte 	return 0;
3955d949cac1SHarald Welte }
3956d949cac1SHarald Welte 
3957d949cac1SHarald Welte /* Patch for VT1702 */
3958d949cac1SHarald Welte 
3959d949cac1SHarald Welte /* capture mixer elements */
396090dd48a1STakashi Iwai static const struct snd_kcontrol_new vt1702_capture_mixer[] = {
3961d949cac1SHarald Welte 	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
3962d949cac1SHarald Welte 	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
3963d949cac1SHarald Welte 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
3964d949cac1SHarald Welte 	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT),
3965d949cac1SHarald Welte 	HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT),
3966d949cac1SHarald Welte 	HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT),
3967d949cac1SHarald Welte 	HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0,
3968d949cac1SHarald Welte 			 HDA_INPUT),
3969d949cac1SHarald Welte 	{
3970d949cac1SHarald Welte 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3971d949cac1SHarald Welte 		/* The multiple "Capture Source" controls confuse alsamixer
3972d949cac1SHarald Welte 		 * So call somewhat different..
3973d949cac1SHarald Welte 		 */
3974d949cac1SHarald Welte 		/* .name = "Capture Source", */
3975d949cac1SHarald Welte 		.name = "Input Source",
3976d949cac1SHarald Welte 		.count = 1,
3977d949cac1SHarald Welte 		.info = via_mux_enum_info,
3978d949cac1SHarald Welte 		.get = via_mux_enum_get,
3979d949cac1SHarald Welte 		.put = via_mux_enum_put,
3980d949cac1SHarald Welte 	},
3981d949cac1SHarald Welte 	{ } /* end */
3982d949cac1SHarald Welte };
3983d949cac1SHarald Welte 
398490dd48a1STakashi Iwai static const struct hda_verb vt1702_volume_init_verbs[] = {
3985d949cac1SHarald Welte 	/*
3986d949cac1SHarald Welte 	 * Unmute ADC0-1 and set the default input to mic-in
3987d949cac1SHarald Welte 	 */
3988d949cac1SHarald Welte 	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3989d949cac1SHarald Welte 	{0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3990d949cac1SHarald Welte 	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3991d949cac1SHarald Welte 
3992d949cac1SHarald Welte 
3993d949cac1SHarald Welte 	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3994d949cac1SHarald Welte 	 * mixer widget
3995d949cac1SHarald Welte 	 */
3996d949cac1SHarald Welte 	/* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */
3997d949cac1SHarald Welte 	{0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3998d949cac1SHarald Welte 	{0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3999d949cac1SHarald Welte 	{0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4000d949cac1SHarald Welte 	{0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
4001d949cac1SHarald Welte 	{0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4002d949cac1SHarald Welte 
4003d949cac1SHarald Welte 	/* Setup default input of PW4 to MW0 */
4004d949cac1SHarald Welte 	{0x17, AC_VERB_SET_CONNECT_SEL, 0x1},
4005d949cac1SHarald Welte 	/* PW6 PW7 Output enable */
4006d949cac1SHarald Welte 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4007d949cac1SHarald Welte 	{0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4008bc7e7e5cSLydia Wang 	/* mixer enable */
4009bc7e7e5cSLydia Wang 	{0x1, 0xF88, 0x3},
4010bc7e7e5cSLydia Wang 	/* GPIO 0~2 */
4011bc7e7e5cSLydia Wang 	{0x1, 0xF82, 0x3F},
4012d949cac1SHarald Welte 	{ }
4013d949cac1SHarald Welte };
4014d949cac1SHarald Welte 
401590dd48a1STakashi Iwai static const struct hda_verb vt1702_uniwill_init_verbs[] = {
4016a34df19aSLydia Wang 	{0x17, AC_VERB_SET_UNSOLICITED_ENABLE,
4017a34df19aSLydia Wang 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
4018a34df19aSLydia Wang 	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4019a34df19aSLydia Wang 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4020a34df19aSLydia Wang 	{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4021a34df19aSLydia Wang 	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
402269e52a80SHarald Welte 	{ }
402369e52a80SHarald Welte };
402469e52a80SHarald Welte 
402590dd48a1STakashi Iwai static const struct hda_pcm_stream vt1702_pcm_analog_playback = {
40260aa62aefSHarald Welte 	.substreams = 2,
4027d949cac1SHarald Welte 	.channels_min = 2,
4028d949cac1SHarald Welte 	.channels_max = 2,
4029d949cac1SHarald Welte 	.nid = 0x10, /* NID to query formats and rates */
4030d949cac1SHarald Welte 	.ops = {
4031d949cac1SHarald Welte 		.open = via_playback_pcm_open,
40320aa62aefSHarald Welte 		.prepare = via_playback_multi_pcm_prepare,
403317314379SLydia Wang 		.cleanup = via_playback_multi_pcm_cleanup,
403417314379SLydia Wang 		.close = via_pcm_open_close
4035d949cac1SHarald Welte 	},
4036d949cac1SHarald Welte };
4037d949cac1SHarald Welte 
403890dd48a1STakashi Iwai static const struct hda_pcm_stream vt1702_pcm_analog_capture = {
4039d949cac1SHarald Welte 	.substreams = 3,
4040d949cac1SHarald Welte 	.channels_min = 2,
4041d949cac1SHarald Welte 	.channels_max = 2,
4042d949cac1SHarald Welte 	.nid = 0x12, /* NID to query formats and rates */
4043d949cac1SHarald Welte 	.ops = {
404417314379SLydia Wang 		.open = via_pcm_open_close,
4045d949cac1SHarald Welte 		.prepare = via_capture_pcm_prepare,
404617314379SLydia Wang 		.cleanup = via_capture_pcm_cleanup,
404717314379SLydia Wang 		.close = via_pcm_open_close
4048d949cac1SHarald Welte 	},
4049d949cac1SHarald Welte };
4050d949cac1SHarald Welte 
405190dd48a1STakashi Iwai static const struct hda_pcm_stream vt1702_pcm_digital_playback = {
40525691ec7fSHarald Welte 	.substreams = 2,
4053d949cac1SHarald Welte 	.channels_min = 2,
4054d949cac1SHarald Welte 	.channels_max = 2,
4055d949cac1SHarald Welte 	/* NID is set in via_build_pcms */
4056d949cac1SHarald Welte 	.ops = {
4057d949cac1SHarald Welte 		.open = via_dig_playback_pcm_open,
4058d949cac1SHarald Welte 		.close = via_dig_playback_pcm_close,
40599da29271STakashi Iwai 		.prepare = via_dig_playback_pcm_prepare,
40609da29271STakashi Iwai 		.cleanup = via_dig_playback_pcm_cleanup
4061d949cac1SHarald Welte 	},
4062d949cac1SHarald Welte };
4063d949cac1SHarald Welte 
4064d949cac1SHarald Welte /* fill in the dac_nids table from the parsed pin configuration */
4065d949cac1SHarald Welte static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
4066d949cac1SHarald Welte 				     const struct auto_pin_cfg *cfg)
4067d949cac1SHarald Welte {
4068d949cac1SHarald Welte 	spec->multiout.num_dacs = 1;
4069d949cac1SHarald Welte 	spec->multiout.dac_nids = spec->private_dac_nids;
4070d949cac1SHarald Welte 
4071d949cac1SHarald Welte 	if (cfg->line_out_pins[0]) {
4072d949cac1SHarald Welte 		/* config dac list */
4073dda14410STakashi Iwai 		spec->private_dac_nids[0] = 0x10;
4074d949cac1SHarald Welte 	}
4075d949cac1SHarald Welte 
4076d949cac1SHarald Welte 	return 0;
4077d949cac1SHarald Welte }
4078d949cac1SHarald Welte 
4079d949cac1SHarald Welte /* add playback controls from the parsed DAC table */
4080d949cac1SHarald Welte static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
4081d949cac1SHarald Welte 					     const struct auto_pin_cfg *cfg)
4082d949cac1SHarald Welte {
4083d949cac1SHarald Welte 	int err;
4084d949cac1SHarald Welte 
4085d949cac1SHarald Welte 	if (!cfg->line_out_pins[0])
4086d949cac1SHarald Welte 		return -1;
4087d949cac1SHarald Welte 
4088d949cac1SHarald Welte 	/* add control to mixer index 0 */
4089d949cac1SHarald Welte 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4090d949cac1SHarald Welte 			      "Master Front Playback Volume",
4091d949cac1SHarald Welte 			      HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
4092d949cac1SHarald Welte 	if (err < 0)
4093d949cac1SHarald Welte 		return err;
4094d949cac1SHarald Welte 	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
4095d949cac1SHarald Welte 			      "Master Front Playback Switch",
4096d949cac1SHarald Welte 			      HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
4097d949cac1SHarald Welte 	if (err < 0)
4098d949cac1SHarald Welte 		return err;
4099d949cac1SHarald Welte 
4100d949cac1SHarald Welte 	/* Front */
4101d949cac1SHarald Welte 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4102d949cac1SHarald Welte 			      "Front Playback Volume",
4103d949cac1SHarald Welte 			      HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT));
4104d949cac1SHarald Welte 	if (err < 0)
4105d949cac1SHarald Welte 		return err;
4106d949cac1SHarald Welte 	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
4107d949cac1SHarald Welte 			      "Front Playback Switch",
4108d949cac1SHarald Welte 			      HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT));
4109d949cac1SHarald Welte 	if (err < 0)
4110d949cac1SHarald Welte 		return err;
4111d949cac1SHarald Welte 
4112d949cac1SHarald Welte 	return 0;
4113d949cac1SHarald Welte }
4114d949cac1SHarald Welte 
4115d949cac1SHarald Welte static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
4116d949cac1SHarald Welte {
41170713efebSLydia Wang 	int err, i;
41180713efebSLydia Wang 	struct hda_input_mux *imux;
4119ea734963STakashi Iwai 	static const char * const texts[] = { "ON", "OFF", NULL};
4120d949cac1SHarald Welte 	if (!pin)
4121d949cac1SHarald Welte 		return 0;
4122d949cac1SHarald Welte 	spec->multiout.hp_nid = 0x1D;
4123cdc1784dSLydia Wang 	spec->hp_independent_mode_index = 0;
4124d949cac1SHarald Welte 
4125d949cac1SHarald Welte 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4126d949cac1SHarald Welte 			      "Headphone Playback Volume",
4127d949cac1SHarald Welte 			      HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT));
4128d949cac1SHarald Welte 	if (err < 0)
4129d949cac1SHarald Welte 		return err;
4130d949cac1SHarald Welte 
4131d949cac1SHarald Welte 	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
4132d949cac1SHarald Welte 			      "Headphone Playback Switch",
4133d949cac1SHarald Welte 			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4134d949cac1SHarald Welte 	if (err < 0)
4135d949cac1SHarald Welte 		return err;
4136d949cac1SHarald Welte 
41370713efebSLydia Wang 	imux = &spec->private_imux[1];
41380aa62aefSHarald Welte 
41390713efebSLydia Wang 	/* for hp mode select */
414010a20af7STakashi Iwai 	for (i = 0; texts[i]; i++)
414110a20af7STakashi Iwai 		snd_hda_add_imux_item(imux, texts[i], i, NULL);
41420713efebSLydia Wang 
41430713efebSLydia Wang 	spec->hp_mux = &spec->private_imux[1];
4144d949cac1SHarald Welte 	return 0;
4145d949cac1SHarald Welte }
4146d949cac1SHarald Welte 
4147d949cac1SHarald Welte /* create playback/capture controls for input pins */
414810a20af7STakashi Iwai static int vt1702_auto_create_analog_input_ctls(struct hda_codec *codec,
4149d949cac1SHarald Welte 						const struct auto_pin_cfg *cfg)
4150d949cac1SHarald Welte {
415190dd48a1STakashi Iwai 	static const hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff };
415210a20af7STakashi Iwai 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x1a, pin_idxs,
4153f3268512STakashi Iwai 						ARRAY_SIZE(pin_idxs));
4154d949cac1SHarald Welte }
4155d949cac1SHarald Welte 
4156d949cac1SHarald Welte static int vt1702_parse_auto_config(struct hda_codec *codec)
4157d949cac1SHarald Welte {
4158d949cac1SHarald Welte 	struct via_spec *spec = codec->spec;
4159d949cac1SHarald Welte 	int err;
4160d949cac1SHarald Welte 
41619da29271STakashi Iwai 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
4162d949cac1SHarald Welte 	if (err < 0)
4163d949cac1SHarald Welte 		return err;
4164d949cac1SHarald Welte 	err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg);
4165d949cac1SHarald Welte 	if (err < 0)
4166d949cac1SHarald Welte 		return err;
4167d949cac1SHarald Welte 	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
4168d949cac1SHarald Welte 		return 0; /* can't find valid BIOS pin config */
4169d949cac1SHarald Welte 
4170d949cac1SHarald Welte 	err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg);
4171d949cac1SHarald Welte 	if (err < 0)
4172d949cac1SHarald Welte 		return err;
4173d949cac1SHarald Welte 	err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
4174d949cac1SHarald Welte 	if (err < 0)
4175d949cac1SHarald Welte 		return err;
4176c2c02ea3SLydia Wang 	/* limit AA path volume to 0 dB */
4177c2c02ea3SLydia Wang 	snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT,
4178c2c02ea3SLydia Wang 				  (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4179c2c02ea3SLydia Wang 				  (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4180c2c02ea3SLydia Wang 				  (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4181c2c02ea3SLydia Wang 				  (1 << AC_AMPCAP_MUTE_SHIFT));
418210a20af7STakashi Iwai 	err = vt1702_auto_create_analog_input_ctls(codec, &spec->autocfg);
4183d949cac1SHarald Welte 	if (err < 0)
4184d949cac1SHarald Welte 		return err;
4185d949cac1SHarald Welte 
4186d949cac1SHarald Welte 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4187d949cac1SHarald Welte 
41889da29271STakashi Iwai 	fill_dig_outs(codec);
418998aa34c0SHarald Welte 
4190603c4019STakashi Iwai 	if (spec->kctls.list)
4191603c4019STakashi Iwai 		spec->mixers[spec->num_mixers++] = spec->kctls.list;
4192d949cac1SHarald Welte 
41930aa62aefSHarald Welte 	spec->input_mux = &spec->private_imux[0];
41940aa62aefSHarald Welte 
4195f8fdd495SHarald Welte 	if (spec->hp_mux)
41963d83e577STakashi Iwai 		via_hp_build(codec);
4197d949cac1SHarald Welte 
4198d949cac1SHarald Welte 	return 1;
4199d949cac1SHarald Welte }
4200d949cac1SHarald Welte 
4201d949cac1SHarald Welte #ifdef CONFIG_SND_HDA_POWER_SAVE
420290dd48a1STakashi Iwai static const struct hda_amp_list vt1702_loopbacks[] = {
4203d949cac1SHarald Welte 	{ 0x1A, HDA_INPUT, 1 },
4204d949cac1SHarald Welte 	{ 0x1A, HDA_INPUT, 2 },
4205d949cac1SHarald Welte 	{ 0x1A, HDA_INPUT, 3 },
4206d949cac1SHarald Welte 	{ 0x1A, HDA_INPUT, 4 },
4207d949cac1SHarald Welte 	{ } /* end */
4208d949cac1SHarald Welte };
4209d949cac1SHarald Welte #endif
4210d949cac1SHarald Welte 
42113e95b9abSLydia Wang static void set_widgets_power_state_vt1702(struct hda_codec *codec)
42123e95b9abSLydia Wang {
42133e95b9abSLydia Wang 	int imux_is_smixer =
42143e95b9abSLydia Wang 	snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
42153e95b9abSLydia Wang 	unsigned int parm;
42163e95b9abSLydia Wang 	/* inputs */
42173e95b9abSLydia Wang 	/* PW 1/2/5 (14h/15h/18h) */
42183e95b9abSLydia Wang 	parm = AC_PWRST_D3;
42193e95b9abSLydia Wang 	set_pin_power_state(codec, 0x14, &parm);
42203e95b9abSLydia Wang 	set_pin_power_state(codec, 0x15, &parm);
42213e95b9abSLydia Wang 	set_pin_power_state(codec, 0x18, &parm);
42223e95b9abSLydia Wang 	if (imux_is_smixer)
42233e95b9abSLydia Wang 		parm = AC_PWRST_D0; /* SW0 (13h) = stereo mixer (idx 3) */
42243e95b9abSLydia Wang 	/* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
42253e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm);
42263e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE, parm);
42273e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
42283e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, parm);
42293e95b9abSLydia Wang 
42303e95b9abSLydia Wang 	/* outputs */
42313e95b9abSLydia Wang 	/* PW 3/4 (16h/17h) */
42323e95b9abSLydia Wang 	parm = AC_PWRST_D3;
42333e95b9abSLydia Wang 	set_pin_power_state(codec, 0x17, &parm);
42343e95b9abSLydia Wang 	set_pin_power_state(codec, 0x16, &parm);
42353e95b9abSLydia Wang 	/* MW0 (1ah), AOW 0/1 (10h/1dh) */
42363e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
42373e95b9abSLydia Wang 			    imux_is_smixer ? AC_PWRST_D0 : parm);
42383e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
42393e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm);
42403e95b9abSLydia Wang }
42413e95b9abSLydia Wang 
4242d949cac1SHarald Welte static int patch_vt1702(struct hda_codec *codec)
4243d949cac1SHarald Welte {
4244d949cac1SHarald Welte 	struct via_spec *spec;
4245d949cac1SHarald Welte 	int err;
4246d949cac1SHarald Welte 
4247d949cac1SHarald Welte 	/* create a codec specific record */
42485b0cb1d8SJaroslav Kysela 	spec = via_new_spec(codec);
4249d949cac1SHarald Welte 	if (spec == NULL)
4250d949cac1SHarald Welte 		return -ENOMEM;
4251d949cac1SHarald Welte 
4252d949cac1SHarald Welte 	/* automatic parse from the BIOS config */
4253d949cac1SHarald Welte 	err = vt1702_parse_auto_config(codec);
4254d949cac1SHarald Welte 	if (err < 0) {
4255d949cac1SHarald Welte 		via_free(codec);
4256d949cac1SHarald Welte 		return err;
4257d949cac1SHarald Welte 	} else if (!err) {
4258d949cac1SHarald Welte 		printk(KERN_INFO "hda_codec: Cannot set up configuration "
4259d949cac1SHarald Welte 		       "from BIOS.  Using genenic mode...\n");
4260d949cac1SHarald Welte 	}
4261d949cac1SHarald Welte 
426269e52a80SHarald Welte 	spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs;
426369e52a80SHarald Welte 	spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs;
4264d949cac1SHarald Welte 
4265d949cac1SHarald Welte 	spec->stream_name_analog = "VT1702 Analog";
4266d949cac1SHarald Welte 	spec->stream_analog_playback = &vt1702_pcm_analog_playback;
4267d949cac1SHarald Welte 	spec->stream_analog_capture = &vt1702_pcm_analog_capture;
4268d949cac1SHarald Welte 
4269d949cac1SHarald Welte 	spec->stream_name_digital = "VT1702 Digital";
4270d949cac1SHarald Welte 	spec->stream_digital_playback = &vt1702_pcm_digital_playback;
4271d949cac1SHarald Welte 
4272d949cac1SHarald Welte 	if (!spec->adc_nids && spec->input_mux) {
4273d949cac1SHarald Welte 		spec->adc_nids = vt1702_adc_nids;
4274d949cac1SHarald Welte 		spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
4275337b9d02STakashi Iwai 		get_mux_nids(codec);
4276d949cac1SHarald Welte 		spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
4277d949cac1SHarald Welte 		spec->num_mixers++;
4278d949cac1SHarald Welte 	}
4279d949cac1SHarald Welte 
4280d949cac1SHarald Welte 	codec->patch_ops = via_patch_ops;
4281d949cac1SHarald Welte 
4282d949cac1SHarald Welte 	codec->patch_ops.init = via_auto_init;
428369e52a80SHarald Welte 	codec->patch_ops.unsol_event = via_unsol_event;
4284d949cac1SHarald Welte #ifdef CONFIG_SND_HDA_POWER_SAVE
4285d949cac1SHarald Welte 	spec->loopback.amplist = vt1702_loopbacks;
4286d949cac1SHarald Welte #endif
4287d949cac1SHarald Welte 
42883e95b9abSLydia Wang 	spec->set_widgets_power_state =  set_widgets_power_state_vt1702;
4289d949cac1SHarald Welte 	return 0;
4290d949cac1SHarald Welte }
4291d949cac1SHarald Welte 
4292eb7188caSLydia Wang /* Patch for VT1718S */
4293eb7188caSLydia Wang 
4294eb7188caSLydia Wang /* capture mixer elements */
429590dd48a1STakashi Iwai static const struct snd_kcontrol_new vt1718S_capture_mixer[] = {
4296eb7188caSLydia Wang 	HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
4297eb7188caSLydia Wang 	HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
4298eb7188caSLydia Wang 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
4299eb7188caSLydia Wang 	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
4300eb7188caSLydia Wang 	HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
4301eb7188caSLydia Wang 	HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0,
4302eb7188caSLydia Wang 			 HDA_INPUT),
4303eb7188caSLydia Wang 	{
4304eb7188caSLydia Wang 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4305eb7188caSLydia Wang 		/* The multiple "Capture Source" controls confuse alsamixer
4306eb7188caSLydia Wang 		 * So call somewhat different..
4307eb7188caSLydia Wang 		 */
4308eb7188caSLydia Wang 		.name = "Input Source",
4309eb7188caSLydia Wang 		.count = 2,
4310eb7188caSLydia Wang 		.info = via_mux_enum_info,
4311eb7188caSLydia Wang 		.get = via_mux_enum_get,
4312eb7188caSLydia Wang 		.put = via_mux_enum_put,
4313eb7188caSLydia Wang 	},
4314eb7188caSLydia Wang 	{ } /* end */
4315eb7188caSLydia Wang };
4316eb7188caSLydia Wang 
431790dd48a1STakashi Iwai static const struct hda_verb vt1718S_volume_init_verbs[] = {
4318eb7188caSLydia Wang 	/*
4319eb7188caSLydia Wang 	 * Unmute ADC0-1 and set the default input to mic-in
4320eb7188caSLydia Wang 	 */
4321eb7188caSLydia Wang 	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4322eb7188caSLydia Wang 	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4323eb7188caSLydia Wang 
43244ab2d53aSLydia Wang 	/* Enable MW0 adjust Gain 5 */
43254ab2d53aSLydia Wang 	{0x1, 0xfb2, 0x10},
4326eb7188caSLydia Wang 	/* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4327eb7188caSLydia Wang 	 * mixer widget
4328eb7188caSLydia Wang 	 */
4329eb7188caSLydia Wang 	/* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
4330eb7188caSLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4331eb7188caSLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4332eb7188caSLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4333eb7188caSLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
43344ab2d53aSLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
4335eb7188caSLydia Wang 
4336eb7188caSLydia Wang 	/* Setup default input of Front HP to MW9 */
4337eb7188caSLydia Wang 	{0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
4338eb7188caSLydia Wang 	/* PW9 PW10 Output enable */
4339eb7188caSLydia Wang 	{0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
4340eb7188caSLydia Wang 	{0x2e, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
4341eb7188caSLydia Wang 	/* PW11 Input enable */
4342eb7188caSLydia Wang 	{0x2f, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_IN_EN},
4343eb7188caSLydia Wang 	/* Enable Boost Volume backdoor */
4344eb7188caSLydia Wang 	{0x1, 0xf88, 0x8},
4345eb7188caSLydia Wang 	/* MW0/1/2/3/4: un-mute index 0 (AOWx), mute index 1 (MW9) */
4346eb7188caSLydia Wang 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4347eb7188caSLydia Wang 	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4348eb7188caSLydia Wang 	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4349eb7188caSLydia Wang 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4350eb7188caSLydia Wang 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4351eb7188caSLydia Wang 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4352eb7188caSLydia Wang 	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4353eb7188caSLydia Wang 	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4354eb7188caSLydia Wang 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4355eb7188caSLydia Wang 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4356eb7188caSLydia Wang 	/* set MUX1 = 2 (AOW4), MUX2 = 1 (AOW3) */
4357eb7188caSLydia Wang 	{0x34, AC_VERB_SET_CONNECT_SEL, 0x2},
4358eb7188caSLydia Wang 	{0x35, AC_VERB_SET_CONNECT_SEL, 0x1},
4359eb7188caSLydia Wang 	/* Unmute MW4's index 0 */
4360eb7188caSLydia Wang 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4361eb7188caSLydia Wang 	{ }
4362eb7188caSLydia Wang };
4363eb7188caSLydia Wang 
4364eb7188caSLydia Wang 
436590dd48a1STakashi Iwai static const struct hda_verb vt1718S_uniwill_init_verbs[] = {
4366eb7188caSLydia Wang 	{0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
4367eb7188caSLydia Wang 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
4368eb7188caSLydia Wang 	{0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4369eb7188caSLydia Wang 	{0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4370eb7188caSLydia Wang 	{0x26, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4371eb7188caSLydia Wang 	{0x27, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4372eb7188caSLydia Wang 	{0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4373eb7188caSLydia Wang 	{0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4374eb7188caSLydia Wang 	{0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4375eb7188caSLydia Wang 	{ }
4376eb7188caSLydia Wang };
4377eb7188caSLydia Wang 
437890dd48a1STakashi Iwai static const struct hda_pcm_stream vt1718S_pcm_analog_playback = {
4379eb7188caSLydia Wang 	.substreams = 2,
4380eb7188caSLydia Wang 	.channels_min = 2,
4381eb7188caSLydia Wang 	.channels_max = 10,
4382eb7188caSLydia Wang 	.nid = 0x8, /* NID to query formats and rates */
4383eb7188caSLydia Wang 	.ops = {
4384eb7188caSLydia Wang 		.open = via_playback_pcm_open,
4385eb7188caSLydia Wang 		.prepare = via_playback_multi_pcm_prepare,
4386eb7188caSLydia Wang 		.cleanup = via_playback_multi_pcm_cleanup,
4387eb7188caSLydia Wang 		.close = via_pcm_open_close,
4388eb7188caSLydia Wang 	},
4389eb7188caSLydia Wang };
4390eb7188caSLydia Wang 
439190dd48a1STakashi Iwai static const struct hda_pcm_stream vt1718S_pcm_analog_capture = {
4392eb7188caSLydia Wang 	.substreams = 2,
4393eb7188caSLydia Wang 	.channels_min = 2,
4394eb7188caSLydia Wang 	.channels_max = 2,
4395eb7188caSLydia Wang 	.nid = 0x10, /* NID to query formats and rates */
4396eb7188caSLydia Wang 	.ops = {
4397eb7188caSLydia Wang 		.open = via_pcm_open_close,
4398eb7188caSLydia Wang 		.prepare = via_capture_pcm_prepare,
4399eb7188caSLydia Wang 		.cleanup = via_capture_pcm_cleanup,
4400eb7188caSLydia Wang 		.close = via_pcm_open_close,
4401eb7188caSLydia Wang 	},
4402eb7188caSLydia Wang };
4403eb7188caSLydia Wang 
440490dd48a1STakashi Iwai static const struct hda_pcm_stream vt1718S_pcm_digital_playback = {
4405eb7188caSLydia Wang 	.substreams = 2,
4406eb7188caSLydia Wang 	.channels_min = 2,
4407eb7188caSLydia Wang 	.channels_max = 2,
4408eb7188caSLydia Wang 	/* NID is set in via_build_pcms */
4409eb7188caSLydia Wang 	.ops = {
4410eb7188caSLydia Wang 		.open = via_dig_playback_pcm_open,
4411eb7188caSLydia Wang 		.close = via_dig_playback_pcm_close,
4412eb7188caSLydia Wang 		.prepare = via_dig_playback_pcm_prepare,
4413eb7188caSLydia Wang 		.cleanup = via_dig_playback_pcm_cleanup
4414eb7188caSLydia Wang 	},
4415eb7188caSLydia Wang };
4416eb7188caSLydia Wang 
441790dd48a1STakashi Iwai static const struct hda_pcm_stream vt1718S_pcm_digital_capture = {
4418eb7188caSLydia Wang 	.substreams = 1,
4419eb7188caSLydia Wang 	.channels_min = 2,
4420eb7188caSLydia Wang 	.channels_max = 2,
4421eb7188caSLydia Wang };
4422eb7188caSLydia Wang 
4423eb7188caSLydia Wang /* fill in the dac_nids table from the parsed pin configuration */
4424eb7188caSLydia Wang static int vt1718S_auto_fill_dac_nids(struct via_spec *spec,
4425eb7188caSLydia Wang 				     const struct auto_pin_cfg *cfg)
4426eb7188caSLydia Wang {
4427eb7188caSLydia Wang 	int i;
4428eb7188caSLydia Wang 	hda_nid_t nid;
4429eb7188caSLydia Wang 
4430eb7188caSLydia Wang 	spec->multiout.num_dacs = cfg->line_outs;
4431eb7188caSLydia Wang 
4432eb7188caSLydia Wang 	spec->multiout.dac_nids = spec->private_dac_nids;
4433eb7188caSLydia Wang 
4434eb7188caSLydia Wang 	for (i = 0; i < 4; i++) {
4435eb7188caSLydia Wang 		nid = cfg->line_out_pins[i];
4436eb7188caSLydia Wang 		if (nid) {
4437eb7188caSLydia Wang 			/* config dac list */
4438eb7188caSLydia Wang 			switch (i) {
4439eb7188caSLydia Wang 			case AUTO_SEQ_FRONT:
4440dda14410STakashi Iwai 				spec->private_dac_nids[i] = 0x8;
4441eb7188caSLydia Wang 				break;
4442eb7188caSLydia Wang 			case AUTO_SEQ_CENLFE:
4443dda14410STakashi Iwai 				spec->private_dac_nids[i] = 0xa;
4444eb7188caSLydia Wang 				break;
4445eb7188caSLydia Wang 			case AUTO_SEQ_SURROUND:
4446dda14410STakashi Iwai 				spec->private_dac_nids[i] = 0x9;
4447eb7188caSLydia Wang 				break;
4448eb7188caSLydia Wang 			case AUTO_SEQ_SIDE:
4449dda14410STakashi Iwai 				spec->private_dac_nids[i] = 0xb;
4450eb7188caSLydia Wang 				break;
4451eb7188caSLydia Wang 			}
4452eb7188caSLydia Wang 		}
4453eb7188caSLydia Wang 	}
4454eb7188caSLydia Wang 
4455eb7188caSLydia Wang 	return 0;
4456eb7188caSLydia Wang }
4457eb7188caSLydia Wang 
4458eb7188caSLydia Wang /* add playback controls from the parsed DAC table */
4459eb7188caSLydia Wang static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec,
4460eb7188caSLydia Wang 					     const struct auto_pin_cfg *cfg)
4461eb7188caSLydia Wang {
4462eb7188caSLydia Wang 	char name[32];
4463ea734963STakashi Iwai 	static const char * const chname[4] = {
4464ea734963STakashi Iwai 		"Front", "Surround", "C/LFE", "Side"
4465ea734963STakashi Iwai 	};
4466eb7188caSLydia Wang 	hda_nid_t nid_vols[] = {0x8, 0x9, 0xa, 0xb};
4467eb7188caSLydia Wang 	hda_nid_t nid_mutes[] = {0x24, 0x25, 0x26, 0x27};
4468eb7188caSLydia Wang 	hda_nid_t nid, nid_vol, nid_mute = 0;
4469eb7188caSLydia Wang 	int i, err;
4470eb7188caSLydia Wang 
4471eb7188caSLydia Wang 	for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
4472eb7188caSLydia Wang 		nid = cfg->line_out_pins[i];
4473eb7188caSLydia Wang 
4474eb7188caSLydia Wang 		if (!nid)
4475eb7188caSLydia Wang 			continue;
4476eb7188caSLydia Wang 		nid_vol = nid_vols[i];
4477eb7188caSLydia Wang 		nid_mute = nid_mutes[i];
4478eb7188caSLydia Wang 
4479eb7188caSLydia Wang 		if (i == AUTO_SEQ_CENLFE) {
4480eb7188caSLydia Wang 			/* Center/LFE */
4481eb7188caSLydia Wang 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4482eb7188caSLydia Wang 					      "Center Playback Volume",
4483eb7188caSLydia Wang 					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
4484eb7188caSLydia Wang 								  HDA_OUTPUT));
4485eb7188caSLydia Wang 			if (err < 0)
4486eb7188caSLydia Wang 				return err;
4487eb7188caSLydia Wang 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4488eb7188caSLydia Wang 					      "LFE Playback Volume",
4489eb7188caSLydia Wang 					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
4490eb7188caSLydia Wang 								  HDA_OUTPUT));
4491eb7188caSLydia Wang 			if (err < 0)
4492eb7188caSLydia Wang 				return err;
4493eb7188caSLydia Wang 			err = via_add_control(
4494eb7188caSLydia Wang 				spec, VIA_CTL_WIDGET_MUTE,
4495eb7188caSLydia Wang 				"Center Playback Switch",
4496eb7188caSLydia Wang 				HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0,
4497eb7188caSLydia Wang 						    HDA_OUTPUT));
4498eb7188caSLydia Wang 			if (err < 0)
4499eb7188caSLydia Wang 				return err;
4500eb7188caSLydia Wang 			err = via_add_control(
4501eb7188caSLydia Wang 				spec, VIA_CTL_WIDGET_MUTE,
4502eb7188caSLydia Wang 				"LFE Playback Switch",
4503eb7188caSLydia Wang 				HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0,
4504eb7188caSLydia Wang 						    HDA_OUTPUT));
4505eb7188caSLydia Wang 			if (err < 0)
4506eb7188caSLydia Wang 				return err;
4507eb7188caSLydia Wang 		} else if (i == AUTO_SEQ_FRONT) {
4508eb7188caSLydia Wang 			/* Front */
4509eb7188caSLydia Wang 			sprintf(name, "%s Playback Volume", chname[i]);
4510eb7188caSLydia Wang 			err = via_add_control(
4511eb7188caSLydia Wang 				spec, VIA_CTL_WIDGET_VOL, name,
4512eb7188caSLydia Wang 				HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
4513eb7188caSLydia Wang 			if (err < 0)
4514eb7188caSLydia Wang 				return err;
4515eb7188caSLydia Wang 			sprintf(name, "%s Playback Switch", chname[i]);
4516eb7188caSLydia Wang 			err = via_add_control(
4517eb7188caSLydia Wang 				spec, VIA_CTL_WIDGET_MUTE, name,
4518eb7188caSLydia Wang 				HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
4519eb7188caSLydia Wang 						    HDA_OUTPUT));
4520eb7188caSLydia Wang 			if (err < 0)
4521eb7188caSLydia Wang 				return err;
4522eb7188caSLydia Wang 		} else {
4523eb7188caSLydia Wang 			sprintf(name, "%s Playback Volume", chname[i]);
4524eb7188caSLydia Wang 			err = via_add_control(
4525eb7188caSLydia Wang 				spec, VIA_CTL_WIDGET_VOL, name,
4526eb7188caSLydia Wang 				HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
4527eb7188caSLydia Wang 			if (err < 0)
4528eb7188caSLydia Wang 				return err;
4529eb7188caSLydia Wang 			sprintf(name, "%s Playback Switch", chname[i]);
4530eb7188caSLydia Wang 			err = via_add_control(
4531eb7188caSLydia Wang 				spec, VIA_CTL_WIDGET_MUTE, name,
4532eb7188caSLydia Wang 				HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
4533eb7188caSLydia Wang 						    HDA_OUTPUT));
4534eb7188caSLydia Wang 			if (err < 0)
4535eb7188caSLydia Wang 				return err;
4536eb7188caSLydia Wang 		}
4537eb7188caSLydia Wang 	}
4538eb7188caSLydia Wang 	return 0;
4539eb7188caSLydia Wang }
4540eb7188caSLydia Wang 
4541eb7188caSLydia Wang static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
4542eb7188caSLydia Wang {
4543eb7188caSLydia Wang 	int err;
4544eb7188caSLydia Wang 
4545eb7188caSLydia Wang 	if (!pin)
4546eb7188caSLydia Wang 		return 0;
4547eb7188caSLydia Wang 
4548eb7188caSLydia Wang 	spec->multiout.hp_nid = 0xc; /* AOW4 */
4549eb7188caSLydia Wang 	spec->hp_independent_mode_index = 1;
4550eb7188caSLydia Wang 
4551eb7188caSLydia Wang 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4552eb7188caSLydia Wang 			      "Headphone Playback Volume",
4553eb7188caSLydia Wang 			      HDA_COMPOSE_AMP_VAL(0xc, 3, 0, HDA_OUTPUT));
4554eb7188caSLydia Wang 	if (err < 0)
4555eb7188caSLydia Wang 		return err;
4556eb7188caSLydia Wang 
4557eb7188caSLydia Wang 	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
4558eb7188caSLydia Wang 			      "Headphone Playback Switch",
4559eb7188caSLydia Wang 			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4560eb7188caSLydia Wang 	if (err < 0)
4561eb7188caSLydia Wang 		return err;
4562eb7188caSLydia Wang 
4563eb7188caSLydia Wang 	create_hp_imux(spec);
4564eb7188caSLydia Wang 	return 0;
4565eb7188caSLydia Wang }
4566eb7188caSLydia Wang 
4567eb7188caSLydia Wang /* create playback/capture controls for input pins */
456810a20af7STakashi Iwai static int vt1718S_auto_create_analog_input_ctls(struct hda_codec *codec,
4569eb7188caSLydia Wang 						const struct auto_pin_cfg *cfg)
4570eb7188caSLydia Wang {
457190dd48a1STakashi Iwai 	static const hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff };
457210a20af7STakashi Iwai 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
4573f3268512STakashi Iwai 						ARRAY_SIZE(pin_idxs));
4574eb7188caSLydia Wang }
4575eb7188caSLydia Wang 
4576eb7188caSLydia Wang static int vt1718S_parse_auto_config(struct hda_codec *codec)
4577eb7188caSLydia Wang {
4578eb7188caSLydia Wang 	struct via_spec *spec = codec->spec;
4579eb7188caSLydia Wang 	int err;
4580eb7188caSLydia Wang 
4581eb7188caSLydia Wang 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
4582eb7188caSLydia Wang 
4583eb7188caSLydia Wang 	if (err < 0)
4584eb7188caSLydia Wang 		return err;
4585eb7188caSLydia Wang 	err = vt1718S_auto_fill_dac_nids(spec, &spec->autocfg);
4586eb7188caSLydia Wang 	if (err < 0)
4587eb7188caSLydia Wang 		return err;
4588eb7188caSLydia Wang 	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
4589eb7188caSLydia Wang 		return 0; /* can't find valid BIOS pin config */
4590eb7188caSLydia Wang 
4591eb7188caSLydia Wang 	err = vt1718S_auto_create_multi_out_ctls(spec, &spec->autocfg);
4592eb7188caSLydia Wang 	if (err < 0)
4593eb7188caSLydia Wang 		return err;
4594eb7188caSLydia Wang 	err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
4595eb7188caSLydia Wang 	if (err < 0)
4596eb7188caSLydia Wang 		return err;
459710a20af7STakashi Iwai 	err = vt1718S_auto_create_analog_input_ctls(codec, &spec->autocfg);
4598eb7188caSLydia Wang 	if (err < 0)
4599eb7188caSLydia Wang 		return err;
4600eb7188caSLydia Wang 
4601eb7188caSLydia Wang 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4602eb7188caSLydia Wang 
4603eb7188caSLydia Wang 	fill_dig_outs(codec);
4604eb7188caSLydia Wang 
4605eb7188caSLydia Wang 	if (spec->autocfg.dig_in_pin && codec->vendor_id == 0x11060428)
4606eb7188caSLydia Wang 		spec->dig_in_nid = 0x13;
4607eb7188caSLydia Wang 
4608eb7188caSLydia Wang 	if (spec->kctls.list)
4609eb7188caSLydia Wang 		spec->mixers[spec->num_mixers++] = spec->kctls.list;
4610eb7188caSLydia Wang 
4611eb7188caSLydia Wang 	spec->input_mux = &spec->private_imux[0];
4612eb7188caSLydia Wang 
4613eb7188caSLydia Wang 	if (spec->hp_mux)
46143d83e577STakashi Iwai 		via_hp_build(codec);
4615eb7188caSLydia Wang 
46165b0cb1d8SJaroslav Kysela 	via_smart51_build(spec);
4617eb7188caSLydia Wang 
4618eb7188caSLydia Wang 	return 1;
4619eb7188caSLydia Wang }
4620eb7188caSLydia Wang 
4621eb7188caSLydia Wang #ifdef CONFIG_SND_HDA_POWER_SAVE
462290dd48a1STakashi Iwai static const struct hda_amp_list vt1718S_loopbacks[] = {
4623eb7188caSLydia Wang 	{ 0x21, HDA_INPUT, 1 },
4624eb7188caSLydia Wang 	{ 0x21, HDA_INPUT, 2 },
4625eb7188caSLydia Wang 	{ 0x21, HDA_INPUT, 3 },
4626eb7188caSLydia Wang 	{ 0x21, HDA_INPUT, 4 },
4627eb7188caSLydia Wang 	{ } /* end */
4628eb7188caSLydia Wang };
4629eb7188caSLydia Wang #endif
4630eb7188caSLydia Wang 
46313e95b9abSLydia Wang static void set_widgets_power_state_vt1718S(struct hda_codec *codec)
46323e95b9abSLydia Wang {
46333e95b9abSLydia Wang 	struct via_spec *spec = codec->spec;
46343e95b9abSLydia Wang 	int imux_is_smixer;
46353e95b9abSLydia Wang 	unsigned int parm;
46363e95b9abSLydia Wang 	/* MUX6 (1eh) = stereo mixer */
46373e95b9abSLydia Wang 	imux_is_smixer =
46383e95b9abSLydia Wang 	snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
46393e95b9abSLydia Wang 	/* inputs */
46403e95b9abSLydia Wang 	/* PW 5/6/7 (29h/2ah/2bh) */
46413e95b9abSLydia Wang 	parm = AC_PWRST_D3;
46423e95b9abSLydia Wang 	set_pin_power_state(codec, 0x29, &parm);
46433e95b9abSLydia Wang 	set_pin_power_state(codec, 0x2a, &parm);
46443e95b9abSLydia Wang 	set_pin_power_state(codec, 0x2b, &parm);
46453e95b9abSLydia Wang 	if (imux_is_smixer)
46463e95b9abSLydia Wang 		parm = AC_PWRST_D0;
46473e95b9abSLydia Wang 	/* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */
46483e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm);
46493e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
46503e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
46513e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
46523e95b9abSLydia Wang 
46533e95b9abSLydia Wang 	/* outputs */
46543e95b9abSLydia Wang 	/* PW3 (27h), MW2 (1ah), AOW3 (bh) */
46553e95b9abSLydia Wang 	parm = AC_PWRST_D3;
46563e95b9abSLydia Wang 	set_pin_power_state(codec, 0x27, &parm);
46573e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, parm);
46583e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, parm);
46593e95b9abSLydia Wang 
46603e95b9abSLydia Wang 	/* PW2 (26h), AOW2 (ah) */
46613e95b9abSLydia Wang 	parm = AC_PWRST_D3;
46623e95b9abSLydia Wang 	set_pin_power_state(codec, 0x26, &parm);
46633e95b9abSLydia Wang 	if (spec->smart51_enabled)
46643e95b9abSLydia Wang 		set_pin_power_state(codec, 0x2b, &parm);
46653e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE, parm);
46663e95b9abSLydia Wang 
46673e95b9abSLydia Wang 	/* PW0 (24h), AOW0 (8h) */
46683e95b9abSLydia Wang 	parm = AC_PWRST_D3;
46693e95b9abSLydia Wang 	set_pin_power_state(codec, 0x24, &parm);
46703e95b9abSLydia Wang 	if (!spec->hp_independent_mode) /* check for redirected HP */
46713e95b9abSLydia Wang 		set_pin_power_state(codec, 0x28, &parm);
46723e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm);
46733e95b9abSLydia Wang 	/* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
46743e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE,
46753e95b9abSLydia Wang 			    imux_is_smixer ? AC_PWRST_D0 : parm);
46763e95b9abSLydia Wang 
46773e95b9abSLydia Wang 	/* PW1 (25h), AOW1 (9h) */
46783e95b9abSLydia Wang 	parm = AC_PWRST_D3;
46793e95b9abSLydia Wang 	set_pin_power_state(codec, 0x25, &parm);
46803e95b9abSLydia Wang 	if (spec->smart51_enabled)
46813e95b9abSLydia Wang 		set_pin_power_state(codec, 0x2a, &parm);
46823e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE, parm);
46833e95b9abSLydia Wang 
46843e95b9abSLydia Wang 	if (spec->hp_independent_mode) {
46853e95b9abSLydia Wang 		/* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */
46863e95b9abSLydia Wang 		parm = AC_PWRST_D3;
46873e95b9abSLydia Wang 		set_pin_power_state(codec, 0x28, &parm);
46883e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x1b, 0,
46893e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
46903e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x34, 0,
46913e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
46923e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0xc, 0,
46933e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
46943e95b9abSLydia Wang 	}
46953e95b9abSLydia Wang }
46963e95b9abSLydia Wang 
4697eb7188caSLydia Wang static int patch_vt1718S(struct hda_codec *codec)
4698eb7188caSLydia Wang {
4699eb7188caSLydia Wang 	struct via_spec *spec;
4700eb7188caSLydia Wang 	int err;
4701eb7188caSLydia Wang 
4702eb7188caSLydia Wang 	/* create a codec specific record */
47035b0cb1d8SJaroslav Kysela 	spec = via_new_spec(codec);
4704eb7188caSLydia Wang 	if (spec == NULL)
4705eb7188caSLydia Wang 		return -ENOMEM;
4706eb7188caSLydia Wang 
4707eb7188caSLydia Wang 	/* automatic parse from the BIOS config */
4708eb7188caSLydia Wang 	err = vt1718S_parse_auto_config(codec);
4709eb7188caSLydia Wang 	if (err < 0) {
4710eb7188caSLydia Wang 		via_free(codec);
4711eb7188caSLydia Wang 		return err;
4712eb7188caSLydia Wang 	} else if (!err) {
4713eb7188caSLydia Wang 		printk(KERN_INFO "hda_codec: Cannot set up configuration "
4714eb7188caSLydia Wang 		       "from BIOS.  Using genenic mode...\n");
4715eb7188caSLydia Wang 	}
4716eb7188caSLydia Wang 
4717eb7188caSLydia Wang 	spec->init_verbs[spec->num_iverbs++] = vt1718S_volume_init_verbs;
4718eb7188caSLydia Wang 	spec->init_verbs[spec->num_iverbs++] = vt1718S_uniwill_init_verbs;
4719eb7188caSLydia Wang 
4720bb3c6bfcSLydia Wang 	if (codec->vendor_id == 0x11060441)
4721bb3c6bfcSLydia Wang 		spec->stream_name_analog = "VT2020 Analog";
4722bb3c6bfcSLydia Wang 	else if (codec->vendor_id == 0x11064441)
4723bb3c6bfcSLydia Wang 		spec->stream_name_analog = "VT1828S Analog";
4724bb3c6bfcSLydia Wang 	else
4725eb7188caSLydia Wang 		spec->stream_name_analog = "VT1718S Analog";
4726eb7188caSLydia Wang 	spec->stream_analog_playback = &vt1718S_pcm_analog_playback;
4727eb7188caSLydia Wang 	spec->stream_analog_capture = &vt1718S_pcm_analog_capture;
4728eb7188caSLydia Wang 
4729bb3c6bfcSLydia Wang 	if (codec->vendor_id == 0x11060441)
4730bb3c6bfcSLydia Wang 		spec->stream_name_digital = "VT2020 Digital";
4731bb3c6bfcSLydia Wang 	else if (codec->vendor_id == 0x11064441)
4732bb3c6bfcSLydia Wang 		spec->stream_name_digital = "VT1828S Digital";
4733bb3c6bfcSLydia Wang 	else
4734eb7188caSLydia Wang 		spec->stream_name_digital = "VT1718S Digital";
4735eb7188caSLydia Wang 	spec->stream_digital_playback = &vt1718S_pcm_digital_playback;
4736bb3c6bfcSLydia Wang 	if (codec->vendor_id == 0x11060428 || codec->vendor_id == 0x11060441)
4737eb7188caSLydia Wang 		spec->stream_digital_capture = &vt1718S_pcm_digital_capture;
4738eb7188caSLydia Wang 
4739eb7188caSLydia Wang 	if (!spec->adc_nids && spec->input_mux) {
4740eb7188caSLydia Wang 		spec->adc_nids = vt1718S_adc_nids;
4741eb7188caSLydia Wang 		spec->num_adc_nids = ARRAY_SIZE(vt1718S_adc_nids);
4742eb7188caSLydia Wang 		get_mux_nids(codec);
4743bb3c6bfcSLydia Wang 		override_mic_boost(codec, 0x2b, 0, 3, 40);
4744bb3c6bfcSLydia Wang 		override_mic_boost(codec, 0x29, 0, 3, 40);
4745eb7188caSLydia Wang 		spec->mixers[spec->num_mixers] = vt1718S_capture_mixer;
4746eb7188caSLydia Wang 		spec->num_mixers++;
4747eb7188caSLydia Wang 	}
4748eb7188caSLydia Wang 
4749eb7188caSLydia Wang 	codec->patch_ops = via_patch_ops;
4750eb7188caSLydia Wang 
4751eb7188caSLydia Wang 	codec->patch_ops.init = via_auto_init;
47520f48327eSStephen Rothwell 	codec->patch_ops.unsol_event = via_unsol_event;
4753eb7188caSLydia Wang 
4754eb7188caSLydia Wang #ifdef CONFIG_SND_HDA_POWER_SAVE
4755eb7188caSLydia Wang 	spec->loopback.amplist = vt1718S_loopbacks;
4756eb7188caSLydia Wang #endif
4757eb7188caSLydia Wang 
47583e95b9abSLydia Wang 	spec->set_widgets_power_state =  set_widgets_power_state_vt1718S;
47593e95b9abSLydia Wang 
4760eb7188caSLydia Wang 	return 0;
4761eb7188caSLydia Wang }
4762f3db423dSLydia Wang 
4763f3db423dSLydia Wang /* Patch for VT1716S */
4764f3db423dSLydia Wang 
4765f3db423dSLydia Wang static int vt1716s_dmic_info(struct snd_kcontrol *kcontrol,
4766f3db423dSLydia Wang 			    struct snd_ctl_elem_info *uinfo)
4767f3db423dSLydia Wang {
4768f3db423dSLydia Wang 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
4769f3db423dSLydia Wang 	uinfo->count = 1;
4770f3db423dSLydia Wang 	uinfo->value.integer.min = 0;
4771f3db423dSLydia Wang 	uinfo->value.integer.max = 1;
4772f3db423dSLydia Wang 	return 0;
4773f3db423dSLydia Wang }
4774f3db423dSLydia Wang 
4775f3db423dSLydia Wang static int vt1716s_dmic_get(struct snd_kcontrol *kcontrol,
4776f3db423dSLydia Wang 			   struct snd_ctl_elem_value *ucontrol)
4777f3db423dSLydia Wang {
4778f3db423dSLydia Wang 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4779f3db423dSLydia Wang 	int index = 0;
4780f3db423dSLydia Wang 
4781f3db423dSLydia Wang 	index = snd_hda_codec_read(codec, 0x26, 0,
4782f3db423dSLydia Wang 					       AC_VERB_GET_CONNECT_SEL, 0);
4783f3db423dSLydia Wang 	if (index != -1)
4784f3db423dSLydia Wang 		*ucontrol->value.integer.value = index;
4785f3db423dSLydia Wang 
4786f3db423dSLydia Wang 	return 0;
4787f3db423dSLydia Wang }
4788f3db423dSLydia Wang 
4789f3db423dSLydia Wang static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,
4790f3db423dSLydia Wang 			   struct snd_ctl_elem_value *ucontrol)
4791f3db423dSLydia Wang {
4792f3db423dSLydia Wang 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4793f3db423dSLydia Wang 	struct via_spec *spec = codec->spec;
4794f3db423dSLydia Wang 	int index = *ucontrol->value.integer.value;
4795f3db423dSLydia Wang 
4796f3db423dSLydia Wang 	snd_hda_codec_write(codec, 0x26, 0,
4797f3db423dSLydia Wang 					       AC_VERB_SET_CONNECT_SEL, index);
4798f3db423dSLydia Wang 	spec->dmic_enabled = index;
47993e95b9abSLydia Wang 	set_widgets_power_state(codec);
4800f3db423dSLydia Wang 	return 1;
4801f3db423dSLydia Wang }
4802f3db423dSLydia Wang 
4803f3db423dSLydia Wang /* capture mixer elements */
480490dd48a1STakashi Iwai static const struct snd_kcontrol_new vt1716S_capture_mixer[] = {
4805f3db423dSLydia Wang 	HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
4806f3db423dSLydia Wang 	HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
4807f3db423dSLydia Wang 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
4808f3db423dSLydia Wang 	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
4809f3db423dSLydia Wang 	HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT),
4810f3db423dSLydia Wang 	HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0,
4811f3db423dSLydia Wang 			 HDA_INPUT),
4812f3db423dSLydia Wang 	{
4813f3db423dSLydia Wang 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4814f3db423dSLydia Wang 		.name = "Input Source",
4815f3db423dSLydia Wang 		.count = 1,
4816f3db423dSLydia Wang 		.info = via_mux_enum_info,
4817f3db423dSLydia Wang 		.get = via_mux_enum_get,
4818f3db423dSLydia Wang 		.put = via_mux_enum_put,
4819f3db423dSLydia Wang 	},
4820f3db423dSLydia Wang 	{ } /* end */
4821f3db423dSLydia Wang };
4822f3db423dSLydia Wang 
482390dd48a1STakashi Iwai static const struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
4824f3db423dSLydia Wang 	HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT),
4825f3db423dSLydia Wang 	{
4826f3db423dSLydia Wang 	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4827f3db423dSLydia Wang 	 .name = "Digital Mic Capture Switch",
48285b0cb1d8SJaroslav Kysela 	 .subdevice = HDA_SUBDEV_NID_FLAG | 0x26,
4829f3db423dSLydia Wang 	 .count = 1,
4830f3db423dSLydia Wang 	 .info = vt1716s_dmic_info,
4831f3db423dSLydia Wang 	 .get = vt1716s_dmic_get,
4832f3db423dSLydia Wang 	 .put = vt1716s_dmic_put,
4833f3db423dSLydia Wang 	 },
4834f3db423dSLydia Wang 	{}			/* end */
4835f3db423dSLydia Wang };
4836f3db423dSLydia Wang 
4837f3db423dSLydia Wang 
4838f3db423dSLydia Wang /* mono-out mixer elements */
483990dd48a1STakashi Iwai static const struct snd_kcontrol_new vt1716S_mono_out_mixer[] = {
4840f3db423dSLydia Wang 	HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT),
4841f3db423dSLydia Wang 	{ } /* end */
4842f3db423dSLydia Wang };
4843f3db423dSLydia Wang 
484490dd48a1STakashi Iwai static const struct hda_verb vt1716S_volume_init_verbs[] = {
4845f3db423dSLydia Wang 	/*
4846f3db423dSLydia Wang 	 * Unmute ADC0-1 and set the default input to mic-in
4847f3db423dSLydia Wang 	 */
4848f3db423dSLydia Wang 	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4849f3db423dSLydia Wang 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4850f3db423dSLydia Wang 
4851f3db423dSLydia Wang 
4852f3db423dSLydia Wang 	/* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4853f3db423dSLydia Wang 	 * mixer widget
4854f3db423dSLydia Wang 	 */
4855f3db423dSLydia Wang 	/* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
4856f3db423dSLydia Wang 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4857f3db423dSLydia Wang 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4858f3db423dSLydia Wang 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4859f3db423dSLydia Wang 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4860f3db423dSLydia Wang 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4861f3db423dSLydia Wang 
4862f3db423dSLydia Wang 	/* MUX Indices: Stereo Mixer = 5 */
4863f3db423dSLydia Wang 	{0x17, AC_VERB_SET_CONNECT_SEL, 0x5},
4864f3db423dSLydia Wang 
4865f3db423dSLydia Wang 	/* Setup default input of PW4 to MW0 */
4866f3db423dSLydia Wang 	{0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
4867f3db423dSLydia Wang 
4868f3db423dSLydia Wang 	/* Setup default input of SW1 as MW0 */
4869f3db423dSLydia Wang 	{0x18, AC_VERB_SET_CONNECT_SEL, 0x1},
4870f3db423dSLydia Wang 
4871f3db423dSLydia Wang 	/* Setup default input of SW4 as AOW0 */
4872f3db423dSLydia Wang 	{0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
4873f3db423dSLydia Wang 
4874f3db423dSLydia Wang 	/* PW9 PW10 Output enable */
4875f3db423dSLydia Wang 	{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4876f3db423dSLydia Wang 	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4877f3db423dSLydia Wang 
4878f3db423dSLydia Wang 	/* Unmute SW1, PW12 */
4879f3db423dSLydia Wang 	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4880f3db423dSLydia Wang 	{0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4881f3db423dSLydia Wang 	/* PW12 Output enable */
4882f3db423dSLydia Wang 	{0x2a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4883f3db423dSLydia Wang 	/* Enable Boost Volume backdoor */
4884f3db423dSLydia Wang 	{0x1, 0xf8a, 0x80},
4885f3db423dSLydia Wang 	/* don't bybass mixer */
4886f3db423dSLydia Wang 	{0x1, 0xf88, 0xc0},
4887f3db423dSLydia Wang 	/* Enable mono output */
4888f3db423dSLydia Wang 	{0x1, 0xf90, 0x08},
4889f3db423dSLydia Wang 	{ }
4890f3db423dSLydia Wang };
4891f3db423dSLydia Wang 
4892f3db423dSLydia Wang 
489390dd48a1STakashi Iwai static const struct hda_verb vt1716S_uniwill_init_verbs[] = {
4894f3db423dSLydia Wang 	{0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
4895f3db423dSLydia Wang 	 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
4896f3db423dSLydia Wang 	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4897f3db423dSLydia Wang 	{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4898f3db423dSLydia Wang 	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4899f3db423dSLydia Wang 	{0x1c, AC_VERB_SET_UNSOLICITED_ENABLE,
4900f3db423dSLydia Wang 	 AC_USRSP_EN | VIA_MONO_EVENT | VIA_JACK_EVENT},
4901f3db423dSLydia Wang 	{0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4902f3db423dSLydia Wang 	{0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4903f3db423dSLydia Wang 	{ }
4904f3db423dSLydia Wang };
4905f3db423dSLydia Wang 
490690dd48a1STakashi Iwai static const struct hda_pcm_stream vt1716S_pcm_analog_playback = {
4907f3db423dSLydia Wang 	.substreams = 2,
4908f3db423dSLydia Wang 	.channels_min = 2,
4909f3db423dSLydia Wang 	.channels_max = 6,
4910f3db423dSLydia Wang 	.nid = 0x10, /* NID to query formats and rates */
4911f3db423dSLydia Wang 	.ops = {
4912f3db423dSLydia Wang 		.open = via_playback_pcm_open,
4913f3db423dSLydia Wang 		.prepare = via_playback_multi_pcm_prepare,
4914f3db423dSLydia Wang 		.cleanup = via_playback_multi_pcm_cleanup,
4915f3db423dSLydia Wang 		.close = via_pcm_open_close,
4916f3db423dSLydia Wang 	},
4917f3db423dSLydia Wang };
4918f3db423dSLydia Wang 
491990dd48a1STakashi Iwai static const struct hda_pcm_stream vt1716S_pcm_analog_capture = {
4920f3db423dSLydia Wang 	.substreams = 2,
4921f3db423dSLydia Wang 	.channels_min = 2,
4922f3db423dSLydia Wang 	.channels_max = 2,
4923f3db423dSLydia Wang 	.nid = 0x13, /* NID to query formats and rates */
4924f3db423dSLydia Wang 	.ops = {
4925f3db423dSLydia Wang 		.open = via_pcm_open_close,
4926f3db423dSLydia Wang 		.prepare = via_capture_pcm_prepare,
4927f3db423dSLydia Wang 		.cleanup = via_capture_pcm_cleanup,
4928f3db423dSLydia Wang 		.close = via_pcm_open_close,
4929f3db423dSLydia Wang 	},
4930f3db423dSLydia Wang };
4931f3db423dSLydia Wang 
493290dd48a1STakashi Iwai static const struct hda_pcm_stream vt1716S_pcm_digital_playback = {
4933f3db423dSLydia Wang 	.substreams = 2,
4934f3db423dSLydia Wang 	.channels_min = 2,
4935f3db423dSLydia Wang 	.channels_max = 2,
4936f3db423dSLydia Wang 	/* NID is set in via_build_pcms */
4937f3db423dSLydia Wang 	.ops = {
4938f3db423dSLydia Wang 		.open = via_dig_playback_pcm_open,
4939f3db423dSLydia Wang 		.close = via_dig_playback_pcm_close,
4940f3db423dSLydia Wang 		.prepare = via_dig_playback_pcm_prepare,
4941f3db423dSLydia Wang 		.cleanup = via_dig_playback_pcm_cleanup
4942f3db423dSLydia Wang 	},
4943f3db423dSLydia Wang };
4944f3db423dSLydia Wang 
4945f3db423dSLydia Wang /* fill in the dac_nids table from the parsed pin configuration */
4946f3db423dSLydia Wang static int vt1716S_auto_fill_dac_nids(struct via_spec *spec,
4947f3db423dSLydia Wang 				      const struct auto_pin_cfg *cfg)
4948f3db423dSLydia Wang {	int i;
4949f3db423dSLydia Wang 	hda_nid_t nid;
4950f3db423dSLydia Wang 
4951f3db423dSLydia Wang 	spec->multiout.num_dacs = cfg->line_outs;
4952f3db423dSLydia Wang 
4953f3db423dSLydia Wang 	spec->multiout.dac_nids = spec->private_dac_nids;
4954f3db423dSLydia Wang 
4955f3db423dSLydia Wang 	for (i = 0; i < 3; i++) {
4956f3db423dSLydia Wang 		nid = cfg->line_out_pins[i];
4957f3db423dSLydia Wang 		if (nid) {
4958f3db423dSLydia Wang 			/* config dac list */
4959f3db423dSLydia Wang 			switch (i) {
4960f3db423dSLydia Wang 			case AUTO_SEQ_FRONT:
4961dda14410STakashi Iwai 				spec->private_dac_nids[i] = 0x10;
4962f3db423dSLydia Wang 				break;
4963f3db423dSLydia Wang 			case AUTO_SEQ_CENLFE:
4964dda14410STakashi Iwai 				spec->private_dac_nids[i] = 0x25;
4965f3db423dSLydia Wang 				break;
4966f3db423dSLydia Wang 			case AUTO_SEQ_SURROUND:
4967dda14410STakashi Iwai 				spec->private_dac_nids[i] = 0x11;
4968f3db423dSLydia Wang 				break;
4969f3db423dSLydia Wang 			}
4970f3db423dSLydia Wang 		}
4971f3db423dSLydia Wang 	}
4972f3db423dSLydia Wang 
4973f3db423dSLydia Wang 	return 0;
4974f3db423dSLydia Wang }
4975f3db423dSLydia Wang 
4976f3db423dSLydia Wang /* add playback controls from the parsed DAC table */
4977f3db423dSLydia Wang static int vt1716S_auto_create_multi_out_ctls(struct via_spec *spec,
4978f3db423dSLydia Wang 					      const struct auto_pin_cfg *cfg)
4979f3db423dSLydia Wang {
4980f3db423dSLydia Wang 	char name[32];
4981ea734963STakashi Iwai 	static const char * const chname[3] = {
4982ea734963STakashi Iwai 		"Front", "Surround", "C/LFE"
4983ea734963STakashi Iwai 	};
4984f3db423dSLydia Wang 	hda_nid_t nid_vols[] = {0x10, 0x11, 0x25};
4985f3db423dSLydia Wang 	hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x27};
4986f3db423dSLydia Wang 	hda_nid_t nid, nid_vol, nid_mute;
4987f3db423dSLydia Wang 	int i, err;
4988f3db423dSLydia Wang 
4989f3db423dSLydia Wang 	for (i = 0; i <= AUTO_SEQ_CENLFE; i++) {
4990f3db423dSLydia Wang 		nid = cfg->line_out_pins[i];
4991f3db423dSLydia Wang 
4992f3db423dSLydia Wang 		if (!nid)
4993f3db423dSLydia Wang 			continue;
4994f3db423dSLydia Wang 
4995f3db423dSLydia Wang 		nid_vol = nid_vols[i];
4996f3db423dSLydia Wang 		nid_mute = nid_mutes[i];
4997f3db423dSLydia Wang 
4998f3db423dSLydia Wang 		if (i == AUTO_SEQ_CENLFE) {
4999f3db423dSLydia Wang 			err = via_add_control(
5000f3db423dSLydia Wang 				spec, VIA_CTL_WIDGET_VOL,
5001f3db423dSLydia Wang 				"Center Playback Volume",
5002f3db423dSLydia Wang 				HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
5003f3db423dSLydia Wang 			if (err < 0)
5004f3db423dSLydia Wang 				return err;
5005f3db423dSLydia Wang 			err = via_add_control(
5006f3db423dSLydia Wang 				spec, VIA_CTL_WIDGET_VOL,
5007f3db423dSLydia Wang 				"LFE Playback Volume",
5008f3db423dSLydia Wang 				HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
5009f3db423dSLydia Wang 			if (err < 0)
5010f3db423dSLydia Wang 				return err;
5011f3db423dSLydia Wang 			err = via_add_control(
5012f3db423dSLydia Wang 				spec, VIA_CTL_WIDGET_MUTE,
5013f3db423dSLydia Wang 				"Center Playback Switch",
5014f3db423dSLydia Wang 				HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0,
5015f3db423dSLydia Wang 						    HDA_OUTPUT));
5016f3db423dSLydia Wang 			if (err < 0)
5017f3db423dSLydia Wang 				return err;
5018f3db423dSLydia Wang 			err = via_add_control(
5019f3db423dSLydia Wang 				spec, VIA_CTL_WIDGET_MUTE,
5020f3db423dSLydia Wang 				"LFE Playback Switch",
5021f3db423dSLydia Wang 				HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0,
5022f3db423dSLydia Wang 						    HDA_OUTPUT));
5023f3db423dSLydia Wang 			if (err < 0)
5024f3db423dSLydia Wang 				return err;
5025f3db423dSLydia Wang 		} else if (i == AUTO_SEQ_FRONT) {
5026f3db423dSLydia Wang 
5027f3db423dSLydia Wang 			err = via_add_control(
5028f3db423dSLydia Wang 				spec, VIA_CTL_WIDGET_VOL,
5029f3db423dSLydia Wang 				"Master Front Playback Volume",
5030f3db423dSLydia Wang 				HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT));
5031f3db423dSLydia Wang 			if (err < 0)
5032f3db423dSLydia Wang 				return err;
5033f3db423dSLydia Wang 			err = via_add_control(
5034f3db423dSLydia Wang 				spec, VIA_CTL_WIDGET_MUTE,
5035f3db423dSLydia Wang 				"Master Front Playback Switch",
5036f3db423dSLydia Wang 				HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT));
5037f3db423dSLydia Wang 			if (err < 0)
5038f3db423dSLydia Wang 				return err;
5039f3db423dSLydia Wang 
5040f3db423dSLydia Wang 			sprintf(name, "%s Playback Volume", chname[i]);
5041f3db423dSLydia Wang 			err = via_add_control(
5042f3db423dSLydia Wang 				spec, VIA_CTL_WIDGET_VOL, name,
5043f3db423dSLydia Wang 				HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
5044f3db423dSLydia Wang 			if (err < 0)
5045f3db423dSLydia Wang 				return err;
5046f3db423dSLydia Wang 			sprintf(name, "%s Playback Switch", chname[i]);
5047f3db423dSLydia Wang 			err = via_add_control(
5048f3db423dSLydia Wang 				spec, VIA_CTL_WIDGET_MUTE, name,
5049f3db423dSLydia Wang 				HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
5050f3db423dSLydia Wang 						    HDA_OUTPUT));
5051f3db423dSLydia Wang 			if (err < 0)
5052f3db423dSLydia Wang 				return err;
5053f3db423dSLydia Wang 		} else {
5054f3db423dSLydia Wang 			sprintf(name, "%s Playback Volume", chname[i]);
5055f3db423dSLydia Wang 			err = via_add_control(
5056f3db423dSLydia Wang 				spec, VIA_CTL_WIDGET_VOL, name,
5057f3db423dSLydia Wang 				HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
5058f3db423dSLydia Wang 			if (err < 0)
5059f3db423dSLydia Wang 				return err;
5060f3db423dSLydia Wang 			sprintf(name, "%s Playback Switch", chname[i]);
5061f3db423dSLydia Wang 			err = via_add_control(
5062f3db423dSLydia Wang 				spec, VIA_CTL_WIDGET_MUTE, name,
5063f3db423dSLydia Wang 				HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
5064f3db423dSLydia Wang 						    HDA_OUTPUT));
5065f3db423dSLydia Wang 			if (err < 0)
5066f3db423dSLydia Wang 				return err;
5067f3db423dSLydia Wang 		}
5068f3db423dSLydia Wang 	}
5069f3db423dSLydia Wang 	return 0;
5070f3db423dSLydia Wang }
5071f3db423dSLydia Wang 
5072f3db423dSLydia Wang static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
5073f3db423dSLydia Wang {
5074f3db423dSLydia Wang 	int err;
5075f3db423dSLydia Wang 
5076f3db423dSLydia Wang 	if (!pin)
5077f3db423dSLydia Wang 		return 0;
5078f3db423dSLydia Wang 
5079f3db423dSLydia Wang 	spec->multiout.hp_nid = 0x25; /* AOW3 */
5080f3db423dSLydia Wang 	spec->hp_independent_mode_index = 1;
5081f3db423dSLydia Wang 
5082f3db423dSLydia Wang 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
5083f3db423dSLydia Wang 			      "Headphone Playback Volume",
5084f3db423dSLydia Wang 			      HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
5085f3db423dSLydia Wang 	if (err < 0)
5086f3db423dSLydia Wang 		return err;
5087f3db423dSLydia Wang 
5088f3db423dSLydia Wang 	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
5089f3db423dSLydia Wang 			      "Headphone Playback Switch",
5090f3db423dSLydia Wang 			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
5091f3db423dSLydia Wang 	if (err < 0)
5092f3db423dSLydia Wang 		return err;
5093f3db423dSLydia Wang 
5094f3db423dSLydia Wang 	create_hp_imux(spec);
5095f3db423dSLydia Wang 	return 0;
5096f3db423dSLydia Wang }
5097f3db423dSLydia Wang 
5098f3db423dSLydia Wang /* create playback/capture controls for input pins */
509910a20af7STakashi Iwai static int vt1716S_auto_create_analog_input_ctls(struct hda_codec *codec,
5100f3db423dSLydia Wang 						const struct auto_pin_cfg *cfg)
5101f3db423dSLydia Wang {
510290dd48a1STakashi Iwai 	static const hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
510310a20af7STakashi Iwai 	return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
5104f3268512STakashi Iwai 						ARRAY_SIZE(pin_idxs));
5105f3db423dSLydia Wang }
5106f3db423dSLydia Wang 
5107f3db423dSLydia Wang static int vt1716S_parse_auto_config(struct hda_codec *codec)
5108f3db423dSLydia Wang {
5109f3db423dSLydia Wang 	struct via_spec *spec = codec->spec;
5110f3db423dSLydia Wang 	int err;
5111f3db423dSLydia Wang 
5112f3db423dSLydia Wang 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
5113f3db423dSLydia Wang 	if (err < 0)
5114f3db423dSLydia Wang 		return err;
5115f3db423dSLydia Wang 	err = vt1716S_auto_fill_dac_nids(spec, &spec->autocfg);
5116f3db423dSLydia Wang 	if (err < 0)
5117f3db423dSLydia Wang 		return err;
5118f3db423dSLydia Wang 	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
5119f3db423dSLydia Wang 		return 0; /* can't find valid BIOS pin config */
5120f3db423dSLydia Wang 
5121f3db423dSLydia Wang 	err = vt1716S_auto_create_multi_out_ctls(spec, &spec->autocfg);
5122f3db423dSLydia Wang 	if (err < 0)
5123f3db423dSLydia Wang 		return err;
5124f3db423dSLydia Wang 	err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
5125f3db423dSLydia Wang 	if (err < 0)
5126f3db423dSLydia Wang 		return err;
512710a20af7STakashi Iwai 	err = vt1716S_auto_create_analog_input_ctls(codec, &spec->autocfg);
5128f3db423dSLydia Wang 	if (err < 0)
5129f3db423dSLydia Wang 		return err;
5130f3db423dSLydia Wang 
5131f3db423dSLydia Wang 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5132f3db423dSLydia Wang 
5133f3db423dSLydia Wang 	fill_dig_outs(codec);
5134f3db423dSLydia Wang 
5135f3db423dSLydia Wang 	if (spec->kctls.list)
5136f3db423dSLydia Wang 		spec->mixers[spec->num_mixers++] = spec->kctls.list;
5137f3db423dSLydia Wang 
5138f3db423dSLydia Wang 	spec->input_mux = &spec->private_imux[0];
5139f3db423dSLydia Wang 
5140f3db423dSLydia Wang 	if (spec->hp_mux)
51413d83e577STakashi Iwai 		via_hp_build(codec);
5142f3db423dSLydia Wang 
51435b0cb1d8SJaroslav Kysela 	via_smart51_build(spec);
5144f3db423dSLydia Wang 
5145f3db423dSLydia Wang 	return 1;
5146f3db423dSLydia Wang }
5147f3db423dSLydia Wang 
5148f3db423dSLydia Wang #ifdef CONFIG_SND_HDA_POWER_SAVE
514990dd48a1STakashi Iwai static const struct hda_amp_list vt1716S_loopbacks[] = {
5150f3db423dSLydia Wang 	{ 0x16, HDA_INPUT, 1 },
5151f3db423dSLydia Wang 	{ 0x16, HDA_INPUT, 2 },
5152f3db423dSLydia Wang 	{ 0x16, HDA_INPUT, 3 },
5153f3db423dSLydia Wang 	{ 0x16, HDA_INPUT, 4 },
5154f3db423dSLydia Wang 	{ } /* end */
5155f3db423dSLydia Wang };
5156f3db423dSLydia Wang #endif
5157f3db423dSLydia Wang 
51583e95b9abSLydia Wang static void set_widgets_power_state_vt1716S(struct hda_codec *codec)
51593e95b9abSLydia Wang {
51603e95b9abSLydia Wang 	struct via_spec *spec = codec->spec;
51613e95b9abSLydia Wang 	int imux_is_smixer;
51623e95b9abSLydia Wang 	unsigned int parm;
51633e95b9abSLydia Wang 	unsigned int mono_out, present;
51643e95b9abSLydia Wang 	/* SW0 (17h) = stereo mixer */
51653e95b9abSLydia Wang 	imux_is_smixer =
51663e95b9abSLydia Wang 	(snd_hda_codec_read(codec, 0x17, 0,
51673e95b9abSLydia Wang 			    AC_VERB_GET_CONNECT_SEL, 0x00) ==  5);
51683e95b9abSLydia Wang 	/* inputs */
51693e95b9abSLydia Wang 	/* PW 1/2/5 (1ah/1bh/1eh) */
51703e95b9abSLydia Wang 	parm = AC_PWRST_D3;
51713e95b9abSLydia Wang 	set_pin_power_state(codec, 0x1a, &parm);
51723e95b9abSLydia Wang 	set_pin_power_state(codec, 0x1b, &parm);
51733e95b9abSLydia Wang 	set_pin_power_state(codec, 0x1e, &parm);
51743e95b9abSLydia Wang 	if (imux_is_smixer)
51753e95b9abSLydia Wang 		parm = AC_PWRST_D0;
51763e95b9abSLydia Wang 	/* SW0 (17h), AIW0(13h) */
51773e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm);
51783e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm);
51793e95b9abSLydia Wang 
51803e95b9abSLydia Wang 	parm = AC_PWRST_D3;
51813e95b9abSLydia Wang 	set_pin_power_state(codec, 0x1e, &parm);
51823e95b9abSLydia Wang 	/* PW11 (22h) */
51833e95b9abSLydia Wang 	if (spec->dmic_enabled)
51843e95b9abSLydia Wang 		set_pin_power_state(codec, 0x22, &parm);
51853e95b9abSLydia Wang 	else
51863e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x22, 0,
51873e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
51883e95b9abSLydia Wang 
51893e95b9abSLydia Wang 	/* SW2(26h), AIW1(14h) */
51903e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE, parm);
51913e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm);
51923e95b9abSLydia Wang 
51933e95b9abSLydia Wang 	/* outputs */
51943e95b9abSLydia Wang 	/* PW0 (19h), SW1 (18h), AOW1 (11h) */
51953e95b9abSLydia Wang 	parm = AC_PWRST_D3;
51963e95b9abSLydia Wang 	set_pin_power_state(codec, 0x19, &parm);
51973e95b9abSLydia Wang 	/* Smart 5.1 PW2(1bh) */
51983e95b9abSLydia Wang 	if (spec->smart51_enabled)
51993e95b9abSLydia Wang 		set_pin_power_state(codec, 0x1b, &parm);
52003e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm);
52013e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
52023e95b9abSLydia Wang 
52033e95b9abSLydia Wang 	/* PW7 (23h), SW3 (27h), AOW3 (25h) */
52043e95b9abSLydia Wang 	parm = AC_PWRST_D3;
52053e95b9abSLydia Wang 	set_pin_power_state(codec, 0x23, &parm);
52063e95b9abSLydia Wang 	/* Smart 5.1 PW1(1ah) */
52073e95b9abSLydia Wang 	if (spec->smart51_enabled)
52083e95b9abSLydia Wang 		set_pin_power_state(codec, 0x1a, &parm);
52093e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, parm);
52103e95b9abSLydia Wang 
52113e95b9abSLydia Wang 	/* Smart 5.1 PW5(1eh) */
52123e95b9abSLydia Wang 	if (spec->smart51_enabled)
52133e95b9abSLydia Wang 		set_pin_power_state(codec, 0x1e, &parm);
52143e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, parm);
52153e95b9abSLydia Wang 
52163e95b9abSLydia Wang 	/* Mono out */
52173e95b9abSLydia Wang 	/* SW4(28h)->MW1(29h)-> PW12 (2ah)*/
52183e95b9abSLydia Wang 	present = snd_hda_jack_detect(codec, 0x1c);
52193e95b9abSLydia Wang 
52203e95b9abSLydia Wang 	if (present)
52213e95b9abSLydia Wang 		mono_out = 0;
52223e95b9abSLydia Wang 	else {
52233e95b9abSLydia Wang 		present = snd_hda_jack_detect(codec, 0x1d);
52243e95b9abSLydia Wang 		if (!spec->hp_independent_mode && present)
52253e95b9abSLydia Wang 			mono_out = 0;
52263e95b9abSLydia Wang 		else
52273e95b9abSLydia Wang 			mono_out = 1;
52283e95b9abSLydia Wang 	}
52293e95b9abSLydia Wang 	parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3;
52303e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, parm);
52313e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, parm);
52323e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, parm);
52333e95b9abSLydia Wang 
52343e95b9abSLydia Wang 	/* PW 3/4 (1ch/1dh) */
52353e95b9abSLydia Wang 	parm = AC_PWRST_D3;
52363e95b9abSLydia Wang 	set_pin_power_state(codec, 0x1c, &parm);
52373e95b9abSLydia Wang 	set_pin_power_state(codec, 0x1d, &parm);
52383e95b9abSLydia Wang 	/* HP Independent Mode, power on AOW3 */
52393e95b9abSLydia Wang 	if (spec->hp_independent_mode)
52403e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x25, 0,
52413e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
52423e95b9abSLydia Wang 
52433e95b9abSLydia Wang 	/* force to D0 for internal Speaker */
52443e95b9abSLydia Wang 	/* MW0 (16h), AOW0 (10h) */
52453e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
52463e95b9abSLydia Wang 			    imux_is_smixer ? AC_PWRST_D0 : parm);
52473e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
52483e95b9abSLydia Wang 			    mono_out ? AC_PWRST_D0 : parm);
52493e95b9abSLydia Wang }
52503e95b9abSLydia Wang 
5251f3db423dSLydia Wang static int patch_vt1716S(struct hda_codec *codec)
5252f3db423dSLydia Wang {
5253f3db423dSLydia Wang 	struct via_spec *spec;
5254f3db423dSLydia Wang 	int err;
5255f3db423dSLydia Wang 
5256f3db423dSLydia Wang 	/* create a codec specific record */
52575b0cb1d8SJaroslav Kysela 	spec = via_new_spec(codec);
5258f3db423dSLydia Wang 	if (spec == NULL)
5259f3db423dSLydia Wang 		return -ENOMEM;
5260f3db423dSLydia Wang 
5261f3db423dSLydia Wang 	/* automatic parse from the BIOS config */
5262f3db423dSLydia Wang 	err = vt1716S_parse_auto_config(codec);
5263f3db423dSLydia Wang 	if (err < 0) {
5264f3db423dSLydia Wang 		via_free(codec);
5265f3db423dSLydia Wang 		return err;
5266f3db423dSLydia Wang 	} else if (!err) {
5267f3db423dSLydia Wang 		printk(KERN_INFO "hda_codec: Cannot set up configuration "
5268f3db423dSLydia Wang 		       "from BIOS.  Using genenic mode...\n");
5269f3db423dSLydia Wang 	}
5270f3db423dSLydia Wang 
5271f3db423dSLydia Wang 	spec->init_verbs[spec->num_iverbs++]  = vt1716S_volume_init_verbs;
5272f3db423dSLydia Wang 	spec->init_verbs[spec->num_iverbs++] = vt1716S_uniwill_init_verbs;
5273f3db423dSLydia Wang 
5274f3db423dSLydia Wang 	spec->stream_name_analog = "VT1716S Analog";
5275f3db423dSLydia Wang 	spec->stream_analog_playback = &vt1716S_pcm_analog_playback;
5276f3db423dSLydia Wang 	spec->stream_analog_capture = &vt1716S_pcm_analog_capture;
5277f3db423dSLydia Wang 
5278f3db423dSLydia Wang 	spec->stream_name_digital = "VT1716S Digital";
5279f3db423dSLydia Wang 	spec->stream_digital_playback = &vt1716S_pcm_digital_playback;
5280f3db423dSLydia Wang 
5281f3db423dSLydia Wang 	if (!spec->adc_nids && spec->input_mux) {
5282f3db423dSLydia Wang 		spec->adc_nids = vt1716S_adc_nids;
5283f3db423dSLydia Wang 		spec->num_adc_nids = ARRAY_SIZE(vt1716S_adc_nids);
5284f3db423dSLydia Wang 		get_mux_nids(codec);
5285f3db423dSLydia Wang 		override_mic_boost(codec, 0x1a, 0, 3, 40);
5286f3db423dSLydia Wang 		override_mic_boost(codec, 0x1e, 0, 3, 40);
5287f3db423dSLydia Wang 		spec->mixers[spec->num_mixers] = vt1716S_capture_mixer;
5288f3db423dSLydia Wang 		spec->num_mixers++;
5289f3db423dSLydia Wang 	}
5290f3db423dSLydia Wang 
5291f3db423dSLydia Wang 	spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer;
5292f3db423dSLydia Wang 	spec->num_mixers++;
5293f3db423dSLydia Wang 
5294f3db423dSLydia Wang 	spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer;
5295f3db423dSLydia Wang 
5296f3db423dSLydia Wang 	codec->patch_ops = via_patch_ops;
5297f3db423dSLydia Wang 
5298f3db423dSLydia Wang 	codec->patch_ops.init = via_auto_init;
52990f48327eSStephen Rothwell 	codec->patch_ops.unsol_event = via_unsol_event;
5300f3db423dSLydia Wang 
5301f3db423dSLydia Wang #ifdef CONFIG_SND_HDA_POWER_SAVE
5302f3db423dSLydia Wang 	spec->loopback.amplist = vt1716S_loopbacks;
5303f3db423dSLydia Wang #endif
5304f3db423dSLydia Wang 
53053e95b9abSLydia Wang 	spec->set_widgets_power_state = set_widgets_power_state_vt1716S;
5306f3db423dSLydia Wang 	return 0;
5307f3db423dSLydia Wang }
530825eaba2fSLydia Wang 
530925eaba2fSLydia Wang /* for vt2002P */
531025eaba2fSLydia Wang 
531125eaba2fSLydia Wang /* capture mixer elements */
531290dd48a1STakashi Iwai static const struct snd_kcontrol_new vt2002P_capture_mixer[] = {
531325eaba2fSLydia Wang 	HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
531425eaba2fSLydia Wang 	HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
531525eaba2fSLydia Wang 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
531625eaba2fSLydia Wang 	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
531725eaba2fSLydia Wang 	HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
531825eaba2fSLydia Wang 	HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0,
531925eaba2fSLydia Wang 			 HDA_INPUT),
532025eaba2fSLydia Wang 	{
532125eaba2fSLydia Wang 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
532225eaba2fSLydia Wang 		/* The multiple "Capture Source" controls confuse alsamixer
532325eaba2fSLydia Wang 		 * So call somewhat different..
532425eaba2fSLydia Wang 		 */
532525eaba2fSLydia Wang 		/* .name = "Capture Source", */
532625eaba2fSLydia Wang 		.name = "Input Source",
532725eaba2fSLydia Wang 		.count = 2,
532825eaba2fSLydia Wang 		.info = via_mux_enum_info,
532925eaba2fSLydia Wang 		.get = via_mux_enum_get,
533025eaba2fSLydia Wang 		.put = via_mux_enum_put,
533125eaba2fSLydia Wang 	},
533225eaba2fSLydia Wang 	{ } /* end */
533325eaba2fSLydia Wang };
533425eaba2fSLydia Wang 
533590dd48a1STakashi Iwai static const struct hda_verb vt2002P_volume_init_verbs[] = {
5336eadb9a80SLydia Wang 	/* Class-D speaker related verbs */
5337eadb9a80SLydia Wang 	{0x1, 0xfe0, 0x4},
5338eadb9a80SLydia Wang 	{0x1, 0xfe9, 0x80},
5339eadb9a80SLydia Wang 	{0x1, 0xfe2, 0x22},
534025eaba2fSLydia Wang 	/*
534125eaba2fSLydia Wang 	 * Unmute ADC0-1 and set the default input to mic-in
534225eaba2fSLydia Wang 	 */
534325eaba2fSLydia Wang 	{0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
534425eaba2fSLydia Wang 	{0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
534525eaba2fSLydia Wang 
534625eaba2fSLydia Wang 
534725eaba2fSLydia Wang 	/* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
534825eaba2fSLydia Wang 	 * mixer widget
534925eaba2fSLydia Wang 	 */
535025eaba2fSLydia Wang 	/* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
535125eaba2fSLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
535225eaba2fSLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
535325eaba2fSLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
535425eaba2fSLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
535525eaba2fSLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
535625eaba2fSLydia Wang 
535725eaba2fSLydia Wang 	/* MUX Indices: Mic = 0 */
535825eaba2fSLydia Wang 	{0x1e, AC_VERB_SET_CONNECT_SEL, 0},
535925eaba2fSLydia Wang 	{0x1f, AC_VERB_SET_CONNECT_SEL, 0},
536025eaba2fSLydia Wang 
536125eaba2fSLydia Wang 	/* PW9 Output enable */
536225eaba2fSLydia Wang 	{0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
536325eaba2fSLydia Wang 
536425eaba2fSLydia Wang 	/* Enable Boost Volume backdoor */
536525eaba2fSLydia Wang 	{0x1, 0xfb9, 0x24},
536625eaba2fSLydia Wang 
536725eaba2fSLydia Wang 	/* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
536825eaba2fSLydia Wang 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
536925eaba2fSLydia Wang 	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
537025eaba2fSLydia Wang 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
537125eaba2fSLydia Wang 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
537225eaba2fSLydia Wang 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
537325eaba2fSLydia Wang 	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
537425eaba2fSLydia Wang 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
537525eaba2fSLydia Wang 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
537625eaba2fSLydia Wang 
537725eaba2fSLydia Wang 	/* set MUX0/1/4/8 = 0 (AOW0) */
537825eaba2fSLydia Wang 	{0x34, AC_VERB_SET_CONNECT_SEL, 0},
537925eaba2fSLydia Wang 	{0x35, AC_VERB_SET_CONNECT_SEL, 0},
538025eaba2fSLydia Wang 	{0x37, AC_VERB_SET_CONNECT_SEL, 0},
538125eaba2fSLydia Wang 	{0x3b, AC_VERB_SET_CONNECT_SEL, 0},
538225eaba2fSLydia Wang 
538325eaba2fSLydia Wang 	/* set PW0 index=0 (MW0) */
538425eaba2fSLydia Wang 	{0x24, AC_VERB_SET_CONNECT_SEL, 0},
538525eaba2fSLydia Wang 
538625eaba2fSLydia Wang 	/* Enable AOW0 to MW9 */
538725eaba2fSLydia Wang 	{0x1, 0xfb8, 0x88},
538825eaba2fSLydia Wang 	{ }
538925eaba2fSLydia Wang };
539090dd48a1STakashi Iwai static const struct hda_verb vt1802_volume_init_verbs[] = {
539111890956SLydia Wang 	/*
539211890956SLydia Wang 	 * Unmute ADC0-1 and set the default input to mic-in
539311890956SLydia Wang 	 */
539411890956SLydia Wang 	{0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
539511890956SLydia Wang 	{0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
539611890956SLydia Wang 
539711890956SLydia Wang 
539811890956SLydia Wang 	/* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
539911890956SLydia Wang 	 * mixer widget
540011890956SLydia Wang 	 */
540111890956SLydia Wang 	/* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
540211890956SLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
540311890956SLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
540411890956SLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
540511890956SLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
540611890956SLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
540711890956SLydia Wang 
540811890956SLydia Wang 	/* MUX Indices: Mic = 0 */
540911890956SLydia Wang 	{0x1e, AC_VERB_SET_CONNECT_SEL, 0},
541011890956SLydia Wang 	{0x1f, AC_VERB_SET_CONNECT_SEL, 0},
541111890956SLydia Wang 
541211890956SLydia Wang 	/* PW9 Output enable */
541311890956SLydia Wang 	{0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
541411890956SLydia Wang 
541511890956SLydia Wang 	/* Enable Boost Volume backdoor */
541611890956SLydia Wang 	{0x1, 0xfb9, 0x24},
541711890956SLydia Wang 
541811890956SLydia Wang 	/* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
541911890956SLydia Wang 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
542011890956SLydia Wang 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
542111890956SLydia Wang 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
542211890956SLydia Wang 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
542311890956SLydia Wang 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
542411890956SLydia Wang 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
542511890956SLydia Wang 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
542611890956SLydia Wang 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
542711890956SLydia Wang 
542811890956SLydia Wang 	/* set MUX0/1/4/8 = 0 (AOW0) */
542911890956SLydia Wang 	{0x34, AC_VERB_SET_CONNECT_SEL, 0},
543011890956SLydia Wang 	{0x35, AC_VERB_SET_CONNECT_SEL, 0},
543111890956SLydia Wang 	{0x38, AC_VERB_SET_CONNECT_SEL, 0},
543211890956SLydia Wang 	{0x3c, AC_VERB_SET_CONNECT_SEL, 0},
543311890956SLydia Wang 
543411890956SLydia Wang 	/* set PW0 index=0 (MW0) */
543511890956SLydia Wang 	{0x24, AC_VERB_SET_CONNECT_SEL, 0},
543611890956SLydia Wang 
543711890956SLydia Wang 	/* Enable AOW0 to MW9 */
543811890956SLydia Wang 	{0x1, 0xfb8, 0x88},
543911890956SLydia Wang 	{ }
544011890956SLydia Wang };
544125eaba2fSLydia Wang 
544225eaba2fSLydia Wang 
544390dd48a1STakashi Iwai static const struct hda_verb vt2002P_uniwill_init_verbs[] = {
544425eaba2fSLydia Wang 	{0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
544525eaba2fSLydia Wang 	 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
544625eaba2fSLydia Wang 	{0x26, AC_VERB_SET_UNSOLICITED_ENABLE,
544725eaba2fSLydia Wang 	 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
544825eaba2fSLydia Wang 	{0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
544925eaba2fSLydia Wang 	{0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
545025eaba2fSLydia Wang 	{0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
545125eaba2fSLydia Wang 	{ }
545225eaba2fSLydia Wang };
545390dd48a1STakashi Iwai static const struct hda_verb vt1802_uniwill_init_verbs[] = {
545411890956SLydia Wang 	{0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
545511890956SLydia Wang 	 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
545611890956SLydia Wang 	{0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
545711890956SLydia Wang 	 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
545811890956SLydia Wang 	{0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
545911890956SLydia Wang 	{0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
546011890956SLydia Wang 	{0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
546111890956SLydia Wang 	{ }
546211890956SLydia Wang };
546325eaba2fSLydia Wang 
546490dd48a1STakashi Iwai static const struct hda_pcm_stream vt2002P_pcm_analog_playback = {
546525eaba2fSLydia Wang 	.substreams = 2,
546625eaba2fSLydia Wang 	.channels_min = 2,
546725eaba2fSLydia Wang 	.channels_max = 2,
546825eaba2fSLydia Wang 	.nid = 0x8, /* NID to query formats and rates */
546925eaba2fSLydia Wang 	.ops = {
547025eaba2fSLydia Wang 		.open = via_playback_pcm_open,
547125eaba2fSLydia Wang 		.prepare = via_playback_multi_pcm_prepare,
547225eaba2fSLydia Wang 		.cleanup = via_playback_multi_pcm_cleanup,
547325eaba2fSLydia Wang 		.close = via_pcm_open_close,
547425eaba2fSLydia Wang 	},
547525eaba2fSLydia Wang };
547625eaba2fSLydia Wang 
547790dd48a1STakashi Iwai static const struct hda_pcm_stream vt2002P_pcm_analog_capture = {
547825eaba2fSLydia Wang 	.substreams = 2,
547925eaba2fSLydia Wang 	.channels_min = 2,
548025eaba2fSLydia Wang 	.channels_max = 2,
548125eaba2fSLydia Wang 	.nid = 0x10, /* NID to query formats and rates */
548225eaba2fSLydia Wang 	.ops = {
548325eaba2fSLydia Wang 		.open = via_pcm_open_close,
548425eaba2fSLydia Wang 		.prepare = via_capture_pcm_prepare,
548525eaba2fSLydia Wang 		.cleanup = via_capture_pcm_cleanup,
548625eaba2fSLydia Wang 		.close = via_pcm_open_close,
548725eaba2fSLydia Wang 	},
548825eaba2fSLydia Wang };
548925eaba2fSLydia Wang 
549090dd48a1STakashi Iwai static const struct hda_pcm_stream vt2002P_pcm_digital_playback = {
549125eaba2fSLydia Wang 	.substreams = 1,
549225eaba2fSLydia Wang 	.channels_min = 2,
549325eaba2fSLydia Wang 	.channels_max = 2,
549425eaba2fSLydia Wang 	/* NID is set in via_build_pcms */
549525eaba2fSLydia Wang 	.ops = {
549625eaba2fSLydia Wang 		.open = via_dig_playback_pcm_open,
549725eaba2fSLydia Wang 		.close = via_dig_playback_pcm_close,
549825eaba2fSLydia Wang 		.prepare = via_dig_playback_pcm_prepare,
549925eaba2fSLydia Wang 		.cleanup = via_dig_playback_pcm_cleanup
550025eaba2fSLydia Wang 	},
550125eaba2fSLydia Wang };
550225eaba2fSLydia Wang 
550325eaba2fSLydia Wang /* fill in the dac_nids table from the parsed pin configuration */
550425eaba2fSLydia Wang static int vt2002P_auto_fill_dac_nids(struct via_spec *spec,
550525eaba2fSLydia Wang 				      const struct auto_pin_cfg *cfg)
550625eaba2fSLydia Wang {
550725eaba2fSLydia Wang 	spec->multiout.num_dacs = 1;
550825eaba2fSLydia Wang 	spec->multiout.dac_nids = spec->private_dac_nids;
550925eaba2fSLydia Wang 	if (cfg->line_out_pins[0])
5510dda14410STakashi Iwai 		spec->private_dac_nids[0] = 0x8;
551125eaba2fSLydia Wang 	return 0;
551225eaba2fSLydia Wang }
551325eaba2fSLydia Wang 
551425eaba2fSLydia Wang /* add playback controls from the parsed DAC table */
551525eaba2fSLydia Wang static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec,
551625eaba2fSLydia Wang 					     const struct auto_pin_cfg *cfg)
551725eaba2fSLydia Wang {
551825eaba2fSLydia Wang 	int err;
551911890956SLydia Wang 	hda_nid_t sw_nid;
552025eaba2fSLydia Wang 
552125eaba2fSLydia Wang 	if (!cfg->line_out_pins[0])
552225eaba2fSLydia Wang 		return -1;
552325eaba2fSLydia Wang 
552411890956SLydia Wang 	if (spec->codec_type == VT1802)
552511890956SLydia Wang 		sw_nid = 0x28;
552611890956SLydia Wang 	else
552711890956SLydia Wang 		sw_nid = 0x26;
552825eaba2fSLydia Wang 
552925eaba2fSLydia Wang 	/* Line-Out: PortE */
553025eaba2fSLydia Wang 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
553125eaba2fSLydia Wang 			      "Master Front Playback Volume",
553225eaba2fSLydia Wang 			      HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT));
553325eaba2fSLydia Wang 	if (err < 0)
553425eaba2fSLydia Wang 		return err;
553525eaba2fSLydia Wang 	err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
553625eaba2fSLydia Wang 			      "Master Front Playback Switch",
553711890956SLydia Wang 			      HDA_COMPOSE_AMP_VAL(sw_nid, 3, 0, HDA_OUTPUT));
553825eaba2fSLydia Wang 	if (err < 0)
553925eaba2fSLydia Wang 		return err;
554025eaba2fSLydia Wang 
554125eaba2fSLydia Wang 	return 0;
554225eaba2fSLydia Wang }
554325eaba2fSLydia Wang 
554425eaba2fSLydia Wang static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
554525eaba2fSLydia Wang {
554625eaba2fSLydia Wang 	int err;
554725eaba2fSLydia Wang 
554825eaba2fSLydia Wang 	if (!pin)
554925eaba2fSLydia Wang 		return 0;
555025eaba2fSLydia Wang 
555125eaba2fSLydia Wang 	spec->multiout.hp_nid = 0x9;
555225eaba2fSLydia Wang 	spec->hp_independent_mode_index = 1;
555325eaba2fSLydia Wang 
555425eaba2fSLydia Wang 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
555525eaba2fSLydia Wang 			      "Headphone Playback Volume",
555625eaba2fSLydia Wang 			      HDA_COMPOSE_AMP_VAL(
555725eaba2fSLydia Wang 				      spec->multiout.hp_nid, 3, 0, HDA_OUTPUT));
555825eaba2fSLydia Wang 	if (err < 0)
555925eaba2fSLydia Wang 		return err;
556025eaba2fSLydia Wang 
556125eaba2fSLydia Wang 	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
556225eaba2fSLydia Wang 			      "Headphone Playback Switch",
556325eaba2fSLydia Wang 			      HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
556425eaba2fSLydia Wang 	if (err < 0)
556525eaba2fSLydia Wang 		return err;
556625eaba2fSLydia Wang 
556725eaba2fSLydia Wang 	create_hp_imux(spec);
556825eaba2fSLydia Wang 	return 0;
556925eaba2fSLydia Wang }
557025eaba2fSLydia Wang 
557125eaba2fSLydia Wang /* create playback/capture controls for input pins */
557210a20af7STakashi Iwai static int vt2002P_auto_create_analog_input_ctls(struct hda_codec *codec,
557325eaba2fSLydia Wang 						const struct auto_pin_cfg *cfg)
557425eaba2fSLydia Wang {
557510a20af7STakashi Iwai 	struct via_spec *spec = codec->spec;
557625eaba2fSLydia Wang 	struct hda_input_mux *imux = &spec->private_imux[0];
557790dd48a1STakashi Iwai 	static const hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff };
5578f3268512STakashi Iwai 	int err;
557925eaba2fSLydia Wang 
558010a20af7STakashi Iwai 	err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
5581f3268512STakashi Iwai 					       ARRAY_SIZE(pin_idxs));
558225eaba2fSLydia Wang 	if (err < 0)
558325eaba2fSLydia Wang 		return err;
558425eaba2fSLydia Wang 	/* build volume/mute control of loopback */
55857b315bb4STakashi Iwai 	err = via_new_analog_input(spec, "Stereo Mixer", 0, 3, 0x21);
558625eaba2fSLydia Wang 	if (err < 0)
558725eaba2fSLydia Wang 		return err;
558825eaba2fSLydia Wang 
558925eaba2fSLydia Wang 	/* for digital mic select */
559010a20af7STakashi Iwai 	snd_hda_add_imux_item(imux, "Digital Mic", 4, NULL);
559125eaba2fSLydia Wang 
559225eaba2fSLydia Wang 	return 0;
559325eaba2fSLydia Wang }
559425eaba2fSLydia Wang 
559525eaba2fSLydia Wang static int vt2002P_parse_auto_config(struct hda_codec *codec)
559625eaba2fSLydia Wang {
559725eaba2fSLydia Wang 	struct via_spec *spec = codec->spec;
559825eaba2fSLydia Wang 	int err;
559925eaba2fSLydia Wang 
560025eaba2fSLydia Wang 
560125eaba2fSLydia Wang 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
560225eaba2fSLydia Wang 	if (err < 0)
560325eaba2fSLydia Wang 		return err;
560425eaba2fSLydia Wang 
560525eaba2fSLydia Wang 	err = vt2002P_auto_fill_dac_nids(spec, &spec->autocfg);
560625eaba2fSLydia Wang 	if (err < 0)
560725eaba2fSLydia Wang 		return err;
560825eaba2fSLydia Wang 
560925eaba2fSLydia Wang 	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
561025eaba2fSLydia Wang 		return 0; /* can't find valid BIOS pin config */
561125eaba2fSLydia Wang 
561225eaba2fSLydia Wang 	err = vt2002P_auto_create_multi_out_ctls(spec, &spec->autocfg);
561325eaba2fSLydia Wang 	if (err < 0)
561425eaba2fSLydia Wang 		return err;
561525eaba2fSLydia Wang 	err = vt2002P_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
561625eaba2fSLydia Wang 	if (err < 0)
561725eaba2fSLydia Wang 		return err;
561810a20af7STakashi Iwai 	err = vt2002P_auto_create_analog_input_ctls(codec, &spec->autocfg);
561925eaba2fSLydia Wang 	if (err < 0)
562025eaba2fSLydia Wang 		return err;
562125eaba2fSLydia Wang 
562225eaba2fSLydia Wang 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
562325eaba2fSLydia Wang 
562425eaba2fSLydia Wang 	fill_dig_outs(codec);
562525eaba2fSLydia Wang 
562625eaba2fSLydia Wang 	if (spec->kctls.list)
562725eaba2fSLydia Wang 		spec->mixers[spec->num_mixers++] = spec->kctls.list;
562825eaba2fSLydia Wang 
562925eaba2fSLydia Wang 	spec->input_mux = &spec->private_imux[0];
563025eaba2fSLydia Wang 
563125eaba2fSLydia Wang 	if (spec->hp_mux)
56323d83e577STakashi Iwai 		via_hp_build(codec);
563325eaba2fSLydia Wang 
563425eaba2fSLydia Wang 	return 1;
563525eaba2fSLydia Wang }
563625eaba2fSLydia Wang 
563725eaba2fSLydia Wang #ifdef CONFIG_SND_HDA_POWER_SAVE
563890dd48a1STakashi Iwai static const struct hda_amp_list vt2002P_loopbacks[] = {
563925eaba2fSLydia Wang 	{ 0x21, HDA_INPUT, 0 },
564025eaba2fSLydia Wang 	{ 0x21, HDA_INPUT, 1 },
564125eaba2fSLydia Wang 	{ 0x21, HDA_INPUT, 2 },
564225eaba2fSLydia Wang 	{ } /* end */
564325eaba2fSLydia Wang };
564425eaba2fSLydia Wang #endif
564525eaba2fSLydia Wang 
56463e95b9abSLydia Wang static void set_widgets_power_state_vt2002P(struct hda_codec *codec)
56473e95b9abSLydia Wang {
56483e95b9abSLydia Wang 	struct via_spec *spec = codec->spec;
56493e95b9abSLydia Wang 	int imux_is_smixer;
56503e95b9abSLydia Wang 	unsigned int parm;
56513e95b9abSLydia Wang 	unsigned int present;
56523e95b9abSLydia Wang 	/* MUX9 (1eh) = stereo mixer */
56533e95b9abSLydia Wang 	imux_is_smixer =
56543e95b9abSLydia Wang 	snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
56553e95b9abSLydia Wang 	/* inputs */
56563e95b9abSLydia Wang 	/* PW 5/6/7 (29h/2ah/2bh) */
56573e95b9abSLydia Wang 	parm = AC_PWRST_D3;
56583e95b9abSLydia Wang 	set_pin_power_state(codec, 0x29, &parm);
56593e95b9abSLydia Wang 	set_pin_power_state(codec, 0x2a, &parm);
56603e95b9abSLydia Wang 	set_pin_power_state(codec, 0x2b, &parm);
56613e95b9abSLydia Wang 	parm = AC_PWRST_D0;
56623e95b9abSLydia Wang 	/* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */
56633e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm);
56643e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
56653e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
56663e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
56673e95b9abSLydia Wang 
56683e95b9abSLydia Wang 	/* outputs */
56693e95b9abSLydia Wang 	/* AOW0 (8h)*/
56703e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm);
56713e95b9abSLydia Wang 
567211890956SLydia Wang 	if (spec->codec_type == VT1802) {
567311890956SLydia Wang 		/* PW4 (28h), MW4 (18h), MUX4(38h) */
567411890956SLydia Wang 		parm = AC_PWRST_D3;
567511890956SLydia Wang 		set_pin_power_state(codec, 0x28, &parm);
567611890956SLydia Wang 		snd_hda_codec_write(codec, 0x18, 0,
567711890956SLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
567811890956SLydia Wang 		snd_hda_codec_write(codec, 0x38, 0,
567911890956SLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
568011890956SLydia Wang 	} else {
56813e95b9abSLydia Wang 		/* PW4 (26h), MW4 (1ch), MUX4(37h) */
56823e95b9abSLydia Wang 		parm = AC_PWRST_D3;
56833e95b9abSLydia Wang 		set_pin_power_state(codec, 0x26, &parm);
56843e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x1c, 0,
56853e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
56863e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x37, 0,
56873e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
568811890956SLydia Wang 	}
56893e95b9abSLydia Wang 
569011890956SLydia Wang 	if (spec->codec_type == VT1802) {
569111890956SLydia Wang 		/* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
569211890956SLydia Wang 		parm = AC_PWRST_D3;
569311890956SLydia Wang 		set_pin_power_state(codec, 0x25, &parm);
569411890956SLydia Wang 		snd_hda_codec_write(codec, 0x15, 0,
569511890956SLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
569611890956SLydia Wang 		snd_hda_codec_write(codec, 0x35, 0,
569711890956SLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
569811890956SLydia Wang 	} else {
56993e95b9abSLydia Wang 		/* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */
57003e95b9abSLydia Wang 		parm = AC_PWRST_D3;
57013e95b9abSLydia Wang 		set_pin_power_state(codec, 0x25, &parm);
57023e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x19, 0,
57033e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
57043e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x35, 0,
57053e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
570611890956SLydia Wang 	}
57073e95b9abSLydia Wang 
57083e95b9abSLydia Wang 	if (spec->hp_independent_mode)
57093e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x9, 0,
57103e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
57113e95b9abSLydia Wang 
57123e95b9abSLydia Wang 	/* Class-D */
57133e95b9abSLydia Wang 	/* PW0 (24h), MW0(18h/14h), MUX0(34h) */
57143e95b9abSLydia Wang 	present = snd_hda_jack_detect(codec, 0x25);
57153e95b9abSLydia Wang 
57163e95b9abSLydia Wang 	parm = AC_PWRST_D3;
57173e95b9abSLydia Wang 	set_pin_power_state(codec, 0x24, &parm);
57183e95b9abSLydia Wang 	parm = present ? AC_PWRST_D3 : AC_PWRST_D0;
571911890956SLydia Wang 	if (spec->codec_type == VT1802)
572011890956SLydia Wang 		snd_hda_codec_write(codec, 0x14, 0,
572111890956SLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
572211890956SLydia Wang 	else
57233e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x18, 0,
57243e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
57253e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_POWER_STATE, parm);
57263e95b9abSLydia Wang 
57273e95b9abSLydia Wang 	/* Mono Out */
57283e95b9abSLydia Wang 	present = snd_hda_jack_detect(codec, 0x26);
57293e95b9abSLydia Wang 
57303e95b9abSLydia Wang 	parm = present ? AC_PWRST_D3 : AC_PWRST_D0;
573111890956SLydia Wang 	if (spec->codec_type == VT1802) {
573211890956SLydia Wang 		/* PW15 (33h), MW8(1ch), MUX8(3ch) */
573311890956SLydia Wang 		snd_hda_codec_write(codec, 0x33, 0,
573411890956SLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
573511890956SLydia Wang 		snd_hda_codec_write(codec, 0x1c, 0,
573611890956SLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
573711890956SLydia Wang 		snd_hda_codec_write(codec, 0x3c, 0,
573811890956SLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
573911890956SLydia Wang 	} else {
57403e95b9abSLydia Wang 		/* PW15 (31h), MW8(17h), MUX8(3bh) */
57413e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x31, 0,
57423e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
57433e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x17, 0,
57443e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
57453e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x3b, 0,
57463e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, parm);
574711890956SLydia Wang 	}
57483e95b9abSLydia Wang 	/* MW9 (21h) */
57493e95b9abSLydia Wang 	if (imux_is_smixer || !is_aa_path_mute(codec))
57503e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x21, 0,
57513e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
57523e95b9abSLydia Wang 	else
57533e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x21, 0,
57543e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
57553e95b9abSLydia Wang }
575625eaba2fSLydia Wang 
575725eaba2fSLydia Wang /* patch for vt2002P */
575825eaba2fSLydia Wang static int patch_vt2002P(struct hda_codec *codec)
575925eaba2fSLydia Wang {
576025eaba2fSLydia Wang 	struct via_spec *spec;
576125eaba2fSLydia Wang 	int err;
576225eaba2fSLydia Wang 
576325eaba2fSLydia Wang 	/* create a codec specific record */
57645b0cb1d8SJaroslav Kysela 	spec = via_new_spec(codec);
576525eaba2fSLydia Wang 	if (spec == NULL)
576625eaba2fSLydia Wang 		return -ENOMEM;
576725eaba2fSLydia Wang 
576825eaba2fSLydia Wang 	/* automatic parse from the BIOS config */
576925eaba2fSLydia Wang 	err = vt2002P_parse_auto_config(codec);
577025eaba2fSLydia Wang 	if (err < 0) {
577125eaba2fSLydia Wang 		via_free(codec);
577225eaba2fSLydia Wang 		return err;
577325eaba2fSLydia Wang 	} else if (!err) {
577425eaba2fSLydia Wang 		printk(KERN_INFO "hda_codec: Cannot set up configuration "
577525eaba2fSLydia Wang 		       "from BIOS.  Using genenic mode...\n");
577625eaba2fSLydia Wang 	}
577725eaba2fSLydia Wang 
577811890956SLydia Wang 	if (spec->codec_type == VT1802)
577911890956SLydia Wang 		spec->init_verbs[spec->num_iverbs++]  =
578011890956SLydia Wang 			vt1802_volume_init_verbs;
578111890956SLydia Wang 	else
578211890956SLydia Wang 		spec->init_verbs[spec->num_iverbs++]  =
578311890956SLydia Wang 			vt2002P_volume_init_verbs;
578425eaba2fSLydia Wang 
578511890956SLydia Wang 	if (spec->codec_type == VT1802)
578611890956SLydia Wang 		spec->init_verbs[spec->num_iverbs++] =
578711890956SLydia Wang 			vt1802_uniwill_init_verbs;
578811890956SLydia Wang 	else
578911890956SLydia Wang 		spec->init_verbs[spec->num_iverbs++] =
579011890956SLydia Wang 			vt2002P_uniwill_init_verbs;
579111890956SLydia Wang 
579211890956SLydia Wang 	if (spec->codec_type == VT1802)
579311890956SLydia Wang 		spec->stream_name_analog = "VT1802 Analog";
579411890956SLydia Wang 	else
579525eaba2fSLydia Wang 		spec->stream_name_analog = "VT2002P Analog";
579625eaba2fSLydia Wang 	spec->stream_analog_playback = &vt2002P_pcm_analog_playback;
579725eaba2fSLydia Wang 	spec->stream_analog_capture = &vt2002P_pcm_analog_capture;
579825eaba2fSLydia Wang 
579911890956SLydia Wang 	if (spec->codec_type == VT1802)
580011890956SLydia Wang 		spec->stream_name_digital = "VT1802 Digital";
580111890956SLydia Wang 	else
580225eaba2fSLydia Wang 		spec->stream_name_digital = "VT2002P Digital";
580325eaba2fSLydia Wang 	spec->stream_digital_playback = &vt2002P_pcm_digital_playback;
580425eaba2fSLydia Wang 
580525eaba2fSLydia Wang 	if (!spec->adc_nids && spec->input_mux) {
580625eaba2fSLydia Wang 		spec->adc_nids = vt2002P_adc_nids;
580725eaba2fSLydia Wang 		spec->num_adc_nids = ARRAY_SIZE(vt2002P_adc_nids);
580825eaba2fSLydia Wang 		get_mux_nids(codec);
580925eaba2fSLydia Wang 		override_mic_boost(codec, 0x2b, 0, 3, 40);
581025eaba2fSLydia Wang 		override_mic_boost(codec, 0x29, 0, 3, 40);
581125eaba2fSLydia Wang 		spec->mixers[spec->num_mixers] = vt2002P_capture_mixer;
581225eaba2fSLydia Wang 		spec->num_mixers++;
581325eaba2fSLydia Wang 	}
581425eaba2fSLydia Wang 
581525eaba2fSLydia Wang 	codec->patch_ops = via_patch_ops;
581625eaba2fSLydia Wang 
581725eaba2fSLydia Wang 	codec->patch_ops.init = via_auto_init;
58180f48327eSStephen Rothwell 	codec->patch_ops.unsol_event = via_unsol_event;
581925eaba2fSLydia Wang 
582025eaba2fSLydia Wang #ifdef CONFIG_SND_HDA_POWER_SAVE
582125eaba2fSLydia Wang 	spec->loopback.amplist = vt2002P_loopbacks;
582225eaba2fSLydia Wang #endif
582325eaba2fSLydia Wang 
58243e95b9abSLydia Wang 	spec->set_widgets_power_state =  set_widgets_power_state_vt2002P;
582525eaba2fSLydia Wang 	return 0;
582625eaba2fSLydia Wang }
5827ab6734e7SLydia Wang 
5828ab6734e7SLydia Wang /* for vt1812 */
5829ab6734e7SLydia Wang 
5830ab6734e7SLydia Wang /* capture mixer elements */
583190dd48a1STakashi Iwai static const struct snd_kcontrol_new vt1812_capture_mixer[] = {
5832ab6734e7SLydia Wang 	HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
5833ab6734e7SLydia Wang 	HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
5834ab6734e7SLydia Wang 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
5835ab6734e7SLydia Wang 	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
5836ab6734e7SLydia Wang 	HDA_CODEC_MUTE("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
5837ab6734e7SLydia Wang 	HDA_CODEC_MUTE("Front Mic Boost Capture Volume", 0x29, 0x0,
5838ab6734e7SLydia Wang 		       HDA_INPUT),
5839ab6734e7SLydia Wang 	{
5840ab6734e7SLydia Wang 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5841ab6734e7SLydia Wang 		/* The multiple "Capture Source" controls confuse alsamixer
5842ab6734e7SLydia Wang 		 * So call somewhat different..
5843ab6734e7SLydia Wang 		 */
5844ab6734e7SLydia Wang 		.name = "Input Source",
5845ab6734e7SLydia Wang 		.count = 2,
5846ab6734e7SLydia Wang 		.info = via_mux_enum_info,
5847ab6734e7SLydia Wang 		.get = via_mux_enum_get,
5848ab6734e7SLydia Wang 		.put = via_mux_enum_put,
5849ab6734e7SLydia Wang 	},
5850ab6734e7SLydia Wang 	{ } /* end */
5851ab6734e7SLydia Wang };
5852ab6734e7SLydia Wang 
585390dd48a1STakashi Iwai static const struct hda_verb vt1812_volume_init_verbs[] = {
5854ab6734e7SLydia Wang 	/*
5855ab6734e7SLydia Wang 	 * Unmute ADC0-1 and set the default input to mic-in
5856ab6734e7SLydia Wang 	 */
5857ab6734e7SLydia Wang 	{0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5858ab6734e7SLydia Wang 	{0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5859ab6734e7SLydia Wang 
5860ab6734e7SLydia Wang 
5861ab6734e7SLydia Wang 	/* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5862ab6734e7SLydia Wang 	 * mixer widget
5863ab6734e7SLydia Wang 	 */
5864ab6734e7SLydia Wang 	/* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
5865ab6734e7SLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5866ab6734e7SLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5867ab6734e7SLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5868ab6734e7SLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5869ab6734e7SLydia Wang 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5870ab6734e7SLydia Wang 
5871ab6734e7SLydia Wang 	/* MUX Indices: Mic = 0 */
5872ab6734e7SLydia Wang 	{0x1e, AC_VERB_SET_CONNECT_SEL, 0},
5873ab6734e7SLydia Wang 	{0x1f, AC_VERB_SET_CONNECT_SEL, 0},
5874ab6734e7SLydia Wang 
5875ab6734e7SLydia Wang 	/* PW9 Output enable */
5876ab6734e7SLydia Wang 	{0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
5877ab6734e7SLydia Wang 
5878ab6734e7SLydia Wang 	/* Enable Boost Volume backdoor */
5879ab6734e7SLydia Wang 	{0x1, 0xfb9, 0x24},
5880ab6734e7SLydia Wang 
5881ab6734e7SLydia Wang 	/* MW0/1/4/13/15: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
5882ab6734e7SLydia Wang 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5883ab6734e7SLydia Wang 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5884ab6734e7SLydia Wang 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5885ab6734e7SLydia Wang 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5886ab6734e7SLydia Wang 	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5887ab6734e7SLydia Wang 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5888ab6734e7SLydia Wang 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5889ab6734e7SLydia Wang 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5890ab6734e7SLydia Wang 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5891ab6734e7SLydia Wang 	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5892ab6734e7SLydia Wang 
5893ab6734e7SLydia Wang 	/* set MUX0/1/4/13/15 = 0 (AOW0) */
5894ab6734e7SLydia Wang 	{0x34, AC_VERB_SET_CONNECT_SEL, 0},
5895ab6734e7SLydia Wang 	{0x35, AC_VERB_SET_CONNECT_SEL, 0},
5896ab6734e7SLydia Wang 	{0x38, AC_VERB_SET_CONNECT_SEL, 0},
5897ab6734e7SLydia Wang 	{0x3c, AC_VERB_SET_CONNECT_SEL, 0},
5898ab6734e7SLydia Wang 	{0x3d, AC_VERB_SET_CONNECT_SEL, 0},
5899ab6734e7SLydia Wang 
5900ab6734e7SLydia Wang 	/* Enable AOW0 to MW9 */
5901ab6734e7SLydia Wang 	{0x1, 0xfb8, 0xa8},
5902ab6734e7SLydia Wang 	{ }
5903ab6734e7SLydia Wang };
5904ab6734e7SLydia Wang 
5905ab6734e7SLydia Wang 
590690dd48a1STakashi Iwai static const struct hda_verb vt1812_uniwill_init_verbs[] = {
5907ab6734e7SLydia Wang 	{0x33, AC_VERB_SET_UNSOLICITED_ENABLE,
5908ab6734e7SLydia Wang 	 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
5909ab6734e7SLydia Wang 	{0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT },
5910ab6734e7SLydia Wang 	{0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
5911ab6734e7SLydia Wang 	 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
5912ab6734e7SLydia Wang 	{0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5913ab6734e7SLydia Wang 	{0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5914ab6734e7SLydia Wang 	{0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5915ab6734e7SLydia Wang 	{ }
5916ab6734e7SLydia Wang };
5917ab6734e7SLydia Wang 
591890dd48a1STakashi Iwai static const struct hda_pcm_stream vt1812_pcm_analog_playback = {
5919ab6734e7SLydia Wang 	.substreams = 2,
5920ab6734e7SLydia Wang 	.channels_min = 2,
5921ab6734e7SLydia Wang 	.channels_max = 2,
5922ab6734e7SLydia Wang 	.nid = 0x8, /* NID to query formats and rates */
5923ab6734e7SLydia Wang 	.ops = {
5924ab6734e7SLydia Wang 		.open = via_playback_pcm_open,
5925ab6734e7SLydia Wang 		.prepare = via_playback_multi_pcm_prepare,
5926ab6734e7SLydia Wang 		.cleanup = via_playback_multi_pcm_cleanup,
5927ab6734e7SLydia Wang 		.close = via_pcm_open_close,
5928ab6734e7SLydia Wang 	},
5929ab6734e7SLydia Wang };
5930ab6734e7SLydia Wang 
593190dd48a1STakashi Iwai static const struct hda_pcm_stream vt1812_pcm_analog_capture = {
5932ab6734e7SLydia Wang 	.substreams = 2,
5933ab6734e7SLydia Wang 	.channels_min = 2,
5934ab6734e7SLydia Wang 	.channels_max = 2,
5935ab6734e7SLydia Wang 	.nid = 0x10, /* NID to query formats and rates */
5936ab6734e7SLydia Wang 	.ops = {
5937ab6734e7SLydia Wang 		.open = via_pcm_open_close,
5938ab6734e7SLydia Wang 		.prepare = via_capture_pcm_prepare,
5939ab6734e7SLydia Wang 		.cleanup = via_capture_pcm_cleanup,
5940ab6734e7SLydia Wang 		.close = via_pcm_open_close,
5941ab6734e7SLydia Wang 	},
5942ab6734e7SLydia Wang };
5943ab6734e7SLydia Wang 
594490dd48a1STakashi Iwai static const struct hda_pcm_stream vt1812_pcm_digital_playback = {
5945ab6734e7SLydia Wang 	.substreams = 1,
5946ab6734e7SLydia Wang 	.channels_min = 2,
5947ab6734e7SLydia Wang 	.channels_max = 2,
5948ab6734e7SLydia Wang 	/* NID is set in via_build_pcms */
5949ab6734e7SLydia Wang 	.ops = {
5950ab6734e7SLydia Wang 		.open = via_dig_playback_pcm_open,
5951ab6734e7SLydia Wang 		.close = via_dig_playback_pcm_close,
5952ab6734e7SLydia Wang 		.prepare = via_dig_playback_pcm_prepare,
5953ab6734e7SLydia Wang 		.cleanup = via_dig_playback_pcm_cleanup
5954ab6734e7SLydia Wang 	},
5955ab6734e7SLydia Wang };
5956ab6734e7SLydia Wang /* fill in the dac_nids table from the parsed pin configuration */
5957ab6734e7SLydia Wang static int vt1812_auto_fill_dac_nids(struct via_spec *spec,
5958ab6734e7SLydia Wang 				     const struct auto_pin_cfg *cfg)
5959ab6734e7SLydia Wang {
5960ab6734e7SLydia Wang 	spec->multiout.num_dacs = 1;
5961ab6734e7SLydia Wang 	spec->multiout.dac_nids = spec->private_dac_nids;
5962ab6734e7SLydia Wang 	if (cfg->line_out_pins[0])
5963dda14410STakashi Iwai 		spec->private_dac_nids[0] = 0x8;
5964ab6734e7SLydia Wang 	return 0;
5965ab6734e7SLydia Wang }
5966ab6734e7SLydia Wang 
5967ab6734e7SLydia Wang 
5968ab6734e7SLydia Wang /* add playback controls from the parsed DAC table */
5969ab6734e7SLydia Wang static int vt1812_auto_create_multi_out_ctls(struct via_spec *spec,
5970ab6734e7SLydia Wang 					     const struct auto_pin_cfg *cfg)
5971ab6734e7SLydia Wang {
5972ab6734e7SLydia Wang 	int err;
5973ab6734e7SLydia Wang 
5974ab6734e7SLydia Wang 	if (!cfg->line_out_pins[0])
5975ab6734e7SLydia Wang 		return -1;
5976ab6734e7SLydia Wang 
5977ab6734e7SLydia Wang 	/* Line-Out: PortE */
5978ab6734e7SLydia Wang 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
59793d83e577STakashi Iwai 			      "Front Playback Volume",
5980ab6734e7SLydia Wang 			      HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT));
5981ab6734e7SLydia Wang 	if (err < 0)
5982ab6734e7SLydia Wang 		return err;
5983ab6734e7SLydia Wang 	err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
59843d83e577STakashi Iwai 			      "Front Playback Switch",
5985ab6734e7SLydia Wang 			      HDA_COMPOSE_AMP_VAL(0x28, 3, 0, HDA_OUTPUT));
5986ab6734e7SLydia Wang 	if (err < 0)
5987ab6734e7SLydia Wang 		return err;
5988ab6734e7SLydia Wang 
5989ab6734e7SLydia Wang 	return 0;
5990ab6734e7SLydia Wang }
5991ab6734e7SLydia Wang 
5992ab6734e7SLydia Wang static int vt1812_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
5993ab6734e7SLydia Wang {
5994ab6734e7SLydia Wang 	int err;
5995ab6734e7SLydia Wang 
5996ab6734e7SLydia Wang 	if (!pin)
5997ab6734e7SLydia Wang 		return 0;
5998ab6734e7SLydia Wang 
5999ab6734e7SLydia Wang 	spec->multiout.hp_nid = 0x9;
6000ab6734e7SLydia Wang 	spec->hp_independent_mode_index = 1;
6001ab6734e7SLydia Wang 
6002ab6734e7SLydia Wang 
6003ab6734e7SLydia Wang 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
6004ab6734e7SLydia Wang 			      "Headphone Playback Volume",
6005ab6734e7SLydia Wang 			      HDA_COMPOSE_AMP_VAL(
6006ab6734e7SLydia Wang 				      spec->multiout.hp_nid, 3, 0, HDA_OUTPUT));
6007ab6734e7SLydia Wang 	if (err < 0)
6008ab6734e7SLydia Wang 		return err;
6009ab6734e7SLydia Wang 
6010ab6734e7SLydia Wang 	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
6011ab6734e7SLydia Wang 			      "Headphone Playback Switch",
6012ab6734e7SLydia Wang 			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
6013ab6734e7SLydia Wang 	if (err < 0)
6014ab6734e7SLydia Wang 		return err;
6015ab6734e7SLydia Wang 
6016ab6734e7SLydia Wang 	create_hp_imux(spec);
6017ab6734e7SLydia Wang 	return 0;
6018ab6734e7SLydia Wang }
6019ab6734e7SLydia Wang 
6020ab6734e7SLydia Wang /* create playback/capture controls for input pins */
602110a20af7STakashi Iwai static int vt1812_auto_create_analog_input_ctls(struct hda_codec *codec,
6022ab6734e7SLydia Wang 						const struct auto_pin_cfg *cfg)
6023ab6734e7SLydia Wang {
602410a20af7STakashi Iwai 	struct via_spec *spec = codec->spec;
6025ab6734e7SLydia Wang 	struct hda_input_mux *imux = &spec->private_imux[0];
602690dd48a1STakashi Iwai 	static const hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff };
6027f3268512STakashi Iwai 	int err;
6028ab6734e7SLydia Wang 
602910a20af7STakashi Iwai 	err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
6030f3268512STakashi Iwai 					       ARRAY_SIZE(pin_idxs));
6031ab6734e7SLydia Wang 	if (err < 0)
6032ab6734e7SLydia Wang 		return err;
6033f3268512STakashi Iwai 
6034ab6734e7SLydia Wang 	/* build volume/mute control of loopback */
60357b315bb4STakashi Iwai 	err = via_new_analog_input(spec, "Stereo Mixer", 0, 5, 0x21);
6036ab6734e7SLydia Wang 	if (err < 0)
6037ab6734e7SLydia Wang 		return err;
6038ab6734e7SLydia Wang 
6039ab6734e7SLydia Wang 	/* for digital mic select */
604010a20af7STakashi Iwai 	snd_hda_add_imux_item(imux, "Digital Mic", 6, NULL);
6041ab6734e7SLydia Wang 
6042ab6734e7SLydia Wang 	return 0;
6043ab6734e7SLydia Wang }
6044ab6734e7SLydia Wang 
6045ab6734e7SLydia Wang static int vt1812_parse_auto_config(struct hda_codec *codec)
6046ab6734e7SLydia Wang {
6047ab6734e7SLydia Wang 	struct via_spec *spec = codec->spec;
6048ab6734e7SLydia Wang 	int err;
6049ab6734e7SLydia Wang 
6050ab6734e7SLydia Wang 
6051ab6734e7SLydia Wang 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
6052ab6734e7SLydia Wang 	if (err < 0)
6053ab6734e7SLydia Wang 		return err;
6054ab6734e7SLydia Wang 	fill_dig_outs(codec);
6055ab6734e7SLydia Wang 	err = vt1812_auto_fill_dac_nids(spec, &spec->autocfg);
6056ab6734e7SLydia Wang 	if (err < 0)
6057ab6734e7SLydia Wang 		return err;
6058ab6734e7SLydia Wang 
6059ab6734e7SLydia Wang 	if (!spec->autocfg.line_outs && !spec->autocfg.hp_outs)
6060ab6734e7SLydia Wang 		return 0; /* can't find valid BIOS pin config */
6061ab6734e7SLydia Wang 
6062ab6734e7SLydia Wang 	err = vt1812_auto_create_multi_out_ctls(spec, &spec->autocfg);
6063ab6734e7SLydia Wang 	if (err < 0)
6064ab6734e7SLydia Wang 		return err;
6065ab6734e7SLydia Wang 	err = vt1812_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
6066ab6734e7SLydia Wang 	if (err < 0)
6067ab6734e7SLydia Wang 		return err;
606810a20af7STakashi Iwai 	err = vt1812_auto_create_analog_input_ctls(codec, &spec->autocfg);
6069ab6734e7SLydia Wang 	if (err < 0)
6070ab6734e7SLydia Wang 		return err;
6071ab6734e7SLydia Wang 
6072ab6734e7SLydia Wang 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
6073ab6734e7SLydia Wang 
6074ab6734e7SLydia Wang 	fill_dig_outs(codec);
6075ab6734e7SLydia Wang 
6076ab6734e7SLydia Wang 	if (spec->kctls.list)
6077ab6734e7SLydia Wang 		spec->mixers[spec->num_mixers++] = spec->kctls.list;
6078ab6734e7SLydia Wang 
6079ab6734e7SLydia Wang 	spec->input_mux = &spec->private_imux[0];
6080ab6734e7SLydia Wang 
6081ab6734e7SLydia Wang 	if (spec->hp_mux)
60823d83e577STakashi Iwai 		via_hp_build(codec);
6083ab6734e7SLydia Wang 
6084ab6734e7SLydia Wang 	return 1;
6085ab6734e7SLydia Wang }
6086ab6734e7SLydia Wang 
6087ab6734e7SLydia Wang #ifdef CONFIG_SND_HDA_POWER_SAVE
608890dd48a1STakashi Iwai static const struct hda_amp_list vt1812_loopbacks[] = {
6089ab6734e7SLydia Wang 	{ 0x21, HDA_INPUT, 0 },
6090ab6734e7SLydia Wang 	{ 0x21, HDA_INPUT, 1 },
6091ab6734e7SLydia Wang 	{ 0x21, HDA_INPUT, 2 },
6092ab6734e7SLydia Wang 	{ } /* end */
6093ab6734e7SLydia Wang };
6094ab6734e7SLydia Wang #endif
6095ab6734e7SLydia Wang 
60963e95b9abSLydia Wang static void set_widgets_power_state_vt1812(struct hda_codec *codec)
60973e95b9abSLydia Wang {
60983e95b9abSLydia Wang 	struct via_spec *spec = codec->spec;
60993e95b9abSLydia Wang 	int imux_is_smixer =
61003e95b9abSLydia Wang 	snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
61013e95b9abSLydia Wang 	unsigned int parm;
61023e95b9abSLydia Wang 	unsigned int present;
61033e95b9abSLydia Wang 	/* MUX10 (1eh) = stereo mixer */
61043e95b9abSLydia Wang 	imux_is_smixer =
61053e95b9abSLydia Wang 	snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
61063e95b9abSLydia Wang 	/* inputs */
61073e95b9abSLydia Wang 	/* PW 5/6/7 (29h/2ah/2bh) */
61083e95b9abSLydia Wang 	parm = AC_PWRST_D3;
61093e95b9abSLydia Wang 	set_pin_power_state(codec, 0x29, &parm);
61103e95b9abSLydia Wang 	set_pin_power_state(codec, 0x2a, &parm);
61113e95b9abSLydia Wang 	set_pin_power_state(codec, 0x2b, &parm);
61123e95b9abSLydia Wang 	parm = AC_PWRST_D0;
61133e95b9abSLydia Wang 	/* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */
61143e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm);
61153e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
61163e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
61173e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
61183e95b9abSLydia Wang 
61193e95b9abSLydia Wang 	/* outputs */
61203e95b9abSLydia Wang 	/* AOW0 (8h)*/
61213e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x8, 0,
61223e95b9abSLydia Wang 			    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
61233e95b9abSLydia Wang 
61243e95b9abSLydia Wang 	/* PW4 (28h), MW4 (18h), MUX4(38h) */
61253e95b9abSLydia Wang 	parm = AC_PWRST_D3;
61263e95b9abSLydia Wang 	set_pin_power_state(codec, 0x28, &parm);
61273e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm);
61283e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x38, 0, AC_VERB_SET_POWER_STATE, parm);
61293e95b9abSLydia Wang 
61303e95b9abSLydia Wang 	/* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
61313e95b9abSLydia Wang 	parm = AC_PWRST_D3;
61323e95b9abSLydia Wang 	set_pin_power_state(codec, 0x25, &parm);
61333e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_POWER_STATE, parm);
61343e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x35, 0, AC_VERB_SET_POWER_STATE, parm);
61353e95b9abSLydia Wang 	if (spec->hp_independent_mode)
61363e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x9, 0,
61373e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
61383e95b9abSLydia Wang 
61393e95b9abSLydia Wang 	/* Internal Speaker */
61403e95b9abSLydia Wang 	/* PW0 (24h), MW0(14h), MUX0(34h) */
61413e95b9abSLydia Wang 	present = snd_hda_jack_detect(codec, 0x25);
61423e95b9abSLydia Wang 
61433e95b9abSLydia Wang 	parm = AC_PWRST_D3;
61443e95b9abSLydia Wang 	set_pin_power_state(codec, 0x24, &parm);
61453e95b9abSLydia Wang 	if (present) {
61463e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x14, 0,
61473e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
61483e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x34, 0,
61493e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
61503e95b9abSLydia Wang 	} else {
61513e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x14, 0,
61523e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
61533e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x34, 0,
61543e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
61553e95b9abSLydia Wang 	}
61563e95b9abSLydia Wang 
61573e95b9abSLydia Wang 
61583e95b9abSLydia Wang 	/* Mono Out */
61593e95b9abSLydia Wang 	/* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */
61603e95b9abSLydia Wang 	present = snd_hda_jack_detect(codec, 0x28);
61613e95b9abSLydia Wang 
61623e95b9abSLydia Wang 	parm = AC_PWRST_D3;
61633e95b9abSLydia Wang 	set_pin_power_state(codec, 0x31, &parm);
61643e95b9abSLydia Wang 	if (present) {
61653e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x1c, 0,
61663e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
61673e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x3c, 0,
61683e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
61693e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x3e, 0,
61703e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
61713e95b9abSLydia Wang 	} else {
61723e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x1c, 0,
61733e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
61743e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x3c, 0,
61753e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
61763e95b9abSLydia Wang 		snd_hda_codec_write(codec, 0x3e, 0,
61773e95b9abSLydia Wang 				    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
61783e95b9abSLydia Wang 	}
61793e95b9abSLydia Wang 
61803e95b9abSLydia Wang 	/* PW15 (33h), MW15 (1dh), MUX15(3dh) */
61813e95b9abSLydia Wang 	parm = AC_PWRST_D3;
61823e95b9abSLydia Wang 	set_pin_power_state(codec, 0x33, &parm);
61833e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm);
61843e95b9abSLydia Wang 	snd_hda_codec_write(codec, 0x3d, 0, AC_VERB_SET_POWER_STATE, parm);
61853e95b9abSLydia Wang 
61863e95b9abSLydia Wang }
6187ab6734e7SLydia Wang 
6188ab6734e7SLydia Wang /* patch for vt1812 */
6189ab6734e7SLydia Wang static int patch_vt1812(struct hda_codec *codec)
6190ab6734e7SLydia Wang {
6191ab6734e7SLydia Wang 	struct via_spec *spec;
6192ab6734e7SLydia Wang 	int err;
6193ab6734e7SLydia Wang 
6194ab6734e7SLydia Wang 	/* create a codec specific record */
61955b0cb1d8SJaroslav Kysela 	spec = via_new_spec(codec);
6196ab6734e7SLydia Wang 	if (spec == NULL)
6197ab6734e7SLydia Wang 		return -ENOMEM;
6198ab6734e7SLydia Wang 
6199ab6734e7SLydia Wang 	/* automatic parse from the BIOS config */
6200ab6734e7SLydia Wang 	err = vt1812_parse_auto_config(codec);
6201ab6734e7SLydia Wang 	if (err < 0) {
6202ab6734e7SLydia Wang 		via_free(codec);
6203ab6734e7SLydia Wang 		return err;
6204ab6734e7SLydia Wang 	} else if (!err) {
6205ab6734e7SLydia Wang 		printk(KERN_INFO "hda_codec: Cannot set up configuration "
6206ab6734e7SLydia Wang 		       "from BIOS.  Using genenic mode...\n");
6207ab6734e7SLydia Wang 	}
6208ab6734e7SLydia Wang 
6209ab6734e7SLydia Wang 
6210ab6734e7SLydia Wang 	spec->init_verbs[spec->num_iverbs++]  = vt1812_volume_init_verbs;
6211ab6734e7SLydia Wang 	spec->init_verbs[spec->num_iverbs++] = vt1812_uniwill_init_verbs;
6212ab6734e7SLydia Wang 
6213ab6734e7SLydia Wang 	spec->stream_name_analog = "VT1812 Analog";
6214ab6734e7SLydia Wang 	spec->stream_analog_playback = &vt1812_pcm_analog_playback;
6215ab6734e7SLydia Wang 	spec->stream_analog_capture = &vt1812_pcm_analog_capture;
6216ab6734e7SLydia Wang 
6217ab6734e7SLydia Wang 	spec->stream_name_digital = "VT1812 Digital";
6218ab6734e7SLydia Wang 	spec->stream_digital_playback = &vt1812_pcm_digital_playback;
6219ab6734e7SLydia Wang 
6220ab6734e7SLydia Wang 
6221ab6734e7SLydia Wang 	if (!spec->adc_nids && spec->input_mux) {
6222ab6734e7SLydia Wang 		spec->adc_nids = vt1812_adc_nids;
6223ab6734e7SLydia Wang 		spec->num_adc_nids = ARRAY_SIZE(vt1812_adc_nids);
6224ab6734e7SLydia Wang 		get_mux_nids(codec);
6225ab6734e7SLydia Wang 		override_mic_boost(codec, 0x2b, 0, 3, 40);
6226ab6734e7SLydia Wang 		override_mic_boost(codec, 0x29, 0, 3, 40);
6227ab6734e7SLydia Wang 		spec->mixers[spec->num_mixers] = vt1812_capture_mixer;
6228ab6734e7SLydia Wang 		spec->num_mixers++;
6229ab6734e7SLydia Wang 	}
6230ab6734e7SLydia Wang 
6231ab6734e7SLydia Wang 	codec->patch_ops = via_patch_ops;
6232ab6734e7SLydia Wang 
6233ab6734e7SLydia Wang 	codec->patch_ops.init = via_auto_init;
62340f48327eSStephen Rothwell 	codec->patch_ops.unsol_event = via_unsol_event;
6235ab6734e7SLydia Wang 
6236ab6734e7SLydia Wang #ifdef CONFIG_SND_HDA_POWER_SAVE
6237ab6734e7SLydia Wang 	spec->loopback.amplist = vt1812_loopbacks;
6238ab6734e7SLydia Wang #endif
6239ab6734e7SLydia Wang 
62403e95b9abSLydia Wang 	spec->set_widgets_power_state =  set_widgets_power_state_vt1812;
6241ab6734e7SLydia Wang 	return 0;
6242ab6734e7SLydia Wang }
6243ab6734e7SLydia Wang 
6244c577b8a1SJoseph Chan /*
6245c577b8a1SJoseph Chan  * patch entries
6246c577b8a1SJoseph Chan  */
624790dd48a1STakashi Iwai static const struct hda_codec_preset snd_hda_preset_via[] = {
62483218c178STakashi Iwai 	{ .id = 0x11061708, .name = "VT1708", .patch = patch_vt1708},
62493218c178STakashi Iwai 	{ .id = 0x11061709, .name = "VT1708", .patch = patch_vt1708},
62503218c178STakashi Iwai 	{ .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708},
62513218c178STakashi Iwai 	{ .id = 0x1106170b, .name = "VT1708", .patch = patch_vt1708},
62523218c178STakashi Iwai 	{ .id = 0x1106e710, .name = "VT1709 10-Ch",
6253f7278fd0SJosepch Chan 	  .patch = patch_vt1709_10ch},
62543218c178STakashi Iwai 	{ .id = 0x1106e711, .name = "VT1709 10-Ch",
6255f7278fd0SJosepch Chan 	  .patch = patch_vt1709_10ch},
62563218c178STakashi Iwai 	{ .id = 0x1106e712, .name = "VT1709 10-Ch",
6257f7278fd0SJosepch Chan 	  .patch = patch_vt1709_10ch},
62583218c178STakashi Iwai 	{ .id = 0x1106e713, .name = "VT1709 10-Ch",
6259f7278fd0SJosepch Chan 	  .patch = patch_vt1709_10ch},
62603218c178STakashi Iwai 	{ .id = 0x1106e714, .name = "VT1709 6-Ch",
6261f7278fd0SJosepch Chan 	  .patch = patch_vt1709_6ch},
62623218c178STakashi Iwai 	{ .id = 0x1106e715, .name = "VT1709 6-Ch",
6263f7278fd0SJosepch Chan 	  .patch = patch_vt1709_6ch},
62643218c178STakashi Iwai 	{ .id = 0x1106e716, .name = "VT1709 6-Ch",
6265f7278fd0SJosepch Chan 	  .patch = patch_vt1709_6ch},
62663218c178STakashi Iwai 	{ .id = 0x1106e717, .name = "VT1709 6-Ch",
6267f7278fd0SJosepch Chan 	  .patch = patch_vt1709_6ch},
62683218c178STakashi Iwai 	{ .id = 0x1106e720, .name = "VT1708B 8-Ch",
6269f7278fd0SJosepch Chan 	  .patch = patch_vt1708B_8ch},
62703218c178STakashi Iwai 	{ .id = 0x1106e721, .name = "VT1708B 8-Ch",
6271f7278fd0SJosepch Chan 	  .patch = patch_vt1708B_8ch},
62723218c178STakashi Iwai 	{ .id = 0x1106e722, .name = "VT1708B 8-Ch",
6273f7278fd0SJosepch Chan 	  .patch = patch_vt1708B_8ch},
62743218c178STakashi Iwai 	{ .id = 0x1106e723, .name = "VT1708B 8-Ch",
6275f7278fd0SJosepch Chan 	  .patch = patch_vt1708B_8ch},
62763218c178STakashi Iwai 	{ .id = 0x1106e724, .name = "VT1708B 4-Ch",
6277f7278fd0SJosepch Chan 	  .patch = patch_vt1708B_4ch},
62783218c178STakashi Iwai 	{ .id = 0x1106e725, .name = "VT1708B 4-Ch",
6279f7278fd0SJosepch Chan 	  .patch = patch_vt1708B_4ch},
62803218c178STakashi Iwai 	{ .id = 0x1106e726, .name = "VT1708B 4-Ch",
6281f7278fd0SJosepch Chan 	  .patch = patch_vt1708B_4ch},
62823218c178STakashi Iwai 	{ .id = 0x1106e727, .name = "VT1708B 4-Ch",
6283f7278fd0SJosepch Chan 	  .patch = patch_vt1708B_4ch},
62843218c178STakashi Iwai 	{ .id = 0x11060397, .name = "VT1708S",
6285d949cac1SHarald Welte 	  .patch = patch_vt1708S},
62863218c178STakashi Iwai 	{ .id = 0x11061397, .name = "VT1708S",
6287d949cac1SHarald Welte 	  .patch = patch_vt1708S},
62883218c178STakashi Iwai 	{ .id = 0x11062397, .name = "VT1708S",
6289d949cac1SHarald Welte 	  .patch = patch_vt1708S},
62903218c178STakashi Iwai 	{ .id = 0x11063397, .name = "VT1708S",
6291d949cac1SHarald Welte 	  .patch = patch_vt1708S},
6292bc92df7fSLydia Wang 	{ .id = 0x11064397, .name = "VT1705",
6293d949cac1SHarald Welte 	  .patch = patch_vt1708S},
62943218c178STakashi Iwai 	{ .id = 0x11065397, .name = "VT1708S",
6295d949cac1SHarald Welte 	  .patch = patch_vt1708S},
62963218c178STakashi Iwai 	{ .id = 0x11066397, .name = "VT1708S",
6297d949cac1SHarald Welte 	  .patch = patch_vt1708S},
62983218c178STakashi Iwai 	{ .id = 0x11067397, .name = "VT1708S",
6299d949cac1SHarald Welte 	  .patch = patch_vt1708S},
63003218c178STakashi Iwai 	{ .id = 0x11060398, .name = "VT1702",
6301d949cac1SHarald Welte 	  .patch = patch_vt1702},
63023218c178STakashi Iwai 	{ .id = 0x11061398, .name = "VT1702",
6303d949cac1SHarald Welte 	  .patch = patch_vt1702},
63043218c178STakashi Iwai 	{ .id = 0x11062398, .name = "VT1702",
6305d949cac1SHarald Welte 	  .patch = patch_vt1702},
63063218c178STakashi Iwai 	{ .id = 0x11063398, .name = "VT1702",
6307d949cac1SHarald Welte 	  .patch = patch_vt1702},
63083218c178STakashi Iwai 	{ .id = 0x11064398, .name = "VT1702",
6309d949cac1SHarald Welte 	  .patch = patch_vt1702},
63103218c178STakashi Iwai 	{ .id = 0x11065398, .name = "VT1702",
6311d949cac1SHarald Welte 	  .patch = patch_vt1702},
63123218c178STakashi Iwai 	{ .id = 0x11066398, .name = "VT1702",
6313d949cac1SHarald Welte 	  .patch = patch_vt1702},
63143218c178STakashi Iwai 	{ .id = 0x11067398, .name = "VT1702",
6315d949cac1SHarald Welte 	  .patch = patch_vt1702},
6316eb7188caSLydia Wang 	{ .id = 0x11060428, .name = "VT1718S",
6317eb7188caSLydia Wang 	  .patch = patch_vt1718S},
6318eb7188caSLydia Wang 	{ .id = 0x11064428, .name = "VT1718S",
6319eb7188caSLydia Wang 	  .patch = patch_vt1718S},
6320bb3c6bfcSLydia Wang 	{ .id = 0x11060441, .name = "VT2020",
6321bb3c6bfcSLydia Wang 	  .patch = patch_vt1718S},
6322bb3c6bfcSLydia Wang 	{ .id = 0x11064441, .name = "VT1828S",
6323bb3c6bfcSLydia Wang 	  .patch = patch_vt1718S},
6324f3db423dSLydia Wang 	{ .id = 0x11060433, .name = "VT1716S",
6325f3db423dSLydia Wang 	  .patch = patch_vt1716S},
6326f3db423dSLydia Wang 	{ .id = 0x1106a721, .name = "VT1716S",
6327f3db423dSLydia Wang 	  .patch = patch_vt1716S},
632825eaba2fSLydia Wang 	{ .id = 0x11060438, .name = "VT2002P", .patch = patch_vt2002P},
632925eaba2fSLydia Wang 	{ .id = 0x11064438, .name = "VT2002P", .patch = patch_vt2002P},
6330ab6734e7SLydia Wang 	{ .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812},
633136dd5c4aSLydia Wang 	{ .id = 0x11060440, .name = "VT1818S",
633236dd5c4aSLydia Wang 	  .patch = patch_vt1708S},
633311890956SLydia Wang 	{ .id = 0x11060446, .name = "VT1802",
633411890956SLydia Wang 		.patch = patch_vt2002P},
633511890956SLydia Wang 	{ .id = 0x11068446, .name = "VT1802",
633611890956SLydia Wang 		.patch = patch_vt2002P},
6337c577b8a1SJoseph Chan 	{} /* terminator */
6338c577b8a1SJoseph Chan };
63391289e9e8STakashi Iwai 
63401289e9e8STakashi Iwai MODULE_ALIAS("snd-hda-codec-id:1106*");
63411289e9e8STakashi Iwai 
63421289e9e8STakashi Iwai static struct hda_codec_preset_list via_list = {
63431289e9e8STakashi Iwai 	.preset = snd_hda_preset_via,
63441289e9e8STakashi Iwai 	.owner = THIS_MODULE,
63451289e9e8STakashi Iwai };
63461289e9e8STakashi Iwai 
63471289e9e8STakashi Iwai MODULE_LICENSE("GPL");
63481289e9e8STakashi Iwai MODULE_DESCRIPTION("VIA HD-audio codec");
63491289e9e8STakashi Iwai 
63501289e9e8STakashi Iwai static int __init patch_via_init(void)
63511289e9e8STakashi Iwai {
63521289e9e8STakashi Iwai 	return snd_hda_add_codec_preset(&via_list);
63531289e9e8STakashi Iwai }
63541289e9e8STakashi Iwai 
63551289e9e8STakashi Iwai static void __exit patch_via_exit(void)
63561289e9e8STakashi Iwai {
63571289e9e8STakashi Iwai 	snd_hda_delete_codec_preset(&via_list);
63581289e9e8STakashi Iwai }
63591289e9e8STakashi Iwai 
63601289e9e8STakashi Iwai module_init(patch_via_init)
63611289e9e8STakashi Iwai module_exit(patch_via_exit)
6362