blob: 3e148373334db6578203fdb9418c78dd5b727006 [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"
Harvey Harrison3c9a3202008-02-29 11:59:26 +010042#include "hda_patch.h"
Joseph Chanc577b8a2006-11-29 15:29:40 +010043
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 {
Harald Welteeb14a462008-09-09 15:40:38 +080080 AUTO_SEQ_FRONT = 0,
Joseph Chanc577b8a2006-11-29 15:29:40 +010081 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) ||
Harald Welteeb14a462008-09-09 15:40:38 +0800286 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) ||
Harald Welteeb14a462008-09-09 15:40:38 +0800290 IS_VT1708B_4CH_VENDORID(vendor_id)) && (adc_idx == 0))
Josepch Chanf7278fd2007-12-13 16:40:40 +0100291 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;
Takashi Iwai9a081602008-02-12 18:37:26 +0100360 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
361 hinfo);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100362}
363
364static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
365 struct hda_codec *codec,
366 unsigned int stream_tag,
367 unsigned int format,
368 struct snd_pcm_substream *substream)
369{
370 struct via_spec *spec = codec->spec;
371 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
372 stream_tag, format, substream);
373}
374
375static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
376 struct hda_codec *codec,
377 struct snd_pcm_substream *substream)
378{
379 struct via_spec *spec = codec->spec;
380 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
381}
382
383/*
384 * Digital out
385 */
386static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
387 struct hda_codec *codec,
388 struct snd_pcm_substream *substream)
389{
390 struct via_spec *spec = codec->spec;
391 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
392}
393
394static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
395 struct hda_codec *codec,
396 struct snd_pcm_substream *substream)
397{
398 struct via_spec *spec = codec->spec;
399 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
400}
401
Takashi Iwai6b97eb42007-04-05 14:51:48 +0200402static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
403 struct hda_codec *codec,
404 unsigned int stream_tag,
405 unsigned int format,
406 struct snd_pcm_substream *substream)
407{
408 struct via_spec *spec = codec->spec;
409 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
410 stream_tag, format, substream);
411}
412
Joseph Chanc577b8a2006-11-29 15:29:40 +0100413/*
414 * Analog capture
415 */
416static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
417 struct hda_codec *codec,
418 unsigned int stream_tag,
419 unsigned int format,
420 struct snd_pcm_substream *substream)
421{
422 struct via_spec *spec = codec->spec;
423
424 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
425 stream_tag, 0, format);
426 return 0;
427}
428
429static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
430 struct hda_codec *codec,
431 struct snd_pcm_substream *substream)
432{
433 struct via_spec *spec = codec->spec;
Takashi Iwai888afa12008-03-18 09:57:50 +0100434 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100435 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
Takashi Iwaibc9b562382008-05-23 17:50:27 +0200450static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
451 .substreams = 1,
452 .channels_min = 2,
453 .channels_max = 8,
454 .nid = 0x10, /* NID to query formats and rates */
455 /* We got noisy outputs on the right channel on VT1708 when
456 * 24bit samples are used. Until any workaround is found,
457 * disable the 24bit format, so far.
458 */
459 .formats = SNDRV_PCM_FMTBIT_S16_LE,
460 .ops = {
461 .open = via_playback_pcm_open,
462 .prepare = via_playback_pcm_prepare,
463 .cleanup = via_playback_pcm_cleanup
464 },
465};
466
Joseph Chanc577b8a2006-11-29 15:29:40 +0100467static struct hda_pcm_stream vt1708_pcm_analog_capture = {
468 .substreams = 2,
469 .channels_min = 2,
470 .channels_max = 2,
471 .nid = 0x15, /* NID to query formats and rates */
472 .ops = {
473 .prepare = via_capture_pcm_prepare,
474 .cleanup = via_capture_pcm_cleanup
475 },
476};
477
478static struct hda_pcm_stream vt1708_pcm_digital_playback = {
479 .substreams = 1,
480 .channels_min = 2,
481 .channels_max = 2,
482 /* NID is set in via_build_pcms */
483 .ops = {
484 .open = via_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +0200485 .close = via_dig_playback_pcm_close,
486 .prepare = via_dig_playback_pcm_prepare
Joseph Chanc577b8a2006-11-29 15:29:40 +0100487 },
488};
489
490static struct hda_pcm_stream vt1708_pcm_digital_capture = {
491 .substreams = 1,
492 .channels_min = 2,
493 .channels_max = 2,
494};
495
496static int via_build_controls(struct hda_codec *codec)
497{
498 struct via_spec *spec = codec->spec;
499 int err;
500 int i;
501
502 for (i = 0; i < spec->num_mixers; i++) {
503 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
504 if (err < 0)
505 return err;
506 }
507
508 if (spec->multiout.dig_out_nid) {
509 err = snd_hda_create_spdif_out_ctls(codec,
510 spec->multiout.dig_out_nid);
511 if (err < 0)
512 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +0100513 err = snd_hda_create_spdif_share_sw(codec,
514 &spec->multiout);
515 if (err < 0)
516 return err;
517 spec->multiout.share_spdif = 1;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100518 }
519 if (spec->dig_in_nid) {
520 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
521 if (err < 0)
522 return err;
523 }
524 return 0;
525}
526
527static int via_build_pcms(struct hda_codec *codec)
528{
529 struct via_spec *spec = codec->spec;
530 struct hda_pcm *info = spec->pcm_rec;
531
532 codec->num_pcms = 1;
533 codec->pcm_info = info;
534
535 info->name = spec->stream_name_analog;
536 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
537 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
538 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
539 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
540
541 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
542 spec->multiout.max_channels;
543
544 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
545 codec->num_pcms++;
546 info++;
547 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +0100548 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100549 if (spec->multiout.dig_out_nid) {
550 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
551 *(spec->stream_digital_playback);
552 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
553 spec->multiout.dig_out_nid;
554 }
555 if (spec->dig_in_nid) {
556 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
557 *(spec->stream_digital_capture);
558 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
559 spec->dig_in_nid;
560 }
561 }
562
563 return 0;
564}
565
566static void via_free(struct hda_codec *codec)
567{
568 struct via_spec *spec = codec->spec;
569 unsigned int i;
570
571 if (!spec)
572 return;
573
574 if (spec->kctl_alloc) {
575 for (i = 0; i < spec->num_kctl_used; i++)
576 kfree(spec->kctl_alloc[i].name);
577 kfree(spec->kctl_alloc);
578 }
579
580 kfree(codec->spec);
581}
582
583static int via_init(struct hda_codec *codec)
584{
585 struct via_spec *spec = codec->spec;
586 snd_hda_sequence_write(codec, spec->init_verbs);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100587 /* Lydia Add for EAPD enable */
588 if (!spec->dig_in_nid) { /* No Digital In connection */
589 if (IS_VT1708_VENDORID(codec->vendor_id)) {
590 snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
591 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100592 PIN_OUT);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100593 snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
594 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
595 } else if (IS_VT1709_10CH_VENDORID(codec->vendor_id) ||
596 IS_VT1709_6CH_VENDORID(codec->vendor_id)) {
597 snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
598 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100599 PIN_OUT);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100600 snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
601 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
602 } else if (IS_VT1708B_8CH_VENDORID(codec->vendor_id) ||
603 IS_VT1708B_4CH_VENDORID(codec->vendor_id)) {
604 snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
605 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100606 PIN_OUT);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100607 snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
608 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
609 }
Takashi Iwai12b74c82008-01-15 12:39:38 +0100610 } else /* enable SPDIF-input pin */
611 snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
612 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100613
Joseph Chanc577b8a2006-11-29 15:29:40 +0100614 return 0;
615}
616
Takashi Iwaicb53c622007-08-10 17:21:45 +0200617#ifdef CONFIG_SND_HDA_POWER_SAVE
618static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
619{
620 struct via_spec *spec = codec->spec;
621 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
622}
623#endif
624
Joseph Chanc577b8a2006-11-29 15:29:40 +0100625/*
626 */
627static struct hda_codec_ops via_patch_ops = {
628 .build_controls = via_build_controls,
629 .build_pcms = via_build_pcms,
630 .init = via_init,
631 .free = via_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +0200632#ifdef CONFIG_SND_HDA_POWER_SAVE
633 .check_power_status = via_check_power_status,
634#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +0100635};
636
637/* fill in the dac_nids table from the parsed pin configuration */
638static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
639 const struct auto_pin_cfg *cfg)
640{
641 int i;
642 hda_nid_t nid;
643
644 spec->multiout.num_dacs = cfg->line_outs;
645
646 spec->multiout.dac_nids = spec->private_dac_nids;
647
648 for(i = 0; i < 4; i++) {
649 nid = cfg->line_out_pins[i];
650 if (nid) {
651 /* config dac list */
652 switch (i) {
653 case AUTO_SEQ_FRONT:
654 spec->multiout.dac_nids[i] = 0x10;
655 break;
656 case AUTO_SEQ_CENLFE:
657 spec->multiout.dac_nids[i] = 0x12;
658 break;
659 case AUTO_SEQ_SURROUND:
660 spec->multiout.dac_nids[i] = 0x13;
661 break;
662 case AUTO_SEQ_SIDE:
663 spec->multiout.dac_nids[i] = 0x11;
664 break;
665 }
666 }
667 }
668
669 return 0;
670}
671
672/* add playback controls from the parsed DAC table */
673static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
674 const struct auto_pin_cfg *cfg)
675{
676 char name[32];
677 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
678 hda_nid_t nid, nid_vol = 0;
679 int i, err;
680
681 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
682 nid = cfg->line_out_pins[i];
683
684 if (!nid)
685 continue;
686
687 if (i != AUTO_SEQ_FRONT)
688 nid_vol = 0x1b - i + 1;
689
690 if (i == AUTO_SEQ_CENLFE) {
691 /* Center/LFE */
692 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100693 "Center Playback Volume",
694 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
695 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100696 if (err < 0)
697 return err;
698 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
699 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100700 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
701 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100702 if (err < 0)
703 return err;
704 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
705 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100706 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
707 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100708 if (err < 0)
709 return err;
710 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
711 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100712 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
713 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100714 if (err < 0)
715 return err;
716 } else if (i == AUTO_SEQ_FRONT){
717 /* add control to mixer index 0 */
718 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
719 "Master Front Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100720 HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
721 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100722 if (err < 0)
723 return err;
724 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
725 "Master Front Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100726 HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
727 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100728 if (err < 0)
729 return err;
730
731 /* add control to PW3 */
732 sprintf(name, "%s Playback Volume", chname[i]);
733 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100734 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
735 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100736 if (err < 0)
737 return err;
738 sprintf(name, "%s Playback Switch", chname[i]);
739 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100740 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
741 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100742 if (err < 0)
743 return err;
744 } else {
745 sprintf(name, "%s Playback Volume", chname[i]);
746 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100747 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
748 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100749 if (err < 0)
750 return err;
751 sprintf(name, "%s Playback Switch", chname[i]);
752 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100753 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
754 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100755 if (err < 0)
756 return err;
757 }
758 }
759
760 return 0;
761}
762
763static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
764{
765 int err;
766
767 if (!pin)
768 return 0;
769
770 spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
771
772 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
773 "Headphone Playback Volume",
774 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
775 if (err < 0)
776 return err;
777 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
778 "Headphone Playback Switch",
779 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
780 if (err < 0)
781 return err;
782
783 return 0;
784}
785
786/* create playback/capture controls for input pins */
787static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
788 const struct auto_pin_cfg *cfg)
789{
790 static char *labels[] = {
791 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
792 };
793 struct hda_input_mux *imux = &spec->private_imux;
794 int i, err, idx = 0;
795
796 /* for internal loopback recording select */
797 imux->items[imux->num_items].label = "Stereo Mixer";
798 imux->items[imux->num_items].index = idx;
799 imux->num_items++;
800
801 for (i = 0; i < AUTO_PIN_LAST; i++) {
802 if (!cfg->input_pins[i])
803 continue;
804
805 switch (cfg->input_pins[i]) {
806 case 0x1d: /* Mic */
807 idx = 2;
808 break;
809
810 case 0x1e: /* Line In */
811 idx = 3;
812 break;
813
814 case 0x21: /* Front Mic */
815 idx = 4;
816 break;
817
818 case 0x24: /* CD */
819 idx = 1;
820 break;
821 }
822 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
823 idx, 0x17);
824 if (err < 0)
825 return err;
826 imux->items[imux->num_items].label = labels[i];
827 imux->items[imux->num_items].index = idx;
828 imux->num_items++;
829 }
830 return 0;
831}
832
Takashi Iwaicb53c622007-08-10 17:21:45 +0200833#ifdef CONFIG_SND_HDA_POWER_SAVE
834static struct hda_amp_list vt1708_loopbacks[] = {
835 { 0x17, HDA_INPUT, 1 },
836 { 0x17, HDA_INPUT, 2 },
837 { 0x17, HDA_INPUT, 3 },
838 { 0x17, HDA_INPUT, 4 },
839 { } /* end */
840};
841#endif
842
Joseph Chanc577b8a2006-11-29 15:29:40 +0100843static int vt1708_parse_auto_config(struct hda_codec *codec)
844{
845 struct via_spec *spec = codec->spec;
846 int err;
847
848 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
849 if (err < 0)
850 return err;
851 err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
852 if (err < 0)
853 return err;
854 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
855 return 0; /* can't find valid BIOS pin config */
856
857 err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
858 if (err < 0)
859 return err;
860 err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
861 if (err < 0)
862 return err;
863 err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
864 if (err < 0)
865 return err;
866
867 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
868
869 if (spec->autocfg.dig_out_pin)
870 spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
871 if (spec->autocfg.dig_in_pin)
872 spec->dig_in_nid = VT1708_DIGIN_NID;
873
874 if (spec->kctl_alloc)
875 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
876
877 spec->init_verbs = vt1708_volume_init_verbs;
878
879 spec->input_mux = &spec->private_imux;
880
881 return 1;
882}
883
884/* init callback for auto-configuration model -- overriding the default init */
885static int via_auto_init(struct hda_codec *codec)
886{
887 via_init(codec);
888 via_auto_init_multi_out(codec);
889 via_auto_init_hp_out(codec);
890 via_auto_init_analog_input(codec);
891 return 0;
892}
893
894static int patch_vt1708(struct hda_codec *codec)
895{
896 struct via_spec *spec;
897 int err;
898
899 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +0800900 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100901 if (spec == NULL)
902 return -ENOMEM;
903
904 codec->spec = spec;
905
906 /* automatic parse from the BIOS config */
907 err = vt1708_parse_auto_config(codec);
908 if (err < 0) {
909 via_free(codec);
910 return err;
911 } else if (!err) {
912 printk(KERN_INFO "hda_codec: Cannot set up configuration "
913 "from BIOS. Using genenic mode...\n");
914 }
915
916
917 spec->stream_name_analog = "VT1708 Analog";
918 spec->stream_analog_playback = &vt1708_pcm_analog_playback;
Takashi Iwaibc9b562382008-05-23 17:50:27 +0200919 /* disable 32bit format on VT1708 */
920 if (codec->vendor_id == 0x11061708)
921 spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100922 spec->stream_analog_capture = &vt1708_pcm_analog_capture;
923
924 spec->stream_name_digital = "VT1708 Digital";
925 spec->stream_digital_playback = &vt1708_pcm_digital_playback;
926 spec->stream_digital_capture = &vt1708_pcm_digital_capture;
927
928
929 if (!spec->adc_nids && spec->input_mux) {
930 spec->adc_nids = vt1708_adc_nids;
931 spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
932 spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
933 spec->num_mixers++;
934 }
935
936 codec->patch_ops = via_patch_ops;
937
938 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200939#ifdef CONFIG_SND_HDA_POWER_SAVE
940 spec->loopback.amplist = vt1708_loopbacks;
941#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +0100942
943 return 0;
944}
945
946/* capture mixer elements */
947static struct snd_kcontrol_new vt1709_capture_mixer[] = {
948 HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
949 HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
950 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
951 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
952 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
953 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
954 {
955 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
956 /* The multiple "Capture Source" controls confuse alsamixer
957 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +0100958 */
959 /* .name = "Capture Source", */
960 .name = "Input Source",
961 .count = 1,
962 .info = via_mux_enum_info,
963 .get = via_mux_enum_get,
964 .put = via_mux_enum_put,
965 },
966 { } /* end */
967};
968
969/*
970 * generic initialization of ADC, input mixers and output mixers
971 */
972static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
973 /*
974 * Unmute ADC0-2 and set the default input to mic-in
975 */
976 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
977 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
978 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
979
980
Josepch Chanf7278fd2007-12-13 16:40:40 +0100981 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +0100982 * mixer widget
983 */
984 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +0100985 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
986 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
987 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
988 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
989 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100990
991 /*
992 * Set up output selector (0x1a, 0x1b, 0x29)
993 */
994 /* set vol=0 to output mixers */
995 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
996 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
997 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
998
999 /*
1000 * Unmute PW3 and PW4
1001 */
1002 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1003 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1004
1005 /* Set input of PW4 as AOW4 */
1006 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001007 /* PW9 Output enable */
1008 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1009 { }
1010};
1011
1012static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
1013 .substreams = 1,
1014 .channels_min = 2,
1015 .channels_max = 10,
1016 .nid = 0x10, /* NID to query formats and rates */
1017 .ops = {
1018 .open = via_playback_pcm_open,
1019 .prepare = via_playback_pcm_prepare,
1020 .cleanup = via_playback_pcm_cleanup
1021 },
1022};
1023
1024static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
1025 .substreams = 1,
1026 .channels_min = 2,
1027 .channels_max = 6,
1028 .nid = 0x10, /* NID to query formats and rates */
1029 .ops = {
1030 .open = via_playback_pcm_open,
1031 .prepare = via_playback_pcm_prepare,
1032 .cleanup = via_playback_pcm_cleanup
1033 },
1034};
1035
1036static struct hda_pcm_stream vt1709_pcm_analog_capture = {
1037 .substreams = 2,
1038 .channels_min = 2,
1039 .channels_max = 2,
1040 .nid = 0x14, /* NID to query formats and rates */
1041 .ops = {
1042 .prepare = via_capture_pcm_prepare,
1043 .cleanup = via_capture_pcm_cleanup
1044 },
1045};
1046
1047static struct hda_pcm_stream vt1709_pcm_digital_playback = {
1048 .substreams = 1,
1049 .channels_min = 2,
1050 .channels_max = 2,
1051 /* NID is set in via_build_pcms */
1052 .ops = {
1053 .open = via_dig_playback_pcm_open,
1054 .close = via_dig_playback_pcm_close
1055 },
1056};
1057
1058static struct hda_pcm_stream vt1709_pcm_digital_capture = {
1059 .substreams = 1,
1060 .channels_min = 2,
1061 .channels_max = 2,
1062};
1063
1064static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
1065 const struct auto_pin_cfg *cfg)
1066{
1067 int i;
1068 hda_nid_t nid;
1069
1070 if (cfg->line_outs == 4) /* 10 channels */
1071 spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
1072 else if (cfg->line_outs == 3) /* 6 channels */
1073 spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
1074
1075 spec->multiout.dac_nids = spec->private_dac_nids;
1076
1077 if (cfg->line_outs == 4) { /* 10 channels */
1078 for (i = 0; i < cfg->line_outs; i++) {
1079 nid = cfg->line_out_pins[i];
1080 if (nid) {
1081 /* config dac list */
1082 switch (i) {
1083 case AUTO_SEQ_FRONT:
1084 /* AOW0 */
1085 spec->multiout.dac_nids[i] = 0x10;
1086 break;
1087 case AUTO_SEQ_CENLFE:
1088 /* AOW2 */
1089 spec->multiout.dac_nids[i] = 0x12;
1090 break;
1091 case AUTO_SEQ_SURROUND:
1092 /* AOW3 */
1093 spec->multiout.dac_nids[i] = 0x27;
1094 break;
1095 case AUTO_SEQ_SIDE:
1096 /* AOW1 */
1097 spec->multiout.dac_nids[i] = 0x11;
1098 break;
1099 default:
1100 break;
1101 }
1102 }
1103 }
1104 spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
1105
1106 } else if (cfg->line_outs == 3) { /* 6 channels */
1107 for(i = 0; i < cfg->line_outs; i++) {
1108 nid = cfg->line_out_pins[i];
1109 if (nid) {
1110 /* config dac list */
1111 switch(i) {
1112 case AUTO_SEQ_FRONT:
1113 /* AOW0 */
1114 spec->multiout.dac_nids[i] = 0x10;
1115 break;
1116 case AUTO_SEQ_CENLFE:
1117 /* AOW2 */
1118 spec->multiout.dac_nids[i] = 0x12;
1119 break;
1120 case AUTO_SEQ_SURROUND:
1121 /* AOW1 */
1122 spec->multiout.dac_nids[i] = 0x11;
1123 break;
1124 default:
1125 break;
1126 }
1127 }
1128 }
1129 }
1130
1131 return 0;
1132}
1133
1134/* add playback controls from the parsed DAC table */
1135static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
1136 const struct auto_pin_cfg *cfg)
1137{
1138 char name[32];
1139 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1140 hda_nid_t nid = 0;
1141 int i, err;
1142
1143 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1144 nid = cfg->line_out_pins[i];
1145
1146 if (!nid)
1147 continue;
1148
1149 if (i == AUTO_SEQ_CENLFE) {
1150 /* Center/LFE */
1151 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1152 "Center Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001153 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
1154 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001155 if (err < 0)
1156 return err;
1157 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1158 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001159 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
1160 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001161 if (err < 0)
1162 return err;
1163 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1164 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001165 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
1166 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001167 if (err < 0)
1168 return err;
1169 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1170 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001171 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
1172 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001173 if (err < 0)
1174 return err;
1175 } else if (i == AUTO_SEQ_FRONT){
1176 /* add control to mixer index 0 */
1177 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1178 "Master Front Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001179 HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
1180 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001181 if (err < 0)
1182 return err;
1183 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1184 "Master Front Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001185 HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
1186 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001187 if (err < 0)
1188 return err;
1189
1190 /* add control to PW3 */
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(nid, 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(nid, 3, 0,
1200 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001201 if (err < 0)
1202 return err;
1203 } else if (i == AUTO_SEQ_SURROUND) {
1204 sprintf(name, "%s Playback Volume", chname[i]);
1205 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001206 HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
1207 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001208 if (err < 0)
1209 return err;
1210 sprintf(name, "%s Playback Switch", chname[i]);
1211 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001212 HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
1213 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001214 if (err < 0)
1215 return err;
1216 } else if (i == AUTO_SEQ_SIDE) {
1217 sprintf(name, "%s Playback Volume", chname[i]);
1218 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001219 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
1220 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001221 if (err < 0)
1222 return err;
1223 sprintf(name, "%s Playback Switch", chname[i]);
1224 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001225 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
1226 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001227 if (err < 0)
1228 return err;
1229 }
1230 }
1231
1232 return 0;
1233}
1234
1235static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1236{
1237 int err;
1238
1239 if (!pin)
1240 return 0;
1241
1242 if (spec->multiout.num_dacs == 5) /* 10 channels */
1243 spec->multiout.hp_nid = VT1709_HP_DAC_NID;
1244 else if (spec->multiout.num_dacs == 3) /* 6 channels */
1245 spec->multiout.hp_nid = 0;
1246
1247 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1248 "Headphone Playback Volume",
1249 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1250 if (err < 0)
1251 return err;
1252 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1253 "Headphone Playback Switch",
1254 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1255 if (err < 0)
1256 return err;
1257
1258 return 0;
1259}
1260
1261/* create playback/capture controls for input pins */
1262static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
1263 const struct auto_pin_cfg *cfg)
1264{
1265 static char *labels[] = {
1266 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1267 };
1268 struct hda_input_mux *imux = &spec->private_imux;
1269 int i, err, idx = 0;
1270
1271 /* for internal loopback recording select */
1272 imux->items[imux->num_items].label = "Stereo Mixer";
1273 imux->items[imux->num_items].index = idx;
1274 imux->num_items++;
1275
1276 for (i = 0; i < AUTO_PIN_LAST; i++) {
1277 if (!cfg->input_pins[i])
1278 continue;
1279
1280 switch (cfg->input_pins[i]) {
1281 case 0x1d: /* Mic */
1282 idx = 2;
1283 break;
1284
1285 case 0x1e: /* Line In */
1286 idx = 3;
1287 break;
1288
1289 case 0x21: /* Front Mic */
1290 idx = 4;
1291 break;
1292
1293 case 0x23: /* CD */
1294 idx = 1;
1295 break;
1296 }
1297 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
1298 idx, 0x18);
1299 if (err < 0)
1300 return err;
1301 imux->items[imux->num_items].label = labels[i];
1302 imux->items[imux->num_items].index = idx;
1303 imux->num_items++;
1304 }
1305 return 0;
1306}
1307
1308static int vt1709_parse_auto_config(struct hda_codec *codec)
1309{
1310 struct via_spec *spec = codec->spec;
1311 int err;
1312
1313 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1314 if (err < 0)
1315 return err;
1316 err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
1317 if (err < 0)
1318 return err;
1319 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1320 return 0; /* can't find valid BIOS pin config */
1321
1322 err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
1323 if (err < 0)
1324 return err;
1325 err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1326 if (err < 0)
1327 return err;
1328 err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
1329 if (err < 0)
1330 return err;
1331
1332 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1333
1334 if (spec->autocfg.dig_out_pin)
1335 spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
1336 if (spec->autocfg.dig_in_pin)
1337 spec->dig_in_nid = VT1709_DIGIN_NID;
1338
1339 if (spec->kctl_alloc)
1340 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
1341
1342 spec->input_mux = &spec->private_imux;
1343
1344 return 1;
1345}
1346
Takashi Iwaicb53c622007-08-10 17:21:45 +02001347#ifdef CONFIG_SND_HDA_POWER_SAVE
1348static struct hda_amp_list vt1709_loopbacks[] = {
1349 { 0x18, HDA_INPUT, 1 },
1350 { 0x18, HDA_INPUT, 2 },
1351 { 0x18, HDA_INPUT, 3 },
1352 { 0x18, HDA_INPUT, 4 },
1353 { } /* end */
1354};
1355#endif
1356
Joseph Chanc577b8a2006-11-29 15:29:40 +01001357static int patch_vt1709_10ch(struct hda_codec *codec)
1358{
1359 struct via_spec *spec;
1360 int err;
1361
1362 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08001363 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001364 if (spec == NULL)
1365 return -ENOMEM;
1366
1367 codec->spec = spec;
1368
1369 err = vt1709_parse_auto_config(codec);
1370 if (err < 0) {
1371 via_free(codec);
1372 return err;
1373 } else if (!err) {
1374 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
1375 "Using genenic mode...\n");
1376 }
1377
1378 spec->init_verbs = vt1709_10ch_volume_init_verbs;
1379
1380 spec->stream_name_analog = "VT1709 Analog";
1381 spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
1382 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1383
1384 spec->stream_name_digital = "VT1709 Digital";
1385 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1386 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1387
1388
1389 if (!spec->adc_nids && spec->input_mux) {
1390 spec->adc_nids = vt1709_adc_nids;
1391 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
1392 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1393 spec->num_mixers++;
1394 }
1395
1396 codec->patch_ops = via_patch_ops;
1397
1398 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001399#ifdef CONFIG_SND_HDA_POWER_SAVE
1400 spec->loopback.amplist = vt1709_loopbacks;
1401#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001402
1403 return 0;
1404}
1405/*
1406 * generic initialization of ADC, input mixers and output mixers
1407 */
1408static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
1409 /*
1410 * Unmute ADC0-2 and set the default input to mic-in
1411 */
1412 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1413 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1414 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1415
1416
1417 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1418 * mixer widget
1419 */
1420 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1421 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1422 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1423 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1424 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1425 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1426
1427 /*
1428 * Set up output selector (0x1a, 0x1b, 0x29)
1429 */
1430 /* set vol=0 to output mixers */
1431 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1432 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1433 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1434
1435 /*
1436 * Unmute PW3 and PW4
1437 */
1438 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1439 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1440
1441 /* Set input of PW4 as MW0 */
1442 {0x20, AC_VERB_SET_CONNECT_SEL, 0},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001443 /* PW9 Output enable */
1444 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1445 { }
1446};
1447
1448static int patch_vt1709_6ch(struct hda_codec *codec)
1449{
1450 struct via_spec *spec;
1451 int err;
1452
1453 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08001454 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001455 if (spec == NULL)
1456 return -ENOMEM;
1457
1458 codec->spec = spec;
1459
1460 err = vt1709_parse_auto_config(codec);
1461 if (err < 0) {
1462 via_free(codec);
1463 return err;
1464 } else if (!err) {
1465 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
1466 "Using genenic mode...\n");
1467 }
1468
1469 spec->init_verbs = vt1709_6ch_volume_init_verbs;
1470
1471 spec->stream_name_analog = "VT1709 Analog";
1472 spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
1473 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1474
1475 spec->stream_name_digital = "VT1709 Digital";
1476 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1477 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1478
1479
1480 if (!spec->adc_nids && spec->input_mux) {
1481 spec->adc_nids = vt1709_adc_nids;
1482 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
1483 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1484 spec->num_mixers++;
1485 }
1486
1487 codec->patch_ops = via_patch_ops;
1488
1489 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001490#ifdef CONFIG_SND_HDA_POWER_SAVE
1491 spec->loopback.amplist = vt1709_loopbacks;
1492#endif
Josepch Chanf7278fd2007-12-13 16:40:40 +01001493 return 0;
1494}
1495
1496/* capture mixer elements */
1497static struct snd_kcontrol_new vt1708B_capture_mixer[] = {
1498 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
1499 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
1500 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
1501 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
1502 {
1503 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1504 /* The multiple "Capture Source" controls confuse alsamixer
1505 * So call somewhat different..
Josepch Chanf7278fd2007-12-13 16:40:40 +01001506 */
1507 /* .name = "Capture Source", */
1508 .name = "Input Source",
1509 .count = 1,
1510 .info = via_mux_enum_info,
1511 .get = via_mux_enum_get,
1512 .put = via_mux_enum_put,
1513 },
1514 { } /* end */
1515};
1516/*
1517 * generic initialization of ADC, input mixers and output mixers
1518 */
1519static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
1520 /*
1521 * Unmute ADC0-1 and set the default input to mic-in
1522 */
1523 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1524 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1525
1526
1527 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1528 * mixer widget
1529 */
1530 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1531 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1532 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1533 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1534 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1535 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1536
1537 /*
1538 * Set up output mixers
1539 */
1540 /* set vol=0 to output mixers */
1541 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1542 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1543 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1544
1545 /* Setup default input to PW4 */
1546 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1},
1547 /* PW9 Output enable */
1548 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1549 /* PW10 Input enable */
1550 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
1551 { }
1552};
1553
1554static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
1555 /*
1556 * Unmute ADC0-1 and set the default input to mic-in
1557 */
1558 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1559 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1560
1561
1562 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1563 * mixer widget
1564 */
1565 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1566 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1567 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1568 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1569 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1570 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1571
1572 /*
1573 * Set up output mixers
1574 */
1575 /* set vol=0 to output mixers */
1576 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1577 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1578 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1579
1580 /* Setup default input of PW4 to MW0 */
1581 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
1582 /* PW9 Output enable */
1583 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1584 /* PW10 Input enable */
1585 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
1586 { }
1587};
1588
1589static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
1590 .substreams = 1,
1591 .channels_min = 2,
1592 .channels_max = 8,
1593 .nid = 0x10, /* NID to query formats and rates */
1594 .ops = {
1595 .open = via_playback_pcm_open,
1596 .prepare = via_playback_pcm_prepare,
1597 .cleanup = via_playback_pcm_cleanup
1598 },
1599};
1600
1601static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
1602 .substreams = 1,
1603 .channels_min = 2,
1604 .channels_max = 4,
1605 .nid = 0x10, /* NID to query formats and rates */
1606 .ops = {
1607 .open = via_playback_pcm_open,
1608 .prepare = via_playback_pcm_prepare,
1609 .cleanup = via_playback_pcm_cleanup
1610 },
1611};
1612
1613static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
1614 .substreams = 2,
1615 .channels_min = 2,
1616 .channels_max = 2,
1617 .nid = 0x13, /* NID to query formats and rates */
1618 .ops = {
1619 .prepare = via_capture_pcm_prepare,
1620 .cleanup = via_capture_pcm_cleanup
1621 },
1622};
1623
1624static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
1625 .substreams = 1,
1626 .channels_min = 2,
1627 .channels_max = 2,
1628 /* NID is set in via_build_pcms */
1629 .ops = {
1630 .open = via_dig_playback_pcm_open,
1631 .close = via_dig_playback_pcm_close,
1632 .prepare = via_dig_playback_pcm_prepare
1633 },
1634};
1635
1636static struct hda_pcm_stream vt1708B_pcm_digital_capture = {
1637 .substreams = 1,
1638 .channels_min = 2,
1639 .channels_max = 2,
1640};
1641
1642/* fill in the dac_nids table from the parsed pin configuration */
1643static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
1644 const struct auto_pin_cfg *cfg)
1645{
1646 int i;
1647 hda_nid_t nid;
1648
1649 spec->multiout.num_dacs = cfg->line_outs;
1650
1651 spec->multiout.dac_nids = spec->private_dac_nids;
1652
1653 for (i = 0; i < 4; i++) {
1654 nid = cfg->line_out_pins[i];
1655 if (nid) {
1656 /* config dac list */
1657 switch (i) {
1658 case AUTO_SEQ_FRONT:
1659 spec->multiout.dac_nids[i] = 0x10;
1660 break;
1661 case AUTO_SEQ_CENLFE:
1662 spec->multiout.dac_nids[i] = 0x24;
1663 break;
1664 case AUTO_SEQ_SURROUND:
1665 spec->multiout.dac_nids[i] = 0x25;
1666 break;
1667 case AUTO_SEQ_SIDE:
1668 spec->multiout.dac_nids[i] = 0x11;
1669 break;
1670 }
1671 }
1672 }
1673
1674 return 0;
1675}
1676
1677/* add playback controls from the parsed DAC table */
1678static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
1679 const struct auto_pin_cfg *cfg)
1680{
1681 char name[32];
1682 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1683 hda_nid_t nid_vols[] = {0x16, 0x27, 0x26, 0x18};
1684 hda_nid_t nid, nid_vol = 0;
1685 int i, err;
1686
1687 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1688 nid = cfg->line_out_pins[i];
1689
1690 if (!nid)
1691 continue;
1692
1693 nid_vol = nid_vols[i];
1694
1695 if (i == AUTO_SEQ_CENLFE) {
1696 /* Center/LFE */
1697 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1698 "Center Playback Volume",
1699 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1700 HDA_OUTPUT));
1701 if (err < 0)
1702 return err;
1703 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1704 "LFE Playback Volume",
1705 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1706 HDA_OUTPUT));
1707 if (err < 0)
1708 return err;
1709 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1710 "Center Playback Switch",
1711 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1712 HDA_OUTPUT));
1713 if (err < 0)
1714 return err;
1715 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1716 "LFE Playback Switch",
1717 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1718 HDA_OUTPUT));
1719 if (err < 0)
1720 return err;
1721 } else if (i == AUTO_SEQ_FRONT) {
1722 /* add control to mixer index 0 */
1723 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1724 "Master Front Playback Volume",
1725 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1726 HDA_INPUT));
1727 if (err < 0)
1728 return err;
1729 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1730 "Master Front Playback Switch",
1731 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1732 HDA_INPUT));
1733 if (err < 0)
1734 return err;
1735
1736 /* add control to PW3 */
1737 sprintf(name, "%s Playback Volume", chname[i]);
1738 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1739 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1740 HDA_OUTPUT));
1741 if (err < 0)
1742 return err;
1743 sprintf(name, "%s Playback Switch", chname[i]);
1744 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1745 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1746 HDA_OUTPUT));
1747 if (err < 0)
1748 return err;
1749 } else {
1750 sprintf(name, "%s Playback Volume", chname[i]);
1751 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1752 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1753 HDA_OUTPUT));
1754 if (err < 0)
1755 return err;
1756 sprintf(name, "%s Playback Switch", chname[i]);
1757 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1758 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1759 HDA_OUTPUT));
1760 if (err < 0)
1761 return err;
1762 }
1763 }
1764
1765 return 0;
1766}
1767
1768static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1769{
1770 int err;
1771
1772 if (!pin)
1773 return 0;
1774
1775 spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
1776
1777 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1778 "Headphone Playback Volume",
1779 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1780 if (err < 0)
1781 return err;
1782 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1783 "Headphone Playback Switch",
1784 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1785 if (err < 0)
1786 return err;
1787
1788 return 0;
1789}
1790
1791/* create playback/capture controls for input pins */
1792static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
1793 const struct auto_pin_cfg *cfg)
1794{
1795 static char *labels[] = {
1796 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1797 };
1798 struct hda_input_mux *imux = &spec->private_imux;
1799 int i, err, idx = 0;
1800
1801 /* for internal loopback recording select */
1802 imux->items[imux->num_items].label = "Stereo Mixer";
1803 imux->items[imux->num_items].index = idx;
1804 imux->num_items++;
1805
1806 for (i = 0; i < AUTO_PIN_LAST; i++) {
1807 if (!cfg->input_pins[i])
1808 continue;
1809
1810 switch (cfg->input_pins[i]) {
1811 case 0x1a: /* Mic */
1812 idx = 2;
1813 break;
1814
1815 case 0x1b: /* Line In */
1816 idx = 3;
1817 break;
1818
1819 case 0x1e: /* Front Mic */
1820 idx = 4;
1821 break;
1822
1823 case 0x1f: /* CD */
1824 idx = 1;
1825 break;
1826 }
1827 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
1828 idx, 0x16);
1829 if (err < 0)
1830 return err;
1831 imux->items[imux->num_items].label = labels[i];
1832 imux->items[imux->num_items].index = idx;
1833 imux->num_items++;
1834 }
1835 return 0;
1836}
1837
1838static int vt1708B_parse_auto_config(struct hda_codec *codec)
1839{
1840 struct via_spec *spec = codec->spec;
1841 int err;
1842
1843 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1844 if (err < 0)
1845 return err;
1846 err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg);
1847 if (err < 0)
1848 return err;
1849 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1850 return 0; /* can't find valid BIOS pin config */
1851
1852 err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg);
1853 if (err < 0)
1854 return err;
1855 err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1856 if (err < 0)
1857 return err;
1858 err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
1859 if (err < 0)
1860 return err;
1861
1862 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1863
1864 if (spec->autocfg.dig_out_pin)
1865 spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
1866 if (spec->autocfg.dig_in_pin)
1867 spec->dig_in_nid = VT1708B_DIGIN_NID;
1868
1869 if (spec->kctl_alloc)
1870 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
1871
1872 spec->input_mux = &spec->private_imux;
1873
1874 return 1;
1875}
1876
1877#ifdef CONFIG_SND_HDA_POWER_SAVE
1878static struct hda_amp_list vt1708B_loopbacks[] = {
1879 { 0x16, HDA_INPUT, 1 },
1880 { 0x16, HDA_INPUT, 2 },
1881 { 0x16, HDA_INPUT, 3 },
1882 { 0x16, HDA_INPUT, 4 },
1883 { } /* end */
1884};
1885#endif
1886
1887static int patch_vt1708B_8ch(struct hda_codec *codec)
1888{
1889 struct via_spec *spec;
1890 int err;
1891
1892 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08001893 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01001894 if (spec == NULL)
1895 return -ENOMEM;
1896
1897 codec->spec = spec;
1898
1899 /* automatic parse from the BIOS config */
1900 err = vt1708B_parse_auto_config(codec);
1901 if (err < 0) {
1902 via_free(codec);
1903 return err;
1904 } else if (!err) {
1905 printk(KERN_INFO "hda_codec: Cannot set up configuration "
1906 "from BIOS. Using genenic mode...\n");
1907 }
1908
1909 spec->init_verbs = vt1708B_8ch_volume_init_verbs;
1910
1911 spec->stream_name_analog = "VT1708B Analog";
1912 spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
1913 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
1914
1915 spec->stream_name_digital = "VT1708B Digital";
1916 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
1917 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
1918
1919 if (!spec->adc_nids && spec->input_mux) {
1920 spec->adc_nids = vt1708B_adc_nids;
1921 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
1922 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
1923 spec->num_mixers++;
1924 }
1925
1926 codec->patch_ops = via_patch_ops;
1927
1928 codec->patch_ops.init = via_auto_init;
1929#ifdef CONFIG_SND_HDA_POWER_SAVE
1930 spec->loopback.amplist = vt1708B_loopbacks;
1931#endif
1932
1933 return 0;
1934}
1935
1936static int patch_vt1708B_4ch(struct hda_codec *codec)
1937{
1938 struct via_spec *spec;
1939 int err;
1940
1941 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08001942 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01001943 if (spec == NULL)
1944 return -ENOMEM;
1945
1946 codec->spec = spec;
1947
1948 /* automatic parse from the BIOS config */
1949 err = vt1708B_parse_auto_config(codec);
1950 if (err < 0) {
1951 via_free(codec);
1952 return err;
1953 } else if (!err) {
1954 printk(KERN_INFO "hda_codec: Cannot set up configuration "
1955 "from BIOS. Using genenic mode...\n");
1956 }
1957
1958 spec->init_verbs = vt1708B_4ch_volume_init_verbs;
1959
1960 spec->stream_name_analog = "VT1708B Analog";
1961 spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
1962 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
1963
1964 spec->stream_name_digital = "VT1708B Digital";
1965 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
1966 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
1967
1968 if (!spec->adc_nids && spec->input_mux) {
1969 spec->adc_nids = vt1708B_adc_nids;
1970 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
1971 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
1972 spec->num_mixers++;
1973 }
1974
1975 codec->patch_ops = via_patch_ops;
1976
1977 codec->patch_ops.init = via_auto_init;
1978#ifdef CONFIG_SND_HDA_POWER_SAVE
1979 spec->loopback.amplist = vt1708B_loopbacks;
1980#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001981
1982 return 0;
1983}
1984
1985/*
1986 * patch entries
1987 */
1988struct hda_codec_preset snd_hda_preset_via[] = {
1989 { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708},
1990 { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708},
1991 { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708},
1992 { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708},
Josepch Chanf7278fd2007-12-13 16:40:40 +01001993 { .id = 0x1106E710, .name = "VIA VT1709 10-Ch",
1994 .patch = patch_vt1709_10ch},
1995 { .id = 0x1106E711, .name = "VIA VT1709 10-Ch",
1996 .patch = patch_vt1709_10ch},
1997 { .id = 0x1106E712, .name = "VIA VT1709 10-Ch",
1998 .patch = patch_vt1709_10ch},
1999 { .id = 0x1106E713, .name = "VIA VT1709 10-Ch",
2000 .patch = patch_vt1709_10ch},
2001 { .id = 0x1106E714, .name = "VIA VT1709 6-Ch",
2002 .patch = patch_vt1709_6ch},
2003 { .id = 0x1106E715, .name = "VIA VT1709 6-Ch",
2004 .patch = patch_vt1709_6ch},
2005 { .id = 0x1106E716, .name = "VIA VT1709 6-Ch",
2006 .patch = patch_vt1709_6ch},
2007 { .id = 0x1106E717, .name = "VIA VT1709 6-Ch",
2008 .patch = patch_vt1709_6ch},
2009 { .id = 0x1106E720, .name = "VIA VT1708B 8-Ch",
2010 .patch = patch_vt1708B_8ch},
2011 { .id = 0x1106E721, .name = "VIA VT1708B 8-Ch",
2012 .patch = patch_vt1708B_8ch},
2013 { .id = 0x1106E722, .name = "VIA VT1708B 8-Ch",
2014 .patch = patch_vt1708B_8ch},
2015 { .id = 0x1106E723, .name = "VIA VT1708B 8-Ch",
2016 .patch = patch_vt1708B_8ch},
2017 { .id = 0x1106E724, .name = "VIA VT1708B 4-Ch",
2018 .patch = patch_vt1708B_4ch},
2019 { .id = 0x1106E725, .name = "VIA VT1708B 4-Ch",
2020 .patch = patch_vt1708B_4ch},
2021 { .id = 0x1106E726, .name = "VIA VT1708B 4-Ch",
2022 .patch = patch_vt1708B_4ch},
2023 { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch",
2024 .patch = patch_vt1708B_4ch},
Joseph Chanc577b8a2006-11-29 15:29:40 +01002025 {} /* terminator */
2026};