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