blob: d9a5c6a2dd9f1288152e9cf2cb684ebf78bd445e [file] [log] [blame]
Joseph Chanc577b8a2006-11-29 15:29:40 +01001/*
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 */
Josepch Chanf7278fd2007-12-13 16:40:40 +010030/* 2007-09-12 Lydia Wang Add EAPD enable during driver initialization */
31/* 2007-09-17 Lydia Wang Add VT1708B codec support */
Joseph Chanc577b8a2006-11-29 15:29:40 +010032/* */
33/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
34
35
Joseph Chanc577b8a2006-11-29 15:29:40 +010036#include <linux/init.h>
37#include <linux/delay.h>
38#include <linux/slab.h>
Joseph Chanc577b8a2006-11-29 15:29:40 +010039#include <sound/core.h>
40#include "hda_codec.h"
41#include "hda_local.h"
42
43
44/* amp values */
45#define AMP_VAL_IDX_SHIFT 19
46#define AMP_VAL_IDX_MASK (0x0f<<19)
47
48#define NUM_CONTROL_ALLOC 32
49#define NUM_VERB_ALLOC 32
50
51/* Pin Widget NID */
52#define VT1708_HP_NID 0x13
53#define VT1708_DIGOUT_NID 0x14
54#define VT1708_DIGIN_NID 0x16
Josepch Chanf7278fd2007-12-13 16:40:40 +010055#define VT1708_DIGIN_PIN 0x26
Joseph Chanc577b8a2006-11-29 15:29:40 +010056
57#define VT1709_HP_DAC_NID 0x28
58#define VT1709_DIGOUT_NID 0x13
59#define VT1709_DIGIN_NID 0x17
Josepch Chanf7278fd2007-12-13 16:40:40 +010060#define VT1709_DIGIN_PIN 0x25
61
62#define VT1708B_HP_NID 0x25
63#define VT1708B_DIGOUT_NID 0x12
64#define VT1708B_DIGIN_NID 0x15
65#define VT1708B_DIGIN_PIN 0x21
Joseph Chanc577b8a2006-11-29 15:29:40 +010066
67#define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b)
68#define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713)
69#define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717)
Josepch Chanf7278fd2007-12-13 16:40:40 +010070#define IS_VT1708B_8CH_VENDORID(x) ((x) >= 0x1106e720 && (x) <= 0x1106e723)
71#define IS_VT1708B_4CH_VENDORID(x) ((x) >= 0x1106e724 && (x) <= 0x1106e727)
Joseph Chanc577b8a2006-11-29 15:29:40 +010072
73
74enum {
75 VIA_CTL_WIDGET_VOL,
76 VIA_CTL_WIDGET_MUTE,
77};
78
79enum {
80 AUTO_SEQ_FRONT,
81 AUTO_SEQ_SURROUND,
82 AUTO_SEQ_CENLFE,
83 AUTO_SEQ_SIDE
84};
85
86static struct snd_kcontrol_new vt1708_control_templates[] = {
87 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
88 HDA_CODEC_MUTE(NULL, 0, 0, 0),
89};
90
91
92struct via_spec {
93 /* codec parameterization */
94 struct snd_kcontrol_new *mixers[3];
95 unsigned int num_mixers;
96
97 struct hda_verb *init_verbs;
98
99 char *stream_name_analog;
100 struct hda_pcm_stream *stream_analog_playback;
101 struct hda_pcm_stream *stream_analog_capture;
102
103 char *stream_name_digital;
104 struct hda_pcm_stream *stream_digital_playback;
105 struct hda_pcm_stream *stream_digital_capture;
106
107 /* playback */
108 struct hda_multi_out multiout;
109
110 /* capture */
111 unsigned int num_adc_nids;
112 hda_nid_t *adc_nids;
113 hda_nid_t dig_in_nid;
114
115 /* capture source */
116 const struct hda_input_mux *input_mux;
117 unsigned int cur_mux[3];
118
119 /* PCM information */
120 struct hda_pcm pcm_rec[2];
121
122 /* dynamic controls, init_verbs and input_mux */
123 struct auto_pin_cfg autocfg;
124 unsigned int num_kctl_alloc, num_kctl_used;
125 struct snd_kcontrol_new *kctl_alloc;
126 struct hda_input_mux private_imux;
Takashi Iwai41923e42007-10-22 17:20:10 +0200127 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwaicb53c622007-08-10 17:21:45 +0200128
129#ifdef CONFIG_SND_HDA_POWER_SAVE
130 struct hda_loopback_check loopback;
131#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +0100132};
133
134static hda_nid_t vt1708_adc_nids[2] = {
135 /* ADC1-2 */
136 0x15, 0x27
137};
138
139static hda_nid_t vt1709_adc_nids[3] = {
140 /* ADC1-2 */
141 0x14, 0x15, 0x16
142};
143
Josepch Chanf7278fd2007-12-13 16:40:40 +0100144static hda_nid_t vt1708B_adc_nids[2] = {
145 /* ADC1-2 */
146 0x13, 0x14
147};
148
Joseph Chanc577b8a2006-11-29 15:29:40 +0100149/* add dynamic controls */
150static int via_add_control(struct via_spec *spec, int type, const char *name,
151 unsigned long val)
152{
153 struct snd_kcontrol_new *knew;
154
155 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
156 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
157
158 /* array + terminator */
159 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
160 if (!knew)
161 return -ENOMEM;
162 if (spec->kctl_alloc) {
163 memcpy(knew, spec->kctl_alloc,
164 sizeof(*knew) * spec->num_kctl_alloc);
165 kfree(spec->kctl_alloc);
166 }
167 spec->kctl_alloc = knew;
168 spec->num_kctl_alloc = num;
169 }
170
171 knew = &spec->kctl_alloc[spec->num_kctl_used];
172 *knew = vt1708_control_templates[type];
173 knew->name = kstrdup(name, GFP_KERNEL);
174
175 if (!knew->name)
176 return -ENOMEM;
177 knew->private_value = val;
178 spec->num_kctl_used++;
179 return 0;
180}
181
182/* create input playback/capture controls for the given pin */
183static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
184 const char *ctlname, int idx, int mix_nid)
185{
186 char name[32];
187 int err;
188
189 sprintf(name, "%s Playback Volume", ctlname);
190 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
191 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
192 if (err < 0)
193 return err;
194 sprintf(name, "%s Playback Switch", ctlname);
195 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
196 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
197 if (err < 0)
198 return err;
199 return 0;
200}
201
202static void via_auto_set_output_and_unmute(struct hda_codec *codec,
203 hda_nid_t nid, int pin_type,
204 int dac_idx)
205{
206 /* set as output */
207 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
208 pin_type);
209 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
210 AMP_OUT_UNMUTE);
211}
212
213
214static void via_auto_init_multi_out(struct hda_codec *codec)
215{
216 struct via_spec *spec = codec->spec;
217 int i;
218
219 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
220 hda_nid_t nid = spec->autocfg.line_out_pins[i];
221 if (nid)
222 via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
223 }
224}
225
226static void via_auto_init_hp_out(struct hda_codec *codec)
227{
228 struct via_spec *spec = codec->spec;
229 hda_nid_t pin;
230
231 pin = spec->autocfg.hp_pins[0];
232 if (pin) /* connect to front */
233 via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
234}
235
236static void via_auto_init_analog_input(struct hda_codec *codec)
237{
238 struct via_spec *spec = codec->spec;
239 int i;
240
241 for (i = 0; i < AUTO_PIN_LAST; i++) {
242 hda_nid_t nid = spec->autocfg.input_pins[i];
243
244 snd_hda_codec_write(codec, nid, 0,
245 AC_VERB_SET_PIN_WIDGET_CONTROL,
246 (i <= AUTO_PIN_FRONT_MIC ?
247 PIN_VREF50 : PIN_IN));
248
249 }
250}
251/*
252 * input MUX handling
253 */
254static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
255 struct snd_ctl_elem_info *uinfo)
256{
257 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
258 struct via_spec *spec = codec->spec;
259 return snd_hda_input_mux_info(spec->input_mux, uinfo);
260}
261
262static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
263 struct snd_ctl_elem_value *ucontrol)
264{
265 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
266 struct via_spec *spec = codec->spec;
267 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
268
269 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
270 return 0;
271}
272
273static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
274 struct snd_ctl_elem_value *ucontrol)
275{
276 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
277 struct via_spec *spec = codec->spec;
278 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
279 unsigned int vendor_id = codec->vendor_id;
280
281 /* AIW0 lydia 060801 add for correct sw0 input select */
282 if (IS_VT1708_VENDORID(vendor_id) && (adc_idx == 0))
283 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
284 0x18, &spec->cur_mux[adc_idx]);
285 else if ((IS_VT1709_10CH_VENDORID(vendor_id) ||
Josepch Chanf7278fd2007-12-13 16:40:40 +0100286 IS_VT1709_6CH_VENDORID(vendor_id)) && adc_idx == 0)
Joseph Chanc577b8a2006-11-29 15:29:40 +0100287 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
288 0x19, &spec->cur_mux[adc_idx]);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100289 else if ((IS_VT1708B_8CH_VENDORID(vendor_id) ||
290 IS_VT1708B_4CH_VENDORID(vendor_id)) && adc_idx == 0)
291 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
292 0x17, &spec->cur_mux[adc_idx]);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100293 else
294 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
295 spec->adc_nids[adc_idx],
296 &spec->cur_mux[adc_idx]);
297}
298
299/* capture mixer elements */
300static struct snd_kcontrol_new vt1708_capture_mixer[] = {
301 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
302 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
303 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
304 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
305 {
306 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
307 /* The multiple "Capture Source" controls confuse alsamixer
308 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +0100309 */
310 /* .name = "Capture Source", */
311 .name = "Input Source",
312 .count = 1,
313 .info = via_mux_enum_info,
314 .get = via_mux_enum_get,
315 .put = via_mux_enum_put,
316 },
317 { } /* end */
318};
319/*
320 * generic initialization of ADC, input mixers and output mixers
321 */
322static struct hda_verb vt1708_volume_init_verbs[] = {
323 /*
324 * Unmute ADC0-1 and set the default input to mic-in
325 */
326 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
327 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
328
329
Josepch Chanf7278fd2007-12-13 16:40:40 +0100330 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +0100331 * mixer widget
332 */
333 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +0100334 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
335 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
336 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
337 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
338 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100339
340 /*
341 * Set up output mixers (0x19 - 0x1b)
342 */
343 /* set vol=0 to output mixers */
344 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
345 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
346 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
347
348 /* Setup default input to PW4 */
349 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100350 /* PW9 Output enable */
351 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Josepch Chanf7278fd2007-12-13 16:40:40 +0100352 { }
Joseph Chanc577b8a2006-11-29 15:29:40 +0100353};
354
355static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
356 struct hda_codec *codec,
357 struct snd_pcm_substream *substream)
358{
359 struct via_spec *spec = codec->spec;
360 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
361}
362
363static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
364 struct hda_codec *codec,
365 unsigned int stream_tag,
366 unsigned int format,
367 struct snd_pcm_substream *substream)
368{
369 struct via_spec *spec = codec->spec;
370 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
371 stream_tag, format, substream);
372}
373
374static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
375 struct hda_codec *codec,
376 struct snd_pcm_substream *substream)
377{
378 struct via_spec *spec = codec->spec;
379 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
380}
381
382/*
383 * Digital out
384 */
385static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
386 struct hda_codec *codec,
387 struct snd_pcm_substream *substream)
388{
389 struct via_spec *spec = codec->spec;
390 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
391}
392
393static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
394 struct hda_codec *codec,
395 struct snd_pcm_substream *substream)
396{
397 struct via_spec *spec = codec->spec;
398 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
399}
400
Takashi Iwai6b97eb42007-04-05 14:51:48 +0200401static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
402 struct hda_codec *codec,
403 unsigned int stream_tag,
404 unsigned int format,
405 struct snd_pcm_substream *substream)
406{
407 struct via_spec *spec = codec->spec;
408 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
409 stream_tag, format, substream);
410}
411
Joseph Chanc577b8a2006-11-29 15:29:40 +0100412/*
413 * Analog capture
414 */
415static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
416 struct hda_codec *codec,
417 unsigned int stream_tag,
418 unsigned int format,
419 struct snd_pcm_substream *substream)
420{
421 struct via_spec *spec = codec->spec;
422
423 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
424 stream_tag, 0, format);
425 return 0;
426}
427
428static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
429 struct hda_codec *codec,
430 struct snd_pcm_substream *substream)
431{
432 struct via_spec *spec = codec->spec;
433 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
434 0, 0, 0);
435 return 0;
436}
437
438static struct hda_pcm_stream vt1708_pcm_analog_playback = {
439 .substreams = 1,
440 .channels_min = 2,
441 .channels_max = 8,
442 .nid = 0x10, /* NID to query formats and rates */
443 .ops = {
444 .open = via_playback_pcm_open,
445 .prepare = via_playback_pcm_prepare,
446 .cleanup = via_playback_pcm_cleanup
447 },
448};
449
450static struct hda_pcm_stream vt1708_pcm_analog_capture = {
451 .substreams = 2,
452 .channels_min = 2,
453 .channels_max = 2,
454 .nid = 0x15, /* NID to query formats and rates */
455 .ops = {
456 .prepare = via_capture_pcm_prepare,
457 .cleanup = via_capture_pcm_cleanup
458 },
459};
460
461static struct hda_pcm_stream vt1708_pcm_digital_playback = {
462 .substreams = 1,
463 .channels_min = 2,
464 .channels_max = 2,
465 /* NID is set in via_build_pcms */
466 .ops = {
467 .open = via_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +0200468 .close = via_dig_playback_pcm_close,
469 .prepare = via_dig_playback_pcm_prepare
Joseph Chanc577b8a2006-11-29 15:29:40 +0100470 },
471};
472
473static struct hda_pcm_stream vt1708_pcm_digital_capture = {
474 .substreams = 1,
475 .channels_min = 2,
476 .channels_max = 2,
477};
478
479static int via_build_controls(struct hda_codec *codec)
480{
481 struct via_spec *spec = codec->spec;
482 int err;
483 int i;
484
485 for (i = 0; i < spec->num_mixers; i++) {
486 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
487 if (err < 0)
488 return err;
489 }
490
491 if (spec->multiout.dig_out_nid) {
492 err = snd_hda_create_spdif_out_ctls(codec,
493 spec->multiout.dig_out_nid);
494 if (err < 0)
495 return err;
496 }
497 if (spec->dig_in_nid) {
498 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
499 if (err < 0)
500 return err;
501 }
502 return 0;
503}
504
505static int via_build_pcms(struct hda_codec *codec)
506{
507 struct via_spec *spec = codec->spec;
508 struct hda_pcm *info = spec->pcm_rec;
509
510 codec->num_pcms = 1;
511 codec->pcm_info = info;
512
513 info->name = spec->stream_name_analog;
514 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
515 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
516 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
517 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
518
519 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
520 spec->multiout.max_channels;
521
522 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
523 codec->num_pcms++;
524 info++;
525 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +0100526 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100527 if (spec->multiout.dig_out_nid) {
528 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
529 *(spec->stream_digital_playback);
530 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
531 spec->multiout.dig_out_nid;
532 }
533 if (spec->dig_in_nid) {
534 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
535 *(spec->stream_digital_capture);
536 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
537 spec->dig_in_nid;
538 }
539 }
540
541 return 0;
542}
543
544static void via_free(struct hda_codec *codec)
545{
546 struct via_spec *spec = codec->spec;
547 unsigned int i;
548
549 if (!spec)
550 return;
551
552 if (spec->kctl_alloc) {
553 for (i = 0; i < spec->num_kctl_used; i++)
554 kfree(spec->kctl_alloc[i].name);
555 kfree(spec->kctl_alloc);
556 }
557
558 kfree(codec->spec);
559}
560
561static int via_init(struct hda_codec *codec)
562{
563 struct via_spec *spec = codec->spec;
564 snd_hda_sequence_write(codec, spec->init_verbs);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100565 /* Lydia Add for EAPD enable */
566 if (!spec->dig_in_nid) { /* No Digital In connection */
567 if (IS_VT1708_VENDORID(codec->vendor_id)) {
568 snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
569 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100570 PIN_OUT);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100571 snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
572 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
573 } else if (IS_VT1709_10CH_VENDORID(codec->vendor_id) ||
574 IS_VT1709_6CH_VENDORID(codec->vendor_id)) {
575 snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
576 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100577 PIN_OUT);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100578 snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
579 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
580 } else if (IS_VT1708B_8CH_VENDORID(codec->vendor_id) ||
581 IS_VT1708B_4CH_VENDORID(codec->vendor_id)) {
582 snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
583 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100584 PIN_OUT);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100585 snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
586 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
587 }
Takashi Iwai12b74c82008-01-15 12:39:38 +0100588 } else /* enable SPDIF-input pin */
589 snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
590 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100591
Joseph Chanc577b8a2006-11-29 15:29:40 +0100592 return 0;
593}
594
Takashi Iwaicb53c622007-08-10 17:21:45 +0200595#ifdef CONFIG_SND_HDA_POWER_SAVE
596static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
597{
598 struct via_spec *spec = codec->spec;
599 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
600}
601#endif
602
Joseph Chanc577b8a2006-11-29 15:29:40 +0100603/*
604 */
605static struct hda_codec_ops via_patch_ops = {
606 .build_controls = via_build_controls,
607 .build_pcms = via_build_pcms,
608 .init = via_init,
609 .free = via_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +0200610#ifdef CONFIG_SND_HDA_POWER_SAVE
611 .check_power_status = via_check_power_status,
612#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +0100613};
614
615/* fill in the dac_nids table from the parsed pin configuration */
616static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
617 const struct auto_pin_cfg *cfg)
618{
619 int i;
620 hda_nid_t nid;
621
622 spec->multiout.num_dacs = cfg->line_outs;
623
624 spec->multiout.dac_nids = spec->private_dac_nids;
625
626 for(i = 0; i < 4; i++) {
627 nid = cfg->line_out_pins[i];
628 if (nid) {
629 /* config dac list */
630 switch (i) {
631 case AUTO_SEQ_FRONT:
632 spec->multiout.dac_nids[i] = 0x10;
633 break;
634 case AUTO_SEQ_CENLFE:
635 spec->multiout.dac_nids[i] = 0x12;
636 break;
637 case AUTO_SEQ_SURROUND:
638 spec->multiout.dac_nids[i] = 0x13;
639 break;
640 case AUTO_SEQ_SIDE:
641 spec->multiout.dac_nids[i] = 0x11;
642 break;
643 }
644 }
645 }
646
647 return 0;
648}
649
650/* add playback controls from the parsed DAC table */
651static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
652 const struct auto_pin_cfg *cfg)
653{
654 char name[32];
655 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
656 hda_nid_t nid, nid_vol = 0;
657 int i, err;
658
659 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
660 nid = cfg->line_out_pins[i];
661
662 if (!nid)
663 continue;
664
665 if (i != AUTO_SEQ_FRONT)
666 nid_vol = 0x1b - i + 1;
667
668 if (i == AUTO_SEQ_CENLFE) {
669 /* Center/LFE */
670 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100671 "Center Playback Volume",
672 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
673 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100674 if (err < 0)
675 return err;
676 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
677 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100678 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
679 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100680 if (err < 0)
681 return err;
682 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
683 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100684 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
685 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100686 if (err < 0)
687 return err;
688 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
689 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100690 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
691 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100692 if (err < 0)
693 return err;
694 } else if (i == AUTO_SEQ_FRONT){
695 /* add control to mixer index 0 */
696 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
697 "Master Front Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100698 HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
699 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100700 if (err < 0)
701 return err;
702 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
703 "Master Front Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100704 HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
705 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100706 if (err < 0)
707 return err;
708
709 /* add control to PW3 */
710 sprintf(name, "%s Playback Volume", chname[i]);
711 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100712 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
713 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100714 if (err < 0)
715 return err;
716 sprintf(name, "%s Playback Switch", chname[i]);
717 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100718 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
719 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100720 if (err < 0)
721 return err;
722 } else {
723 sprintf(name, "%s Playback Volume", chname[i]);
724 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100725 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
726 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100727 if (err < 0)
728 return err;
729 sprintf(name, "%s Playback Switch", chname[i]);
730 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100731 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
732 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100733 if (err < 0)
734 return err;
735 }
736 }
737
738 return 0;
739}
740
741static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
742{
743 int err;
744
745 if (!pin)
746 return 0;
747
748 spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
749
750 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
751 "Headphone Playback Volume",
752 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
753 if (err < 0)
754 return err;
755 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
756 "Headphone Playback Switch",
757 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
758 if (err < 0)
759 return err;
760
761 return 0;
762}
763
764/* create playback/capture controls for input pins */
765static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
766 const struct auto_pin_cfg *cfg)
767{
768 static char *labels[] = {
769 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
770 };
771 struct hda_input_mux *imux = &spec->private_imux;
772 int i, err, idx = 0;
773
774 /* for internal loopback recording select */
775 imux->items[imux->num_items].label = "Stereo Mixer";
776 imux->items[imux->num_items].index = idx;
777 imux->num_items++;
778
779 for (i = 0; i < AUTO_PIN_LAST; i++) {
780 if (!cfg->input_pins[i])
781 continue;
782
783 switch (cfg->input_pins[i]) {
784 case 0x1d: /* Mic */
785 idx = 2;
786 break;
787
788 case 0x1e: /* Line In */
789 idx = 3;
790 break;
791
792 case 0x21: /* Front Mic */
793 idx = 4;
794 break;
795
796 case 0x24: /* CD */
797 idx = 1;
798 break;
799 }
800 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
801 idx, 0x17);
802 if (err < 0)
803 return err;
804 imux->items[imux->num_items].label = labels[i];
805 imux->items[imux->num_items].index = idx;
806 imux->num_items++;
807 }
808 return 0;
809}
810
Takashi Iwaicb53c622007-08-10 17:21:45 +0200811#ifdef CONFIG_SND_HDA_POWER_SAVE
812static struct hda_amp_list vt1708_loopbacks[] = {
813 { 0x17, HDA_INPUT, 1 },
814 { 0x17, HDA_INPUT, 2 },
815 { 0x17, HDA_INPUT, 3 },
816 { 0x17, HDA_INPUT, 4 },
817 { } /* end */
818};
819#endif
820
Joseph Chanc577b8a2006-11-29 15:29:40 +0100821static int vt1708_parse_auto_config(struct hda_codec *codec)
822{
823 struct via_spec *spec = codec->spec;
824 int err;
825
826 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
827 if (err < 0)
828 return err;
829 err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
830 if (err < 0)
831 return err;
832 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
833 return 0; /* can't find valid BIOS pin config */
834
835 err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
836 if (err < 0)
837 return err;
838 err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
839 if (err < 0)
840 return err;
841 err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
842 if (err < 0)
843 return err;
844
845 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
846
847 if (spec->autocfg.dig_out_pin)
848 spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
849 if (spec->autocfg.dig_in_pin)
850 spec->dig_in_nid = VT1708_DIGIN_NID;
851
852 if (spec->kctl_alloc)
853 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
854
855 spec->init_verbs = vt1708_volume_init_verbs;
856
857 spec->input_mux = &spec->private_imux;
858
859 return 1;
860}
861
862/* init callback for auto-configuration model -- overriding the default init */
863static int via_auto_init(struct hda_codec *codec)
864{
865 via_init(codec);
866 via_auto_init_multi_out(codec);
867 via_auto_init_hp_out(codec);
868 via_auto_init_analog_input(codec);
869 return 0;
870}
871
872static int patch_vt1708(struct hda_codec *codec)
873{
874 struct via_spec *spec;
875 int err;
876
877 /* create a codec specific record */
878 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
879 if (spec == NULL)
880 return -ENOMEM;
881
882 codec->spec = spec;
883
884 /* automatic parse from the BIOS config */
885 err = vt1708_parse_auto_config(codec);
886 if (err < 0) {
887 via_free(codec);
888 return err;
889 } else if (!err) {
890 printk(KERN_INFO "hda_codec: Cannot set up configuration "
891 "from BIOS. Using genenic mode...\n");
892 }
893
894
895 spec->stream_name_analog = "VT1708 Analog";
896 spec->stream_analog_playback = &vt1708_pcm_analog_playback;
897 spec->stream_analog_capture = &vt1708_pcm_analog_capture;
898
899 spec->stream_name_digital = "VT1708 Digital";
900 spec->stream_digital_playback = &vt1708_pcm_digital_playback;
901 spec->stream_digital_capture = &vt1708_pcm_digital_capture;
902
903
904 if (!spec->adc_nids && spec->input_mux) {
905 spec->adc_nids = vt1708_adc_nids;
906 spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
907 spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
908 spec->num_mixers++;
909 }
910
911 codec->patch_ops = via_patch_ops;
912
913 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200914#ifdef CONFIG_SND_HDA_POWER_SAVE
915 spec->loopback.amplist = vt1708_loopbacks;
916#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +0100917
918 return 0;
919}
920
921/* capture mixer elements */
922static struct snd_kcontrol_new vt1709_capture_mixer[] = {
923 HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
924 HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
925 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
926 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
927 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
928 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
929 {
930 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
931 /* The multiple "Capture Source" controls confuse alsamixer
932 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +0100933 */
934 /* .name = "Capture Source", */
935 .name = "Input Source",
936 .count = 1,
937 .info = via_mux_enum_info,
938 .get = via_mux_enum_get,
939 .put = via_mux_enum_put,
940 },
941 { } /* end */
942};
943
944/*
945 * generic initialization of ADC, input mixers and output mixers
946 */
947static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
948 /*
949 * Unmute ADC0-2 and set the default input to mic-in
950 */
951 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
952 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
953 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
954
955
Josepch Chanf7278fd2007-12-13 16:40:40 +0100956 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +0100957 * mixer widget
958 */
959 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +0100960 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
961 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
962 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
963 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
964 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100965
966 /*
967 * Set up output selector (0x1a, 0x1b, 0x29)
968 */
969 /* set vol=0 to output mixers */
970 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
971 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
972 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
973
974 /*
975 * Unmute PW3 and PW4
976 */
977 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
978 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
979
980 /* Set input of PW4 as AOW4 */
981 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100982 /* PW9 Output enable */
983 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
984 { }
985};
986
987static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
988 .substreams = 1,
989 .channels_min = 2,
990 .channels_max = 10,
991 .nid = 0x10, /* NID to query formats and rates */
992 .ops = {
993 .open = via_playback_pcm_open,
994 .prepare = via_playback_pcm_prepare,
995 .cleanup = via_playback_pcm_cleanup
996 },
997};
998
999static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
1000 .substreams = 1,
1001 .channels_min = 2,
1002 .channels_max = 6,
1003 .nid = 0x10, /* NID to query formats and rates */
1004 .ops = {
1005 .open = via_playback_pcm_open,
1006 .prepare = via_playback_pcm_prepare,
1007 .cleanup = via_playback_pcm_cleanup
1008 },
1009};
1010
1011static struct hda_pcm_stream vt1709_pcm_analog_capture = {
1012 .substreams = 2,
1013 .channels_min = 2,
1014 .channels_max = 2,
1015 .nid = 0x14, /* NID to query formats and rates */
1016 .ops = {
1017 .prepare = via_capture_pcm_prepare,
1018 .cleanup = via_capture_pcm_cleanup
1019 },
1020};
1021
1022static struct hda_pcm_stream vt1709_pcm_digital_playback = {
1023 .substreams = 1,
1024 .channels_min = 2,
1025 .channels_max = 2,
1026 /* NID is set in via_build_pcms */
1027 .ops = {
1028 .open = via_dig_playback_pcm_open,
1029 .close = via_dig_playback_pcm_close
1030 },
1031};
1032
1033static struct hda_pcm_stream vt1709_pcm_digital_capture = {
1034 .substreams = 1,
1035 .channels_min = 2,
1036 .channels_max = 2,
1037};
1038
1039static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
1040 const struct auto_pin_cfg *cfg)
1041{
1042 int i;
1043 hda_nid_t nid;
1044
1045 if (cfg->line_outs == 4) /* 10 channels */
1046 spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
1047 else if (cfg->line_outs == 3) /* 6 channels */
1048 spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
1049
1050 spec->multiout.dac_nids = spec->private_dac_nids;
1051
1052 if (cfg->line_outs == 4) { /* 10 channels */
1053 for (i = 0; i < cfg->line_outs; i++) {
1054 nid = cfg->line_out_pins[i];
1055 if (nid) {
1056 /* config dac list */
1057 switch (i) {
1058 case AUTO_SEQ_FRONT:
1059 /* AOW0 */
1060 spec->multiout.dac_nids[i] = 0x10;
1061 break;
1062 case AUTO_SEQ_CENLFE:
1063 /* AOW2 */
1064 spec->multiout.dac_nids[i] = 0x12;
1065 break;
1066 case AUTO_SEQ_SURROUND:
1067 /* AOW3 */
1068 spec->multiout.dac_nids[i] = 0x27;
1069 break;
1070 case AUTO_SEQ_SIDE:
1071 /* AOW1 */
1072 spec->multiout.dac_nids[i] = 0x11;
1073 break;
1074 default:
1075 break;
1076 }
1077 }
1078 }
1079 spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
1080
1081 } else if (cfg->line_outs == 3) { /* 6 channels */
1082 for(i = 0; i < cfg->line_outs; i++) {
1083 nid = cfg->line_out_pins[i];
1084 if (nid) {
1085 /* config dac list */
1086 switch(i) {
1087 case AUTO_SEQ_FRONT:
1088 /* AOW0 */
1089 spec->multiout.dac_nids[i] = 0x10;
1090 break;
1091 case AUTO_SEQ_CENLFE:
1092 /* AOW2 */
1093 spec->multiout.dac_nids[i] = 0x12;
1094 break;
1095 case AUTO_SEQ_SURROUND:
1096 /* AOW1 */
1097 spec->multiout.dac_nids[i] = 0x11;
1098 break;
1099 default:
1100 break;
1101 }
1102 }
1103 }
1104 }
1105
1106 return 0;
1107}
1108
1109/* add playback controls from the parsed DAC table */
1110static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
1111 const struct auto_pin_cfg *cfg)
1112{
1113 char name[32];
1114 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1115 hda_nid_t nid = 0;
1116 int i, err;
1117
1118 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1119 nid = cfg->line_out_pins[i];
1120
1121 if (!nid)
1122 continue;
1123
1124 if (i == AUTO_SEQ_CENLFE) {
1125 /* Center/LFE */
1126 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1127 "Center Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001128 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
1129 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001130 if (err < 0)
1131 return err;
1132 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1133 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001134 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
1135 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001136 if (err < 0)
1137 return err;
1138 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1139 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001140 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
1141 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001142 if (err < 0)
1143 return err;
1144 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1145 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001146 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
1147 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001148 if (err < 0)
1149 return err;
1150 } else if (i == AUTO_SEQ_FRONT){
1151 /* add control to mixer index 0 */
1152 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1153 "Master Front Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001154 HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
1155 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001156 if (err < 0)
1157 return err;
1158 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1159 "Master Front Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001160 HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
1161 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001162 if (err < 0)
1163 return err;
1164
1165 /* add control to PW3 */
1166 sprintf(name, "%s Playback Volume", chname[i]);
1167 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001168 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1169 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001170 if (err < 0)
1171 return err;
1172 sprintf(name, "%s Playback Switch", chname[i]);
1173 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001174 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1175 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001176 if (err < 0)
1177 return err;
1178 } else if (i == AUTO_SEQ_SURROUND) {
1179 sprintf(name, "%s Playback Volume", chname[i]);
1180 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001181 HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
1182 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001183 if (err < 0)
1184 return err;
1185 sprintf(name, "%s Playback Switch", chname[i]);
1186 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001187 HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
1188 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001189 if (err < 0)
1190 return err;
1191 } else if (i == AUTO_SEQ_SIDE) {
1192 sprintf(name, "%s Playback Volume", chname[i]);
1193 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001194 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
1195 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001196 if (err < 0)
1197 return err;
1198 sprintf(name, "%s Playback Switch", chname[i]);
1199 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001200 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
1201 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001202 if (err < 0)
1203 return err;
1204 }
1205 }
1206
1207 return 0;
1208}
1209
1210static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1211{
1212 int err;
1213
1214 if (!pin)
1215 return 0;
1216
1217 if (spec->multiout.num_dacs == 5) /* 10 channels */
1218 spec->multiout.hp_nid = VT1709_HP_DAC_NID;
1219 else if (spec->multiout.num_dacs == 3) /* 6 channels */
1220 spec->multiout.hp_nid = 0;
1221
1222 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1223 "Headphone Playback Volume",
1224 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1225 if (err < 0)
1226 return err;
1227 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1228 "Headphone Playback Switch",
1229 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1230 if (err < 0)
1231 return err;
1232
1233 return 0;
1234}
1235
1236/* create playback/capture controls for input pins */
1237static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
1238 const struct auto_pin_cfg *cfg)
1239{
1240 static char *labels[] = {
1241 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1242 };
1243 struct hda_input_mux *imux = &spec->private_imux;
1244 int i, err, idx = 0;
1245
1246 /* for internal loopback recording select */
1247 imux->items[imux->num_items].label = "Stereo Mixer";
1248 imux->items[imux->num_items].index = idx;
1249 imux->num_items++;
1250
1251 for (i = 0; i < AUTO_PIN_LAST; i++) {
1252 if (!cfg->input_pins[i])
1253 continue;
1254
1255 switch (cfg->input_pins[i]) {
1256 case 0x1d: /* Mic */
1257 idx = 2;
1258 break;
1259
1260 case 0x1e: /* Line In */
1261 idx = 3;
1262 break;
1263
1264 case 0x21: /* Front Mic */
1265 idx = 4;
1266 break;
1267
1268 case 0x23: /* CD */
1269 idx = 1;
1270 break;
1271 }
1272 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
1273 idx, 0x18);
1274 if (err < 0)
1275 return err;
1276 imux->items[imux->num_items].label = labels[i];
1277 imux->items[imux->num_items].index = idx;
1278 imux->num_items++;
1279 }
1280 return 0;
1281}
1282
1283static int vt1709_parse_auto_config(struct hda_codec *codec)
1284{
1285 struct via_spec *spec = codec->spec;
1286 int err;
1287
1288 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1289 if (err < 0)
1290 return err;
1291 err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
1292 if (err < 0)
1293 return err;
1294 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1295 return 0; /* can't find valid BIOS pin config */
1296
1297 err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
1298 if (err < 0)
1299 return err;
1300 err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1301 if (err < 0)
1302 return err;
1303 err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
1304 if (err < 0)
1305 return err;
1306
1307 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1308
1309 if (spec->autocfg.dig_out_pin)
1310 spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
1311 if (spec->autocfg.dig_in_pin)
1312 spec->dig_in_nid = VT1709_DIGIN_NID;
1313
1314 if (spec->kctl_alloc)
1315 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
1316
1317 spec->input_mux = &spec->private_imux;
1318
1319 return 1;
1320}
1321
Takashi Iwaicb53c622007-08-10 17:21:45 +02001322#ifdef CONFIG_SND_HDA_POWER_SAVE
1323static struct hda_amp_list vt1709_loopbacks[] = {
1324 { 0x18, HDA_INPUT, 1 },
1325 { 0x18, HDA_INPUT, 2 },
1326 { 0x18, HDA_INPUT, 3 },
1327 { 0x18, HDA_INPUT, 4 },
1328 { } /* end */
1329};
1330#endif
1331
Joseph Chanc577b8a2006-11-29 15:29:40 +01001332static int patch_vt1709_10ch(struct hda_codec *codec)
1333{
1334 struct via_spec *spec;
1335 int err;
1336
1337 /* create a codec specific record */
1338 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
1339 if (spec == NULL)
1340 return -ENOMEM;
1341
1342 codec->spec = spec;
1343
1344 err = vt1709_parse_auto_config(codec);
1345 if (err < 0) {
1346 via_free(codec);
1347 return err;
1348 } else if (!err) {
1349 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
1350 "Using genenic mode...\n");
1351 }
1352
1353 spec->init_verbs = vt1709_10ch_volume_init_verbs;
1354
1355 spec->stream_name_analog = "VT1709 Analog";
1356 spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
1357 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1358
1359 spec->stream_name_digital = "VT1709 Digital";
1360 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1361 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1362
1363
1364 if (!spec->adc_nids && spec->input_mux) {
1365 spec->adc_nids = vt1709_adc_nids;
1366 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
1367 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1368 spec->num_mixers++;
1369 }
1370
1371 codec->patch_ops = via_patch_ops;
1372
1373 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001374#ifdef CONFIG_SND_HDA_POWER_SAVE
1375 spec->loopback.amplist = vt1709_loopbacks;
1376#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001377
1378 return 0;
1379}
1380/*
1381 * generic initialization of ADC, input mixers and output mixers
1382 */
1383static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
1384 /*
1385 * Unmute ADC0-2 and set the default input to mic-in
1386 */
1387 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1388 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1389 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1390
1391
1392 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1393 * mixer widget
1394 */
1395 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1396 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1397 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1398 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1399 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1400 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1401
1402 /*
1403 * Set up output selector (0x1a, 0x1b, 0x29)
1404 */
1405 /* set vol=0 to output mixers */
1406 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1407 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1408 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1409
1410 /*
1411 * Unmute PW3 and PW4
1412 */
1413 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1414 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1415
1416 /* Set input of PW4 as MW0 */
1417 {0x20, AC_VERB_SET_CONNECT_SEL, 0},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001418 /* PW9 Output enable */
1419 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1420 { }
1421};
1422
1423static int patch_vt1709_6ch(struct hda_codec *codec)
1424{
1425 struct via_spec *spec;
1426 int err;
1427
1428 /* create a codec specific record */
1429 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
1430 if (spec == NULL)
1431 return -ENOMEM;
1432
1433 codec->spec = spec;
1434
1435 err = vt1709_parse_auto_config(codec);
1436 if (err < 0) {
1437 via_free(codec);
1438 return err;
1439 } else if (!err) {
1440 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
1441 "Using genenic mode...\n");
1442 }
1443
1444 spec->init_verbs = vt1709_6ch_volume_init_verbs;
1445
1446 spec->stream_name_analog = "VT1709 Analog";
1447 spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
1448 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1449
1450 spec->stream_name_digital = "VT1709 Digital";
1451 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1452 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1453
1454
1455 if (!spec->adc_nids && spec->input_mux) {
1456 spec->adc_nids = vt1709_adc_nids;
1457 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
1458 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1459 spec->num_mixers++;
1460 }
1461
1462 codec->patch_ops = via_patch_ops;
1463
1464 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001465#ifdef CONFIG_SND_HDA_POWER_SAVE
1466 spec->loopback.amplist = vt1709_loopbacks;
1467#endif
Josepch Chanf7278fd2007-12-13 16:40:40 +01001468 return 0;
1469}
1470
1471/* capture mixer elements */
1472static struct snd_kcontrol_new vt1708B_capture_mixer[] = {
1473 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
1474 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
1475 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
1476 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
1477 {
1478 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1479 /* The multiple "Capture Source" controls confuse alsamixer
1480 * So call somewhat different..
Josepch Chanf7278fd2007-12-13 16:40:40 +01001481 */
1482 /* .name = "Capture Source", */
1483 .name = "Input Source",
1484 .count = 1,
1485 .info = via_mux_enum_info,
1486 .get = via_mux_enum_get,
1487 .put = via_mux_enum_put,
1488 },
1489 { } /* end */
1490};
1491/*
1492 * generic initialization of ADC, input mixers and output mixers
1493 */
1494static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
1495 /*
1496 * Unmute ADC0-1 and set the default input to mic-in
1497 */
1498 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1499 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1500
1501
1502 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1503 * mixer widget
1504 */
1505 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1506 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1507 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1508 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1509 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1510 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1511
1512 /*
1513 * Set up output mixers
1514 */
1515 /* set vol=0 to output mixers */
1516 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1517 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1518 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1519
1520 /* Setup default input to PW4 */
1521 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1},
1522 /* PW9 Output enable */
1523 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1524 /* PW10 Input enable */
1525 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
1526 { }
1527};
1528
1529static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
1530 /*
1531 * Unmute ADC0-1 and set the default input to mic-in
1532 */
1533 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1534 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1535
1536
1537 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1538 * mixer widget
1539 */
1540 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1541 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1542 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1543 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1544 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1545 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1546
1547 /*
1548 * Set up output mixers
1549 */
1550 /* set vol=0 to output mixers */
1551 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1552 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1553 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1554
1555 /* Setup default input of PW4 to MW0 */
1556 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
1557 /* PW9 Output enable */
1558 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1559 /* PW10 Input enable */
1560 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
1561 { }
1562};
1563
1564static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
1565 .substreams = 1,
1566 .channels_min = 2,
1567 .channels_max = 8,
1568 .nid = 0x10, /* NID to query formats and rates */
1569 .ops = {
1570 .open = via_playback_pcm_open,
1571 .prepare = via_playback_pcm_prepare,
1572 .cleanup = via_playback_pcm_cleanup
1573 },
1574};
1575
1576static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
1577 .substreams = 1,
1578 .channels_min = 2,
1579 .channels_max = 4,
1580 .nid = 0x10, /* NID to query formats and rates */
1581 .ops = {
1582 .open = via_playback_pcm_open,
1583 .prepare = via_playback_pcm_prepare,
1584 .cleanup = via_playback_pcm_cleanup
1585 },
1586};
1587
1588static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
1589 .substreams = 2,
1590 .channels_min = 2,
1591 .channels_max = 2,
1592 .nid = 0x13, /* NID to query formats and rates */
1593 .ops = {
1594 .prepare = via_capture_pcm_prepare,
1595 .cleanup = via_capture_pcm_cleanup
1596 },
1597};
1598
1599static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
1600 .substreams = 1,
1601 .channels_min = 2,
1602 .channels_max = 2,
1603 /* NID is set in via_build_pcms */
1604 .ops = {
1605 .open = via_dig_playback_pcm_open,
1606 .close = via_dig_playback_pcm_close,
1607 .prepare = via_dig_playback_pcm_prepare
1608 },
1609};
1610
1611static struct hda_pcm_stream vt1708B_pcm_digital_capture = {
1612 .substreams = 1,
1613 .channels_min = 2,
1614 .channels_max = 2,
1615};
1616
1617/* fill in the dac_nids table from the parsed pin configuration */
1618static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
1619 const struct auto_pin_cfg *cfg)
1620{
1621 int i;
1622 hda_nid_t nid;
1623
1624 spec->multiout.num_dacs = cfg->line_outs;
1625
1626 spec->multiout.dac_nids = spec->private_dac_nids;
1627
1628 for (i = 0; i < 4; i++) {
1629 nid = cfg->line_out_pins[i];
1630 if (nid) {
1631 /* config dac list */
1632 switch (i) {
1633 case AUTO_SEQ_FRONT:
1634 spec->multiout.dac_nids[i] = 0x10;
1635 break;
1636 case AUTO_SEQ_CENLFE:
1637 spec->multiout.dac_nids[i] = 0x24;
1638 break;
1639 case AUTO_SEQ_SURROUND:
1640 spec->multiout.dac_nids[i] = 0x25;
1641 break;
1642 case AUTO_SEQ_SIDE:
1643 spec->multiout.dac_nids[i] = 0x11;
1644 break;
1645 }
1646 }
1647 }
1648
1649 return 0;
1650}
1651
1652/* add playback controls from the parsed DAC table */
1653static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
1654 const struct auto_pin_cfg *cfg)
1655{
1656 char name[32];
1657 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1658 hda_nid_t nid_vols[] = {0x16, 0x27, 0x26, 0x18};
1659 hda_nid_t nid, nid_vol = 0;
1660 int i, err;
1661
1662 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1663 nid = cfg->line_out_pins[i];
1664
1665 if (!nid)
1666 continue;
1667
1668 nid_vol = nid_vols[i];
1669
1670 if (i == AUTO_SEQ_CENLFE) {
1671 /* Center/LFE */
1672 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1673 "Center Playback Volume",
1674 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1675 HDA_OUTPUT));
1676 if (err < 0)
1677 return err;
1678 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1679 "LFE Playback Volume",
1680 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1681 HDA_OUTPUT));
1682 if (err < 0)
1683 return err;
1684 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1685 "Center Playback Switch",
1686 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1687 HDA_OUTPUT));
1688 if (err < 0)
1689 return err;
1690 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1691 "LFE Playback Switch",
1692 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1693 HDA_OUTPUT));
1694 if (err < 0)
1695 return err;
1696 } else if (i == AUTO_SEQ_FRONT) {
1697 /* add control to mixer index 0 */
1698 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1699 "Master Front Playback Volume",
1700 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1701 HDA_INPUT));
1702 if (err < 0)
1703 return err;
1704 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1705 "Master Front Playback Switch",
1706 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1707 HDA_INPUT));
1708 if (err < 0)
1709 return err;
1710
1711 /* add control to PW3 */
1712 sprintf(name, "%s Playback Volume", chname[i]);
1713 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1714 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1715 HDA_OUTPUT));
1716 if (err < 0)
1717 return err;
1718 sprintf(name, "%s Playback Switch", chname[i]);
1719 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1720 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1721 HDA_OUTPUT));
1722 if (err < 0)
1723 return err;
1724 } else {
1725 sprintf(name, "%s Playback Volume", chname[i]);
1726 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1727 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1728 HDA_OUTPUT));
1729 if (err < 0)
1730 return err;
1731 sprintf(name, "%s Playback Switch", chname[i]);
1732 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1733 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1734 HDA_OUTPUT));
1735 if (err < 0)
1736 return err;
1737 }
1738 }
1739
1740 return 0;
1741}
1742
1743static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1744{
1745 int err;
1746
1747 if (!pin)
1748 return 0;
1749
1750 spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
1751
1752 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1753 "Headphone Playback Volume",
1754 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1755 if (err < 0)
1756 return err;
1757 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1758 "Headphone Playback Switch",
1759 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1760 if (err < 0)
1761 return err;
1762
1763 return 0;
1764}
1765
1766/* create playback/capture controls for input pins */
1767static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
1768 const struct auto_pin_cfg *cfg)
1769{
1770 static char *labels[] = {
1771 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1772 };
1773 struct hda_input_mux *imux = &spec->private_imux;
1774 int i, err, idx = 0;
1775
1776 /* for internal loopback recording select */
1777 imux->items[imux->num_items].label = "Stereo Mixer";
1778 imux->items[imux->num_items].index = idx;
1779 imux->num_items++;
1780
1781 for (i = 0; i < AUTO_PIN_LAST; i++) {
1782 if (!cfg->input_pins[i])
1783 continue;
1784
1785 switch (cfg->input_pins[i]) {
1786 case 0x1a: /* Mic */
1787 idx = 2;
1788 break;
1789
1790 case 0x1b: /* Line In */
1791 idx = 3;
1792 break;
1793
1794 case 0x1e: /* Front Mic */
1795 idx = 4;
1796 break;
1797
1798 case 0x1f: /* CD */
1799 idx = 1;
1800 break;
1801 }
1802 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
1803 idx, 0x16);
1804 if (err < 0)
1805 return err;
1806 imux->items[imux->num_items].label = labels[i];
1807 imux->items[imux->num_items].index = idx;
1808 imux->num_items++;
1809 }
1810 return 0;
1811}
1812
1813static int vt1708B_parse_auto_config(struct hda_codec *codec)
1814{
1815 struct via_spec *spec = codec->spec;
1816 int err;
1817
1818 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1819 if (err < 0)
1820 return err;
1821 err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg);
1822 if (err < 0)
1823 return err;
1824 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1825 return 0; /* can't find valid BIOS pin config */
1826
1827 err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg);
1828 if (err < 0)
1829 return err;
1830 err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1831 if (err < 0)
1832 return err;
1833 err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
1834 if (err < 0)
1835 return err;
1836
1837 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1838
1839 if (spec->autocfg.dig_out_pin)
1840 spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
1841 if (spec->autocfg.dig_in_pin)
1842 spec->dig_in_nid = VT1708B_DIGIN_NID;
1843
1844 if (spec->kctl_alloc)
1845 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
1846
1847 spec->input_mux = &spec->private_imux;
1848
1849 return 1;
1850}
1851
1852#ifdef CONFIG_SND_HDA_POWER_SAVE
1853static struct hda_amp_list vt1708B_loopbacks[] = {
1854 { 0x16, HDA_INPUT, 1 },
1855 { 0x16, HDA_INPUT, 2 },
1856 { 0x16, HDA_INPUT, 3 },
1857 { 0x16, HDA_INPUT, 4 },
1858 { } /* end */
1859};
1860#endif
1861
1862static int patch_vt1708B_8ch(struct hda_codec *codec)
1863{
1864 struct via_spec *spec;
1865 int err;
1866
1867 /* create a codec specific record */
1868 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
1869 if (spec == NULL)
1870 return -ENOMEM;
1871
1872 codec->spec = spec;
1873
1874 /* automatic parse from the BIOS config */
1875 err = vt1708B_parse_auto_config(codec);
1876 if (err < 0) {
1877 via_free(codec);
1878 return err;
1879 } else if (!err) {
1880 printk(KERN_INFO "hda_codec: Cannot set up configuration "
1881 "from BIOS. Using genenic mode...\n");
1882 }
1883
1884 spec->init_verbs = vt1708B_8ch_volume_init_verbs;
1885
1886 spec->stream_name_analog = "VT1708B Analog";
1887 spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
1888 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
1889
1890 spec->stream_name_digital = "VT1708B Digital";
1891 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
1892 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
1893
1894 if (!spec->adc_nids && spec->input_mux) {
1895 spec->adc_nids = vt1708B_adc_nids;
1896 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
1897 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
1898 spec->num_mixers++;
1899 }
1900
1901 codec->patch_ops = via_patch_ops;
1902
1903 codec->patch_ops.init = via_auto_init;
1904#ifdef CONFIG_SND_HDA_POWER_SAVE
1905 spec->loopback.amplist = vt1708B_loopbacks;
1906#endif
1907
1908 return 0;
1909}
1910
1911static int patch_vt1708B_4ch(struct hda_codec *codec)
1912{
1913 struct via_spec *spec;
1914 int err;
1915
1916 /* create a codec specific record */
1917 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
1918 if (spec == NULL)
1919 return -ENOMEM;
1920
1921 codec->spec = spec;
1922
1923 /* automatic parse from the BIOS config */
1924 err = vt1708B_parse_auto_config(codec);
1925 if (err < 0) {
1926 via_free(codec);
1927 return err;
1928 } else if (!err) {
1929 printk(KERN_INFO "hda_codec: Cannot set up configuration "
1930 "from BIOS. Using genenic mode...\n");
1931 }
1932
1933 spec->init_verbs = vt1708B_4ch_volume_init_verbs;
1934
1935 spec->stream_name_analog = "VT1708B Analog";
1936 spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
1937 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
1938
1939 spec->stream_name_digital = "VT1708B Digital";
1940 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
1941 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
1942
1943 if (!spec->adc_nids && spec->input_mux) {
1944 spec->adc_nids = vt1708B_adc_nids;
1945 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
1946 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
1947 spec->num_mixers++;
1948 }
1949
1950 codec->patch_ops = via_patch_ops;
1951
1952 codec->patch_ops.init = via_auto_init;
1953#ifdef CONFIG_SND_HDA_POWER_SAVE
1954 spec->loopback.amplist = vt1708B_loopbacks;
1955#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001956
1957 return 0;
1958}
1959
1960/*
1961 * patch entries
1962 */
1963struct hda_codec_preset snd_hda_preset_via[] = {
1964 { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708},
1965 { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708},
1966 { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708},
1967 { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708},
Josepch Chanf7278fd2007-12-13 16:40:40 +01001968 { .id = 0x1106E710, .name = "VIA VT1709 10-Ch",
1969 .patch = patch_vt1709_10ch},
1970 { .id = 0x1106E711, .name = "VIA VT1709 10-Ch",
1971 .patch = patch_vt1709_10ch},
1972 { .id = 0x1106E712, .name = "VIA VT1709 10-Ch",
1973 .patch = patch_vt1709_10ch},
1974 { .id = 0x1106E713, .name = "VIA VT1709 10-Ch",
1975 .patch = patch_vt1709_10ch},
1976 { .id = 0x1106E714, .name = "VIA VT1709 6-Ch",
1977 .patch = patch_vt1709_6ch},
1978 { .id = 0x1106E715, .name = "VIA VT1709 6-Ch",
1979 .patch = patch_vt1709_6ch},
1980 { .id = 0x1106E716, .name = "VIA VT1709 6-Ch",
1981 .patch = patch_vt1709_6ch},
1982 { .id = 0x1106E717, .name = "VIA VT1709 6-Ch",
1983 .patch = patch_vt1709_6ch},
1984 { .id = 0x1106E720, .name = "VIA VT1708B 8-Ch",
1985 .patch = patch_vt1708B_8ch},
1986 { .id = 0x1106E721, .name = "VIA VT1708B 8-Ch",
1987 .patch = patch_vt1708B_8ch},
1988 { .id = 0x1106E722, .name = "VIA VT1708B 8-Ch",
1989 .patch = patch_vt1708B_8ch},
1990 { .id = 0x1106E723, .name = "VIA VT1708B 8-Ch",
1991 .patch = patch_vt1708B_8ch},
1992 { .id = 0x1106E724, .name = "VIA VT1708B 4-Ch",
1993 .patch = patch_vt1708B_4ch},
1994 { .id = 0x1106E725, .name = "VIA VT1708B 4-Ch",
1995 .patch = patch_vt1708B_4ch},
1996 { .id = 0x1106E726, .name = "VIA VT1708B 4-Ch",
1997 .patch = patch_vt1708B_4ch},
1998 { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch",
1999 .patch = patch_vt1708B_4ch},
Joseph Chanc577b8a2006-11-29 15:29:40 +01002000 {} /* terminator */
2001};