blob: 4e5dd4cf36f5f6404852e9ef70a0fc7110fc5730 [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;
526 if (spec->multiout.dig_out_nid) {
527 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
528 *(spec->stream_digital_playback);
529 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
530 spec->multiout.dig_out_nid;
531 }
532 if (spec->dig_in_nid) {
533 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
534 *(spec->stream_digital_capture);
535 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
536 spec->dig_in_nid;
537 }
538 }
539
540 return 0;
541}
542
543static void via_free(struct hda_codec *codec)
544{
545 struct via_spec *spec = codec->spec;
546 unsigned int i;
547
548 if (!spec)
549 return;
550
551 if (spec->kctl_alloc) {
552 for (i = 0; i < spec->num_kctl_used; i++)
553 kfree(spec->kctl_alloc[i].name);
554 kfree(spec->kctl_alloc);
555 }
556
557 kfree(codec->spec);
558}
559
560static int via_init(struct hda_codec *codec)
561{
562 struct via_spec *spec = codec->spec;
563 snd_hda_sequence_write(codec, spec->init_verbs);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100564 /* Lydia Add for EAPD enable */
565 if (!spec->dig_in_nid) { /* No Digital In connection */
566 if (IS_VT1708_VENDORID(codec->vendor_id)) {
567 snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
568 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100569 PIN_OUT);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100570 snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
571 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
572 } else if (IS_VT1709_10CH_VENDORID(codec->vendor_id) ||
573 IS_VT1709_6CH_VENDORID(codec->vendor_id)) {
574 snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
575 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100576 PIN_OUT);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100577 snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
578 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
579 } else if (IS_VT1708B_8CH_VENDORID(codec->vendor_id) ||
580 IS_VT1708B_4CH_VENDORID(codec->vendor_id)) {
581 snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
582 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100583 PIN_OUT);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100584 snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
585 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
586 }
Takashi Iwai12b74c82008-01-15 12:39:38 +0100587 } else /* enable SPDIF-input pin */
588 snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
589 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100590
Joseph Chanc577b8a2006-11-29 15:29:40 +0100591 return 0;
592}
593
Takashi Iwaicb53c622007-08-10 17:21:45 +0200594#ifdef CONFIG_SND_HDA_POWER_SAVE
595static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
596{
597 struct via_spec *spec = codec->spec;
598 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
599}
600#endif
601
Joseph Chanc577b8a2006-11-29 15:29:40 +0100602/*
603 */
604static struct hda_codec_ops via_patch_ops = {
605 .build_controls = via_build_controls,
606 .build_pcms = via_build_pcms,
607 .init = via_init,
608 .free = via_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +0200609#ifdef CONFIG_SND_HDA_POWER_SAVE
610 .check_power_status = via_check_power_status,
611#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +0100612};
613
614/* fill in the dac_nids table from the parsed pin configuration */
615static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
616 const struct auto_pin_cfg *cfg)
617{
618 int i;
619 hda_nid_t nid;
620
621 spec->multiout.num_dacs = cfg->line_outs;
622
623 spec->multiout.dac_nids = spec->private_dac_nids;
624
625 for(i = 0; i < 4; i++) {
626 nid = cfg->line_out_pins[i];
627 if (nid) {
628 /* config dac list */
629 switch (i) {
630 case AUTO_SEQ_FRONT:
631 spec->multiout.dac_nids[i] = 0x10;
632 break;
633 case AUTO_SEQ_CENLFE:
634 spec->multiout.dac_nids[i] = 0x12;
635 break;
636 case AUTO_SEQ_SURROUND:
637 spec->multiout.dac_nids[i] = 0x13;
638 break;
639 case AUTO_SEQ_SIDE:
640 spec->multiout.dac_nids[i] = 0x11;
641 break;
642 }
643 }
644 }
645
646 return 0;
647}
648
649/* add playback controls from the parsed DAC table */
650static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
651 const struct auto_pin_cfg *cfg)
652{
653 char name[32];
654 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
655 hda_nid_t nid, nid_vol = 0;
656 int i, err;
657
658 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
659 nid = cfg->line_out_pins[i];
660
661 if (!nid)
662 continue;
663
664 if (i != AUTO_SEQ_FRONT)
665 nid_vol = 0x1b - i + 1;
666
667 if (i == AUTO_SEQ_CENLFE) {
668 /* Center/LFE */
669 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100670 "Center Playback Volume",
671 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
672 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100673 if (err < 0)
674 return err;
675 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
676 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100677 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
678 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100679 if (err < 0)
680 return err;
681 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
682 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100683 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
684 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100685 if (err < 0)
686 return err;
687 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
688 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100689 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
690 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100691 if (err < 0)
692 return err;
693 } else if (i == AUTO_SEQ_FRONT){
694 /* add control to mixer index 0 */
695 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
696 "Master Front Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100697 HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
698 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100699 if (err < 0)
700 return err;
701 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
702 "Master Front Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100703 HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
704 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100705 if (err < 0)
706 return err;
707
708 /* add control to PW3 */
709 sprintf(name, "%s Playback Volume", chname[i]);
710 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100711 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
712 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100713 if (err < 0)
714 return err;
715 sprintf(name, "%s Playback Switch", chname[i]);
716 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100717 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
718 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100719 if (err < 0)
720 return err;
721 } else {
722 sprintf(name, "%s Playback Volume", chname[i]);
723 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100724 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
725 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100726 if (err < 0)
727 return err;
728 sprintf(name, "%s Playback Switch", chname[i]);
729 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100730 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
731 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100732 if (err < 0)
733 return err;
734 }
735 }
736
737 return 0;
738}
739
740static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
741{
742 int err;
743
744 if (!pin)
745 return 0;
746
747 spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
748
749 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
750 "Headphone Playback Volume",
751 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
752 if (err < 0)
753 return err;
754 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
755 "Headphone Playback Switch",
756 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
757 if (err < 0)
758 return err;
759
760 return 0;
761}
762
763/* create playback/capture controls for input pins */
764static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
765 const struct auto_pin_cfg *cfg)
766{
767 static char *labels[] = {
768 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
769 };
770 struct hda_input_mux *imux = &spec->private_imux;
771 int i, err, idx = 0;
772
773 /* for internal loopback recording select */
774 imux->items[imux->num_items].label = "Stereo Mixer";
775 imux->items[imux->num_items].index = idx;
776 imux->num_items++;
777
778 for (i = 0; i < AUTO_PIN_LAST; i++) {
779 if (!cfg->input_pins[i])
780 continue;
781
782 switch (cfg->input_pins[i]) {
783 case 0x1d: /* Mic */
784 idx = 2;
785 break;
786
787 case 0x1e: /* Line In */
788 idx = 3;
789 break;
790
791 case 0x21: /* Front Mic */
792 idx = 4;
793 break;
794
795 case 0x24: /* CD */
796 idx = 1;
797 break;
798 }
799 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
800 idx, 0x17);
801 if (err < 0)
802 return err;
803 imux->items[imux->num_items].label = labels[i];
804 imux->items[imux->num_items].index = idx;
805 imux->num_items++;
806 }
807 return 0;
808}
809
Takashi Iwaicb53c622007-08-10 17:21:45 +0200810#ifdef CONFIG_SND_HDA_POWER_SAVE
811static struct hda_amp_list vt1708_loopbacks[] = {
812 { 0x17, HDA_INPUT, 1 },
813 { 0x17, HDA_INPUT, 2 },
814 { 0x17, HDA_INPUT, 3 },
815 { 0x17, HDA_INPUT, 4 },
816 { } /* end */
817};
818#endif
819
Joseph Chanc577b8a2006-11-29 15:29:40 +0100820static int vt1708_parse_auto_config(struct hda_codec *codec)
821{
822 struct via_spec *spec = codec->spec;
823 int err;
824
825 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
826 if (err < 0)
827 return err;
828 err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
829 if (err < 0)
830 return err;
831 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
832 return 0; /* can't find valid BIOS pin config */
833
834 err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
835 if (err < 0)
836 return err;
837 err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
838 if (err < 0)
839 return err;
840 err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
841 if (err < 0)
842 return err;
843
844 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
845
846 if (spec->autocfg.dig_out_pin)
847 spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
848 if (spec->autocfg.dig_in_pin)
849 spec->dig_in_nid = VT1708_DIGIN_NID;
850
851 if (spec->kctl_alloc)
852 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
853
854 spec->init_verbs = vt1708_volume_init_verbs;
855
856 spec->input_mux = &spec->private_imux;
857
858 return 1;
859}
860
861/* init callback for auto-configuration model -- overriding the default init */
862static int via_auto_init(struct hda_codec *codec)
863{
864 via_init(codec);
865 via_auto_init_multi_out(codec);
866 via_auto_init_hp_out(codec);
867 via_auto_init_analog_input(codec);
868 return 0;
869}
870
871static int patch_vt1708(struct hda_codec *codec)
872{
873 struct via_spec *spec;
874 int err;
875
876 /* create a codec specific record */
877 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
878 if (spec == NULL)
879 return -ENOMEM;
880
881 codec->spec = spec;
882
883 /* automatic parse from the BIOS config */
884 err = vt1708_parse_auto_config(codec);
885 if (err < 0) {
886 via_free(codec);
887 return err;
888 } else if (!err) {
889 printk(KERN_INFO "hda_codec: Cannot set up configuration "
890 "from BIOS. Using genenic mode...\n");
891 }
892
893
894 spec->stream_name_analog = "VT1708 Analog";
895 spec->stream_analog_playback = &vt1708_pcm_analog_playback;
896 spec->stream_analog_capture = &vt1708_pcm_analog_capture;
897
898 spec->stream_name_digital = "VT1708 Digital";
899 spec->stream_digital_playback = &vt1708_pcm_digital_playback;
900 spec->stream_digital_capture = &vt1708_pcm_digital_capture;
901
902
903 if (!spec->adc_nids && spec->input_mux) {
904 spec->adc_nids = vt1708_adc_nids;
905 spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
906 spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
907 spec->num_mixers++;
908 }
909
910 codec->patch_ops = via_patch_ops;
911
912 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200913#ifdef CONFIG_SND_HDA_POWER_SAVE
914 spec->loopback.amplist = vt1708_loopbacks;
915#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +0100916
917 return 0;
918}
919
920/* capture mixer elements */
921static struct snd_kcontrol_new vt1709_capture_mixer[] = {
922 HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
923 HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
924 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
925 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
926 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
927 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
928 {
929 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
930 /* The multiple "Capture Source" controls confuse alsamixer
931 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +0100932 */
933 /* .name = "Capture Source", */
934 .name = "Input Source",
935 .count = 1,
936 .info = via_mux_enum_info,
937 .get = via_mux_enum_get,
938 .put = via_mux_enum_put,
939 },
940 { } /* end */
941};
942
943/*
944 * generic initialization of ADC, input mixers and output mixers
945 */
946static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
947 /*
948 * Unmute ADC0-2 and set the default input to mic-in
949 */
950 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
951 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
952 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
953
954
Josepch Chanf7278fd2007-12-13 16:40:40 +0100955 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +0100956 * mixer widget
957 */
958 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +0100959 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
960 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
961 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
962 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
963 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100964
965 /*
966 * Set up output selector (0x1a, 0x1b, 0x29)
967 */
968 /* set vol=0 to output mixers */
969 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
970 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
971 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
972
973 /*
974 * Unmute PW3 and PW4
975 */
976 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
977 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
978
979 /* Set input of PW4 as AOW4 */
980 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100981 /* PW9 Output enable */
982 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
983 { }
984};
985
986static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
987 .substreams = 1,
988 .channels_min = 2,
989 .channels_max = 10,
990 .nid = 0x10, /* NID to query formats and rates */
991 .ops = {
992 .open = via_playback_pcm_open,
993 .prepare = via_playback_pcm_prepare,
994 .cleanup = via_playback_pcm_cleanup
995 },
996};
997
998static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
999 .substreams = 1,
1000 .channels_min = 2,
1001 .channels_max = 6,
1002 .nid = 0x10, /* NID to query formats and rates */
1003 .ops = {
1004 .open = via_playback_pcm_open,
1005 .prepare = via_playback_pcm_prepare,
1006 .cleanup = via_playback_pcm_cleanup
1007 },
1008};
1009
1010static struct hda_pcm_stream vt1709_pcm_analog_capture = {
1011 .substreams = 2,
1012 .channels_min = 2,
1013 .channels_max = 2,
1014 .nid = 0x14, /* NID to query formats and rates */
1015 .ops = {
1016 .prepare = via_capture_pcm_prepare,
1017 .cleanup = via_capture_pcm_cleanup
1018 },
1019};
1020
1021static struct hda_pcm_stream vt1709_pcm_digital_playback = {
1022 .substreams = 1,
1023 .channels_min = 2,
1024 .channels_max = 2,
1025 /* NID is set in via_build_pcms */
1026 .ops = {
1027 .open = via_dig_playback_pcm_open,
1028 .close = via_dig_playback_pcm_close
1029 },
1030};
1031
1032static struct hda_pcm_stream vt1709_pcm_digital_capture = {
1033 .substreams = 1,
1034 .channels_min = 2,
1035 .channels_max = 2,
1036};
1037
1038static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
1039 const struct auto_pin_cfg *cfg)
1040{
1041 int i;
1042 hda_nid_t nid;
1043
1044 if (cfg->line_outs == 4) /* 10 channels */
1045 spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
1046 else if (cfg->line_outs == 3) /* 6 channels */
1047 spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
1048
1049 spec->multiout.dac_nids = spec->private_dac_nids;
1050
1051 if (cfg->line_outs == 4) { /* 10 channels */
1052 for (i = 0; i < cfg->line_outs; i++) {
1053 nid = cfg->line_out_pins[i];
1054 if (nid) {
1055 /* config dac list */
1056 switch (i) {
1057 case AUTO_SEQ_FRONT:
1058 /* AOW0 */
1059 spec->multiout.dac_nids[i] = 0x10;
1060 break;
1061 case AUTO_SEQ_CENLFE:
1062 /* AOW2 */
1063 spec->multiout.dac_nids[i] = 0x12;
1064 break;
1065 case AUTO_SEQ_SURROUND:
1066 /* AOW3 */
1067 spec->multiout.dac_nids[i] = 0x27;
1068 break;
1069 case AUTO_SEQ_SIDE:
1070 /* AOW1 */
1071 spec->multiout.dac_nids[i] = 0x11;
1072 break;
1073 default:
1074 break;
1075 }
1076 }
1077 }
1078 spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
1079
1080 } else if (cfg->line_outs == 3) { /* 6 channels */
1081 for(i = 0; i < cfg->line_outs; i++) {
1082 nid = cfg->line_out_pins[i];
1083 if (nid) {
1084 /* config dac list */
1085 switch(i) {
1086 case AUTO_SEQ_FRONT:
1087 /* AOW0 */
1088 spec->multiout.dac_nids[i] = 0x10;
1089 break;
1090 case AUTO_SEQ_CENLFE:
1091 /* AOW2 */
1092 spec->multiout.dac_nids[i] = 0x12;
1093 break;
1094 case AUTO_SEQ_SURROUND:
1095 /* AOW1 */
1096 spec->multiout.dac_nids[i] = 0x11;
1097 break;
1098 default:
1099 break;
1100 }
1101 }
1102 }
1103 }
1104
1105 return 0;
1106}
1107
1108/* add playback controls from the parsed DAC table */
1109static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
1110 const struct auto_pin_cfg *cfg)
1111{
1112 char name[32];
1113 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1114 hda_nid_t nid = 0;
1115 int i, err;
1116
1117 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1118 nid = cfg->line_out_pins[i];
1119
1120 if (!nid)
1121 continue;
1122
1123 if (i == AUTO_SEQ_CENLFE) {
1124 /* Center/LFE */
1125 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1126 "Center Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001127 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
1128 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001129 if (err < 0)
1130 return err;
1131 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1132 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001133 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
1134 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001135 if (err < 0)
1136 return err;
1137 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1138 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001139 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
1140 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001141 if (err < 0)
1142 return err;
1143 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1144 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001145 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
1146 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001147 if (err < 0)
1148 return err;
1149 } else if (i == AUTO_SEQ_FRONT){
1150 /* add control to mixer index 0 */
1151 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1152 "Master Front Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001153 HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
1154 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001155 if (err < 0)
1156 return err;
1157 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1158 "Master Front Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001159 HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
1160 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001161 if (err < 0)
1162 return err;
1163
1164 /* add control to PW3 */
1165 sprintf(name, "%s Playback Volume", chname[i]);
1166 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001167 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1168 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001169 if (err < 0)
1170 return err;
1171 sprintf(name, "%s Playback Switch", chname[i]);
1172 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001173 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1174 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001175 if (err < 0)
1176 return err;
1177 } else if (i == AUTO_SEQ_SURROUND) {
1178 sprintf(name, "%s Playback Volume", chname[i]);
1179 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001180 HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
1181 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001182 if (err < 0)
1183 return err;
1184 sprintf(name, "%s Playback Switch", chname[i]);
1185 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001186 HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
1187 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001188 if (err < 0)
1189 return err;
1190 } else if (i == AUTO_SEQ_SIDE) {
1191 sprintf(name, "%s Playback Volume", chname[i]);
1192 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001193 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
1194 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001195 if (err < 0)
1196 return err;
1197 sprintf(name, "%s Playback Switch", chname[i]);
1198 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001199 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
1200 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001201 if (err < 0)
1202 return err;
1203 }
1204 }
1205
1206 return 0;
1207}
1208
1209static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1210{
1211 int err;
1212
1213 if (!pin)
1214 return 0;
1215
1216 if (spec->multiout.num_dacs == 5) /* 10 channels */
1217 spec->multiout.hp_nid = VT1709_HP_DAC_NID;
1218 else if (spec->multiout.num_dacs == 3) /* 6 channels */
1219 spec->multiout.hp_nid = 0;
1220
1221 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1222 "Headphone Playback Volume",
1223 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1224 if (err < 0)
1225 return err;
1226 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1227 "Headphone Playback Switch",
1228 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1229 if (err < 0)
1230 return err;
1231
1232 return 0;
1233}
1234
1235/* create playback/capture controls for input pins */
1236static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
1237 const struct auto_pin_cfg *cfg)
1238{
1239 static char *labels[] = {
1240 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1241 };
1242 struct hda_input_mux *imux = &spec->private_imux;
1243 int i, err, idx = 0;
1244
1245 /* for internal loopback recording select */
1246 imux->items[imux->num_items].label = "Stereo Mixer";
1247 imux->items[imux->num_items].index = idx;
1248 imux->num_items++;
1249
1250 for (i = 0; i < AUTO_PIN_LAST; i++) {
1251 if (!cfg->input_pins[i])
1252 continue;
1253
1254 switch (cfg->input_pins[i]) {
1255 case 0x1d: /* Mic */
1256 idx = 2;
1257 break;
1258
1259 case 0x1e: /* Line In */
1260 idx = 3;
1261 break;
1262
1263 case 0x21: /* Front Mic */
1264 idx = 4;
1265 break;
1266
1267 case 0x23: /* CD */
1268 idx = 1;
1269 break;
1270 }
1271 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
1272 idx, 0x18);
1273 if (err < 0)
1274 return err;
1275 imux->items[imux->num_items].label = labels[i];
1276 imux->items[imux->num_items].index = idx;
1277 imux->num_items++;
1278 }
1279 return 0;
1280}
1281
1282static int vt1709_parse_auto_config(struct hda_codec *codec)
1283{
1284 struct via_spec *spec = codec->spec;
1285 int err;
1286
1287 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1288 if (err < 0)
1289 return err;
1290 err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
1291 if (err < 0)
1292 return err;
1293 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1294 return 0; /* can't find valid BIOS pin config */
1295
1296 err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
1297 if (err < 0)
1298 return err;
1299 err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1300 if (err < 0)
1301 return err;
1302 err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
1303 if (err < 0)
1304 return err;
1305
1306 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1307
1308 if (spec->autocfg.dig_out_pin)
1309 spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
1310 if (spec->autocfg.dig_in_pin)
1311 spec->dig_in_nid = VT1709_DIGIN_NID;
1312
1313 if (spec->kctl_alloc)
1314 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
1315
1316 spec->input_mux = &spec->private_imux;
1317
1318 return 1;
1319}
1320
Takashi Iwaicb53c622007-08-10 17:21:45 +02001321#ifdef CONFIG_SND_HDA_POWER_SAVE
1322static struct hda_amp_list vt1709_loopbacks[] = {
1323 { 0x18, HDA_INPUT, 1 },
1324 { 0x18, HDA_INPUT, 2 },
1325 { 0x18, HDA_INPUT, 3 },
1326 { 0x18, HDA_INPUT, 4 },
1327 { } /* end */
1328};
1329#endif
1330
Joseph Chanc577b8a2006-11-29 15:29:40 +01001331static int patch_vt1709_10ch(struct hda_codec *codec)
1332{
1333 struct via_spec *spec;
1334 int err;
1335
1336 /* create a codec specific record */
1337 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
1338 if (spec == NULL)
1339 return -ENOMEM;
1340
1341 codec->spec = spec;
1342
1343 err = vt1709_parse_auto_config(codec);
1344 if (err < 0) {
1345 via_free(codec);
1346 return err;
1347 } else if (!err) {
1348 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
1349 "Using genenic mode...\n");
1350 }
1351
1352 spec->init_verbs = vt1709_10ch_volume_init_verbs;
1353
1354 spec->stream_name_analog = "VT1709 Analog";
1355 spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
1356 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1357
1358 spec->stream_name_digital = "VT1709 Digital";
1359 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1360 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1361
1362
1363 if (!spec->adc_nids && spec->input_mux) {
1364 spec->adc_nids = vt1709_adc_nids;
1365 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
1366 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1367 spec->num_mixers++;
1368 }
1369
1370 codec->patch_ops = via_patch_ops;
1371
1372 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001373#ifdef CONFIG_SND_HDA_POWER_SAVE
1374 spec->loopback.amplist = vt1709_loopbacks;
1375#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001376
1377 return 0;
1378}
1379/*
1380 * generic initialization of ADC, input mixers and output mixers
1381 */
1382static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
1383 /*
1384 * Unmute ADC0-2 and set the default input to mic-in
1385 */
1386 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1387 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1388 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1389
1390
1391 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1392 * mixer widget
1393 */
1394 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1395 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1396 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1397 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1398 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1399 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1400
1401 /*
1402 * Set up output selector (0x1a, 0x1b, 0x29)
1403 */
1404 /* set vol=0 to output mixers */
1405 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1406 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1407 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1408
1409 /*
1410 * Unmute PW3 and PW4
1411 */
1412 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1413 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1414
1415 /* Set input of PW4 as MW0 */
1416 {0x20, AC_VERB_SET_CONNECT_SEL, 0},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001417 /* PW9 Output enable */
1418 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1419 { }
1420};
1421
1422static int patch_vt1709_6ch(struct hda_codec *codec)
1423{
1424 struct via_spec *spec;
1425 int err;
1426
1427 /* create a codec specific record */
1428 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
1429 if (spec == NULL)
1430 return -ENOMEM;
1431
1432 codec->spec = spec;
1433
1434 err = vt1709_parse_auto_config(codec);
1435 if (err < 0) {
1436 via_free(codec);
1437 return err;
1438 } else if (!err) {
1439 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
1440 "Using genenic mode...\n");
1441 }
1442
1443 spec->init_verbs = vt1709_6ch_volume_init_verbs;
1444
1445 spec->stream_name_analog = "VT1709 Analog";
1446 spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
1447 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1448
1449 spec->stream_name_digital = "VT1709 Digital";
1450 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1451 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1452
1453
1454 if (!spec->adc_nids && spec->input_mux) {
1455 spec->adc_nids = vt1709_adc_nids;
1456 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
1457 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1458 spec->num_mixers++;
1459 }
1460
1461 codec->patch_ops = via_patch_ops;
1462
1463 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001464#ifdef CONFIG_SND_HDA_POWER_SAVE
1465 spec->loopback.amplist = vt1709_loopbacks;
1466#endif
Josepch Chanf7278fd2007-12-13 16:40:40 +01001467 return 0;
1468}
1469
1470/* capture mixer elements */
1471static struct snd_kcontrol_new vt1708B_capture_mixer[] = {
1472 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
1473 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
1474 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
1475 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
1476 {
1477 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1478 /* The multiple "Capture Source" controls confuse alsamixer
1479 * So call somewhat different..
Josepch Chanf7278fd2007-12-13 16:40:40 +01001480 */
1481 /* .name = "Capture Source", */
1482 .name = "Input Source",
1483 .count = 1,
1484 .info = via_mux_enum_info,
1485 .get = via_mux_enum_get,
1486 .put = via_mux_enum_put,
1487 },
1488 { } /* end */
1489};
1490/*
1491 * generic initialization of ADC, input mixers and output mixers
1492 */
1493static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
1494 /*
1495 * Unmute ADC0-1 and set the default input to mic-in
1496 */
1497 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1498 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1499
1500
1501 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1502 * mixer widget
1503 */
1504 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1505 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1506 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1507 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1508 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1509 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1510
1511 /*
1512 * Set up output mixers
1513 */
1514 /* set vol=0 to output mixers */
1515 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1516 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1517 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1518
1519 /* Setup default input to PW4 */
1520 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1},
1521 /* PW9 Output enable */
1522 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1523 /* PW10 Input enable */
1524 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
1525 { }
1526};
1527
1528static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
1529 /*
1530 * Unmute ADC0-1 and set the default input to mic-in
1531 */
1532 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1533 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1534
1535
1536 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1537 * mixer widget
1538 */
1539 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1540 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1541 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1542 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1543 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1544 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1545
1546 /*
1547 * Set up output mixers
1548 */
1549 /* set vol=0 to output mixers */
1550 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1551 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1552 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1553
1554 /* Setup default input of PW4 to MW0 */
1555 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
1556 /* PW9 Output enable */
1557 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1558 /* PW10 Input enable */
1559 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
1560 { }
1561};
1562
1563static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
1564 .substreams = 1,
1565 .channels_min = 2,
1566 .channels_max = 8,
1567 .nid = 0x10, /* NID to query formats and rates */
1568 .ops = {
1569 .open = via_playback_pcm_open,
1570 .prepare = via_playback_pcm_prepare,
1571 .cleanup = via_playback_pcm_cleanup
1572 },
1573};
1574
1575static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
1576 .substreams = 1,
1577 .channels_min = 2,
1578 .channels_max = 4,
1579 .nid = 0x10, /* NID to query formats and rates */
1580 .ops = {
1581 .open = via_playback_pcm_open,
1582 .prepare = via_playback_pcm_prepare,
1583 .cleanup = via_playback_pcm_cleanup
1584 },
1585};
1586
1587static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
1588 .substreams = 2,
1589 .channels_min = 2,
1590 .channels_max = 2,
1591 .nid = 0x13, /* NID to query formats and rates */
1592 .ops = {
1593 .prepare = via_capture_pcm_prepare,
1594 .cleanup = via_capture_pcm_cleanup
1595 },
1596};
1597
1598static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
1599 .substreams = 1,
1600 .channels_min = 2,
1601 .channels_max = 2,
1602 /* NID is set in via_build_pcms */
1603 .ops = {
1604 .open = via_dig_playback_pcm_open,
1605 .close = via_dig_playback_pcm_close,
1606 .prepare = via_dig_playback_pcm_prepare
1607 },
1608};
1609
1610static struct hda_pcm_stream vt1708B_pcm_digital_capture = {
1611 .substreams = 1,
1612 .channels_min = 2,
1613 .channels_max = 2,
1614};
1615
1616/* fill in the dac_nids table from the parsed pin configuration */
1617static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
1618 const struct auto_pin_cfg *cfg)
1619{
1620 int i;
1621 hda_nid_t nid;
1622
1623 spec->multiout.num_dacs = cfg->line_outs;
1624
1625 spec->multiout.dac_nids = spec->private_dac_nids;
1626
1627 for (i = 0; i < 4; i++) {
1628 nid = cfg->line_out_pins[i];
1629 if (nid) {
1630 /* config dac list */
1631 switch (i) {
1632 case AUTO_SEQ_FRONT:
1633 spec->multiout.dac_nids[i] = 0x10;
1634 break;
1635 case AUTO_SEQ_CENLFE:
1636 spec->multiout.dac_nids[i] = 0x24;
1637 break;
1638 case AUTO_SEQ_SURROUND:
1639 spec->multiout.dac_nids[i] = 0x25;
1640 break;
1641 case AUTO_SEQ_SIDE:
1642 spec->multiout.dac_nids[i] = 0x11;
1643 break;
1644 }
1645 }
1646 }
1647
1648 return 0;
1649}
1650
1651/* add playback controls from the parsed DAC table */
1652static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
1653 const struct auto_pin_cfg *cfg)
1654{
1655 char name[32];
1656 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1657 hda_nid_t nid_vols[] = {0x16, 0x27, 0x26, 0x18};
1658 hda_nid_t nid, nid_vol = 0;
1659 int i, err;
1660
1661 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1662 nid = cfg->line_out_pins[i];
1663
1664 if (!nid)
1665 continue;
1666
1667 nid_vol = nid_vols[i];
1668
1669 if (i == AUTO_SEQ_CENLFE) {
1670 /* Center/LFE */
1671 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1672 "Center Playback Volume",
1673 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1674 HDA_OUTPUT));
1675 if (err < 0)
1676 return err;
1677 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1678 "LFE Playback Volume",
1679 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1680 HDA_OUTPUT));
1681 if (err < 0)
1682 return err;
1683 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1684 "Center Playback Switch",
1685 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1686 HDA_OUTPUT));
1687 if (err < 0)
1688 return err;
1689 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1690 "LFE Playback Switch",
1691 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1692 HDA_OUTPUT));
1693 if (err < 0)
1694 return err;
1695 } else if (i == AUTO_SEQ_FRONT) {
1696 /* add control to mixer index 0 */
1697 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1698 "Master Front Playback Volume",
1699 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1700 HDA_INPUT));
1701 if (err < 0)
1702 return err;
1703 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1704 "Master Front Playback Switch",
1705 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1706 HDA_INPUT));
1707 if (err < 0)
1708 return err;
1709
1710 /* add control to PW3 */
1711 sprintf(name, "%s Playback Volume", chname[i]);
1712 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1713 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1714 HDA_OUTPUT));
1715 if (err < 0)
1716 return err;
1717 sprintf(name, "%s Playback Switch", chname[i]);
1718 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1719 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1720 HDA_OUTPUT));
1721 if (err < 0)
1722 return err;
1723 } else {
1724 sprintf(name, "%s Playback Volume", chname[i]);
1725 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1726 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1727 HDA_OUTPUT));
1728 if (err < 0)
1729 return err;
1730 sprintf(name, "%s Playback Switch", chname[i]);
1731 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1732 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1733 HDA_OUTPUT));
1734 if (err < 0)
1735 return err;
1736 }
1737 }
1738
1739 return 0;
1740}
1741
1742static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1743{
1744 int err;
1745
1746 if (!pin)
1747 return 0;
1748
1749 spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
1750
1751 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1752 "Headphone Playback Volume",
1753 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1754 if (err < 0)
1755 return err;
1756 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1757 "Headphone Playback Switch",
1758 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1759 if (err < 0)
1760 return err;
1761
1762 return 0;
1763}
1764
1765/* create playback/capture controls for input pins */
1766static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
1767 const struct auto_pin_cfg *cfg)
1768{
1769 static char *labels[] = {
1770 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1771 };
1772 struct hda_input_mux *imux = &spec->private_imux;
1773 int i, err, idx = 0;
1774
1775 /* for internal loopback recording select */
1776 imux->items[imux->num_items].label = "Stereo Mixer";
1777 imux->items[imux->num_items].index = idx;
1778 imux->num_items++;
1779
1780 for (i = 0; i < AUTO_PIN_LAST; i++) {
1781 if (!cfg->input_pins[i])
1782 continue;
1783
1784 switch (cfg->input_pins[i]) {
1785 case 0x1a: /* Mic */
1786 idx = 2;
1787 break;
1788
1789 case 0x1b: /* Line In */
1790 idx = 3;
1791 break;
1792
1793 case 0x1e: /* Front Mic */
1794 idx = 4;
1795 break;
1796
1797 case 0x1f: /* CD */
1798 idx = 1;
1799 break;
1800 }
1801 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
1802 idx, 0x16);
1803 if (err < 0)
1804 return err;
1805 imux->items[imux->num_items].label = labels[i];
1806 imux->items[imux->num_items].index = idx;
1807 imux->num_items++;
1808 }
1809 return 0;
1810}
1811
1812static int vt1708B_parse_auto_config(struct hda_codec *codec)
1813{
1814 struct via_spec *spec = codec->spec;
1815 int err;
1816
1817 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1818 if (err < 0)
1819 return err;
1820 err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg);
1821 if (err < 0)
1822 return err;
1823 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1824 return 0; /* can't find valid BIOS pin config */
1825
1826 err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg);
1827 if (err < 0)
1828 return err;
1829 err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1830 if (err < 0)
1831 return err;
1832 err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
1833 if (err < 0)
1834 return err;
1835
1836 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1837
1838 if (spec->autocfg.dig_out_pin)
1839 spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
1840 if (spec->autocfg.dig_in_pin)
1841 spec->dig_in_nid = VT1708B_DIGIN_NID;
1842
1843 if (spec->kctl_alloc)
1844 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
1845
1846 spec->input_mux = &spec->private_imux;
1847
1848 return 1;
1849}
1850
1851#ifdef CONFIG_SND_HDA_POWER_SAVE
1852static struct hda_amp_list vt1708B_loopbacks[] = {
1853 { 0x16, HDA_INPUT, 1 },
1854 { 0x16, HDA_INPUT, 2 },
1855 { 0x16, HDA_INPUT, 3 },
1856 { 0x16, HDA_INPUT, 4 },
1857 { } /* end */
1858};
1859#endif
1860
1861static int patch_vt1708B_8ch(struct hda_codec *codec)
1862{
1863 struct via_spec *spec;
1864 int err;
1865
1866 /* create a codec specific record */
1867 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
1868 if (spec == NULL)
1869 return -ENOMEM;
1870
1871 codec->spec = spec;
1872
1873 /* automatic parse from the BIOS config */
1874 err = vt1708B_parse_auto_config(codec);
1875 if (err < 0) {
1876 via_free(codec);
1877 return err;
1878 } else if (!err) {
1879 printk(KERN_INFO "hda_codec: Cannot set up configuration "
1880 "from BIOS. Using genenic mode...\n");
1881 }
1882
1883 spec->init_verbs = vt1708B_8ch_volume_init_verbs;
1884
1885 spec->stream_name_analog = "VT1708B Analog";
1886 spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
1887 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
1888
1889 spec->stream_name_digital = "VT1708B Digital";
1890 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
1891 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
1892
1893 if (!spec->adc_nids && spec->input_mux) {
1894 spec->adc_nids = vt1708B_adc_nids;
1895 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
1896 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
1897 spec->num_mixers++;
1898 }
1899
1900 codec->patch_ops = via_patch_ops;
1901
1902 codec->patch_ops.init = via_auto_init;
1903#ifdef CONFIG_SND_HDA_POWER_SAVE
1904 spec->loopback.amplist = vt1708B_loopbacks;
1905#endif
1906
1907 return 0;
1908}
1909
1910static int patch_vt1708B_4ch(struct hda_codec *codec)
1911{
1912 struct via_spec *spec;
1913 int err;
1914
1915 /* create a codec specific record */
1916 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
1917 if (spec == NULL)
1918 return -ENOMEM;
1919
1920 codec->spec = spec;
1921
1922 /* automatic parse from the BIOS config */
1923 err = vt1708B_parse_auto_config(codec);
1924 if (err < 0) {
1925 via_free(codec);
1926 return err;
1927 } else if (!err) {
1928 printk(KERN_INFO "hda_codec: Cannot set up configuration "
1929 "from BIOS. Using genenic mode...\n");
1930 }
1931
1932 spec->init_verbs = vt1708B_4ch_volume_init_verbs;
1933
1934 spec->stream_name_analog = "VT1708B Analog";
1935 spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
1936 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
1937
1938 spec->stream_name_digital = "VT1708B Digital";
1939 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
1940 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
1941
1942 if (!spec->adc_nids && spec->input_mux) {
1943 spec->adc_nids = vt1708B_adc_nids;
1944 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
1945 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
1946 spec->num_mixers++;
1947 }
1948
1949 codec->patch_ops = via_patch_ops;
1950
1951 codec->patch_ops.init = via_auto_init;
1952#ifdef CONFIG_SND_HDA_POWER_SAVE
1953 spec->loopback.amplist = vt1708B_loopbacks;
1954#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001955
1956 return 0;
1957}
1958
1959/*
1960 * patch entries
1961 */
1962struct hda_codec_preset snd_hda_preset_via[] = {
1963 { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708},
1964 { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708},
1965 { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708},
1966 { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708},
Josepch Chanf7278fd2007-12-13 16:40:40 +01001967 { .id = 0x1106E710, .name = "VIA VT1709 10-Ch",
1968 .patch = patch_vt1709_10ch},
1969 { .id = 0x1106E711, .name = "VIA VT1709 10-Ch",
1970 .patch = patch_vt1709_10ch},
1971 { .id = 0x1106E712, .name = "VIA VT1709 10-Ch",
1972 .patch = patch_vt1709_10ch},
1973 { .id = 0x1106E713, .name = "VIA VT1709 10-Ch",
1974 .patch = patch_vt1709_10ch},
1975 { .id = 0x1106E714, .name = "VIA VT1709 6-Ch",
1976 .patch = patch_vt1709_6ch},
1977 { .id = 0x1106E715, .name = "VIA VT1709 6-Ch",
1978 .patch = patch_vt1709_6ch},
1979 { .id = 0x1106E716, .name = "VIA VT1709 6-Ch",
1980 .patch = patch_vt1709_6ch},
1981 { .id = 0x1106E717, .name = "VIA VT1709 6-Ch",
1982 .patch = patch_vt1709_6ch},
1983 { .id = 0x1106E720, .name = "VIA VT1708B 8-Ch",
1984 .patch = patch_vt1708B_8ch},
1985 { .id = 0x1106E721, .name = "VIA VT1708B 8-Ch",
1986 .patch = patch_vt1708B_8ch},
1987 { .id = 0x1106E722, .name = "VIA VT1708B 8-Ch",
1988 .patch = patch_vt1708B_8ch},
1989 { .id = 0x1106E723, .name = "VIA VT1708B 8-Ch",
1990 .patch = patch_vt1708B_8ch},
1991 { .id = 0x1106E724, .name = "VIA VT1708B 4-Ch",
1992 .patch = patch_vt1708B_4ch},
1993 { .id = 0x1106E725, .name = "VIA VT1708B 4-Ch",
1994 .patch = patch_vt1708B_4ch},
1995 { .id = 0x1106E726, .name = "VIA VT1708B 4-Ch",
1996 .patch = patch_vt1708B_4ch},
1997 { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch",
1998 .patch = patch_vt1708B_4ch},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001999 {} /* terminator */
2000};