xref: /openbmc/linux/sound/pci/hda/patch_via.c (revision c577b8a16fd19a33a8865ca6451287d284a0faf6)
1*c577b8a1SJoseph Chan /*
2*c577b8a1SJoseph Chan  * Universal Interface for Intel High Definition Audio Codec
3*c577b8a1SJoseph Chan  *
4*c577b8a1SJoseph Chan  * HD audio interface patch for VIA VT1708 codec
5*c577b8a1SJoseph Chan  *
6*c577b8a1SJoseph Chan  * Copyright (c) 2006 Lydia Wang <lydiawang@viatech.com>
7*c577b8a1SJoseph Chan  *                    Takashi Iwai <tiwai@suse.de>
8*c577b8a1SJoseph Chan  *
9*c577b8a1SJoseph Chan  *  This driver is free software; you can redistribute it and/or modify
10*c577b8a1SJoseph Chan  *  it under the terms of the GNU General Public License as published by
11*c577b8a1SJoseph Chan  *  the Free Software Foundation; either version 2 of the License, or
12*c577b8a1SJoseph Chan  *  (at your option) any later version.
13*c577b8a1SJoseph Chan  *
14*c577b8a1SJoseph Chan  *  This driver is distributed in the hope that it will be useful,
15*c577b8a1SJoseph Chan  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16*c577b8a1SJoseph Chan  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17*c577b8a1SJoseph Chan  *  GNU General Public License for more details.
18*c577b8a1SJoseph Chan  *
19*c577b8a1SJoseph Chan  *  You should have received a copy of the GNU General Public License
20*c577b8a1SJoseph Chan  *  along with this program; if not, write to the Free Software
21*c577b8a1SJoseph Chan  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
22*c577b8a1SJoseph Chan  */
23*c577b8a1SJoseph Chan 
24*c577b8a1SJoseph Chan /* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */
25*c577b8a1SJoseph Chan /*                                                                           */
26*c577b8a1SJoseph Chan /* 2006-03-03  Lydia Wang  Create the basic patch to support VT1708 codec    */
27*c577b8a1SJoseph Chan /* 2006-03-14  Lydia Wang  Modify hard code for some pin widget nid          */
28*c577b8a1SJoseph Chan /* 2006-08-02  Lydia Wang  Add support to VT1709 codec                       */
29*c577b8a1SJoseph Chan /* 2006-09-08  Lydia Wang  Fix internal loopback recording source select bug */
30*c577b8a1SJoseph Chan /*                                                                           */
31*c577b8a1SJoseph Chan /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
32*c577b8a1SJoseph Chan 
33*c577b8a1SJoseph Chan 
34*c577b8a1SJoseph Chan #include <sound/driver.h>
35*c577b8a1SJoseph Chan #include <linux/init.h>
36*c577b8a1SJoseph Chan #include <linux/delay.h>
37*c577b8a1SJoseph Chan #include <linux/slab.h>
38*c577b8a1SJoseph Chan #include <linux/pci.h>
39*c577b8a1SJoseph Chan #include <sound/core.h>
40*c577b8a1SJoseph Chan #include "hda_codec.h"
41*c577b8a1SJoseph Chan #include "hda_local.h"
42*c577b8a1SJoseph Chan 
43*c577b8a1SJoseph Chan 
44*c577b8a1SJoseph Chan /* amp values */
45*c577b8a1SJoseph Chan #define AMP_VAL_IDX_SHIFT	19
46*c577b8a1SJoseph Chan #define AMP_VAL_IDX_MASK	(0x0f<<19)
47*c577b8a1SJoseph Chan 
48*c577b8a1SJoseph Chan #define NUM_CONTROL_ALLOC	32
49*c577b8a1SJoseph Chan #define NUM_VERB_ALLOC		32
50*c577b8a1SJoseph Chan 
51*c577b8a1SJoseph Chan /* Pin Widget NID */
52*c577b8a1SJoseph Chan #define VT1708_HP_NID		0x13
53*c577b8a1SJoseph Chan #define VT1708_DIGOUT_NID	0x14
54*c577b8a1SJoseph Chan #define VT1708_DIGIN_NID	0x16
55*c577b8a1SJoseph Chan 
56*c577b8a1SJoseph Chan #define VT1709_HP_DAC_NID	0x28
57*c577b8a1SJoseph Chan #define VT1709_DIGOUT_NID	0x13
58*c577b8a1SJoseph Chan #define VT1709_DIGIN_NID	0x17
59*c577b8a1SJoseph Chan 
60*c577b8a1SJoseph Chan #define IS_VT1708_VENDORID(x)		((x) >= 0x11061708 && (x) <= 0x1106170b)
61*c577b8a1SJoseph Chan #define IS_VT1709_10CH_VENDORID(x)	((x) >= 0x1106e710 && (x) <= 0x1106e713)
62*c577b8a1SJoseph Chan #define IS_VT1709_6CH_VENDORID(x)	((x) >= 0x1106e714 && (x) <= 0x1106e717)
63*c577b8a1SJoseph Chan 
64*c577b8a1SJoseph Chan 
65*c577b8a1SJoseph Chan enum {
66*c577b8a1SJoseph Chan 	VIA_CTL_WIDGET_VOL,
67*c577b8a1SJoseph Chan 	VIA_CTL_WIDGET_MUTE,
68*c577b8a1SJoseph Chan };
69*c577b8a1SJoseph Chan 
70*c577b8a1SJoseph Chan enum {
71*c577b8a1SJoseph Chan 	AUTO_SEQ_FRONT,
72*c577b8a1SJoseph Chan 	AUTO_SEQ_SURROUND,
73*c577b8a1SJoseph Chan 	AUTO_SEQ_CENLFE,
74*c577b8a1SJoseph Chan 	AUTO_SEQ_SIDE
75*c577b8a1SJoseph Chan };
76*c577b8a1SJoseph Chan 
77*c577b8a1SJoseph Chan static struct snd_kcontrol_new vt1708_control_templates[] = {
78*c577b8a1SJoseph Chan 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
79*c577b8a1SJoseph Chan 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
80*c577b8a1SJoseph Chan };
81*c577b8a1SJoseph Chan 
82*c577b8a1SJoseph Chan 
83*c577b8a1SJoseph Chan struct via_spec {
84*c577b8a1SJoseph Chan 	/* codec parameterization */
85*c577b8a1SJoseph Chan 	struct snd_kcontrol_new *mixers[3];
86*c577b8a1SJoseph Chan 	unsigned int num_mixers;
87*c577b8a1SJoseph Chan 
88*c577b8a1SJoseph Chan 	struct hda_verb *init_verbs;
89*c577b8a1SJoseph Chan 
90*c577b8a1SJoseph Chan 	char *stream_name_analog;
91*c577b8a1SJoseph Chan 	struct hda_pcm_stream *stream_analog_playback;
92*c577b8a1SJoseph Chan 	struct hda_pcm_stream *stream_analog_capture;
93*c577b8a1SJoseph Chan 
94*c577b8a1SJoseph Chan 	char *stream_name_digital;
95*c577b8a1SJoseph Chan 	struct hda_pcm_stream *stream_digital_playback;
96*c577b8a1SJoseph Chan 	struct hda_pcm_stream *stream_digital_capture;
97*c577b8a1SJoseph Chan 
98*c577b8a1SJoseph Chan 	/* playback */
99*c577b8a1SJoseph Chan 	struct hda_multi_out multiout;
100*c577b8a1SJoseph Chan 
101*c577b8a1SJoseph Chan 	/* capture */
102*c577b8a1SJoseph Chan 	unsigned int num_adc_nids;
103*c577b8a1SJoseph Chan 	hda_nid_t *adc_nids;
104*c577b8a1SJoseph Chan 	hda_nid_t dig_in_nid;
105*c577b8a1SJoseph Chan 
106*c577b8a1SJoseph Chan 	/* capture source */
107*c577b8a1SJoseph Chan 	const struct hda_input_mux *input_mux;
108*c577b8a1SJoseph Chan 	unsigned int cur_mux[3];
109*c577b8a1SJoseph Chan 
110*c577b8a1SJoseph Chan 	/* PCM information */
111*c577b8a1SJoseph Chan 	struct hda_pcm pcm_rec[2];
112*c577b8a1SJoseph Chan 
113*c577b8a1SJoseph Chan 	/* dynamic controls, init_verbs and input_mux */
114*c577b8a1SJoseph Chan 	struct auto_pin_cfg autocfg;
115*c577b8a1SJoseph Chan 	unsigned int num_kctl_alloc, num_kctl_used;
116*c577b8a1SJoseph Chan 	struct snd_kcontrol_new *kctl_alloc;
117*c577b8a1SJoseph Chan 	struct hda_input_mux private_imux;
118*c577b8a1SJoseph Chan 	hda_nid_t private_dac_nids[4];
119*c577b8a1SJoseph Chan };
120*c577b8a1SJoseph Chan 
121*c577b8a1SJoseph Chan static hda_nid_t vt1708_adc_nids[2] = {
122*c577b8a1SJoseph Chan 	/* ADC1-2 */
123*c577b8a1SJoseph Chan 	0x15, 0x27
124*c577b8a1SJoseph Chan };
125*c577b8a1SJoseph Chan 
126*c577b8a1SJoseph Chan static hda_nid_t vt1709_adc_nids[3] = {
127*c577b8a1SJoseph Chan 	/* ADC1-2 */
128*c577b8a1SJoseph Chan 	0x14, 0x15, 0x16
129*c577b8a1SJoseph Chan };
130*c577b8a1SJoseph Chan 
131*c577b8a1SJoseph Chan /* add dynamic controls */
132*c577b8a1SJoseph Chan static int via_add_control(struct via_spec *spec, int type, const char *name,
133*c577b8a1SJoseph Chan 			   unsigned long val)
134*c577b8a1SJoseph Chan {
135*c577b8a1SJoseph Chan 	struct snd_kcontrol_new *knew;
136*c577b8a1SJoseph Chan 
137*c577b8a1SJoseph Chan 	if (spec->num_kctl_used >= spec->num_kctl_alloc) {
138*c577b8a1SJoseph Chan 		int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
139*c577b8a1SJoseph Chan 
140*c577b8a1SJoseph Chan 		/* array + terminator */
141*c577b8a1SJoseph Chan 		knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
142*c577b8a1SJoseph Chan 		if (!knew)
143*c577b8a1SJoseph Chan 			return -ENOMEM;
144*c577b8a1SJoseph Chan 		if (spec->kctl_alloc) {
145*c577b8a1SJoseph Chan 			memcpy(knew, spec->kctl_alloc,
146*c577b8a1SJoseph Chan 			       sizeof(*knew) * spec->num_kctl_alloc);
147*c577b8a1SJoseph Chan 			kfree(spec->kctl_alloc);
148*c577b8a1SJoseph Chan 		}
149*c577b8a1SJoseph Chan 		spec->kctl_alloc = knew;
150*c577b8a1SJoseph Chan 		spec->num_kctl_alloc = num;
151*c577b8a1SJoseph Chan 	}
152*c577b8a1SJoseph Chan 
153*c577b8a1SJoseph Chan 	knew = &spec->kctl_alloc[spec->num_kctl_used];
154*c577b8a1SJoseph Chan 	*knew = vt1708_control_templates[type];
155*c577b8a1SJoseph Chan 	knew->name = kstrdup(name, GFP_KERNEL);
156*c577b8a1SJoseph Chan 
157*c577b8a1SJoseph Chan 	if (!knew->name)
158*c577b8a1SJoseph Chan 		return -ENOMEM;
159*c577b8a1SJoseph Chan 	knew->private_value = val;
160*c577b8a1SJoseph Chan 	spec->num_kctl_used++;
161*c577b8a1SJoseph Chan 	return 0;
162*c577b8a1SJoseph Chan }
163*c577b8a1SJoseph Chan 
164*c577b8a1SJoseph Chan /* create input playback/capture controls for the given pin */
165*c577b8a1SJoseph Chan static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
166*c577b8a1SJoseph Chan 				const char *ctlname, int idx, int mix_nid)
167*c577b8a1SJoseph Chan {
168*c577b8a1SJoseph Chan 	char name[32];
169*c577b8a1SJoseph Chan 	int err;
170*c577b8a1SJoseph Chan 
171*c577b8a1SJoseph Chan 	sprintf(name, "%s Playback Volume", ctlname);
172*c577b8a1SJoseph Chan 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
173*c577b8a1SJoseph Chan 			      HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
174*c577b8a1SJoseph Chan 	if (err < 0)
175*c577b8a1SJoseph Chan 		return err;
176*c577b8a1SJoseph Chan 	sprintf(name, "%s Playback Switch", ctlname);
177*c577b8a1SJoseph Chan 	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
178*c577b8a1SJoseph Chan 			      HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
179*c577b8a1SJoseph Chan 	if (err < 0)
180*c577b8a1SJoseph Chan 		return err;
181*c577b8a1SJoseph Chan 	return 0;
182*c577b8a1SJoseph Chan }
183*c577b8a1SJoseph Chan 
184*c577b8a1SJoseph Chan static void via_auto_set_output_and_unmute(struct hda_codec *codec,
185*c577b8a1SJoseph Chan 					   hda_nid_t nid, int pin_type,
186*c577b8a1SJoseph Chan 					   int dac_idx)
187*c577b8a1SJoseph Chan {
188*c577b8a1SJoseph Chan 	/* set as output */
189*c577b8a1SJoseph Chan 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
190*c577b8a1SJoseph Chan 			    pin_type);
191*c577b8a1SJoseph Chan 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
192*c577b8a1SJoseph Chan 			    AMP_OUT_UNMUTE);
193*c577b8a1SJoseph Chan }
194*c577b8a1SJoseph Chan 
195*c577b8a1SJoseph Chan 
196*c577b8a1SJoseph Chan static void via_auto_init_multi_out(struct hda_codec *codec)
197*c577b8a1SJoseph Chan {
198*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
199*c577b8a1SJoseph Chan 	int i;
200*c577b8a1SJoseph Chan 
201*c577b8a1SJoseph Chan 	for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
202*c577b8a1SJoseph Chan 		hda_nid_t nid = spec->autocfg.line_out_pins[i];
203*c577b8a1SJoseph Chan 		if (nid)
204*c577b8a1SJoseph Chan 			via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
205*c577b8a1SJoseph Chan 	}
206*c577b8a1SJoseph Chan }
207*c577b8a1SJoseph Chan 
208*c577b8a1SJoseph Chan static void via_auto_init_hp_out(struct hda_codec *codec)
209*c577b8a1SJoseph Chan {
210*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
211*c577b8a1SJoseph Chan 	hda_nid_t pin;
212*c577b8a1SJoseph Chan 
213*c577b8a1SJoseph Chan 	pin = spec->autocfg.hp_pins[0];
214*c577b8a1SJoseph Chan 	if (pin) /* connect to front */
215*c577b8a1SJoseph Chan 		via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
216*c577b8a1SJoseph Chan }
217*c577b8a1SJoseph Chan 
218*c577b8a1SJoseph Chan static void via_auto_init_analog_input(struct hda_codec *codec)
219*c577b8a1SJoseph Chan {
220*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
221*c577b8a1SJoseph Chan 	int i;
222*c577b8a1SJoseph Chan 
223*c577b8a1SJoseph Chan 	for (i = 0; i < AUTO_PIN_LAST; i++) {
224*c577b8a1SJoseph Chan 		hda_nid_t nid = spec->autocfg.input_pins[i];
225*c577b8a1SJoseph Chan 
226*c577b8a1SJoseph Chan 		snd_hda_codec_write(codec, nid, 0,
227*c577b8a1SJoseph Chan 				    AC_VERB_SET_PIN_WIDGET_CONTROL,
228*c577b8a1SJoseph Chan 				    (i <= AUTO_PIN_FRONT_MIC ?
229*c577b8a1SJoseph Chan 				     PIN_VREF50 : PIN_IN));
230*c577b8a1SJoseph Chan 
231*c577b8a1SJoseph Chan 	}
232*c577b8a1SJoseph Chan }
233*c577b8a1SJoseph Chan /*
234*c577b8a1SJoseph Chan  * input MUX handling
235*c577b8a1SJoseph Chan  */
236*c577b8a1SJoseph Chan static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
237*c577b8a1SJoseph Chan 			     struct snd_ctl_elem_info *uinfo)
238*c577b8a1SJoseph Chan {
239*c577b8a1SJoseph Chan 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
240*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
241*c577b8a1SJoseph Chan 	return snd_hda_input_mux_info(spec->input_mux, uinfo);
242*c577b8a1SJoseph Chan }
243*c577b8a1SJoseph Chan 
244*c577b8a1SJoseph Chan static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
245*c577b8a1SJoseph Chan 			    struct snd_ctl_elem_value *ucontrol)
246*c577b8a1SJoseph Chan {
247*c577b8a1SJoseph Chan 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
248*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
249*c577b8a1SJoseph Chan 	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
250*c577b8a1SJoseph Chan 
251*c577b8a1SJoseph Chan 	ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
252*c577b8a1SJoseph Chan 	return 0;
253*c577b8a1SJoseph Chan }
254*c577b8a1SJoseph Chan 
255*c577b8a1SJoseph Chan static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
256*c577b8a1SJoseph Chan 			    struct snd_ctl_elem_value *ucontrol)
257*c577b8a1SJoseph Chan {
258*c577b8a1SJoseph Chan 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
259*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
260*c577b8a1SJoseph Chan 	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
261*c577b8a1SJoseph Chan 	unsigned int vendor_id = codec->vendor_id;
262*c577b8a1SJoseph Chan 
263*c577b8a1SJoseph Chan 	/* AIW0  lydia 060801 add for correct sw0 input select */
264*c577b8a1SJoseph Chan 	if (IS_VT1708_VENDORID(vendor_id) && (adc_idx == 0))
265*c577b8a1SJoseph Chan 		return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
266*c577b8a1SJoseph Chan 					     0x18, &spec->cur_mux[adc_idx]);
267*c577b8a1SJoseph Chan 	else if ((IS_VT1709_10CH_VENDORID(vendor_id) ||
268*c577b8a1SJoseph Chan 		  IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0) )
269*c577b8a1SJoseph Chan 		return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
270*c577b8a1SJoseph Chan 					     0x19, &spec->cur_mux[adc_idx]);
271*c577b8a1SJoseph Chan 	else
272*c577b8a1SJoseph Chan 		return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
273*c577b8a1SJoseph Chan 					     spec->adc_nids[adc_idx],
274*c577b8a1SJoseph Chan 					     &spec->cur_mux[adc_idx]);
275*c577b8a1SJoseph Chan }
276*c577b8a1SJoseph Chan 
277*c577b8a1SJoseph Chan /* capture mixer elements */
278*c577b8a1SJoseph Chan static struct snd_kcontrol_new vt1708_capture_mixer[] = {
279*c577b8a1SJoseph Chan 	HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
280*c577b8a1SJoseph Chan 	HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
281*c577b8a1SJoseph Chan 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
282*c577b8a1SJoseph Chan 	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
283*c577b8a1SJoseph Chan 	{
284*c577b8a1SJoseph Chan 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
285*c577b8a1SJoseph Chan 		/* The multiple "Capture Source" controls confuse alsamixer
286*c577b8a1SJoseph Chan 		 * So call somewhat different..
287*c577b8a1SJoseph Chan 		 * FIXME: the controls appear in the "playback" view!
288*c577b8a1SJoseph Chan 		 */
289*c577b8a1SJoseph Chan 		/* .name = "Capture Source", */
290*c577b8a1SJoseph Chan 		.name = "Input Source",
291*c577b8a1SJoseph Chan 		.count = 1,
292*c577b8a1SJoseph Chan 		.info = via_mux_enum_info,
293*c577b8a1SJoseph Chan 		.get = via_mux_enum_get,
294*c577b8a1SJoseph Chan 		.put = via_mux_enum_put,
295*c577b8a1SJoseph Chan 	},
296*c577b8a1SJoseph Chan 	{ } /* end */
297*c577b8a1SJoseph Chan };
298*c577b8a1SJoseph Chan /*
299*c577b8a1SJoseph Chan  * generic initialization of ADC, input mixers and output mixers
300*c577b8a1SJoseph Chan  */
301*c577b8a1SJoseph Chan static struct hda_verb vt1708_volume_init_verbs[] = {
302*c577b8a1SJoseph Chan 	/*
303*c577b8a1SJoseph Chan 	 * Unmute ADC0-1 and set the default input to mic-in
304*c577b8a1SJoseph Chan 	 */
305*c577b8a1SJoseph Chan 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
306*c577b8a1SJoseph Chan 	{0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
307*c577b8a1SJoseph Chan 
308*c577b8a1SJoseph Chan 
309*c577b8a1SJoseph Chan 	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
310*c577b8a1SJoseph Chan 	 * mixer widget
311*c577b8a1SJoseph Chan 	 */
312*c577b8a1SJoseph Chan 	/* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
313*c577b8a1SJoseph Chan 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
314*c577b8a1SJoseph Chan 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
315*c577b8a1SJoseph Chan 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
316*c577b8a1SJoseph Chan 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
317*c577b8a1SJoseph Chan 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
318*c577b8a1SJoseph Chan 
319*c577b8a1SJoseph Chan 	/*
320*c577b8a1SJoseph Chan 	 * Set up output mixers (0x19 - 0x1b)
321*c577b8a1SJoseph Chan 	 */
322*c577b8a1SJoseph Chan 	/* set vol=0 to output mixers */
323*c577b8a1SJoseph Chan 	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
324*c577b8a1SJoseph Chan 	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
325*c577b8a1SJoseph Chan 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
326*c577b8a1SJoseph Chan 
327*c577b8a1SJoseph Chan 	/* Setup default input to PW4 */
328*c577b8a1SJoseph Chan 	{0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
329*c577b8a1SJoseph Chan 	/* Set mic as default input of sw0 */
330*c577b8a1SJoseph Chan 	{0x18, AC_VERB_SET_CONNECT_SEL, 0x2},
331*c577b8a1SJoseph Chan 	/* PW9 Output enable */
332*c577b8a1SJoseph Chan 	{0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
333*c577b8a1SJoseph Chan };
334*c577b8a1SJoseph Chan 
335*c577b8a1SJoseph Chan static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
336*c577b8a1SJoseph Chan 				 struct hda_codec *codec,
337*c577b8a1SJoseph Chan 				 struct snd_pcm_substream *substream)
338*c577b8a1SJoseph Chan {
339*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
340*c577b8a1SJoseph Chan 	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
341*c577b8a1SJoseph Chan }
342*c577b8a1SJoseph Chan 
343*c577b8a1SJoseph Chan static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
344*c577b8a1SJoseph Chan 				    struct hda_codec *codec,
345*c577b8a1SJoseph Chan 				    unsigned int stream_tag,
346*c577b8a1SJoseph Chan 				    unsigned int format,
347*c577b8a1SJoseph Chan 				    struct snd_pcm_substream *substream)
348*c577b8a1SJoseph Chan {
349*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
350*c577b8a1SJoseph Chan 	return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
351*c577b8a1SJoseph Chan 						stream_tag, format, substream);
352*c577b8a1SJoseph Chan }
353*c577b8a1SJoseph Chan 
354*c577b8a1SJoseph Chan static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
355*c577b8a1SJoseph Chan 				    struct hda_codec *codec,
356*c577b8a1SJoseph Chan 				    struct snd_pcm_substream *substream)
357*c577b8a1SJoseph Chan {
358*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
359*c577b8a1SJoseph Chan 	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
360*c577b8a1SJoseph Chan }
361*c577b8a1SJoseph Chan 
362*c577b8a1SJoseph Chan /*
363*c577b8a1SJoseph Chan  * Digital out
364*c577b8a1SJoseph Chan  */
365*c577b8a1SJoseph Chan static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
366*c577b8a1SJoseph Chan 				     struct hda_codec *codec,
367*c577b8a1SJoseph Chan 				     struct snd_pcm_substream *substream)
368*c577b8a1SJoseph Chan {
369*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
370*c577b8a1SJoseph Chan 	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
371*c577b8a1SJoseph Chan }
372*c577b8a1SJoseph Chan 
373*c577b8a1SJoseph Chan static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
374*c577b8a1SJoseph Chan 				      struct hda_codec *codec,
375*c577b8a1SJoseph Chan 				      struct snd_pcm_substream *substream)
376*c577b8a1SJoseph Chan {
377*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
378*c577b8a1SJoseph Chan 	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
379*c577b8a1SJoseph Chan }
380*c577b8a1SJoseph Chan 
381*c577b8a1SJoseph Chan /*
382*c577b8a1SJoseph Chan  * Analog capture
383*c577b8a1SJoseph Chan  */
384*c577b8a1SJoseph Chan static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
385*c577b8a1SJoseph Chan 				   struct hda_codec *codec,
386*c577b8a1SJoseph Chan 				   unsigned int stream_tag,
387*c577b8a1SJoseph Chan 				   unsigned int format,
388*c577b8a1SJoseph Chan 				   struct snd_pcm_substream *substream)
389*c577b8a1SJoseph Chan {
390*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
391*c577b8a1SJoseph Chan 
392*c577b8a1SJoseph Chan 	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
393*c577b8a1SJoseph Chan 				   stream_tag, 0, format);
394*c577b8a1SJoseph Chan 	return 0;
395*c577b8a1SJoseph Chan }
396*c577b8a1SJoseph Chan 
397*c577b8a1SJoseph Chan static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
398*c577b8a1SJoseph Chan 				   struct hda_codec *codec,
399*c577b8a1SJoseph Chan 				   struct snd_pcm_substream *substream)
400*c577b8a1SJoseph Chan {
401*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
402*c577b8a1SJoseph Chan 	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
403*c577b8a1SJoseph Chan 				   0, 0, 0);
404*c577b8a1SJoseph Chan 	return 0;
405*c577b8a1SJoseph Chan }
406*c577b8a1SJoseph Chan 
407*c577b8a1SJoseph Chan static struct hda_pcm_stream vt1708_pcm_analog_playback = {
408*c577b8a1SJoseph Chan 	.substreams = 1,
409*c577b8a1SJoseph Chan 	.channels_min = 2,
410*c577b8a1SJoseph Chan 	.channels_max = 8,
411*c577b8a1SJoseph Chan 	.nid = 0x10, /* NID to query formats and rates */
412*c577b8a1SJoseph Chan 	.ops = {
413*c577b8a1SJoseph Chan 		.open = via_playback_pcm_open,
414*c577b8a1SJoseph Chan 		.prepare = via_playback_pcm_prepare,
415*c577b8a1SJoseph Chan 		.cleanup = via_playback_pcm_cleanup
416*c577b8a1SJoseph Chan 	},
417*c577b8a1SJoseph Chan };
418*c577b8a1SJoseph Chan 
419*c577b8a1SJoseph Chan static struct hda_pcm_stream vt1708_pcm_analog_capture = {
420*c577b8a1SJoseph Chan 	.substreams = 2,
421*c577b8a1SJoseph Chan 	.channels_min = 2,
422*c577b8a1SJoseph Chan 	.channels_max = 2,
423*c577b8a1SJoseph Chan 	.nid = 0x15, /* NID to query formats and rates */
424*c577b8a1SJoseph Chan 	.ops = {
425*c577b8a1SJoseph Chan 		.prepare = via_capture_pcm_prepare,
426*c577b8a1SJoseph Chan 		.cleanup = via_capture_pcm_cleanup
427*c577b8a1SJoseph Chan 	},
428*c577b8a1SJoseph Chan };
429*c577b8a1SJoseph Chan 
430*c577b8a1SJoseph Chan static struct hda_pcm_stream vt1708_pcm_digital_playback = {
431*c577b8a1SJoseph Chan 	.substreams = 1,
432*c577b8a1SJoseph Chan 	.channels_min = 2,
433*c577b8a1SJoseph Chan 	.channels_max = 2,
434*c577b8a1SJoseph Chan 	/* NID is set in via_build_pcms */
435*c577b8a1SJoseph Chan 	.ops = {
436*c577b8a1SJoseph Chan 		.open = via_dig_playback_pcm_open,
437*c577b8a1SJoseph Chan 		.close = via_dig_playback_pcm_close
438*c577b8a1SJoseph Chan 	},
439*c577b8a1SJoseph Chan };
440*c577b8a1SJoseph Chan 
441*c577b8a1SJoseph Chan static struct hda_pcm_stream vt1708_pcm_digital_capture = {
442*c577b8a1SJoseph Chan 	.substreams = 1,
443*c577b8a1SJoseph Chan 	.channels_min = 2,
444*c577b8a1SJoseph Chan 	.channels_max = 2,
445*c577b8a1SJoseph Chan };
446*c577b8a1SJoseph Chan 
447*c577b8a1SJoseph Chan static int via_build_controls(struct hda_codec *codec)
448*c577b8a1SJoseph Chan {
449*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
450*c577b8a1SJoseph Chan 	int err;
451*c577b8a1SJoseph Chan 	int i;
452*c577b8a1SJoseph Chan 
453*c577b8a1SJoseph Chan 	for (i = 0; i < spec->num_mixers; i++) {
454*c577b8a1SJoseph Chan 		err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
455*c577b8a1SJoseph Chan 		if (err < 0)
456*c577b8a1SJoseph Chan 			return err;
457*c577b8a1SJoseph Chan 	}
458*c577b8a1SJoseph Chan 
459*c577b8a1SJoseph Chan 	if (spec->multiout.dig_out_nid) {
460*c577b8a1SJoseph Chan 		err = snd_hda_create_spdif_out_ctls(codec,
461*c577b8a1SJoseph Chan 						    spec->multiout.dig_out_nid);
462*c577b8a1SJoseph Chan 		if (err < 0)
463*c577b8a1SJoseph Chan 			return err;
464*c577b8a1SJoseph Chan 	}
465*c577b8a1SJoseph Chan 	if (spec->dig_in_nid) {
466*c577b8a1SJoseph Chan 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
467*c577b8a1SJoseph Chan 		if (err < 0)
468*c577b8a1SJoseph Chan 			return err;
469*c577b8a1SJoseph Chan 	}
470*c577b8a1SJoseph Chan 	return 0;
471*c577b8a1SJoseph Chan }
472*c577b8a1SJoseph Chan 
473*c577b8a1SJoseph Chan static int via_build_pcms(struct hda_codec *codec)
474*c577b8a1SJoseph Chan {
475*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
476*c577b8a1SJoseph Chan 	struct hda_pcm *info = spec->pcm_rec;
477*c577b8a1SJoseph Chan 
478*c577b8a1SJoseph Chan 	codec->num_pcms = 1;
479*c577b8a1SJoseph Chan 	codec->pcm_info = info;
480*c577b8a1SJoseph Chan 
481*c577b8a1SJoseph Chan 	info->name = spec->stream_name_analog;
482*c577b8a1SJoseph Chan 	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
483*c577b8a1SJoseph Chan 	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
484*c577b8a1SJoseph Chan 	info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
485*c577b8a1SJoseph Chan 	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
486*c577b8a1SJoseph Chan 
487*c577b8a1SJoseph Chan 	info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
488*c577b8a1SJoseph Chan 		spec->multiout.max_channels;
489*c577b8a1SJoseph Chan 
490*c577b8a1SJoseph Chan 	if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
491*c577b8a1SJoseph Chan 		codec->num_pcms++;
492*c577b8a1SJoseph Chan 		info++;
493*c577b8a1SJoseph Chan 		info->name = spec->stream_name_digital;
494*c577b8a1SJoseph Chan 		if (spec->multiout.dig_out_nid) {
495*c577b8a1SJoseph Chan 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
496*c577b8a1SJoseph Chan 				*(spec->stream_digital_playback);
497*c577b8a1SJoseph Chan 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
498*c577b8a1SJoseph Chan 				spec->multiout.dig_out_nid;
499*c577b8a1SJoseph Chan 		}
500*c577b8a1SJoseph Chan 		if (spec->dig_in_nid) {
501*c577b8a1SJoseph Chan 			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
502*c577b8a1SJoseph Chan 				*(spec->stream_digital_capture);
503*c577b8a1SJoseph Chan 			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
504*c577b8a1SJoseph Chan 				spec->dig_in_nid;
505*c577b8a1SJoseph Chan 		}
506*c577b8a1SJoseph Chan 	}
507*c577b8a1SJoseph Chan 
508*c577b8a1SJoseph Chan 	return 0;
509*c577b8a1SJoseph Chan }
510*c577b8a1SJoseph Chan 
511*c577b8a1SJoseph Chan static void via_free(struct hda_codec *codec)
512*c577b8a1SJoseph Chan {
513*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
514*c577b8a1SJoseph Chan 	unsigned int i;
515*c577b8a1SJoseph Chan 
516*c577b8a1SJoseph Chan 	if (!spec)
517*c577b8a1SJoseph Chan 		return;
518*c577b8a1SJoseph Chan 
519*c577b8a1SJoseph Chan 	if (spec->kctl_alloc) {
520*c577b8a1SJoseph Chan 		for (i = 0; i < spec->num_kctl_used; i++)
521*c577b8a1SJoseph Chan 			kfree(spec->kctl_alloc[i].name);
522*c577b8a1SJoseph Chan 		kfree(spec->kctl_alloc);
523*c577b8a1SJoseph Chan 	}
524*c577b8a1SJoseph Chan 
525*c577b8a1SJoseph Chan 	kfree(codec->spec);
526*c577b8a1SJoseph Chan }
527*c577b8a1SJoseph Chan 
528*c577b8a1SJoseph Chan static int via_init(struct hda_codec *codec)
529*c577b8a1SJoseph Chan {
530*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
531*c577b8a1SJoseph Chan 	snd_hda_sequence_write(codec, spec->init_verbs);
532*c577b8a1SJoseph Chan  	return 0;
533*c577b8a1SJoseph Chan }
534*c577b8a1SJoseph Chan 
535*c577b8a1SJoseph Chan #ifdef CONFIG_PM
536*c577b8a1SJoseph Chan /*
537*c577b8a1SJoseph Chan  * resume
538*c577b8a1SJoseph Chan  */
539*c577b8a1SJoseph Chan static int via_resume(struct hda_codec *codec)
540*c577b8a1SJoseph Chan {
541*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
542*c577b8a1SJoseph Chan 	int i;
543*c577b8a1SJoseph Chan 
544*c577b8a1SJoseph Chan 	via_init(codec);
545*c577b8a1SJoseph Chan 	for (i = 0; i < spec->num_mixers; i++)
546*c577b8a1SJoseph Chan 		snd_hda_resume_ctls(codec, spec->mixers[i]);
547*c577b8a1SJoseph Chan 	if (spec->multiout.dig_out_nid)
548*c577b8a1SJoseph Chan 		snd_hda_resume_spdif_out(codec);
549*c577b8a1SJoseph Chan 	if (spec->dig_in_nid)
550*c577b8a1SJoseph Chan 		snd_hda_resume_spdif_in(codec);
551*c577b8a1SJoseph Chan 
552*c577b8a1SJoseph Chan 	return 0;
553*c577b8a1SJoseph Chan }
554*c577b8a1SJoseph Chan #endif
555*c577b8a1SJoseph Chan 
556*c577b8a1SJoseph Chan /*
557*c577b8a1SJoseph Chan  */
558*c577b8a1SJoseph Chan static struct hda_codec_ops via_patch_ops = {
559*c577b8a1SJoseph Chan 	.build_controls = via_build_controls,
560*c577b8a1SJoseph Chan 	.build_pcms = via_build_pcms,
561*c577b8a1SJoseph Chan 	.init = via_init,
562*c577b8a1SJoseph Chan 	.free = via_free,
563*c577b8a1SJoseph Chan #ifdef CONFIG_PM
564*c577b8a1SJoseph Chan 	.resume = via_resume,
565*c577b8a1SJoseph Chan #endif
566*c577b8a1SJoseph Chan };
567*c577b8a1SJoseph Chan 
568*c577b8a1SJoseph Chan /* fill in the dac_nids table from the parsed pin configuration */
569*c577b8a1SJoseph Chan static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
570*c577b8a1SJoseph Chan 				     const struct auto_pin_cfg *cfg)
571*c577b8a1SJoseph Chan {
572*c577b8a1SJoseph Chan 	int i;
573*c577b8a1SJoseph Chan 	hda_nid_t nid;
574*c577b8a1SJoseph Chan 
575*c577b8a1SJoseph Chan 	spec->multiout.num_dacs = cfg->line_outs;
576*c577b8a1SJoseph Chan 
577*c577b8a1SJoseph Chan 	spec->multiout.dac_nids = spec->private_dac_nids;
578*c577b8a1SJoseph Chan 
579*c577b8a1SJoseph Chan 	for(i = 0; i < 4; i++) {
580*c577b8a1SJoseph Chan 		nid = cfg->line_out_pins[i];
581*c577b8a1SJoseph Chan 		if (nid) {
582*c577b8a1SJoseph Chan 			/* config dac list */
583*c577b8a1SJoseph Chan 			switch (i) {
584*c577b8a1SJoseph Chan 			case AUTO_SEQ_FRONT:
585*c577b8a1SJoseph Chan 				spec->multiout.dac_nids[i] = 0x10;
586*c577b8a1SJoseph Chan 				break;
587*c577b8a1SJoseph Chan 			case AUTO_SEQ_CENLFE:
588*c577b8a1SJoseph Chan 				spec->multiout.dac_nids[i] = 0x12;
589*c577b8a1SJoseph Chan 				break;
590*c577b8a1SJoseph Chan 			case AUTO_SEQ_SURROUND:
591*c577b8a1SJoseph Chan 				spec->multiout.dac_nids[i] = 0x13;
592*c577b8a1SJoseph Chan 				break;
593*c577b8a1SJoseph Chan 			case AUTO_SEQ_SIDE:
594*c577b8a1SJoseph Chan 				spec->multiout.dac_nids[i] = 0x11;
595*c577b8a1SJoseph Chan 				break;
596*c577b8a1SJoseph Chan 			}
597*c577b8a1SJoseph Chan 		}
598*c577b8a1SJoseph Chan 	}
599*c577b8a1SJoseph Chan 
600*c577b8a1SJoseph Chan 	return 0;
601*c577b8a1SJoseph Chan }
602*c577b8a1SJoseph Chan 
603*c577b8a1SJoseph Chan /* add playback controls from the parsed DAC table */
604*c577b8a1SJoseph Chan static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
605*c577b8a1SJoseph Chan 					     const struct auto_pin_cfg *cfg)
606*c577b8a1SJoseph Chan {
607*c577b8a1SJoseph Chan 	char name[32];
608*c577b8a1SJoseph Chan 	static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
609*c577b8a1SJoseph Chan 	hda_nid_t nid, nid_vol = 0;
610*c577b8a1SJoseph Chan 	int i, err;
611*c577b8a1SJoseph Chan 
612*c577b8a1SJoseph Chan 	for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
613*c577b8a1SJoseph Chan 		nid = cfg->line_out_pins[i];
614*c577b8a1SJoseph Chan 
615*c577b8a1SJoseph Chan 		if (!nid)
616*c577b8a1SJoseph Chan 			continue;
617*c577b8a1SJoseph Chan 
618*c577b8a1SJoseph Chan 		if (i != AUTO_SEQ_FRONT)
619*c577b8a1SJoseph Chan 			nid_vol = 0x1b - i + 1;
620*c577b8a1SJoseph Chan 
621*c577b8a1SJoseph Chan 		if (i == AUTO_SEQ_CENLFE) {
622*c577b8a1SJoseph Chan 			/* Center/LFE */
623*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
624*c577b8a1SJoseph Chan 					      "Center Playback Volume",
625*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
626*c577b8a1SJoseph Chan 			if (err < 0)
627*c577b8a1SJoseph Chan 				return err;
628*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
629*c577b8a1SJoseph Chan 					      "LFE Playback Volume",
630*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
631*c577b8a1SJoseph Chan 			if (err < 0)
632*c577b8a1SJoseph Chan 				return err;
633*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
634*c577b8a1SJoseph Chan 					      "Center Playback Switch",
635*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
636*c577b8a1SJoseph Chan 			if (err < 0)
637*c577b8a1SJoseph Chan 				return err;
638*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
639*c577b8a1SJoseph Chan 					      "LFE Playback Switch",
640*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
641*c577b8a1SJoseph Chan 			if (err < 0)
642*c577b8a1SJoseph Chan 				return err;
643*c577b8a1SJoseph Chan 		} else if (i == AUTO_SEQ_FRONT){
644*c577b8a1SJoseph Chan 			/* add control to mixer index 0 */
645*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
646*c577b8a1SJoseph Chan 					      "Master Front Playback Volume",
647*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT));
648*c577b8a1SJoseph Chan 			if (err < 0)
649*c577b8a1SJoseph Chan 				return err;
650*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
651*c577b8a1SJoseph Chan 					      "Master Front Playback Switch",
652*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT));
653*c577b8a1SJoseph Chan 			if (err < 0)
654*c577b8a1SJoseph Chan 				return err;
655*c577b8a1SJoseph Chan 
656*c577b8a1SJoseph Chan 			/* add control to PW3 */
657*c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Volume", chname[i]);
658*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
659*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
660*c577b8a1SJoseph Chan 			if (err < 0)
661*c577b8a1SJoseph Chan 				return err;
662*c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Switch", chname[i]);
663*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
664*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
665*c577b8a1SJoseph Chan 			if (err < 0)
666*c577b8a1SJoseph Chan 				return err;
667*c577b8a1SJoseph Chan 		} else {
668*c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Volume", chname[i]);
669*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
670*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
671*c577b8a1SJoseph Chan 			if (err < 0)
672*c577b8a1SJoseph Chan 				return err;
673*c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Switch", chname[i]);
674*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
675*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
676*c577b8a1SJoseph Chan 			if (err < 0)
677*c577b8a1SJoseph Chan 				return err;
678*c577b8a1SJoseph Chan 		}
679*c577b8a1SJoseph Chan 	}
680*c577b8a1SJoseph Chan 
681*c577b8a1SJoseph Chan 	return 0;
682*c577b8a1SJoseph Chan }
683*c577b8a1SJoseph Chan 
684*c577b8a1SJoseph Chan static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
685*c577b8a1SJoseph Chan {
686*c577b8a1SJoseph Chan 	int err;
687*c577b8a1SJoseph Chan 
688*c577b8a1SJoseph Chan 	if (!pin)
689*c577b8a1SJoseph Chan 		return 0;
690*c577b8a1SJoseph Chan 
691*c577b8a1SJoseph Chan 	spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
692*c577b8a1SJoseph Chan 
693*c577b8a1SJoseph Chan 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
694*c577b8a1SJoseph Chan 			      "Headphone Playback Volume",
695*c577b8a1SJoseph Chan 			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
696*c577b8a1SJoseph Chan 	if (err < 0)
697*c577b8a1SJoseph Chan 		return err;
698*c577b8a1SJoseph Chan 	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
699*c577b8a1SJoseph Chan 			      "Headphone Playback Switch",
700*c577b8a1SJoseph Chan 			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
701*c577b8a1SJoseph Chan 	if (err < 0)
702*c577b8a1SJoseph Chan 		return err;
703*c577b8a1SJoseph Chan 
704*c577b8a1SJoseph Chan 	return 0;
705*c577b8a1SJoseph Chan }
706*c577b8a1SJoseph Chan 
707*c577b8a1SJoseph Chan /* create playback/capture controls for input pins */
708*c577b8a1SJoseph Chan static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
709*c577b8a1SJoseph Chan 						const struct auto_pin_cfg *cfg)
710*c577b8a1SJoseph Chan {
711*c577b8a1SJoseph Chan 	static char *labels[] = {
712*c577b8a1SJoseph Chan 		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
713*c577b8a1SJoseph Chan 	};
714*c577b8a1SJoseph Chan 	struct hda_input_mux *imux = &spec->private_imux;
715*c577b8a1SJoseph Chan 	int i, err, idx = 0;
716*c577b8a1SJoseph Chan 
717*c577b8a1SJoseph Chan 	/* for internal loopback recording select */
718*c577b8a1SJoseph Chan 	imux->items[imux->num_items].label = "Stereo Mixer";
719*c577b8a1SJoseph Chan 	imux->items[imux->num_items].index = idx;
720*c577b8a1SJoseph Chan 	imux->num_items++;
721*c577b8a1SJoseph Chan 
722*c577b8a1SJoseph Chan 	for (i = 0; i < AUTO_PIN_LAST; i++) {
723*c577b8a1SJoseph Chan 		if (!cfg->input_pins[i])
724*c577b8a1SJoseph Chan 			continue;
725*c577b8a1SJoseph Chan 
726*c577b8a1SJoseph Chan 		switch (cfg->input_pins[i]) {
727*c577b8a1SJoseph Chan 		case 0x1d: /* Mic */
728*c577b8a1SJoseph Chan 			idx = 2;
729*c577b8a1SJoseph Chan 			break;
730*c577b8a1SJoseph Chan 
731*c577b8a1SJoseph Chan 		case 0x1e: /* Line In */
732*c577b8a1SJoseph Chan 			idx = 3;
733*c577b8a1SJoseph Chan 			break;
734*c577b8a1SJoseph Chan 
735*c577b8a1SJoseph Chan 		case 0x21: /* Front Mic */
736*c577b8a1SJoseph Chan 			idx = 4;
737*c577b8a1SJoseph Chan 			break;
738*c577b8a1SJoseph Chan 
739*c577b8a1SJoseph Chan 		case 0x24: /* CD */
740*c577b8a1SJoseph Chan 			idx = 1;
741*c577b8a1SJoseph Chan 			break;
742*c577b8a1SJoseph Chan 		}
743*c577b8a1SJoseph Chan 		err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
744*c577b8a1SJoseph Chan 					   idx, 0x17);
745*c577b8a1SJoseph Chan 		if (err < 0)
746*c577b8a1SJoseph Chan 			return err;
747*c577b8a1SJoseph Chan 		imux->items[imux->num_items].label = labels[i];
748*c577b8a1SJoseph Chan 		imux->items[imux->num_items].index = idx;
749*c577b8a1SJoseph Chan 		imux->num_items++;
750*c577b8a1SJoseph Chan 	}
751*c577b8a1SJoseph Chan 	return 0;
752*c577b8a1SJoseph Chan }
753*c577b8a1SJoseph Chan 
754*c577b8a1SJoseph Chan static int vt1708_parse_auto_config(struct hda_codec *codec)
755*c577b8a1SJoseph Chan {
756*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
757*c577b8a1SJoseph Chan 	int err;
758*c577b8a1SJoseph Chan 
759*c577b8a1SJoseph Chan 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
760*c577b8a1SJoseph Chan 	if (err < 0)
761*c577b8a1SJoseph Chan 		return err;
762*c577b8a1SJoseph Chan 	err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
763*c577b8a1SJoseph Chan 	if (err < 0)
764*c577b8a1SJoseph Chan 		return err;
765*c577b8a1SJoseph Chan 	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
766*c577b8a1SJoseph Chan 		return 0; /* can't find valid BIOS pin config */
767*c577b8a1SJoseph Chan 
768*c577b8a1SJoseph Chan 	err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
769*c577b8a1SJoseph Chan 	if (err < 0)
770*c577b8a1SJoseph Chan 		return err;
771*c577b8a1SJoseph Chan 	err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
772*c577b8a1SJoseph Chan 	if (err < 0)
773*c577b8a1SJoseph Chan 		return err;
774*c577b8a1SJoseph Chan 	err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
775*c577b8a1SJoseph Chan 	if (err < 0)
776*c577b8a1SJoseph Chan 		return err;
777*c577b8a1SJoseph Chan 
778*c577b8a1SJoseph Chan 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
779*c577b8a1SJoseph Chan 
780*c577b8a1SJoseph Chan 	if (spec->autocfg.dig_out_pin)
781*c577b8a1SJoseph Chan 		spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
782*c577b8a1SJoseph Chan 	if (spec->autocfg.dig_in_pin)
783*c577b8a1SJoseph Chan 		spec->dig_in_nid = VT1708_DIGIN_NID;
784*c577b8a1SJoseph Chan 
785*c577b8a1SJoseph Chan 	if (spec->kctl_alloc)
786*c577b8a1SJoseph Chan 		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
787*c577b8a1SJoseph Chan 
788*c577b8a1SJoseph Chan 	spec->init_verbs = vt1708_volume_init_verbs;
789*c577b8a1SJoseph Chan 
790*c577b8a1SJoseph Chan 	spec->input_mux = &spec->private_imux;
791*c577b8a1SJoseph Chan 
792*c577b8a1SJoseph Chan 	return 1;
793*c577b8a1SJoseph Chan }
794*c577b8a1SJoseph Chan 
795*c577b8a1SJoseph Chan /* init callback for auto-configuration model -- overriding the default init */
796*c577b8a1SJoseph Chan static int via_auto_init(struct hda_codec *codec)
797*c577b8a1SJoseph Chan {
798*c577b8a1SJoseph Chan 	via_init(codec);
799*c577b8a1SJoseph Chan 	via_auto_init_multi_out(codec);
800*c577b8a1SJoseph Chan 	via_auto_init_hp_out(codec);
801*c577b8a1SJoseph Chan 	via_auto_init_analog_input(codec);
802*c577b8a1SJoseph Chan 	return 0;
803*c577b8a1SJoseph Chan }
804*c577b8a1SJoseph Chan 
805*c577b8a1SJoseph Chan static int patch_vt1708(struct hda_codec *codec)
806*c577b8a1SJoseph Chan {
807*c577b8a1SJoseph Chan 	struct via_spec *spec;
808*c577b8a1SJoseph Chan 	int err;
809*c577b8a1SJoseph Chan 
810*c577b8a1SJoseph Chan 	/* create a codec specific record */
811*c577b8a1SJoseph Chan 	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
812*c577b8a1SJoseph Chan 	if (spec == NULL)
813*c577b8a1SJoseph Chan 		return -ENOMEM;
814*c577b8a1SJoseph Chan 
815*c577b8a1SJoseph Chan 	codec->spec = spec;
816*c577b8a1SJoseph Chan 
817*c577b8a1SJoseph Chan 	/* automatic parse from the BIOS config */
818*c577b8a1SJoseph Chan 	err = vt1708_parse_auto_config(codec);
819*c577b8a1SJoseph Chan 	if (err < 0) {
820*c577b8a1SJoseph Chan 		via_free(codec);
821*c577b8a1SJoseph Chan 		return err;
822*c577b8a1SJoseph Chan 	} else if (!err) {
823*c577b8a1SJoseph Chan 		printk(KERN_INFO "hda_codec: Cannot set up configuration "
824*c577b8a1SJoseph Chan 		       "from BIOS.  Using genenic mode...\n");
825*c577b8a1SJoseph Chan 	}
826*c577b8a1SJoseph Chan 
827*c577b8a1SJoseph Chan 
828*c577b8a1SJoseph Chan 	spec->stream_name_analog = "VT1708 Analog";
829*c577b8a1SJoseph Chan 	spec->stream_analog_playback = &vt1708_pcm_analog_playback;
830*c577b8a1SJoseph Chan 	spec->stream_analog_capture = &vt1708_pcm_analog_capture;
831*c577b8a1SJoseph Chan 
832*c577b8a1SJoseph Chan 	spec->stream_name_digital = "VT1708 Digital";
833*c577b8a1SJoseph Chan 	spec->stream_digital_playback = &vt1708_pcm_digital_playback;
834*c577b8a1SJoseph Chan 	spec->stream_digital_capture = &vt1708_pcm_digital_capture;
835*c577b8a1SJoseph Chan 
836*c577b8a1SJoseph Chan 
837*c577b8a1SJoseph Chan 	if (!spec->adc_nids && spec->input_mux) {
838*c577b8a1SJoseph Chan 		spec->adc_nids = vt1708_adc_nids;
839*c577b8a1SJoseph Chan 		spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
840*c577b8a1SJoseph Chan 		spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
841*c577b8a1SJoseph Chan 		spec->num_mixers++;
842*c577b8a1SJoseph Chan 	}
843*c577b8a1SJoseph Chan 
844*c577b8a1SJoseph Chan 	codec->patch_ops = via_patch_ops;
845*c577b8a1SJoseph Chan 
846*c577b8a1SJoseph Chan 	codec->patch_ops.init = via_auto_init;
847*c577b8a1SJoseph Chan 
848*c577b8a1SJoseph Chan 	return 0;
849*c577b8a1SJoseph Chan }
850*c577b8a1SJoseph Chan 
851*c577b8a1SJoseph Chan /* capture mixer elements */
852*c577b8a1SJoseph Chan static struct snd_kcontrol_new vt1709_capture_mixer[] = {
853*c577b8a1SJoseph Chan 	HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
854*c577b8a1SJoseph Chan 	HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
855*c577b8a1SJoseph Chan 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
856*c577b8a1SJoseph Chan 	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
857*c577b8a1SJoseph Chan 	HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
858*c577b8a1SJoseph Chan 	HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
859*c577b8a1SJoseph Chan 	{
860*c577b8a1SJoseph Chan 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
861*c577b8a1SJoseph Chan 		/* The multiple "Capture Source" controls confuse alsamixer
862*c577b8a1SJoseph Chan 		 * So call somewhat different..
863*c577b8a1SJoseph Chan 		 * FIXME: the controls appear in the "playback" view!
864*c577b8a1SJoseph Chan 		 */
865*c577b8a1SJoseph Chan 		/* .name = "Capture Source", */
866*c577b8a1SJoseph Chan 		.name = "Input Source",
867*c577b8a1SJoseph Chan 		.count = 1,
868*c577b8a1SJoseph Chan 		.info = via_mux_enum_info,
869*c577b8a1SJoseph Chan 		.get = via_mux_enum_get,
870*c577b8a1SJoseph Chan 		.put = via_mux_enum_put,
871*c577b8a1SJoseph Chan 	},
872*c577b8a1SJoseph Chan 	{ } /* end */
873*c577b8a1SJoseph Chan };
874*c577b8a1SJoseph Chan 
875*c577b8a1SJoseph Chan /*
876*c577b8a1SJoseph Chan  * generic initialization of ADC, input mixers and output mixers
877*c577b8a1SJoseph Chan  */
878*c577b8a1SJoseph Chan static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
879*c577b8a1SJoseph Chan 	/*
880*c577b8a1SJoseph Chan 	 * Unmute ADC0-2 and set the default input to mic-in
881*c577b8a1SJoseph Chan 	 */
882*c577b8a1SJoseph Chan 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
883*c577b8a1SJoseph Chan 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
884*c577b8a1SJoseph Chan 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
885*c577b8a1SJoseph Chan 
886*c577b8a1SJoseph Chan 
887*c577b8a1SJoseph Chan 	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
888*c577b8a1SJoseph Chan 	 * mixer widget
889*c577b8a1SJoseph Chan 	 */
890*c577b8a1SJoseph Chan 	/* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
891*c577b8a1SJoseph Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
892*c577b8a1SJoseph Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
893*c577b8a1SJoseph Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
894*c577b8a1SJoseph Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
895*c577b8a1SJoseph Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
896*c577b8a1SJoseph Chan 
897*c577b8a1SJoseph Chan 	/*
898*c577b8a1SJoseph Chan 	 * Set up output selector (0x1a, 0x1b, 0x29)
899*c577b8a1SJoseph Chan 	 */
900*c577b8a1SJoseph Chan 	/* set vol=0 to output mixers */
901*c577b8a1SJoseph Chan 	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
902*c577b8a1SJoseph Chan 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
903*c577b8a1SJoseph Chan 	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
904*c577b8a1SJoseph Chan 
905*c577b8a1SJoseph Chan 	/*
906*c577b8a1SJoseph Chan 	 *  Unmute PW3 and PW4
907*c577b8a1SJoseph Chan 	 */
908*c577b8a1SJoseph Chan 	{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
909*c577b8a1SJoseph Chan 	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
910*c577b8a1SJoseph Chan 
911*c577b8a1SJoseph Chan 	/* Set input of PW4 as AOW4 */
912*c577b8a1SJoseph Chan 	{0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
913*c577b8a1SJoseph Chan 	/* Set mic as default input of sw0 */
914*c577b8a1SJoseph Chan 	{0x19, AC_VERB_SET_CONNECT_SEL, 0x2},
915*c577b8a1SJoseph Chan 	/* PW9 Output enable */
916*c577b8a1SJoseph Chan 	{0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
917*c577b8a1SJoseph Chan 	{ }
918*c577b8a1SJoseph Chan };
919*c577b8a1SJoseph Chan 
920*c577b8a1SJoseph Chan static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
921*c577b8a1SJoseph Chan 	.substreams = 1,
922*c577b8a1SJoseph Chan 	.channels_min = 2,
923*c577b8a1SJoseph Chan 	.channels_max = 10,
924*c577b8a1SJoseph Chan 	.nid = 0x10, /* NID to query formats and rates */
925*c577b8a1SJoseph Chan 	.ops = {
926*c577b8a1SJoseph Chan 		.open = via_playback_pcm_open,
927*c577b8a1SJoseph Chan 		.prepare = via_playback_pcm_prepare,
928*c577b8a1SJoseph Chan 		.cleanup = via_playback_pcm_cleanup
929*c577b8a1SJoseph Chan 	},
930*c577b8a1SJoseph Chan };
931*c577b8a1SJoseph Chan 
932*c577b8a1SJoseph Chan static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
933*c577b8a1SJoseph Chan 	.substreams = 1,
934*c577b8a1SJoseph Chan 	.channels_min = 2,
935*c577b8a1SJoseph Chan 	.channels_max = 6,
936*c577b8a1SJoseph Chan 	.nid = 0x10, /* NID to query formats and rates */
937*c577b8a1SJoseph Chan 	.ops = {
938*c577b8a1SJoseph Chan 		.open = via_playback_pcm_open,
939*c577b8a1SJoseph Chan 		.prepare = via_playback_pcm_prepare,
940*c577b8a1SJoseph Chan 		.cleanup = via_playback_pcm_cleanup
941*c577b8a1SJoseph Chan 	},
942*c577b8a1SJoseph Chan };
943*c577b8a1SJoseph Chan 
944*c577b8a1SJoseph Chan static struct hda_pcm_stream vt1709_pcm_analog_capture = {
945*c577b8a1SJoseph Chan 	.substreams = 2,
946*c577b8a1SJoseph Chan 	.channels_min = 2,
947*c577b8a1SJoseph Chan 	.channels_max = 2,
948*c577b8a1SJoseph Chan 	.nid = 0x14, /* NID to query formats and rates */
949*c577b8a1SJoseph Chan 	.ops = {
950*c577b8a1SJoseph Chan 		.prepare = via_capture_pcm_prepare,
951*c577b8a1SJoseph Chan 		.cleanup = via_capture_pcm_cleanup
952*c577b8a1SJoseph Chan 	},
953*c577b8a1SJoseph Chan };
954*c577b8a1SJoseph Chan 
955*c577b8a1SJoseph Chan static struct hda_pcm_stream vt1709_pcm_digital_playback = {
956*c577b8a1SJoseph Chan 	.substreams = 1,
957*c577b8a1SJoseph Chan 	.channels_min = 2,
958*c577b8a1SJoseph Chan 	.channels_max = 2,
959*c577b8a1SJoseph Chan 	/* NID is set in via_build_pcms */
960*c577b8a1SJoseph Chan 	.ops = {
961*c577b8a1SJoseph Chan 		.open = via_dig_playback_pcm_open,
962*c577b8a1SJoseph Chan 		.close = via_dig_playback_pcm_close
963*c577b8a1SJoseph Chan 	},
964*c577b8a1SJoseph Chan };
965*c577b8a1SJoseph Chan 
966*c577b8a1SJoseph Chan static struct hda_pcm_stream vt1709_pcm_digital_capture = {
967*c577b8a1SJoseph Chan 	.substreams = 1,
968*c577b8a1SJoseph Chan 	.channels_min = 2,
969*c577b8a1SJoseph Chan 	.channels_max = 2,
970*c577b8a1SJoseph Chan };
971*c577b8a1SJoseph Chan 
972*c577b8a1SJoseph Chan static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
973*c577b8a1SJoseph Chan 				     const struct auto_pin_cfg *cfg)
974*c577b8a1SJoseph Chan {
975*c577b8a1SJoseph Chan 	int i;
976*c577b8a1SJoseph Chan 	hda_nid_t nid;
977*c577b8a1SJoseph Chan 
978*c577b8a1SJoseph Chan 	if (cfg->line_outs == 4)  /* 10 channels */
979*c577b8a1SJoseph Chan 		spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
980*c577b8a1SJoseph Chan 	else if (cfg->line_outs == 3) /* 6 channels */
981*c577b8a1SJoseph Chan 		spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
982*c577b8a1SJoseph Chan 
983*c577b8a1SJoseph Chan 	spec->multiout.dac_nids = spec->private_dac_nids;
984*c577b8a1SJoseph Chan 
985*c577b8a1SJoseph Chan 	if (cfg->line_outs == 4) { /* 10 channels */
986*c577b8a1SJoseph Chan 		for (i = 0; i < cfg->line_outs; i++) {
987*c577b8a1SJoseph Chan 			nid = cfg->line_out_pins[i];
988*c577b8a1SJoseph Chan 			if (nid) {
989*c577b8a1SJoseph Chan 				/* config dac list */
990*c577b8a1SJoseph Chan 				switch (i) {
991*c577b8a1SJoseph Chan 				case AUTO_SEQ_FRONT:
992*c577b8a1SJoseph Chan 					/* AOW0 */
993*c577b8a1SJoseph Chan 					spec->multiout.dac_nids[i] = 0x10;
994*c577b8a1SJoseph Chan 					break;
995*c577b8a1SJoseph Chan 				case AUTO_SEQ_CENLFE:
996*c577b8a1SJoseph Chan 					/* AOW2 */
997*c577b8a1SJoseph Chan 					spec->multiout.dac_nids[i] = 0x12;
998*c577b8a1SJoseph Chan 					break;
999*c577b8a1SJoseph Chan 				case AUTO_SEQ_SURROUND:
1000*c577b8a1SJoseph Chan 					/* AOW3 */
1001*c577b8a1SJoseph Chan 					spec->multiout.dac_nids[i] = 0x27;
1002*c577b8a1SJoseph Chan 					break;
1003*c577b8a1SJoseph Chan 				case AUTO_SEQ_SIDE:
1004*c577b8a1SJoseph Chan 					/* AOW1 */
1005*c577b8a1SJoseph Chan 					spec->multiout.dac_nids[i] = 0x11;
1006*c577b8a1SJoseph Chan 					break;
1007*c577b8a1SJoseph Chan 				default:
1008*c577b8a1SJoseph Chan 					break;
1009*c577b8a1SJoseph Chan 				}
1010*c577b8a1SJoseph Chan 			}
1011*c577b8a1SJoseph Chan 		}
1012*c577b8a1SJoseph Chan 		spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
1013*c577b8a1SJoseph Chan 
1014*c577b8a1SJoseph Chan 	} else if (cfg->line_outs == 3) { /* 6 channels */
1015*c577b8a1SJoseph Chan 		for(i = 0; i < cfg->line_outs; i++) {
1016*c577b8a1SJoseph Chan 			nid = cfg->line_out_pins[i];
1017*c577b8a1SJoseph Chan 			if (nid) {
1018*c577b8a1SJoseph Chan 				/* config dac list */
1019*c577b8a1SJoseph Chan 				switch(i) {
1020*c577b8a1SJoseph Chan 				case AUTO_SEQ_FRONT:
1021*c577b8a1SJoseph Chan 					/* AOW0 */
1022*c577b8a1SJoseph Chan 					spec->multiout.dac_nids[i] = 0x10;
1023*c577b8a1SJoseph Chan 					break;
1024*c577b8a1SJoseph Chan 				case AUTO_SEQ_CENLFE:
1025*c577b8a1SJoseph Chan 					/* AOW2 */
1026*c577b8a1SJoseph Chan 					spec->multiout.dac_nids[i] = 0x12;
1027*c577b8a1SJoseph Chan 					break;
1028*c577b8a1SJoseph Chan 				case AUTO_SEQ_SURROUND:
1029*c577b8a1SJoseph Chan 					/* AOW1 */
1030*c577b8a1SJoseph Chan 					spec->multiout.dac_nids[i] = 0x11;
1031*c577b8a1SJoseph Chan 					break;
1032*c577b8a1SJoseph Chan 				default:
1033*c577b8a1SJoseph Chan 					break;
1034*c577b8a1SJoseph Chan 				}
1035*c577b8a1SJoseph Chan 			}
1036*c577b8a1SJoseph Chan 		}
1037*c577b8a1SJoseph Chan 	}
1038*c577b8a1SJoseph Chan 
1039*c577b8a1SJoseph Chan 	return 0;
1040*c577b8a1SJoseph Chan }
1041*c577b8a1SJoseph Chan 
1042*c577b8a1SJoseph Chan /* add playback controls from the parsed DAC table */
1043*c577b8a1SJoseph Chan static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
1044*c577b8a1SJoseph Chan 					     const struct auto_pin_cfg *cfg)
1045*c577b8a1SJoseph Chan {
1046*c577b8a1SJoseph Chan 	char name[32];
1047*c577b8a1SJoseph Chan 	static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1048*c577b8a1SJoseph Chan 	hda_nid_t nid = 0;
1049*c577b8a1SJoseph Chan 	int i, err;
1050*c577b8a1SJoseph Chan 
1051*c577b8a1SJoseph Chan 	for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1052*c577b8a1SJoseph Chan 		nid = cfg->line_out_pins[i];
1053*c577b8a1SJoseph Chan 
1054*c577b8a1SJoseph Chan 		if (!nid)
1055*c577b8a1SJoseph Chan 			continue;
1056*c577b8a1SJoseph Chan 
1057*c577b8a1SJoseph Chan 		if (i == AUTO_SEQ_CENLFE) {
1058*c577b8a1SJoseph Chan 			/* Center/LFE */
1059*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1060*c577b8a1SJoseph Chan 					      "Center Playback Volume",
1061*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT));
1062*c577b8a1SJoseph Chan 			if (err < 0)
1063*c577b8a1SJoseph Chan 				return err;
1064*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1065*c577b8a1SJoseph Chan 					      "LFE Playback Volume",
1066*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT));
1067*c577b8a1SJoseph Chan 			if (err < 0)
1068*c577b8a1SJoseph Chan 				return err;
1069*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1070*c577b8a1SJoseph Chan 					      "Center Playback Switch",
1071*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT));
1072*c577b8a1SJoseph Chan 			if (err < 0)
1073*c577b8a1SJoseph Chan 				return err;
1074*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1075*c577b8a1SJoseph Chan 					      "LFE Playback Switch",
1076*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT));
1077*c577b8a1SJoseph Chan 			if (err < 0)
1078*c577b8a1SJoseph Chan 				return err;
1079*c577b8a1SJoseph Chan 		} else if (i == AUTO_SEQ_FRONT){
1080*c577b8a1SJoseph Chan 			/* add control to mixer index 0 */
1081*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1082*c577b8a1SJoseph Chan 					      "Master Front Playback Volume",
1083*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT));
1084*c577b8a1SJoseph Chan 			if (err < 0)
1085*c577b8a1SJoseph Chan 				return err;
1086*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1087*c577b8a1SJoseph Chan 					      "Master Front Playback Switch",
1088*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT));
1089*c577b8a1SJoseph Chan 			if (err < 0)
1090*c577b8a1SJoseph Chan 				return err;
1091*c577b8a1SJoseph Chan 
1092*c577b8a1SJoseph Chan 			/* add control to PW3 */
1093*c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Volume", chname[i]);
1094*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1095*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
1096*c577b8a1SJoseph Chan 			if (err < 0)
1097*c577b8a1SJoseph Chan 				return err;
1098*c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Switch", chname[i]);
1099*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1100*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
1101*c577b8a1SJoseph Chan 			if (err < 0)
1102*c577b8a1SJoseph Chan 				return err;
1103*c577b8a1SJoseph Chan 		} else if (i == AUTO_SEQ_SURROUND) {
1104*c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Volume", chname[i]);
1105*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1106*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT));
1107*c577b8a1SJoseph Chan 			if (err < 0)
1108*c577b8a1SJoseph Chan 				return err;
1109*c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Switch", chname[i]);
1110*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1111*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT));
1112*c577b8a1SJoseph Chan 			if (err < 0)
1113*c577b8a1SJoseph Chan 				return err;
1114*c577b8a1SJoseph Chan 		} else if (i == AUTO_SEQ_SIDE) {
1115*c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Volume", chname[i]);
1116*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1117*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT));
1118*c577b8a1SJoseph Chan 			if (err < 0)
1119*c577b8a1SJoseph Chan 				return err;
1120*c577b8a1SJoseph Chan 			sprintf(name, "%s Playback Switch", chname[i]);
1121*c577b8a1SJoseph Chan 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1122*c577b8a1SJoseph Chan 					      HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT));
1123*c577b8a1SJoseph Chan 			if (err < 0)
1124*c577b8a1SJoseph Chan 				return err;
1125*c577b8a1SJoseph Chan 		}
1126*c577b8a1SJoseph Chan 	}
1127*c577b8a1SJoseph Chan 
1128*c577b8a1SJoseph Chan 	return 0;
1129*c577b8a1SJoseph Chan }
1130*c577b8a1SJoseph Chan 
1131*c577b8a1SJoseph Chan static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1132*c577b8a1SJoseph Chan {
1133*c577b8a1SJoseph Chan 	int err;
1134*c577b8a1SJoseph Chan 
1135*c577b8a1SJoseph Chan 	if (!pin)
1136*c577b8a1SJoseph Chan 		return 0;
1137*c577b8a1SJoseph Chan 
1138*c577b8a1SJoseph Chan 	if (spec->multiout.num_dacs == 5) /* 10 channels */
1139*c577b8a1SJoseph Chan 		spec->multiout.hp_nid = VT1709_HP_DAC_NID;
1140*c577b8a1SJoseph Chan 	else if (spec->multiout.num_dacs == 3) /* 6 channels */
1141*c577b8a1SJoseph Chan 		spec->multiout.hp_nid = 0;
1142*c577b8a1SJoseph Chan 
1143*c577b8a1SJoseph Chan 	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1144*c577b8a1SJoseph Chan 			      "Headphone Playback Volume",
1145*c577b8a1SJoseph Chan 			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1146*c577b8a1SJoseph Chan 	if (err < 0)
1147*c577b8a1SJoseph Chan 		return err;
1148*c577b8a1SJoseph Chan 	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1149*c577b8a1SJoseph Chan 			      "Headphone Playback Switch",
1150*c577b8a1SJoseph Chan 			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1151*c577b8a1SJoseph Chan 	if (err < 0)
1152*c577b8a1SJoseph Chan 		return err;
1153*c577b8a1SJoseph Chan 
1154*c577b8a1SJoseph Chan 	return 0;
1155*c577b8a1SJoseph Chan }
1156*c577b8a1SJoseph Chan 
1157*c577b8a1SJoseph Chan /* create playback/capture controls for input pins */
1158*c577b8a1SJoseph Chan static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
1159*c577b8a1SJoseph Chan 						const struct auto_pin_cfg *cfg)
1160*c577b8a1SJoseph Chan {
1161*c577b8a1SJoseph Chan 	static char *labels[] = {
1162*c577b8a1SJoseph Chan 		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1163*c577b8a1SJoseph Chan 	};
1164*c577b8a1SJoseph Chan 	struct hda_input_mux *imux = &spec->private_imux;
1165*c577b8a1SJoseph Chan 	int i, err, idx = 0;
1166*c577b8a1SJoseph Chan 
1167*c577b8a1SJoseph Chan 	/* for internal loopback recording select */
1168*c577b8a1SJoseph Chan 	imux->items[imux->num_items].label = "Stereo Mixer";
1169*c577b8a1SJoseph Chan 	imux->items[imux->num_items].index = idx;
1170*c577b8a1SJoseph Chan 	imux->num_items++;
1171*c577b8a1SJoseph Chan 
1172*c577b8a1SJoseph Chan 	for (i = 0; i < AUTO_PIN_LAST; i++) {
1173*c577b8a1SJoseph Chan 		if (!cfg->input_pins[i])
1174*c577b8a1SJoseph Chan 			continue;
1175*c577b8a1SJoseph Chan 
1176*c577b8a1SJoseph Chan 		switch (cfg->input_pins[i]) {
1177*c577b8a1SJoseph Chan 		case 0x1d: /* Mic */
1178*c577b8a1SJoseph Chan 			idx = 2;
1179*c577b8a1SJoseph Chan 			break;
1180*c577b8a1SJoseph Chan 
1181*c577b8a1SJoseph Chan 		case 0x1e: /* Line In */
1182*c577b8a1SJoseph Chan 			idx = 3;
1183*c577b8a1SJoseph Chan 			break;
1184*c577b8a1SJoseph Chan 
1185*c577b8a1SJoseph Chan 		case 0x21: /* Front Mic */
1186*c577b8a1SJoseph Chan 			idx = 4;
1187*c577b8a1SJoseph Chan 			break;
1188*c577b8a1SJoseph Chan 
1189*c577b8a1SJoseph Chan 		case 0x23: /* CD */
1190*c577b8a1SJoseph Chan 			idx = 1;
1191*c577b8a1SJoseph Chan 			break;
1192*c577b8a1SJoseph Chan 		}
1193*c577b8a1SJoseph Chan 		err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
1194*c577b8a1SJoseph Chan 					   idx, 0x18);
1195*c577b8a1SJoseph Chan 		if (err < 0)
1196*c577b8a1SJoseph Chan 			return err;
1197*c577b8a1SJoseph Chan 		imux->items[imux->num_items].label = labels[i];
1198*c577b8a1SJoseph Chan 		imux->items[imux->num_items].index = idx;
1199*c577b8a1SJoseph Chan 		imux->num_items++;
1200*c577b8a1SJoseph Chan 	}
1201*c577b8a1SJoseph Chan 	return 0;
1202*c577b8a1SJoseph Chan }
1203*c577b8a1SJoseph Chan 
1204*c577b8a1SJoseph Chan static int vt1709_parse_auto_config(struct hda_codec *codec)
1205*c577b8a1SJoseph Chan {
1206*c577b8a1SJoseph Chan 	struct via_spec *spec = codec->spec;
1207*c577b8a1SJoseph Chan 	int err;
1208*c577b8a1SJoseph Chan 
1209*c577b8a1SJoseph Chan 	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1210*c577b8a1SJoseph Chan 	if (err < 0)
1211*c577b8a1SJoseph Chan 		return err;
1212*c577b8a1SJoseph Chan 	err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
1213*c577b8a1SJoseph Chan 	if (err < 0)
1214*c577b8a1SJoseph Chan 		return err;
1215*c577b8a1SJoseph Chan 	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1216*c577b8a1SJoseph Chan 		return 0; /* can't find valid BIOS pin config */
1217*c577b8a1SJoseph Chan 
1218*c577b8a1SJoseph Chan 	err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
1219*c577b8a1SJoseph Chan 	if (err < 0)
1220*c577b8a1SJoseph Chan 		return err;
1221*c577b8a1SJoseph Chan 	err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1222*c577b8a1SJoseph Chan 	if (err < 0)
1223*c577b8a1SJoseph Chan 		return err;
1224*c577b8a1SJoseph Chan 	err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
1225*c577b8a1SJoseph Chan 	if (err < 0)
1226*c577b8a1SJoseph Chan 		return err;
1227*c577b8a1SJoseph Chan 
1228*c577b8a1SJoseph Chan 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1229*c577b8a1SJoseph Chan 
1230*c577b8a1SJoseph Chan 	if (spec->autocfg.dig_out_pin)
1231*c577b8a1SJoseph Chan 		spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
1232*c577b8a1SJoseph Chan 	if (spec->autocfg.dig_in_pin)
1233*c577b8a1SJoseph Chan 		spec->dig_in_nid = VT1709_DIGIN_NID;
1234*c577b8a1SJoseph Chan 
1235*c577b8a1SJoseph Chan 	if (spec->kctl_alloc)
1236*c577b8a1SJoseph Chan 		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
1237*c577b8a1SJoseph Chan 
1238*c577b8a1SJoseph Chan 	spec->input_mux = &spec->private_imux;
1239*c577b8a1SJoseph Chan 
1240*c577b8a1SJoseph Chan 	return 1;
1241*c577b8a1SJoseph Chan }
1242*c577b8a1SJoseph Chan 
1243*c577b8a1SJoseph Chan static int patch_vt1709_10ch(struct hda_codec *codec)
1244*c577b8a1SJoseph Chan {
1245*c577b8a1SJoseph Chan 	struct via_spec *spec;
1246*c577b8a1SJoseph Chan 	int err;
1247*c577b8a1SJoseph Chan 
1248*c577b8a1SJoseph Chan 	/* create a codec specific record */
1249*c577b8a1SJoseph Chan 	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
1250*c577b8a1SJoseph Chan 	if (spec == NULL)
1251*c577b8a1SJoseph Chan 		return -ENOMEM;
1252*c577b8a1SJoseph Chan 
1253*c577b8a1SJoseph Chan 	codec->spec = spec;
1254*c577b8a1SJoseph Chan 
1255*c577b8a1SJoseph Chan 	err = vt1709_parse_auto_config(codec);
1256*c577b8a1SJoseph Chan 	if (err < 0) {
1257*c577b8a1SJoseph Chan 		via_free(codec);
1258*c577b8a1SJoseph Chan 		return err;
1259*c577b8a1SJoseph Chan 	} else if (!err) {
1260*c577b8a1SJoseph Chan 		printk(KERN_INFO "hda_codec: Cannot set up configuration.  "
1261*c577b8a1SJoseph Chan 		       "Using genenic mode...\n");
1262*c577b8a1SJoseph Chan 	}
1263*c577b8a1SJoseph Chan 
1264*c577b8a1SJoseph Chan 	spec->init_verbs = vt1709_10ch_volume_init_verbs;
1265*c577b8a1SJoseph Chan 
1266*c577b8a1SJoseph Chan 	spec->stream_name_analog = "VT1709 Analog";
1267*c577b8a1SJoseph Chan 	spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
1268*c577b8a1SJoseph Chan 	spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1269*c577b8a1SJoseph Chan 
1270*c577b8a1SJoseph Chan 	spec->stream_name_digital = "VT1709 Digital";
1271*c577b8a1SJoseph Chan 	spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1272*c577b8a1SJoseph Chan 	spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1273*c577b8a1SJoseph Chan 
1274*c577b8a1SJoseph Chan 
1275*c577b8a1SJoseph Chan 	if (!spec->adc_nids && spec->input_mux) {
1276*c577b8a1SJoseph Chan 		spec->adc_nids = vt1709_adc_nids;
1277*c577b8a1SJoseph Chan 		spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
1278*c577b8a1SJoseph Chan 		spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1279*c577b8a1SJoseph Chan 		spec->num_mixers++;
1280*c577b8a1SJoseph Chan 	}
1281*c577b8a1SJoseph Chan 
1282*c577b8a1SJoseph Chan 	codec->patch_ops = via_patch_ops;
1283*c577b8a1SJoseph Chan 
1284*c577b8a1SJoseph Chan 	codec->patch_ops.init = via_auto_init;
1285*c577b8a1SJoseph Chan 
1286*c577b8a1SJoseph Chan 	return 0;
1287*c577b8a1SJoseph Chan }
1288*c577b8a1SJoseph Chan /*
1289*c577b8a1SJoseph Chan  * generic initialization of ADC, input mixers and output mixers
1290*c577b8a1SJoseph Chan  */
1291*c577b8a1SJoseph Chan static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
1292*c577b8a1SJoseph Chan 	/*
1293*c577b8a1SJoseph Chan 	 * Unmute ADC0-2 and set the default input to mic-in
1294*c577b8a1SJoseph Chan 	 */
1295*c577b8a1SJoseph Chan 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1296*c577b8a1SJoseph Chan 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1297*c577b8a1SJoseph Chan 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1298*c577b8a1SJoseph Chan 
1299*c577b8a1SJoseph Chan 
1300*c577b8a1SJoseph Chan 	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1301*c577b8a1SJoseph Chan 	 * mixer widget
1302*c577b8a1SJoseph Chan 	 */
1303*c577b8a1SJoseph Chan 	/* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1304*c577b8a1SJoseph Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1305*c577b8a1SJoseph Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1306*c577b8a1SJoseph Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1307*c577b8a1SJoseph Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1308*c577b8a1SJoseph Chan 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1309*c577b8a1SJoseph Chan 
1310*c577b8a1SJoseph Chan 	/*
1311*c577b8a1SJoseph Chan 	 * Set up output selector (0x1a, 0x1b, 0x29)
1312*c577b8a1SJoseph Chan 	 */
1313*c577b8a1SJoseph Chan 	/* set vol=0 to output mixers */
1314*c577b8a1SJoseph Chan 	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1315*c577b8a1SJoseph Chan 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1316*c577b8a1SJoseph Chan 	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1317*c577b8a1SJoseph Chan 
1318*c577b8a1SJoseph Chan 	/*
1319*c577b8a1SJoseph Chan 	 *  Unmute PW3 and PW4
1320*c577b8a1SJoseph Chan 	 */
1321*c577b8a1SJoseph Chan 	{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1322*c577b8a1SJoseph Chan 	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1323*c577b8a1SJoseph Chan 
1324*c577b8a1SJoseph Chan 	/* Set input of PW4 as MW0 */
1325*c577b8a1SJoseph Chan 	{0x20, AC_VERB_SET_CONNECT_SEL, 0},
1326*c577b8a1SJoseph Chan 	/* Set mic as default input of sw0 */
1327*c577b8a1SJoseph Chan 	{0x19, AC_VERB_SET_CONNECT_SEL, 0x2},
1328*c577b8a1SJoseph Chan 	/* PW9 Output enable */
1329*c577b8a1SJoseph Chan 	{0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1330*c577b8a1SJoseph Chan 	{ }
1331*c577b8a1SJoseph Chan };
1332*c577b8a1SJoseph Chan 
1333*c577b8a1SJoseph Chan static int patch_vt1709_6ch(struct hda_codec *codec)
1334*c577b8a1SJoseph Chan {
1335*c577b8a1SJoseph Chan 	struct via_spec *spec;
1336*c577b8a1SJoseph Chan 	int err;
1337*c577b8a1SJoseph Chan 
1338*c577b8a1SJoseph Chan 	/* create a codec specific record */
1339*c577b8a1SJoseph Chan 	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
1340*c577b8a1SJoseph Chan 	if (spec == NULL)
1341*c577b8a1SJoseph Chan 		return -ENOMEM;
1342*c577b8a1SJoseph Chan 
1343*c577b8a1SJoseph Chan 	codec->spec = spec;
1344*c577b8a1SJoseph Chan 
1345*c577b8a1SJoseph Chan 	err = vt1709_parse_auto_config(codec);
1346*c577b8a1SJoseph Chan 	if (err < 0) {
1347*c577b8a1SJoseph Chan 		via_free(codec);
1348*c577b8a1SJoseph Chan 		return err;
1349*c577b8a1SJoseph Chan 	} else if (!err) {
1350*c577b8a1SJoseph Chan 		printk(KERN_INFO "hda_codec: Cannot set up configuration.  "
1351*c577b8a1SJoseph Chan 		       "Using genenic mode...\n");
1352*c577b8a1SJoseph Chan 	}
1353*c577b8a1SJoseph Chan 
1354*c577b8a1SJoseph Chan 	spec->init_verbs = vt1709_6ch_volume_init_verbs;
1355*c577b8a1SJoseph Chan 
1356*c577b8a1SJoseph Chan 	spec->stream_name_analog = "VT1709 Analog";
1357*c577b8a1SJoseph Chan 	spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
1358*c577b8a1SJoseph Chan 	spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1359*c577b8a1SJoseph Chan 
1360*c577b8a1SJoseph Chan 	spec->stream_name_digital = "VT1709 Digital";
1361*c577b8a1SJoseph Chan 	spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1362*c577b8a1SJoseph Chan 	spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1363*c577b8a1SJoseph Chan 
1364*c577b8a1SJoseph Chan 
1365*c577b8a1SJoseph Chan 	if (!spec->adc_nids && spec->input_mux) {
1366*c577b8a1SJoseph Chan 		spec->adc_nids = vt1709_adc_nids;
1367*c577b8a1SJoseph Chan 		spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
1368*c577b8a1SJoseph Chan 		spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1369*c577b8a1SJoseph Chan 		spec->num_mixers++;
1370*c577b8a1SJoseph Chan 	}
1371*c577b8a1SJoseph Chan 
1372*c577b8a1SJoseph Chan 	codec->patch_ops = via_patch_ops;
1373*c577b8a1SJoseph Chan 
1374*c577b8a1SJoseph Chan 	codec->patch_ops.init = via_auto_init;
1375*c577b8a1SJoseph Chan 
1376*c577b8a1SJoseph Chan 	return 0;
1377*c577b8a1SJoseph Chan }
1378*c577b8a1SJoseph Chan 
1379*c577b8a1SJoseph Chan /*
1380*c577b8a1SJoseph Chan  * patch entries
1381*c577b8a1SJoseph Chan  */
1382*c577b8a1SJoseph Chan struct hda_codec_preset snd_hda_preset_via[] = {
1383*c577b8a1SJoseph Chan 	{ .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708},
1384*c577b8a1SJoseph Chan 	{ .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708},
1385*c577b8a1SJoseph Chan 	{ .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708},
1386*c577b8a1SJoseph Chan 	{ .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708},
1387*c577b8a1SJoseph Chan 	{ .id = 0x1106E710, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
1388*c577b8a1SJoseph Chan 	{ .id = 0x1106E711, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
1389*c577b8a1SJoseph Chan 	{ .id = 0x1106E712, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
1390*c577b8a1SJoseph Chan 	{ .id = 0x1106E713, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
1391*c577b8a1SJoseph Chan 	{ .id = 0x1106E714, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
1392*c577b8a1SJoseph Chan 	{ .id = 0x1106E715, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
1393*c577b8a1SJoseph Chan 	{ .id = 0x1106E716, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
1394*c577b8a1SJoseph Chan 	{ .id = 0x1106E717, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
1395*c577b8a1SJoseph Chan 	{} /* terminator */
1396*c577b8a1SJoseph Chan };
1397