blob: d42d8f753f11bc85f4ad66a690348b8f8923b8e8 [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
36#include <sound/driver.h>
37#include <linux/init.h>
38#include <linux/delay.h>
39#include <linux/slab.h>
Joseph Chanc577b8a2006-11-29 15:29:40 +010040#include <sound/core.h>
41#include "hda_codec.h"
42#include "hda_local.h"
43
44
45/* amp values */
46#define AMP_VAL_IDX_SHIFT 19
47#define AMP_VAL_IDX_MASK (0x0f<<19)
48
49#define NUM_CONTROL_ALLOC 32
50#define NUM_VERB_ALLOC 32
51
52/* Pin Widget NID */
53#define VT1708_HP_NID 0x13
54#define VT1708_DIGOUT_NID 0x14
55#define VT1708_DIGIN_NID 0x16
Josepch Chanf7278fd2007-12-13 16:40:40 +010056#define VT1708_DIGIN_PIN 0x26
Joseph Chanc577b8a2006-11-29 15:29:40 +010057
58#define VT1709_HP_DAC_NID 0x28
59#define VT1709_DIGOUT_NID 0x13
60#define VT1709_DIGIN_NID 0x17
Josepch Chanf7278fd2007-12-13 16:40:40 +010061#define VT1709_DIGIN_PIN 0x25
62
63#define VT1708B_HP_NID 0x25
64#define VT1708B_DIGOUT_NID 0x12
65#define VT1708B_DIGIN_NID 0x15
66#define VT1708B_DIGIN_PIN 0x21
Joseph Chanc577b8a2006-11-29 15:29:40 +010067
68#define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b)
69#define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713)
70#define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717)
Josepch Chanf7278fd2007-12-13 16:40:40 +010071#define IS_VT1708B_8CH_VENDORID(x) ((x) >= 0x1106e720 && (x) <= 0x1106e723)
72#define IS_VT1708B_4CH_VENDORID(x) ((x) >= 0x1106e724 && (x) <= 0x1106e727)
Joseph Chanc577b8a2006-11-29 15:29:40 +010073
74
75enum {
76 VIA_CTL_WIDGET_VOL,
77 VIA_CTL_WIDGET_MUTE,
78};
79
80enum {
81 AUTO_SEQ_FRONT,
82 AUTO_SEQ_SURROUND,
83 AUTO_SEQ_CENLFE,
84 AUTO_SEQ_SIDE
85};
86
87static struct snd_kcontrol_new vt1708_control_templates[] = {
88 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
89 HDA_CODEC_MUTE(NULL, 0, 0, 0),
90};
91
92
93struct via_spec {
94 /* codec parameterization */
95 struct snd_kcontrol_new *mixers[3];
96 unsigned int num_mixers;
97
98 struct hda_verb *init_verbs;
99
100 char *stream_name_analog;
101 struct hda_pcm_stream *stream_analog_playback;
102 struct hda_pcm_stream *stream_analog_capture;
103
104 char *stream_name_digital;
105 struct hda_pcm_stream *stream_digital_playback;
106 struct hda_pcm_stream *stream_digital_capture;
107
108 /* playback */
109 struct hda_multi_out multiout;
110
111 /* capture */
112 unsigned int num_adc_nids;
113 hda_nid_t *adc_nids;
114 hda_nid_t dig_in_nid;
115
116 /* capture source */
117 const struct hda_input_mux *input_mux;
118 unsigned int cur_mux[3];
119
120 /* PCM information */
121 struct hda_pcm pcm_rec[2];
122
123 /* dynamic controls, init_verbs and input_mux */
124 struct auto_pin_cfg autocfg;
125 unsigned int num_kctl_alloc, num_kctl_used;
126 struct snd_kcontrol_new *kctl_alloc;
127 struct hda_input_mux private_imux;
Takashi Iwai41923e42007-10-22 17:20:10 +0200128 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwaicb53c622007-08-10 17:21:45 +0200129
130#ifdef CONFIG_SND_HDA_POWER_SAVE
131 struct hda_loopback_check loopback;
132#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +0100133};
134
135static hda_nid_t vt1708_adc_nids[2] = {
136 /* ADC1-2 */
137 0x15, 0x27
138};
139
140static hda_nid_t vt1709_adc_nids[3] = {
141 /* ADC1-2 */
142 0x14, 0x15, 0x16
143};
144
Josepch Chanf7278fd2007-12-13 16:40:40 +0100145static hda_nid_t vt1708B_adc_nids[2] = {
146 /* ADC1-2 */
147 0x13, 0x14
148};
149
Joseph Chanc577b8a2006-11-29 15:29:40 +0100150/* add dynamic controls */
151static int via_add_control(struct via_spec *spec, int type, const char *name,
152 unsigned long val)
153{
154 struct snd_kcontrol_new *knew;
155
156 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
157 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
158
159 /* array + terminator */
160 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
161 if (!knew)
162 return -ENOMEM;
163 if (spec->kctl_alloc) {
164 memcpy(knew, spec->kctl_alloc,
165 sizeof(*knew) * spec->num_kctl_alloc);
166 kfree(spec->kctl_alloc);
167 }
168 spec->kctl_alloc = knew;
169 spec->num_kctl_alloc = num;
170 }
171
172 knew = &spec->kctl_alloc[spec->num_kctl_used];
173 *knew = vt1708_control_templates[type];
174 knew->name = kstrdup(name, GFP_KERNEL);
175
176 if (!knew->name)
177 return -ENOMEM;
178 knew->private_value = val;
179 spec->num_kctl_used++;
180 return 0;
181}
182
183/* create input playback/capture controls for the given pin */
184static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
185 const char *ctlname, int idx, int mix_nid)
186{
187 char name[32];
188 int err;
189
190 sprintf(name, "%s Playback Volume", ctlname);
191 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
192 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
193 if (err < 0)
194 return err;
195 sprintf(name, "%s Playback Switch", ctlname);
196 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
197 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
198 if (err < 0)
199 return err;
200 return 0;
201}
202
203static void via_auto_set_output_and_unmute(struct hda_codec *codec,
204 hda_nid_t nid, int pin_type,
205 int dac_idx)
206{
207 /* set as output */
208 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
209 pin_type);
210 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
211 AMP_OUT_UNMUTE);
212}
213
214
215static void via_auto_init_multi_out(struct hda_codec *codec)
216{
217 struct via_spec *spec = codec->spec;
218 int i;
219
220 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
221 hda_nid_t nid = spec->autocfg.line_out_pins[i];
222 if (nid)
223 via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
224 }
225}
226
227static void via_auto_init_hp_out(struct hda_codec *codec)
228{
229 struct via_spec *spec = codec->spec;
230 hda_nid_t pin;
231
232 pin = spec->autocfg.hp_pins[0];
233 if (pin) /* connect to front */
234 via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
235}
236
237static void via_auto_init_analog_input(struct hda_codec *codec)
238{
239 struct via_spec *spec = codec->spec;
240 int i;
241
242 for (i = 0; i < AUTO_PIN_LAST; i++) {
243 hda_nid_t nid = spec->autocfg.input_pins[i];
244
245 snd_hda_codec_write(codec, nid, 0,
246 AC_VERB_SET_PIN_WIDGET_CONTROL,
247 (i <= AUTO_PIN_FRONT_MIC ?
248 PIN_VREF50 : PIN_IN));
249
250 }
251}
252/*
253 * input MUX handling
254 */
255static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
256 struct snd_ctl_elem_info *uinfo)
257{
258 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
259 struct via_spec *spec = codec->spec;
260 return snd_hda_input_mux_info(spec->input_mux, uinfo);
261}
262
263static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
264 struct snd_ctl_elem_value *ucontrol)
265{
266 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
267 struct via_spec *spec = codec->spec;
268 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
269
270 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
271 return 0;
272}
273
274static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
275 struct snd_ctl_elem_value *ucontrol)
276{
277 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
278 struct via_spec *spec = codec->spec;
279 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
280 unsigned int vendor_id = codec->vendor_id;
281
282 /* AIW0 lydia 060801 add for correct sw0 input select */
283 if (IS_VT1708_VENDORID(vendor_id) && (adc_idx == 0))
284 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
285 0x18, &spec->cur_mux[adc_idx]);
286 else if ((IS_VT1709_10CH_VENDORID(vendor_id) ||
Josepch Chanf7278fd2007-12-13 16:40:40 +0100287 IS_VT1709_6CH_VENDORID(vendor_id)) && adc_idx == 0)
Joseph Chanc577b8a2006-11-29 15:29:40 +0100288 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
289 0x19, &spec->cur_mux[adc_idx]);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100290 else if ((IS_VT1708B_8CH_VENDORID(vendor_id) ||
291 IS_VT1708B_4CH_VENDORID(vendor_id)) && adc_idx == 0)
292 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
293 0x17, &spec->cur_mux[adc_idx]);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100294 else
295 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
296 spec->adc_nids[adc_idx],
297 &spec->cur_mux[adc_idx]);
298}
299
300/* capture mixer elements */
301static struct snd_kcontrol_new vt1708_capture_mixer[] = {
302 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
303 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
304 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
305 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
306 {
307 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
308 /* The multiple "Capture Source" controls confuse alsamixer
309 * So call somewhat different..
310 * FIXME: the controls appear in the "playback" view!
311 */
312 /* .name = "Capture Source", */
313 .name = "Input Source",
314 .count = 1,
315 .info = via_mux_enum_info,
316 .get = via_mux_enum_get,
317 .put = via_mux_enum_put,
318 },
319 { } /* end */
320};
321/*
322 * generic initialization of ADC, input mixers and output mixers
323 */
324static struct hda_verb vt1708_volume_init_verbs[] = {
325 /*
326 * Unmute ADC0-1 and set the default input to mic-in
327 */
328 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
329 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
330
331
Josepch Chanf7278fd2007-12-13 16:40:40 +0100332 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +0100333 * mixer widget
334 */
335 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +0100336 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
337 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
338 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
339 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
340 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100341
342 /*
343 * Set up output mixers (0x19 - 0x1b)
344 */
345 /* set vol=0 to output mixers */
346 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
347 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
348 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
349
350 /* Setup default input to PW4 */
351 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100352 /* PW9 Output enable */
353 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Josepch Chanf7278fd2007-12-13 16:40:40 +0100354 { }
Joseph Chanc577b8a2006-11-29 15:29:40 +0100355};
356
357static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
358 struct hda_codec *codec,
359 struct snd_pcm_substream *substream)
360{
361 struct via_spec *spec = codec->spec;
362 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
363}
364
365static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
366 struct hda_codec *codec,
367 unsigned int stream_tag,
368 unsigned int format,
369 struct snd_pcm_substream *substream)
370{
371 struct via_spec *spec = codec->spec;
372 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
373 stream_tag, format, substream);
374}
375
376static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
377 struct hda_codec *codec,
378 struct snd_pcm_substream *substream)
379{
380 struct via_spec *spec = codec->spec;
381 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
382}
383
384/*
385 * Digital out
386 */
387static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
388 struct hda_codec *codec,
389 struct snd_pcm_substream *substream)
390{
391 struct via_spec *spec = codec->spec;
392 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
393}
394
395static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
396 struct hda_codec *codec,
397 struct snd_pcm_substream *substream)
398{
399 struct via_spec *spec = codec->spec;
400 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
401}
402
Takashi Iwai6b97eb42007-04-05 14:51:48 +0200403static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
404 struct hda_codec *codec,
405 unsigned int stream_tag,
406 unsigned int format,
407 struct snd_pcm_substream *substream)
408{
409 struct via_spec *spec = codec->spec;
410 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
411 stream_tag, format, substream);
412}
413
Joseph Chanc577b8a2006-11-29 15:29:40 +0100414/*
415 * Analog capture
416 */
417static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
418 struct hda_codec *codec,
419 unsigned int stream_tag,
420 unsigned int format,
421 struct snd_pcm_substream *substream)
422{
423 struct via_spec *spec = codec->spec;
424
425 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
426 stream_tag, 0, format);
427 return 0;
428}
429
430static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
431 struct hda_codec *codec,
432 struct snd_pcm_substream *substream)
433{
434 struct via_spec *spec = codec->spec;
435 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
436 0, 0, 0);
437 return 0;
438}
439
440static struct hda_pcm_stream vt1708_pcm_analog_playback = {
441 .substreams = 1,
442 .channels_min = 2,
443 .channels_max = 8,
444 .nid = 0x10, /* NID to query formats and rates */
445 .ops = {
446 .open = via_playback_pcm_open,
447 .prepare = via_playback_pcm_prepare,
448 .cleanup = via_playback_pcm_cleanup
449 },
450};
451
452static struct hda_pcm_stream vt1708_pcm_analog_capture = {
453 .substreams = 2,
454 .channels_min = 2,
455 .channels_max = 2,
456 .nid = 0x15, /* NID to query formats and rates */
457 .ops = {
458 .prepare = via_capture_pcm_prepare,
459 .cleanup = via_capture_pcm_cleanup
460 },
461};
462
463static struct hda_pcm_stream vt1708_pcm_digital_playback = {
464 .substreams = 1,
465 .channels_min = 2,
466 .channels_max = 2,
467 /* NID is set in via_build_pcms */
468 .ops = {
469 .open = via_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +0200470 .close = via_dig_playback_pcm_close,
471 .prepare = via_dig_playback_pcm_prepare
Joseph Chanc577b8a2006-11-29 15:29:40 +0100472 },
473};
474
475static struct hda_pcm_stream vt1708_pcm_digital_capture = {
476 .substreams = 1,
477 .channels_min = 2,
478 .channels_max = 2,
479};
480
481static int via_build_controls(struct hda_codec *codec)
482{
483 struct via_spec *spec = codec->spec;
484 int err;
485 int i;
486
487 for (i = 0; i < spec->num_mixers; i++) {
488 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
489 if (err < 0)
490 return err;
491 }
492
493 if (spec->multiout.dig_out_nid) {
494 err = snd_hda_create_spdif_out_ctls(codec,
495 spec->multiout.dig_out_nid);
496 if (err < 0)
497 return err;
498 }
499 if (spec->dig_in_nid) {
500 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
501 if (err < 0)
502 return err;
503 }
504 return 0;
505}
506
507static int via_build_pcms(struct hda_codec *codec)
508{
509 struct via_spec *spec = codec->spec;
510 struct hda_pcm *info = spec->pcm_rec;
511
512 codec->num_pcms = 1;
513 codec->pcm_info = info;
514
515 info->name = spec->stream_name_analog;
516 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
517 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
518 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
519 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
520
521 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
522 spec->multiout.max_channels;
523
524 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
525 codec->num_pcms++;
526 info++;
527 info->name = spec->stream_name_digital;
528 if (spec->multiout.dig_out_nid) {
529 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
530 *(spec->stream_digital_playback);
531 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
532 spec->multiout.dig_out_nid;
533 }
534 if (spec->dig_in_nid) {
535 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
536 *(spec->stream_digital_capture);
537 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
538 spec->dig_in_nid;
539 }
540 }
541
542 return 0;
543}
544
545static void via_free(struct hda_codec *codec)
546{
547 struct via_spec *spec = codec->spec;
548 unsigned int i;
549
550 if (!spec)
551 return;
552
553 if (spec->kctl_alloc) {
554 for (i = 0; i < spec->num_kctl_used; i++)
555 kfree(spec->kctl_alloc[i].name);
556 kfree(spec->kctl_alloc);
557 }
558
559 kfree(codec->spec);
560}
561
562static int via_init(struct hda_codec *codec)
563{
564 struct via_spec *spec = codec->spec;
565 snd_hda_sequence_write(codec, spec->init_verbs);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100566 /* Lydia Add for EAPD enable */
567 if (!spec->dig_in_nid) { /* No Digital In connection */
568 if (IS_VT1708_VENDORID(codec->vendor_id)) {
569 snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
570 AC_VERB_SET_PIN_WIDGET_CONTROL,
571 0x40);
572 snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
573 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
574 } else if (IS_VT1709_10CH_VENDORID(codec->vendor_id) ||
575 IS_VT1709_6CH_VENDORID(codec->vendor_id)) {
576 snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
577 AC_VERB_SET_PIN_WIDGET_CONTROL,
578 0x40);
579 snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
580 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
581 } else if (IS_VT1708B_8CH_VENDORID(codec->vendor_id) ||
582 IS_VT1708B_4CH_VENDORID(codec->vendor_id)) {
583 snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
584 AC_VERB_SET_PIN_WIDGET_CONTROL,
585 0x40);
586 snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
587 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
588 }
589 }
590
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..
932 * FIXME: the controls appear in the "playback" view!
933 */
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..
1481 * FIXME: the controls appear in the "playback" view!
1482 */
1483 /* .name = "Capture Source", */
1484 .name = "Input Source",
1485 .count = 1,
1486 .info = via_mux_enum_info,
1487 .get = via_mux_enum_get,
1488 .put = via_mux_enum_put,
1489 },
1490 { } /* end */
1491};
1492/*
1493 * generic initialization of ADC, input mixers and output mixers
1494 */
1495static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
1496 /*
1497 * Unmute ADC0-1 and set the default input to mic-in
1498 */
1499 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1500 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1501
1502
1503 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1504 * mixer widget
1505 */
1506 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1507 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1508 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1509 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1510 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1511 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1512
1513 /*
1514 * Set up output mixers
1515 */
1516 /* set vol=0 to output mixers */
1517 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1518 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1519 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1520
1521 /* Setup default input to PW4 */
1522 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1},
1523 /* PW9 Output enable */
1524 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1525 /* PW10 Input enable */
1526 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
1527 { }
1528};
1529
1530static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
1531 /*
1532 * Unmute ADC0-1 and set the default input to mic-in
1533 */
1534 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1535 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1536
1537
1538 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1539 * mixer widget
1540 */
1541 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1542 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1543 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1544 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1545 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1546 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1547
1548 /*
1549 * Set up output mixers
1550 */
1551 /* set vol=0 to output mixers */
1552 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1553 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1554 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1555
1556 /* Setup default input of PW4 to MW0 */
1557 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
1558 /* PW9 Output enable */
1559 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1560 /* PW10 Input enable */
1561 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
1562 { }
1563};
1564
1565static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
1566 .substreams = 1,
1567 .channels_min = 2,
1568 .channels_max = 8,
1569 .nid = 0x10, /* NID to query formats and rates */
1570 .ops = {
1571 .open = via_playback_pcm_open,
1572 .prepare = via_playback_pcm_prepare,
1573 .cleanup = via_playback_pcm_cleanup
1574 },
1575};
1576
1577static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
1578 .substreams = 1,
1579 .channels_min = 2,
1580 .channels_max = 4,
1581 .nid = 0x10, /* NID to query formats and rates */
1582 .ops = {
1583 .open = via_playback_pcm_open,
1584 .prepare = via_playback_pcm_prepare,
1585 .cleanup = via_playback_pcm_cleanup
1586 },
1587};
1588
1589static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
1590 .substreams = 2,
1591 .channels_min = 2,
1592 .channels_max = 2,
1593 .nid = 0x13, /* NID to query formats and rates */
1594 .ops = {
1595 .prepare = via_capture_pcm_prepare,
1596 .cleanup = via_capture_pcm_cleanup
1597 },
1598};
1599
1600static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
1601 .substreams = 1,
1602 .channels_min = 2,
1603 .channels_max = 2,
1604 /* NID is set in via_build_pcms */
1605 .ops = {
1606 .open = via_dig_playback_pcm_open,
1607 .close = via_dig_playback_pcm_close,
1608 .prepare = via_dig_playback_pcm_prepare
1609 },
1610};
1611
1612static struct hda_pcm_stream vt1708B_pcm_digital_capture = {
1613 .substreams = 1,
1614 .channels_min = 2,
1615 .channels_max = 2,
1616};
1617
1618/* fill in the dac_nids table from the parsed pin configuration */
1619static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
1620 const struct auto_pin_cfg *cfg)
1621{
1622 int i;
1623 hda_nid_t nid;
1624
1625 spec->multiout.num_dacs = cfg->line_outs;
1626
1627 spec->multiout.dac_nids = spec->private_dac_nids;
1628
1629 for (i = 0; i < 4; i++) {
1630 nid = cfg->line_out_pins[i];
1631 if (nid) {
1632 /* config dac list */
1633 switch (i) {
1634 case AUTO_SEQ_FRONT:
1635 spec->multiout.dac_nids[i] = 0x10;
1636 break;
1637 case AUTO_SEQ_CENLFE:
1638 spec->multiout.dac_nids[i] = 0x24;
1639 break;
1640 case AUTO_SEQ_SURROUND:
1641 spec->multiout.dac_nids[i] = 0x25;
1642 break;
1643 case AUTO_SEQ_SIDE:
1644 spec->multiout.dac_nids[i] = 0x11;
1645 break;
1646 }
1647 }
1648 }
1649
1650 return 0;
1651}
1652
1653/* add playback controls from the parsed DAC table */
1654static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
1655 const struct auto_pin_cfg *cfg)
1656{
1657 char name[32];
1658 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1659 hda_nid_t nid_vols[] = {0x16, 0x27, 0x26, 0x18};
1660 hda_nid_t nid, nid_vol = 0;
1661 int i, err;
1662
1663 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1664 nid = cfg->line_out_pins[i];
1665
1666 if (!nid)
1667 continue;
1668
1669 nid_vol = nid_vols[i];
1670
1671 if (i == AUTO_SEQ_CENLFE) {
1672 /* Center/LFE */
1673 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1674 "Center Playback Volume",
1675 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1676 HDA_OUTPUT));
1677 if (err < 0)
1678 return err;
1679 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1680 "LFE Playback Volume",
1681 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1682 HDA_OUTPUT));
1683 if (err < 0)
1684 return err;
1685 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1686 "Center Playback Switch",
1687 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1688 HDA_OUTPUT));
1689 if (err < 0)
1690 return err;
1691 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1692 "LFE Playback Switch",
1693 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1694 HDA_OUTPUT));
1695 if (err < 0)
1696 return err;
1697 } else if (i == AUTO_SEQ_FRONT) {
1698 /* add control to mixer index 0 */
1699 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1700 "Master Front Playback Volume",
1701 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1702 HDA_INPUT));
1703 if (err < 0)
1704 return err;
1705 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1706 "Master Front Playback Switch",
1707 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1708 HDA_INPUT));
1709 if (err < 0)
1710 return err;
1711
1712 /* add control to PW3 */
1713 sprintf(name, "%s Playback Volume", chname[i]);
1714 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1715 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1716 HDA_OUTPUT));
1717 if (err < 0)
1718 return err;
1719 sprintf(name, "%s Playback Switch", chname[i]);
1720 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1721 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1722 HDA_OUTPUT));
1723 if (err < 0)
1724 return err;
1725 } else {
1726 sprintf(name, "%s Playback Volume", chname[i]);
1727 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1728 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1729 HDA_OUTPUT));
1730 if (err < 0)
1731 return err;
1732 sprintf(name, "%s Playback Switch", chname[i]);
1733 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1734 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1735 HDA_OUTPUT));
1736 if (err < 0)
1737 return err;
1738 }
1739 }
1740
1741 return 0;
1742}
1743
1744static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1745{
1746 int err;
1747
1748 if (!pin)
1749 return 0;
1750
1751 spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
1752
1753 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1754 "Headphone Playback Volume",
1755 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1756 if (err < 0)
1757 return err;
1758 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1759 "Headphone Playback Switch",
1760 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1761 if (err < 0)
1762 return err;
1763
1764 return 0;
1765}
1766
1767/* create playback/capture controls for input pins */
1768static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
1769 const struct auto_pin_cfg *cfg)
1770{
1771 static char *labels[] = {
1772 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1773 };
1774 struct hda_input_mux *imux = &spec->private_imux;
1775 int i, err, idx = 0;
1776
1777 /* for internal loopback recording select */
1778 imux->items[imux->num_items].label = "Stereo Mixer";
1779 imux->items[imux->num_items].index = idx;
1780 imux->num_items++;
1781
1782 for (i = 0; i < AUTO_PIN_LAST; i++) {
1783 if (!cfg->input_pins[i])
1784 continue;
1785
1786 switch (cfg->input_pins[i]) {
1787 case 0x1a: /* Mic */
1788 idx = 2;
1789 break;
1790
1791 case 0x1b: /* Line In */
1792 idx = 3;
1793 break;
1794
1795 case 0x1e: /* Front Mic */
1796 idx = 4;
1797 break;
1798
1799 case 0x1f: /* CD */
1800 idx = 1;
1801 break;
1802 }
1803 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
1804 idx, 0x16);
1805 if (err < 0)
1806 return err;
1807 imux->items[imux->num_items].label = labels[i];
1808 imux->items[imux->num_items].index = idx;
1809 imux->num_items++;
1810 }
1811 return 0;
1812}
1813
1814static int vt1708B_parse_auto_config(struct hda_codec *codec)
1815{
1816 struct via_spec *spec = codec->spec;
1817 int err;
1818
1819 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1820 if (err < 0)
1821 return err;
1822 err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg);
1823 if (err < 0)
1824 return err;
1825 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1826 return 0; /* can't find valid BIOS pin config */
1827
1828 err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg);
1829 if (err < 0)
1830 return err;
1831 err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1832 if (err < 0)
1833 return err;
1834 err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
1835 if (err < 0)
1836 return err;
1837
1838 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1839
1840 if (spec->autocfg.dig_out_pin)
1841 spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
1842 if (spec->autocfg.dig_in_pin)
1843 spec->dig_in_nid = VT1708B_DIGIN_NID;
1844
1845 if (spec->kctl_alloc)
1846 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
1847
1848 spec->input_mux = &spec->private_imux;
1849
1850 return 1;
1851}
1852
1853#ifdef CONFIG_SND_HDA_POWER_SAVE
1854static struct hda_amp_list vt1708B_loopbacks[] = {
1855 { 0x16, HDA_INPUT, 1 },
1856 { 0x16, HDA_INPUT, 2 },
1857 { 0x16, HDA_INPUT, 3 },
1858 { 0x16, HDA_INPUT, 4 },
1859 { } /* end */
1860};
1861#endif
1862
1863static int patch_vt1708B_8ch(struct hda_codec *codec)
1864{
1865 struct via_spec *spec;
1866 int err;
1867
1868 /* create a codec specific record */
1869 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
1870 if (spec == NULL)
1871 return -ENOMEM;
1872
1873 codec->spec = spec;
1874
1875 /* automatic parse from the BIOS config */
1876 err = vt1708B_parse_auto_config(codec);
1877 if (err < 0) {
1878 via_free(codec);
1879 return err;
1880 } else if (!err) {
1881 printk(KERN_INFO "hda_codec: Cannot set up configuration "
1882 "from BIOS. Using genenic mode...\n");
1883 }
1884
1885 spec->init_verbs = vt1708B_8ch_volume_init_verbs;
1886
1887 spec->stream_name_analog = "VT1708B Analog";
1888 spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
1889 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
1890
1891 spec->stream_name_digital = "VT1708B Digital";
1892 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
1893 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
1894
1895 if (!spec->adc_nids && spec->input_mux) {
1896 spec->adc_nids = vt1708B_adc_nids;
1897 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
1898 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
1899 spec->num_mixers++;
1900 }
1901
1902 codec->patch_ops = via_patch_ops;
1903
1904 codec->patch_ops.init = via_auto_init;
1905#ifdef CONFIG_SND_HDA_POWER_SAVE
1906 spec->loopback.amplist = vt1708B_loopbacks;
1907#endif
1908
1909 return 0;
1910}
1911
1912static int patch_vt1708B_4ch(struct hda_codec *codec)
1913{
1914 struct via_spec *spec;
1915 int err;
1916
1917 /* create a codec specific record */
1918 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
1919 if (spec == NULL)
1920 return -ENOMEM;
1921
1922 codec->spec = spec;
1923
1924 /* automatic parse from the BIOS config */
1925 err = vt1708B_parse_auto_config(codec);
1926 if (err < 0) {
1927 via_free(codec);
1928 return err;
1929 } else if (!err) {
1930 printk(KERN_INFO "hda_codec: Cannot set up configuration "
1931 "from BIOS. Using genenic mode...\n");
1932 }
1933
1934 spec->init_verbs = vt1708B_4ch_volume_init_verbs;
1935
1936 spec->stream_name_analog = "VT1708B Analog";
1937 spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
1938 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
1939
1940 spec->stream_name_digital = "VT1708B Digital";
1941 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
1942 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
1943
1944 if (!spec->adc_nids && spec->input_mux) {
1945 spec->adc_nids = vt1708B_adc_nids;
1946 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
1947 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
1948 spec->num_mixers++;
1949 }
1950
1951 codec->patch_ops = via_patch_ops;
1952
1953 codec->patch_ops.init = via_auto_init;
1954#ifdef CONFIG_SND_HDA_POWER_SAVE
1955 spec->loopback.amplist = vt1708B_loopbacks;
1956#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001957
1958 return 0;
1959}
1960
1961/*
1962 * patch entries
1963 */
1964struct hda_codec_preset snd_hda_preset_via[] = {
1965 { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708},
1966 { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708},
1967 { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708},
1968 { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708},
Josepch Chanf7278fd2007-12-13 16:40:40 +01001969 { .id = 0x1106E710, .name = "VIA VT1709 10-Ch",
1970 .patch = patch_vt1709_10ch},
1971 { .id = 0x1106E711, .name = "VIA VT1709 10-Ch",
1972 .patch = patch_vt1709_10ch},
1973 { .id = 0x1106E712, .name = "VIA VT1709 10-Ch",
1974 .patch = patch_vt1709_10ch},
1975 { .id = 0x1106E713, .name = "VIA VT1709 10-Ch",
1976 .patch = patch_vt1709_10ch},
1977 { .id = 0x1106E714, .name = "VIA VT1709 6-Ch",
1978 .patch = patch_vt1709_6ch},
1979 { .id = 0x1106E715, .name = "VIA VT1709 6-Ch",
1980 .patch = patch_vt1709_6ch},
1981 { .id = 0x1106E716, .name = "VIA VT1709 6-Ch",
1982 .patch = patch_vt1709_6ch},
1983 { .id = 0x1106E717, .name = "VIA VT1709 6-Ch",
1984 .patch = patch_vt1709_6ch},
1985 { .id = 0x1106E720, .name = "VIA VT1708B 8-Ch",
1986 .patch = patch_vt1708B_8ch},
1987 { .id = 0x1106E721, .name = "VIA VT1708B 8-Ch",
1988 .patch = patch_vt1708B_8ch},
1989 { .id = 0x1106E722, .name = "VIA VT1708B 8-Ch",
1990 .patch = patch_vt1708B_8ch},
1991 { .id = 0x1106E723, .name = "VIA VT1708B 8-Ch",
1992 .patch = patch_vt1708B_8ch},
1993 { .id = 0x1106E724, .name = "VIA VT1708B 4-Ch",
1994 .patch = patch_vt1708B_4ch},
1995 { .id = 0x1106E725, .name = "VIA VT1708B 4-Ch",
1996 .patch = patch_vt1708B_4ch},
1997 { .id = 0x1106E726, .name = "VIA VT1708B 4-Ch",
1998 .patch = patch_vt1708B_4ch},
1999 { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch",
2000 .patch = patch_vt1708B_4ch},
Joseph Chanc577b8a2006-11-29 15:29:40 +01002001 {} /* terminator */
2002};