blob: 91b72add1a8d6b547e60cecc5ff91bfd06ac6438 [file] [log] [blame]
Joseph Chanc577b8a2006-11-29 15:29:40 +01001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
Harald Welted949cac2008-09-09 15:56:01 +08004 * HD audio interface patch for VIA VT1702/VT1708/VT1709 codec
Joseph Chanc577b8a2006-11-29 15:29:40 +01005 *
Harald Welte76d9b0d2008-09-09 15:50:37 +08006 * Copyright (c) 2006-2008 Lydia Wang <lydiawang@viatech.com>
7 * Takashi Iwai <tiwai@suse.de>
Joseph Chanc577b8a2006-11-29 15:29:40 +01008 *
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 */
Harald Welte76d9b0d2008-09-09 15:50:37 +080032/* 2007-11-14 Lydia Wang Add VT1708A codec HP and CD pin connect config */
Harald Weltefb4cb772008-09-09 15:53:36 +080033/* 2008-02-03 Lydia Wang Fix Rear channels and Back channels inverse issue */
Harald Welted949cac2008-09-09 15:56:01 +080034/* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */
Joseph Chanc577b8a2006-11-29 15:29:40 +010035/* */
36/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
37
38
Joseph Chanc577b8a2006-11-29 15:29:40 +010039#include <linux/init.h>
40#include <linux/delay.h>
41#include <linux/slab.h>
Joseph Chanc577b8a2006-11-29 15:29:40 +010042#include <sound/core.h>
43#include "hda_codec.h"
44#include "hda_local.h"
Harvey Harrison3c9a3202008-02-29 11:59:26 +010045#include "hda_patch.h"
Joseph Chanc577b8a2006-11-29 15:29:40 +010046
47/* amp values */
48#define AMP_VAL_IDX_SHIFT 19
49#define AMP_VAL_IDX_MASK (0x0f<<19)
50
51#define NUM_CONTROL_ALLOC 32
52#define NUM_VERB_ALLOC 32
53
54/* Pin Widget NID */
55#define VT1708_HP_NID 0x13
56#define VT1708_DIGOUT_NID 0x14
57#define VT1708_DIGIN_NID 0x16
Josepch Chanf7278fd2007-12-13 16:40:40 +010058#define VT1708_DIGIN_PIN 0x26
Harald Welted949cac2008-09-09 15:56:01 +080059#define VT1708_HP_PIN_NID 0x20
60#define VT1708_CD_PIN_NID 0x24
Joseph Chanc577b8a2006-11-29 15:29:40 +010061
62#define VT1709_HP_DAC_NID 0x28
63#define VT1709_DIGOUT_NID 0x13
64#define VT1709_DIGIN_NID 0x17
Josepch Chanf7278fd2007-12-13 16:40:40 +010065#define VT1709_DIGIN_PIN 0x25
66
67#define VT1708B_HP_NID 0x25
68#define VT1708B_DIGOUT_NID 0x12
69#define VT1708B_DIGIN_NID 0x15
70#define VT1708B_DIGIN_PIN 0x21
Joseph Chanc577b8a2006-11-29 15:29:40 +010071
Harald Welted949cac2008-09-09 15:56:01 +080072#define VT1708S_HP_NID 0x25
73#define VT1708S_DIGOUT_NID 0x12
74
75#define VT1702_HP_NID 0x17
76#define VT1702_DIGOUT_NID 0x11
77
Joseph Chanc577b8a2006-11-29 15:29:40 +010078#define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b)
79#define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713)
80#define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717)
Josepch Chanf7278fd2007-12-13 16:40:40 +010081#define IS_VT1708B_8CH_VENDORID(x) ((x) >= 0x1106e720 && (x) <= 0x1106e723)
82#define IS_VT1708B_4CH_VENDORID(x) ((x) >= 0x1106e724 && (x) <= 0x1106e727)
Harald Welted949cac2008-09-09 15:56:01 +080083#define IS_VT1708S_VENDORID(x) ((x) >= 0x11060397 && (x) <= 0x11067397)
84#define IS_VT1702_VENDORID(x) ((x) >= 0x11060398 && (x) <= 0x11067398)
Joseph Chanc577b8a2006-11-29 15:29:40 +010085
86enum {
87 VIA_CTL_WIDGET_VOL,
88 VIA_CTL_WIDGET_MUTE,
89};
90
91enum {
Harald Welteeb14a462008-09-09 15:40:38 +080092 AUTO_SEQ_FRONT = 0,
Joseph Chanc577b8a2006-11-29 15:29:40 +010093 AUTO_SEQ_SURROUND,
94 AUTO_SEQ_CENLFE,
95 AUTO_SEQ_SIDE
96};
97
98static struct snd_kcontrol_new vt1708_control_templates[] = {
99 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
100 HDA_CODEC_MUTE(NULL, 0, 0, 0),
101};
102
103
104struct via_spec {
105 /* codec parameterization */
106 struct snd_kcontrol_new *mixers[3];
107 unsigned int num_mixers;
108
109 struct hda_verb *init_verbs;
110
111 char *stream_name_analog;
112 struct hda_pcm_stream *stream_analog_playback;
113 struct hda_pcm_stream *stream_analog_capture;
114
115 char *stream_name_digital;
116 struct hda_pcm_stream *stream_digital_playback;
117 struct hda_pcm_stream *stream_digital_capture;
118
119 /* playback */
120 struct hda_multi_out multiout;
121
122 /* capture */
123 unsigned int num_adc_nids;
124 hda_nid_t *adc_nids;
125 hda_nid_t dig_in_nid;
126
127 /* capture source */
128 const struct hda_input_mux *input_mux;
129 unsigned int cur_mux[3];
130
131 /* PCM information */
132 struct hda_pcm pcm_rec[2];
133
134 /* dynamic controls, init_verbs and input_mux */
135 struct auto_pin_cfg autocfg;
136 unsigned int num_kctl_alloc, num_kctl_used;
137 struct snd_kcontrol_new *kctl_alloc;
138 struct hda_input_mux private_imux;
Takashi Iwai41923e42007-10-22 17:20:10 +0200139 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwaicb53c622007-08-10 17:21:45 +0200140
141#ifdef CONFIG_SND_HDA_POWER_SAVE
142 struct hda_loopback_check loopback;
143#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +0100144};
145
146static hda_nid_t vt1708_adc_nids[2] = {
147 /* ADC1-2 */
148 0x15, 0x27
149};
150
151static hda_nid_t vt1709_adc_nids[3] = {
152 /* ADC1-2 */
153 0x14, 0x15, 0x16
154};
155
Josepch Chanf7278fd2007-12-13 16:40:40 +0100156static hda_nid_t vt1708B_adc_nids[2] = {
157 /* ADC1-2 */
158 0x13, 0x14
159};
160
Harald Welted949cac2008-09-09 15:56:01 +0800161static hda_nid_t vt1708S_adc_nids[2] = {
162 /* ADC1-2 */
163 0x13, 0x14
164};
165
166static hda_nid_t vt1702_adc_nids[3] = {
167 /* ADC1-2 */
168 0x12, 0x20, 0x1F
169};
170
Joseph Chanc577b8a2006-11-29 15:29:40 +0100171/* add dynamic controls */
172static int via_add_control(struct via_spec *spec, int type, const char *name,
173 unsigned long val)
174{
175 struct snd_kcontrol_new *knew;
176
177 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
178 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
179
180 /* array + terminator */
181 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
182 if (!knew)
183 return -ENOMEM;
184 if (spec->kctl_alloc) {
185 memcpy(knew, spec->kctl_alloc,
186 sizeof(*knew) * spec->num_kctl_alloc);
187 kfree(spec->kctl_alloc);
188 }
189 spec->kctl_alloc = knew;
190 spec->num_kctl_alloc = num;
191 }
192
193 knew = &spec->kctl_alloc[spec->num_kctl_used];
194 *knew = vt1708_control_templates[type];
195 knew->name = kstrdup(name, GFP_KERNEL);
196
197 if (!knew->name)
198 return -ENOMEM;
199 knew->private_value = val;
200 spec->num_kctl_used++;
201 return 0;
202}
203
204/* create input playback/capture controls for the given pin */
205static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
206 const char *ctlname, int idx, int mix_nid)
207{
208 char name[32];
209 int err;
210
211 sprintf(name, "%s Playback Volume", ctlname);
212 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
213 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
214 if (err < 0)
215 return err;
216 sprintf(name, "%s Playback Switch", ctlname);
217 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
218 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
219 if (err < 0)
220 return err;
221 return 0;
222}
223
224static void via_auto_set_output_and_unmute(struct hda_codec *codec,
225 hda_nid_t nid, int pin_type,
226 int dac_idx)
227{
228 /* set as output */
229 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
230 pin_type);
231 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
232 AMP_OUT_UNMUTE);
233}
234
235
236static void via_auto_init_multi_out(struct hda_codec *codec)
237{
238 struct via_spec *spec = codec->spec;
239 int i;
240
241 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
242 hda_nid_t nid = spec->autocfg.line_out_pins[i];
243 if (nid)
244 via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
245 }
246}
247
248static void via_auto_init_hp_out(struct hda_codec *codec)
249{
250 struct via_spec *spec = codec->spec;
251 hda_nid_t pin;
252
253 pin = spec->autocfg.hp_pins[0];
254 if (pin) /* connect to front */
255 via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
256}
257
258static void via_auto_init_analog_input(struct hda_codec *codec)
259{
260 struct via_spec *spec = codec->spec;
261 int i;
262
263 for (i = 0; i < AUTO_PIN_LAST; i++) {
264 hda_nid_t nid = spec->autocfg.input_pins[i];
265
266 snd_hda_codec_write(codec, nid, 0,
267 AC_VERB_SET_PIN_WIDGET_CONTROL,
268 (i <= AUTO_PIN_FRONT_MIC ?
269 PIN_VREF50 : PIN_IN));
270
271 }
272}
273/*
274 * input MUX handling
275 */
276static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
277 struct snd_ctl_elem_info *uinfo)
278{
279 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
280 struct via_spec *spec = codec->spec;
281 return snd_hda_input_mux_info(spec->input_mux, uinfo);
282}
283
284static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
285 struct snd_ctl_elem_value *ucontrol)
286{
287 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
288 struct via_spec *spec = codec->spec;
289 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
290
291 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
292 return 0;
293}
294
295static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
296 struct snd_ctl_elem_value *ucontrol)
297{
298 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
299 struct via_spec *spec = codec->spec;
300 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
301 unsigned int vendor_id = codec->vendor_id;
302
303 /* AIW0 lydia 060801 add for correct sw0 input select */
304 if (IS_VT1708_VENDORID(vendor_id) && (adc_idx == 0))
305 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
306 0x18, &spec->cur_mux[adc_idx]);
307 else if ((IS_VT1709_10CH_VENDORID(vendor_id) ||
Harald Welteeb14a462008-09-09 15:40:38 +0800308 IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0))
Joseph Chanc577b8a2006-11-29 15:29:40 +0100309 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
310 0x19, &spec->cur_mux[adc_idx]);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100311 else if ((IS_VT1708B_8CH_VENDORID(vendor_id) ||
Harald Welteeb14a462008-09-09 15:40:38 +0800312 IS_VT1708B_4CH_VENDORID(vendor_id)) && (adc_idx == 0))
Josepch Chanf7278fd2007-12-13 16:40:40 +0100313 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
314 0x17, &spec->cur_mux[adc_idx]);
Harald Welted949cac2008-09-09 15:56:01 +0800315 else if (IS_VT1702_VENDORID(vendor_id) && (adc_idx == 0))
316 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
317 0x13, &spec->cur_mux[adc_idx]);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100318 else
319 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
320 spec->adc_nids[adc_idx],
321 &spec->cur_mux[adc_idx]);
322}
323
324/* capture mixer elements */
325static struct snd_kcontrol_new vt1708_capture_mixer[] = {
326 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
327 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
328 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
329 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
330 {
331 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
332 /* The multiple "Capture Source" controls confuse alsamixer
333 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +0100334 */
335 /* .name = "Capture Source", */
336 .name = "Input Source",
337 .count = 1,
338 .info = via_mux_enum_info,
339 .get = via_mux_enum_get,
340 .put = via_mux_enum_put,
341 },
342 { } /* end */
343};
344/*
345 * generic initialization of ADC, input mixers and output mixers
346 */
347static struct hda_verb vt1708_volume_init_verbs[] = {
348 /*
349 * Unmute ADC0-1 and set the default input to mic-in
350 */
351 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
352 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
353
354
Josepch Chanf7278fd2007-12-13 16:40:40 +0100355 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +0100356 * mixer widget
357 */
358 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +0100359 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
360 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
361 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
362 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
363 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100364
365 /*
366 * Set up output mixers (0x19 - 0x1b)
367 */
368 /* set vol=0 to output mixers */
369 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
370 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
371 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
372
373 /* Setup default input to PW4 */
374 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100375 /* PW9 Output enable */
376 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Josepch Chanf7278fd2007-12-13 16:40:40 +0100377 { }
Joseph Chanc577b8a2006-11-29 15:29:40 +0100378};
379
380static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
381 struct hda_codec *codec,
382 struct snd_pcm_substream *substream)
383{
384 struct via_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +0100385 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
386 hinfo);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100387}
388
389static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
390 struct hda_codec *codec,
391 unsigned int stream_tag,
392 unsigned int format,
393 struct snd_pcm_substream *substream)
394{
395 struct via_spec *spec = codec->spec;
396 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
397 stream_tag, format, substream);
398}
399
400static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
401 struct hda_codec *codec,
402 struct snd_pcm_substream *substream)
403{
404 struct via_spec *spec = codec->spec;
405 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
406}
407
408/*
409 * Digital out
410 */
411static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
412 struct hda_codec *codec,
413 struct snd_pcm_substream *substream)
414{
415 struct via_spec *spec = codec->spec;
416 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
417}
418
419static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
420 struct hda_codec *codec,
421 struct snd_pcm_substream *substream)
422{
423 struct via_spec *spec = codec->spec;
424 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
425}
426
Takashi Iwai6b97eb42007-04-05 14:51:48 +0200427static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
428 struct hda_codec *codec,
429 unsigned int stream_tag,
430 unsigned int format,
431 struct snd_pcm_substream *substream)
432{
433 struct via_spec *spec = codec->spec;
434 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
435 stream_tag, format, substream);
436}
437
Joseph Chanc577b8a2006-11-29 15:29:40 +0100438/*
439 * Analog capture
440 */
441static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
442 struct hda_codec *codec,
443 unsigned int stream_tag,
444 unsigned int format,
445 struct snd_pcm_substream *substream)
446{
447 struct via_spec *spec = codec->spec;
448
449 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
450 stream_tag, 0, format);
451 return 0;
452}
453
454static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
455 struct hda_codec *codec,
456 struct snd_pcm_substream *substream)
457{
458 struct via_spec *spec = codec->spec;
Takashi Iwai888afa12008-03-18 09:57:50 +0100459 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100460 return 0;
461}
462
463static struct hda_pcm_stream vt1708_pcm_analog_playback = {
464 .substreams = 1,
465 .channels_min = 2,
466 .channels_max = 8,
467 .nid = 0x10, /* NID to query formats and rates */
468 .ops = {
469 .open = via_playback_pcm_open,
470 .prepare = via_playback_pcm_prepare,
471 .cleanup = via_playback_pcm_cleanup
472 },
473};
474
Takashi Iwaibc9b5622008-05-23 17:50:27 +0200475static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
476 .substreams = 1,
477 .channels_min = 2,
478 .channels_max = 8,
479 .nid = 0x10, /* NID to query formats and rates */
480 /* We got noisy outputs on the right channel on VT1708 when
481 * 24bit samples are used. Until any workaround is found,
482 * disable the 24bit format, so far.
483 */
484 .formats = SNDRV_PCM_FMTBIT_S16_LE,
485 .ops = {
486 .open = via_playback_pcm_open,
487 .prepare = via_playback_pcm_prepare,
488 .cleanup = via_playback_pcm_cleanup
489 },
490};
491
Joseph Chanc577b8a2006-11-29 15:29:40 +0100492static struct hda_pcm_stream vt1708_pcm_analog_capture = {
493 .substreams = 2,
494 .channels_min = 2,
495 .channels_max = 2,
496 .nid = 0x15, /* NID to query formats and rates */
497 .ops = {
498 .prepare = via_capture_pcm_prepare,
499 .cleanup = via_capture_pcm_cleanup
500 },
501};
502
503static struct hda_pcm_stream vt1708_pcm_digital_playback = {
504 .substreams = 1,
505 .channels_min = 2,
506 .channels_max = 2,
507 /* NID is set in via_build_pcms */
508 .ops = {
509 .open = via_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +0200510 .close = via_dig_playback_pcm_close,
511 .prepare = via_dig_playback_pcm_prepare
Joseph Chanc577b8a2006-11-29 15:29:40 +0100512 },
513};
514
515static struct hda_pcm_stream vt1708_pcm_digital_capture = {
516 .substreams = 1,
517 .channels_min = 2,
518 .channels_max = 2,
519};
520
521static int via_build_controls(struct hda_codec *codec)
522{
523 struct via_spec *spec = codec->spec;
524 int err;
525 int i;
526
527 for (i = 0; i < spec->num_mixers; i++) {
528 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
529 if (err < 0)
530 return err;
531 }
532
533 if (spec->multiout.dig_out_nid) {
534 err = snd_hda_create_spdif_out_ctls(codec,
535 spec->multiout.dig_out_nid);
536 if (err < 0)
537 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +0100538 err = snd_hda_create_spdif_share_sw(codec,
539 &spec->multiout);
540 if (err < 0)
541 return err;
542 spec->multiout.share_spdif = 1;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100543 }
544 if (spec->dig_in_nid) {
545 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
546 if (err < 0)
547 return err;
548 }
549 return 0;
550}
551
552static int via_build_pcms(struct hda_codec *codec)
553{
554 struct via_spec *spec = codec->spec;
555 struct hda_pcm *info = spec->pcm_rec;
556
557 codec->num_pcms = 1;
558 codec->pcm_info = info;
559
560 info->name = spec->stream_name_analog;
561 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
562 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
563 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
564 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
565
566 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
567 spec->multiout.max_channels;
568
569 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
570 codec->num_pcms++;
571 info++;
572 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +0100573 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100574 if (spec->multiout.dig_out_nid) {
575 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
576 *(spec->stream_digital_playback);
577 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
578 spec->multiout.dig_out_nid;
579 }
580 if (spec->dig_in_nid) {
581 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
582 *(spec->stream_digital_capture);
583 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
584 spec->dig_in_nid;
585 }
586 }
587
588 return 0;
589}
590
591static void via_free(struct hda_codec *codec)
592{
593 struct via_spec *spec = codec->spec;
594 unsigned int i;
595
596 if (!spec)
597 return;
598
599 if (spec->kctl_alloc) {
600 for (i = 0; i < spec->num_kctl_used; i++)
601 kfree(spec->kctl_alloc[i].name);
602 kfree(spec->kctl_alloc);
603 }
604
605 kfree(codec->spec);
606}
607
608static int via_init(struct hda_codec *codec)
609{
610 struct via_spec *spec = codec->spec;
611 snd_hda_sequence_write(codec, spec->init_verbs);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100612 /* Lydia Add for EAPD enable */
613 if (!spec->dig_in_nid) { /* No Digital In connection */
614 if (IS_VT1708_VENDORID(codec->vendor_id)) {
615 snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
616 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100617 PIN_OUT);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100618 snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
619 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
620 } else if (IS_VT1709_10CH_VENDORID(codec->vendor_id) ||
621 IS_VT1709_6CH_VENDORID(codec->vendor_id)) {
622 snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
623 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100624 PIN_OUT);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100625 snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
626 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
627 } else if (IS_VT1708B_8CH_VENDORID(codec->vendor_id) ||
628 IS_VT1708B_4CH_VENDORID(codec->vendor_id)) {
629 snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
630 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100631 PIN_OUT);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100632 snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
633 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
634 }
Takashi Iwai12b74c82008-01-15 12:39:38 +0100635 } else /* enable SPDIF-input pin */
636 snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
637 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100638
Joseph Chanc577b8a2006-11-29 15:29:40 +0100639 return 0;
640}
641
Takashi Iwaicb53c622007-08-10 17:21:45 +0200642#ifdef CONFIG_SND_HDA_POWER_SAVE
643static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
644{
645 struct via_spec *spec = codec->spec;
646 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
647}
648#endif
649
Joseph Chanc577b8a2006-11-29 15:29:40 +0100650/*
651 */
652static struct hda_codec_ops via_patch_ops = {
653 .build_controls = via_build_controls,
654 .build_pcms = via_build_pcms,
655 .init = via_init,
656 .free = via_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +0200657#ifdef CONFIG_SND_HDA_POWER_SAVE
658 .check_power_status = via_check_power_status,
659#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +0100660};
661
662/* fill in the dac_nids table from the parsed pin configuration */
663static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
664 const struct auto_pin_cfg *cfg)
665{
666 int i;
667 hda_nid_t nid;
668
669 spec->multiout.num_dacs = cfg->line_outs;
670
671 spec->multiout.dac_nids = spec->private_dac_nids;
672
673 for(i = 0; i < 4; i++) {
674 nid = cfg->line_out_pins[i];
675 if (nid) {
676 /* config dac list */
677 switch (i) {
678 case AUTO_SEQ_FRONT:
679 spec->multiout.dac_nids[i] = 0x10;
680 break;
681 case AUTO_SEQ_CENLFE:
682 spec->multiout.dac_nids[i] = 0x12;
683 break;
684 case AUTO_SEQ_SURROUND:
Harald Weltefb4cb772008-09-09 15:53:36 +0800685 spec->multiout.dac_nids[i] = 0x11;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100686 break;
687 case AUTO_SEQ_SIDE:
Harald Weltefb4cb772008-09-09 15:53:36 +0800688 spec->multiout.dac_nids[i] = 0x13;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100689 break;
690 }
691 }
692 }
693
694 return 0;
695}
696
697/* add playback controls from the parsed DAC table */
698static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
699 const struct auto_pin_cfg *cfg)
700{
701 char name[32];
702 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
703 hda_nid_t nid, nid_vol = 0;
704 int i, err;
705
706 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
707 nid = cfg->line_out_pins[i];
708
709 if (!nid)
710 continue;
711
712 if (i != AUTO_SEQ_FRONT)
Harald Weltefb4cb772008-09-09 15:53:36 +0800713 nid_vol = 0x18 + i;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100714
715 if (i == AUTO_SEQ_CENLFE) {
716 /* Center/LFE */
717 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100718 "Center Playback Volume",
719 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
720 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100721 if (err < 0)
722 return err;
723 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
724 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100725 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
726 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100727 if (err < 0)
728 return err;
729 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
730 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100731 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
732 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100733 if (err < 0)
734 return err;
735 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
736 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100737 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
738 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100739 if (err < 0)
740 return err;
741 } else if (i == AUTO_SEQ_FRONT){
742 /* add control to mixer index 0 */
743 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
744 "Master Front Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100745 HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
746 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100747 if (err < 0)
748 return err;
749 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
750 "Master Front Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +0100751 HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
752 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100753 if (err < 0)
754 return err;
755
756 /* add control to PW3 */
757 sprintf(name, "%s Playback Volume", chname[i]);
758 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100759 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
760 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100761 if (err < 0)
762 return err;
763 sprintf(name, "%s Playback Switch", chname[i]);
764 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100765 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
766 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100767 if (err < 0)
768 return err;
769 } else {
770 sprintf(name, "%s Playback Volume", chname[i]);
771 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100772 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
773 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100774 if (err < 0)
775 return err;
776 sprintf(name, "%s Playback Switch", chname[i]);
777 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100778 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
779 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +0100780 if (err < 0)
781 return err;
782 }
783 }
784
785 return 0;
786}
787
788static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
789{
790 int err;
791
792 if (!pin)
793 return 0;
794
795 spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
796
797 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
798 "Headphone Playback Volume",
799 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
800 if (err < 0)
801 return err;
802 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
803 "Headphone Playback Switch",
804 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
805 if (err < 0)
806 return err;
807
808 return 0;
809}
810
811/* create playback/capture controls for input pins */
812static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
813 const struct auto_pin_cfg *cfg)
814{
815 static char *labels[] = {
816 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
817 };
818 struct hda_input_mux *imux = &spec->private_imux;
819 int i, err, idx = 0;
820
821 /* for internal loopback recording select */
822 imux->items[imux->num_items].label = "Stereo Mixer";
823 imux->items[imux->num_items].index = idx;
824 imux->num_items++;
825
826 for (i = 0; i < AUTO_PIN_LAST; i++) {
827 if (!cfg->input_pins[i])
828 continue;
829
830 switch (cfg->input_pins[i]) {
831 case 0x1d: /* Mic */
832 idx = 2;
833 break;
834
835 case 0x1e: /* Line In */
836 idx = 3;
837 break;
838
839 case 0x21: /* Front Mic */
840 idx = 4;
841 break;
842
843 case 0x24: /* CD */
844 idx = 1;
845 break;
846 }
847 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
848 idx, 0x17);
849 if (err < 0)
850 return err;
851 imux->items[imux->num_items].label = labels[i];
852 imux->items[imux->num_items].index = idx;
853 imux->num_items++;
854 }
855 return 0;
856}
857
Takashi Iwaicb53c622007-08-10 17:21:45 +0200858#ifdef CONFIG_SND_HDA_POWER_SAVE
859static struct hda_amp_list vt1708_loopbacks[] = {
860 { 0x17, HDA_INPUT, 1 },
861 { 0x17, HDA_INPUT, 2 },
862 { 0x17, HDA_INPUT, 3 },
863 { 0x17, HDA_INPUT, 4 },
864 { } /* end */
865};
866#endif
867
Harald Welte76d9b0d2008-09-09 15:50:37 +0800868static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
869{
870 unsigned int def_conf;
871 unsigned char seqassoc;
872
873 def_conf = snd_hda_codec_read(codec, nid, 0,
874 AC_VERB_GET_CONFIG_DEFAULT, 0);
875 seqassoc = (unsigned char) get_defcfg_association(def_conf);
876 seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
877 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) {
878 if (seqassoc == 0xff) {
879 def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
880 snd_hda_codec_write(codec, nid, 0,
881 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
882 def_conf >> 24);
883 }
884 }
885
886 return;
887}
888
Joseph Chanc577b8a2006-11-29 15:29:40 +0100889static int vt1708_parse_auto_config(struct hda_codec *codec)
890{
891 struct via_spec *spec = codec->spec;
892 int err;
893
Harald Welte76d9b0d2008-09-09 15:50:37 +0800894 /* Add HP and CD pin config connect bit re-config action */
895 vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
896 vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
897
Joseph Chanc577b8a2006-11-29 15:29:40 +0100898 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
899 if (err < 0)
900 return err;
901 err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
902 if (err < 0)
903 return err;
904 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
905 return 0; /* can't find valid BIOS pin config */
906
907 err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
908 if (err < 0)
909 return err;
910 err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
911 if (err < 0)
912 return err;
913 err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
914 if (err < 0)
915 return err;
916
917 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
918
919 if (spec->autocfg.dig_out_pin)
920 spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
921 if (spec->autocfg.dig_in_pin)
922 spec->dig_in_nid = VT1708_DIGIN_NID;
923
924 if (spec->kctl_alloc)
925 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
926
927 spec->init_verbs = vt1708_volume_init_verbs;
928
929 spec->input_mux = &spec->private_imux;
930
931 return 1;
932}
933
934/* init callback for auto-configuration model -- overriding the default init */
935static int via_auto_init(struct hda_codec *codec)
936{
937 via_init(codec);
938 via_auto_init_multi_out(codec);
939 via_auto_init_hp_out(codec);
940 via_auto_init_analog_input(codec);
941 return 0;
942}
943
944static int patch_vt1708(struct hda_codec *codec)
945{
946 struct via_spec *spec;
947 int err;
948
949 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +0800950 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100951 if (spec == NULL)
952 return -ENOMEM;
953
954 codec->spec = spec;
955
956 /* automatic parse from the BIOS config */
957 err = vt1708_parse_auto_config(codec);
958 if (err < 0) {
959 via_free(codec);
960 return err;
961 } else if (!err) {
962 printk(KERN_INFO "hda_codec: Cannot set up configuration "
963 "from BIOS. Using genenic mode...\n");
964 }
965
966
967 spec->stream_name_analog = "VT1708 Analog";
968 spec->stream_analog_playback = &vt1708_pcm_analog_playback;
Takashi Iwaibc9b5622008-05-23 17:50:27 +0200969 /* disable 32bit format on VT1708 */
970 if (codec->vendor_id == 0x11061708)
971 spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100972 spec->stream_analog_capture = &vt1708_pcm_analog_capture;
973
974 spec->stream_name_digital = "VT1708 Digital";
975 spec->stream_digital_playback = &vt1708_pcm_digital_playback;
976 spec->stream_digital_capture = &vt1708_pcm_digital_capture;
977
978
979 if (!spec->adc_nids && spec->input_mux) {
980 spec->adc_nids = vt1708_adc_nids;
981 spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
982 spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
983 spec->num_mixers++;
984 }
985
986 codec->patch_ops = via_patch_ops;
987
988 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200989#ifdef CONFIG_SND_HDA_POWER_SAVE
990 spec->loopback.amplist = vt1708_loopbacks;
991#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +0100992
993 return 0;
994}
995
996/* capture mixer elements */
997static struct snd_kcontrol_new vt1709_capture_mixer[] = {
998 HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
999 HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
1000 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
1001 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
1002 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
1003 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
1004 {
1005 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1006 /* The multiple "Capture Source" controls confuse alsamixer
1007 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +01001008 */
1009 /* .name = "Capture Source", */
1010 .name = "Input Source",
1011 .count = 1,
1012 .info = via_mux_enum_info,
1013 .get = via_mux_enum_get,
1014 .put = via_mux_enum_put,
1015 },
1016 { } /* end */
1017};
1018
1019/*
1020 * generic initialization of ADC, input mixers and output mixers
1021 */
1022static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
1023 /*
1024 * Unmute ADC0-2 and set the default input to mic-in
1025 */
1026 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1027 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1028 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1029
1030
Josepch Chanf7278fd2007-12-13 16:40:40 +01001031 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +01001032 * mixer widget
1033 */
1034 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +01001035 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1036 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1037 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1038 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1039 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001040
1041 /*
1042 * Set up output selector (0x1a, 0x1b, 0x29)
1043 */
1044 /* set vol=0 to output mixers */
1045 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1046 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1047 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1048
1049 /*
1050 * Unmute PW3 and PW4
1051 */
1052 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1053 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1054
1055 /* Set input of PW4 as AOW4 */
1056 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001057 /* PW9 Output enable */
1058 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1059 { }
1060};
1061
1062static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
1063 .substreams = 1,
1064 .channels_min = 2,
1065 .channels_max = 10,
1066 .nid = 0x10, /* NID to query formats and rates */
1067 .ops = {
1068 .open = via_playback_pcm_open,
1069 .prepare = via_playback_pcm_prepare,
1070 .cleanup = via_playback_pcm_cleanup
1071 },
1072};
1073
1074static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
1075 .substreams = 1,
1076 .channels_min = 2,
1077 .channels_max = 6,
1078 .nid = 0x10, /* NID to query formats and rates */
1079 .ops = {
1080 .open = via_playback_pcm_open,
1081 .prepare = via_playback_pcm_prepare,
1082 .cleanup = via_playback_pcm_cleanup
1083 },
1084};
1085
1086static struct hda_pcm_stream vt1709_pcm_analog_capture = {
1087 .substreams = 2,
1088 .channels_min = 2,
1089 .channels_max = 2,
1090 .nid = 0x14, /* NID to query formats and rates */
1091 .ops = {
1092 .prepare = via_capture_pcm_prepare,
1093 .cleanup = via_capture_pcm_cleanup
1094 },
1095};
1096
1097static struct hda_pcm_stream vt1709_pcm_digital_playback = {
1098 .substreams = 1,
1099 .channels_min = 2,
1100 .channels_max = 2,
1101 /* NID is set in via_build_pcms */
1102 .ops = {
1103 .open = via_dig_playback_pcm_open,
1104 .close = via_dig_playback_pcm_close
1105 },
1106};
1107
1108static struct hda_pcm_stream vt1709_pcm_digital_capture = {
1109 .substreams = 1,
1110 .channels_min = 2,
1111 .channels_max = 2,
1112};
1113
1114static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
1115 const struct auto_pin_cfg *cfg)
1116{
1117 int i;
1118 hda_nid_t nid;
1119
1120 if (cfg->line_outs == 4) /* 10 channels */
1121 spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
1122 else if (cfg->line_outs == 3) /* 6 channels */
1123 spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
1124
1125 spec->multiout.dac_nids = spec->private_dac_nids;
1126
1127 if (cfg->line_outs == 4) { /* 10 channels */
1128 for (i = 0; i < cfg->line_outs; i++) {
1129 nid = cfg->line_out_pins[i];
1130 if (nid) {
1131 /* config dac list */
1132 switch (i) {
1133 case AUTO_SEQ_FRONT:
1134 /* AOW0 */
1135 spec->multiout.dac_nids[i] = 0x10;
1136 break;
1137 case AUTO_SEQ_CENLFE:
1138 /* AOW2 */
1139 spec->multiout.dac_nids[i] = 0x12;
1140 break;
1141 case AUTO_SEQ_SURROUND:
1142 /* AOW3 */
Harald Weltefb4cb772008-09-09 15:53:36 +08001143 spec->multiout.dac_nids[i] = 0x11;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001144 break;
1145 case AUTO_SEQ_SIDE:
1146 /* AOW1 */
Harald Weltefb4cb772008-09-09 15:53:36 +08001147 spec->multiout.dac_nids[i] = 0x27;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001148 break;
1149 default:
1150 break;
1151 }
1152 }
1153 }
1154 spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
1155
1156 } else if (cfg->line_outs == 3) { /* 6 channels */
1157 for(i = 0; i < cfg->line_outs; i++) {
1158 nid = cfg->line_out_pins[i];
1159 if (nid) {
1160 /* config dac list */
1161 switch(i) {
1162 case AUTO_SEQ_FRONT:
1163 /* AOW0 */
1164 spec->multiout.dac_nids[i] = 0x10;
1165 break;
1166 case AUTO_SEQ_CENLFE:
1167 /* AOW2 */
1168 spec->multiout.dac_nids[i] = 0x12;
1169 break;
1170 case AUTO_SEQ_SURROUND:
1171 /* AOW1 */
1172 spec->multiout.dac_nids[i] = 0x11;
1173 break;
1174 default:
1175 break;
1176 }
1177 }
1178 }
1179 }
1180
1181 return 0;
1182}
1183
1184/* add playback controls from the parsed DAC table */
1185static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
1186 const struct auto_pin_cfg *cfg)
1187{
1188 char name[32];
1189 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1190 hda_nid_t nid = 0;
1191 int i, err;
1192
1193 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1194 nid = cfg->line_out_pins[i];
1195
1196 if (!nid)
1197 continue;
1198
1199 if (i == AUTO_SEQ_CENLFE) {
1200 /* Center/LFE */
1201 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1202 "Center Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001203 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
1204 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001205 if (err < 0)
1206 return err;
1207 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1208 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001209 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
1210 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001211 if (err < 0)
1212 return err;
1213 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1214 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001215 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
1216 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001217 if (err < 0)
1218 return err;
1219 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1220 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001221 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
1222 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001223 if (err < 0)
1224 return err;
1225 } else if (i == AUTO_SEQ_FRONT){
1226 /* add control to mixer index 0 */
1227 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1228 "Master Front Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001229 HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
1230 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001231 if (err < 0)
1232 return err;
1233 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1234 "Master Front Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001235 HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
1236 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001237 if (err < 0)
1238 return err;
1239
1240 /* add control to PW3 */
1241 sprintf(name, "%s Playback Volume", chname[i]);
1242 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001243 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1244 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001245 if (err < 0)
1246 return err;
1247 sprintf(name, "%s Playback Switch", chname[i]);
1248 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001249 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1250 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001251 if (err < 0)
1252 return err;
1253 } else if (i == AUTO_SEQ_SURROUND) {
1254 sprintf(name, "%s Playback Volume", chname[i]);
1255 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001256 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001257 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001258 if (err < 0)
1259 return err;
1260 sprintf(name, "%s Playback Switch", chname[i]);
1261 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001262 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001263 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001264 if (err < 0)
1265 return err;
1266 } else if (i == AUTO_SEQ_SIDE) {
1267 sprintf(name, "%s Playback Volume", chname[i]);
1268 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001269 HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001270 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001271 if (err < 0)
1272 return err;
1273 sprintf(name, "%s Playback Switch", chname[i]);
1274 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001275 HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001276 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001277 if (err < 0)
1278 return err;
1279 }
1280 }
1281
1282 return 0;
1283}
1284
1285static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1286{
1287 int err;
1288
1289 if (!pin)
1290 return 0;
1291
1292 if (spec->multiout.num_dacs == 5) /* 10 channels */
1293 spec->multiout.hp_nid = VT1709_HP_DAC_NID;
1294 else if (spec->multiout.num_dacs == 3) /* 6 channels */
1295 spec->multiout.hp_nid = 0;
1296
1297 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1298 "Headphone Playback Volume",
1299 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1300 if (err < 0)
1301 return err;
1302 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1303 "Headphone Playback Switch",
1304 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1305 if (err < 0)
1306 return err;
1307
1308 return 0;
1309}
1310
1311/* create playback/capture controls for input pins */
1312static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
1313 const struct auto_pin_cfg *cfg)
1314{
1315 static char *labels[] = {
1316 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1317 };
1318 struct hda_input_mux *imux = &spec->private_imux;
1319 int i, err, idx = 0;
1320
1321 /* for internal loopback recording select */
1322 imux->items[imux->num_items].label = "Stereo Mixer";
1323 imux->items[imux->num_items].index = idx;
1324 imux->num_items++;
1325
1326 for (i = 0; i < AUTO_PIN_LAST; i++) {
1327 if (!cfg->input_pins[i])
1328 continue;
1329
1330 switch (cfg->input_pins[i]) {
1331 case 0x1d: /* Mic */
1332 idx = 2;
1333 break;
1334
1335 case 0x1e: /* Line In */
1336 idx = 3;
1337 break;
1338
1339 case 0x21: /* Front Mic */
1340 idx = 4;
1341 break;
1342
1343 case 0x23: /* CD */
1344 idx = 1;
1345 break;
1346 }
1347 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
1348 idx, 0x18);
1349 if (err < 0)
1350 return err;
1351 imux->items[imux->num_items].label = labels[i];
1352 imux->items[imux->num_items].index = idx;
1353 imux->num_items++;
1354 }
1355 return 0;
1356}
1357
1358static int vt1709_parse_auto_config(struct hda_codec *codec)
1359{
1360 struct via_spec *spec = codec->spec;
1361 int err;
1362
1363 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1364 if (err < 0)
1365 return err;
1366 err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
1367 if (err < 0)
1368 return err;
1369 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1370 return 0; /* can't find valid BIOS pin config */
1371
1372 err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
1373 if (err < 0)
1374 return err;
1375 err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1376 if (err < 0)
1377 return err;
1378 err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
1379 if (err < 0)
1380 return err;
1381
1382 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1383
1384 if (spec->autocfg.dig_out_pin)
1385 spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
1386 if (spec->autocfg.dig_in_pin)
1387 spec->dig_in_nid = VT1709_DIGIN_NID;
1388
1389 if (spec->kctl_alloc)
1390 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
1391
1392 spec->input_mux = &spec->private_imux;
1393
1394 return 1;
1395}
1396
Takashi Iwaicb53c622007-08-10 17:21:45 +02001397#ifdef CONFIG_SND_HDA_POWER_SAVE
1398static struct hda_amp_list vt1709_loopbacks[] = {
1399 { 0x18, HDA_INPUT, 1 },
1400 { 0x18, HDA_INPUT, 2 },
1401 { 0x18, HDA_INPUT, 3 },
1402 { 0x18, HDA_INPUT, 4 },
1403 { } /* end */
1404};
1405#endif
1406
Joseph Chanc577b8a2006-11-29 15:29:40 +01001407static int patch_vt1709_10ch(struct hda_codec *codec)
1408{
1409 struct via_spec *spec;
1410 int err;
1411
1412 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08001413 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001414 if (spec == NULL)
1415 return -ENOMEM;
1416
1417 codec->spec = spec;
1418
1419 err = vt1709_parse_auto_config(codec);
1420 if (err < 0) {
1421 via_free(codec);
1422 return err;
1423 } else if (!err) {
1424 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
1425 "Using genenic mode...\n");
1426 }
1427
1428 spec->init_verbs = vt1709_10ch_volume_init_verbs;
1429
1430 spec->stream_name_analog = "VT1709 Analog";
1431 spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
1432 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1433
1434 spec->stream_name_digital = "VT1709 Digital";
1435 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1436 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1437
1438
1439 if (!spec->adc_nids && spec->input_mux) {
1440 spec->adc_nids = vt1709_adc_nids;
1441 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
1442 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1443 spec->num_mixers++;
1444 }
1445
1446 codec->patch_ops = via_patch_ops;
1447
1448 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001449#ifdef CONFIG_SND_HDA_POWER_SAVE
1450 spec->loopback.amplist = vt1709_loopbacks;
1451#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001452
1453 return 0;
1454}
1455/*
1456 * generic initialization of ADC, input mixers and output mixers
1457 */
1458static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
1459 /*
1460 * Unmute ADC0-2 and set the default input to mic-in
1461 */
1462 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1463 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1464 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1465
1466
1467 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1468 * mixer widget
1469 */
1470 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1471 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1472 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1473 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1474 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1475 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1476
1477 /*
1478 * Set up output selector (0x1a, 0x1b, 0x29)
1479 */
1480 /* set vol=0 to output mixers */
1481 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1482 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1483 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1484
1485 /*
1486 * Unmute PW3 and PW4
1487 */
1488 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1489 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1490
1491 /* Set input of PW4 as MW0 */
1492 {0x20, AC_VERB_SET_CONNECT_SEL, 0},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001493 /* PW9 Output enable */
1494 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1495 { }
1496};
1497
1498static int patch_vt1709_6ch(struct hda_codec *codec)
1499{
1500 struct via_spec *spec;
1501 int err;
1502
1503 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08001504 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001505 if (spec == NULL)
1506 return -ENOMEM;
1507
1508 codec->spec = spec;
1509
1510 err = vt1709_parse_auto_config(codec);
1511 if (err < 0) {
1512 via_free(codec);
1513 return err;
1514 } else if (!err) {
1515 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
1516 "Using genenic mode...\n");
1517 }
1518
1519 spec->init_verbs = vt1709_6ch_volume_init_verbs;
1520
1521 spec->stream_name_analog = "VT1709 Analog";
1522 spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
1523 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1524
1525 spec->stream_name_digital = "VT1709 Digital";
1526 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1527 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1528
1529
1530 if (!spec->adc_nids && spec->input_mux) {
1531 spec->adc_nids = vt1709_adc_nids;
1532 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
1533 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1534 spec->num_mixers++;
1535 }
1536
1537 codec->patch_ops = via_patch_ops;
1538
1539 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001540#ifdef CONFIG_SND_HDA_POWER_SAVE
1541 spec->loopback.amplist = vt1709_loopbacks;
1542#endif
Josepch Chanf7278fd2007-12-13 16:40:40 +01001543 return 0;
1544}
1545
1546/* capture mixer elements */
1547static struct snd_kcontrol_new vt1708B_capture_mixer[] = {
1548 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
1549 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
1550 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
1551 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
1552 {
1553 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1554 /* The multiple "Capture Source" controls confuse alsamixer
1555 * So call somewhat different..
Josepch Chanf7278fd2007-12-13 16:40:40 +01001556 */
1557 /* .name = "Capture Source", */
1558 .name = "Input Source",
1559 .count = 1,
1560 .info = via_mux_enum_info,
1561 .get = via_mux_enum_get,
1562 .put = via_mux_enum_put,
1563 },
1564 { } /* end */
1565};
1566/*
1567 * generic initialization of ADC, input mixers and output mixers
1568 */
1569static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
1570 /*
1571 * Unmute ADC0-1 and set the default input to mic-in
1572 */
1573 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1574 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1575
1576
1577 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1578 * mixer widget
1579 */
1580 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1581 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1582 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1583 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1584 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1585 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1586
1587 /*
1588 * Set up output mixers
1589 */
1590 /* set vol=0 to output mixers */
1591 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1592 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1593 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1594
1595 /* Setup default input to PW4 */
1596 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1},
1597 /* PW9 Output enable */
1598 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1599 /* PW10 Input enable */
1600 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
1601 { }
1602};
1603
1604static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
1605 /*
1606 * Unmute ADC0-1 and set the default input to mic-in
1607 */
1608 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1609 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1610
1611
1612 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1613 * mixer widget
1614 */
1615 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1616 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1617 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1618 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1619 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1620 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1621
1622 /*
1623 * Set up output mixers
1624 */
1625 /* set vol=0 to output mixers */
1626 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1627 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1628 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1629
1630 /* Setup default input of PW4 to MW0 */
1631 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
1632 /* PW9 Output enable */
1633 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1634 /* PW10 Input enable */
1635 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
1636 { }
1637};
1638
1639static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
1640 .substreams = 1,
1641 .channels_min = 2,
1642 .channels_max = 8,
1643 .nid = 0x10, /* NID to query formats and rates */
1644 .ops = {
1645 .open = via_playback_pcm_open,
1646 .prepare = via_playback_pcm_prepare,
1647 .cleanup = via_playback_pcm_cleanup
1648 },
1649};
1650
1651static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
1652 .substreams = 1,
1653 .channels_min = 2,
1654 .channels_max = 4,
1655 .nid = 0x10, /* NID to query formats and rates */
1656 .ops = {
1657 .open = via_playback_pcm_open,
1658 .prepare = via_playback_pcm_prepare,
1659 .cleanup = via_playback_pcm_cleanup
1660 },
1661};
1662
1663static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
1664 .substreams = 2,
1665 .channels_min = 2,
1666 .channels_max = 2,
1667 .nid = 0x13, /* NID to query formats and rates */
1668 .ops = {
1669 .prepare = via_capture_pcm_prepare,
1670 .cleanup = via_capture_pcm_cleanup
1671 },
1672};
1673
1674static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
1675 .substreams = 1,
1676 .channels_min = 2,
1677 .channels_max = 2,
1678 /* NID is set in via_build_pcms */
1679 .ops = {
1680 .open = via_dig_playback_pcm_open,
1681 .close = via_dig_playback_pcm_close,
1682 .prepare = via_dig_playback_pcm_prepare
1683 },
1684};
1685
1686static struct hda_pcm_stream vt1708B_pcm_digital_capture = {
1687 .substreams = 1,
1688 .channels_min = 2,
1689 .channels_max = 2,
1690};
1691
1692/* fill in the dac_nids table from the parsed pin configuration */
1693static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
1694 const struct auto_pin_cfg *cfg)
1695{
1696 int i;
1697 hda_nid_t nid;
1698
1699 spec->multiout.num_dacs = cfg->line_outs;
1700
1701 spec->multiout.dac_nids = spec->private_dac_nids;
1702
1703 for (i = 0; i < 4; i++) {
1704 nid = cfg->line_out_pins[i];
1705 if (nid) {
1706 /* config dac list */
1707 switch (i) {
1708 case AUTO_SEQ_FRONT:
1709 spec->multiout.dac_nids[i] = 0x10;
1710 break;
1711 case AUTO_SEQ_CENLFE:
1712 spec->multiout.dac_nids[i] = 0x24;
1713 break;
1714 case AUTO_SEQ_SURROUND:
Harald Weltefb4cb772008-09-09 15:53:36 +08001715 spec->multiout.dac_nids[i] = 0x11;
Josepch Chanf7278fd2007-12-13 16:40:40 +01001716 break;
1717 case AUTO_SEQ_SIDE:
Harald Weltefb4cb772008-09-09 15:53:36 +08001718 spec->multiout.dac_nids[i] = 0x25;
Josepch Chanf7278fd2007-12-13 16:40:40 +01001719 break;
1720 }
1721 }
1722 }
1723
1724 return 0;
1725}
1726
1727/* add playback controls from the parsed DAC table */
1728static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
1729 const struct auto_pin_cfg *cfg)
1730{
1731 char name[32];
1732 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
Harald Weltefb4cb772008-09-09 15:53:36 +08001733 hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27};
Josepch Chanf7278fd2007-12-13 16:40:40 +01001734 hda_nid_t nid, nid_vol = 0;
1735 int i, err;
1736
1737 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1738 nid = cfg->line_out_pins[i];
1739
1740 if (!nid)
1741 continue;
1742
1743 nid_vol = nid_vols[i];
1744
1745 if (i == AUTO_SEQ_CENLFE) {
1746 /* Center/LFE */
1747 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1748 "Center Playback Volume",
1749 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1750 HDA_OUTPUT));
1751 if (err < 0)
1752 return err;
1753 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1754 "LFE Playback Volume",
1755 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1756 HDA_OUTPUT));
1757 if (err < 0)
1758 return err;
1759 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1760 "Center Playback Switch",
1761 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1762 HDA_OUTPUT));
1763 if (err < 0)
1764 return err;
1765 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1766 "LFE Playback Switch",
1767 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1768 HDA_OUTPUT));
1769 if (err < 0)
1770 return err;
1771 } else if (i == AUTO_SEQ_FRONT) {
1772 /* add control to mixer index 0 */
1773 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1774 "Master Front Playback Volume",
1775 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1776 HDA_INPUT));
1777 if (err < 0)
1778 return err;
1779 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1780 "Master Front Playback Switch",
1781 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1782 HDA_INPUT));
1783 if (err < 0)
1784 return err;
1785
1786 /* add control to PW3 */
1787 sprintf(name, "%s Playback Volume", chname[i]);
1788 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1789 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1790 HDA_OUTPUT));
1791 if (err < 0)
1792 return err;
1793 sprintf(name, "%s Playback Switch", chname[i]);
1794 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1795 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1796 HDA_OUTPUT));
1797 if (err < 0)
1798 return err;
1799 } else {
1800 sprintf(name, "%s Playback Volume", chname[i]);
1801 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1802 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1803 HDA_OUTPUT));
1804 if (err < 0)
1805 return err;
1806 sprintf(name, "%s Playback Switch", chname[i]);
1807 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1808 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1809 HDA_OUTPUT));
1810 if (err < 0)
1811 return err;
1812 }
1813 }
1814
1815 return 0;
1816}
1817
1818static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1819{
1820 int err;
1821
1822 if (!pin)
1823 return 0;
1824
1825 spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
1826
1827 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1828 "Headphone Playback Volume",
1829 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1830 if (err < 0)
1831 return err;
1832 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1833 "Headphone Playback Switch",
1834 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1835 if (err < 0)
1836 return err;
1837
1838 return 0;
1839}
1840
1841/* create playback/capture controls for input pins */
1842static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
1843 const struct auto_pin_cfg *cfg)
1844{
1845 static char *labels[] = {
1846 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1847 };
1848 struct hda_input_mux *imux = &spec->private_imux;
1849 int i, err, idx = 0;
1850
1851 /* for internal loopback recording select */
1852 imux->items[imux->num_items].label = "Stereo Mixer";
1853 imux->items[imux->num_items].index = idx;
1854 imux->num_items++;
1855
1856 for (i = 0; i < AUTO_PIN_LAST; i++) {
1857 if (!cfg->input_pins[i])
1858 continue;
1859
1860 switch (cfg->input_pins[i]) {
1861 case 0x1a: /* Mic */
1862 idx = 2;
1863 break;
1864
1865 case 0x1b: /* Line In */
1866 idx = 3;
1867 break;
1868
1869 case 0x1e: /* Front Mic */
1870 idx = 4;
1871 break;
1872
1873 case 0x1f: /* CD */
1874 idx = 1;
1875 break;
1876 }
1877 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
1878 idx, 0x16);
1879 if (err < 0)
1880 return err;
1881 imux->items[imux->num_items].label = labels[i];
1882 imux->items[imux->num_items].index = idx;
1883 imux->num_items++;
1884 }
1885 return 0;
1886}
1887
1888static int vt1708B_parse_auto_config(struct hda_codec *codec)
1889{
1890 struct via_spec *spec = codec->spec;
1891 int err;
1892
1893 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1894 if (err < 0)
1895 return err;
1896 err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg);
1897 if (err < 0)
1898 return err;
1899 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1900 return 0; /* can't find valid BIOS pin config */
1901
1902 err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg);
1903 if (err < 0)
1904 return err;
1905 err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1906 if (err < 0)
1907 return err;
1908 err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
1909 if (err < 0)
1910 return err;
1911
1912 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1913
1914 if (spec->autocfg.dig_out_pin)
1915 spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
1916 if (spec->autocfg.dig_in_pin)
1917 spec->dig_in_nid = VT1708B_DIGIN_NID;
1918
1919 if (spec->kctl_alloc)
1920 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
1921
1922 spec->input_mux = &spec->private_imux;
1923
1924 return 1;
1925}
1926
1927#ifdef CONFIG_SND_HDA_POWER_SAVE
1928static struct hda_amp_list vt1708B_loopbacks[] = {
1929 { 0x16, HDA_INPUT, 1 },
1930 { 0x16, HDA_INPUT, 2 },
1931 { 0x16, HDA_INPUT, 3 },
1932 { 0x16, HDA_INPUT, 4 },
1933 { } /* end */
1934};
1935#endif
1936
1937static int patch_vt1708B_8ch(struct hda_codec *codec)
1938{
1939 struct via_spec *spec;
1940 int err;
1941
1942 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08001943 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01001944 if (spec == NULL)
1945 return -ENOMEM;
1946
1947 codec->spec = spec;
1948
1949 /* automatic parse from the BIOS config */
1950 err = vt1708B_parse_auto_config(codec);
1951 if (err < 0) {
1952 via_free(codec);
1953 return err;
1954 } else if (!err) {
1955 printk(KERN_INFO "hda_codec: Cannot set up configuration "
1956 "from BIOS. Using genenic mode...\n");
1957 }
1958
1959 spec->init_verbs = vt1708B_8ch_volume_init_verbs;
1960
1961 spec->stream_name_analog = "VT1708B Analog";
1962 spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
1963 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
1964
1965 spec->stream_name_digital = "VT1708B Digital";
1966 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
1967 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
1968
1969 if (!spec->adc_nids && spec->input_mux) {
1970 spec->adc_nids = vt1708B_adc_nids;
1971 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
1972 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
1973 spec->num_mixers++;
1974 }
1975
1976 codec->patch_ops = via_patch_ops;
1977
1978 codec->patch_ops.init = via_auto_init;
1979#ifdef CONFIG_SND_HDA_POWER_SAVE
1980 spec->loopback.amplist = vt1708B_loopbacks;
1981#endif
1982
1983 return 0;
1984}
1985
1986static int patch_vt1708B_4ch(struct hda_codec *codec)
1987{
1988 struct via_spec *spec;
1989 int err;
1990
1991 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08001992 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01001993 if (spec == NULL)
1994 return -ENOMEM;
1995
1996 codec->spec = spec;
1997
1998 /* automatic parse from the BIOS config */
1999 err = vt1708B_parse_auto_config(codec);
2000 if (err < 0) {
2001 via_free(codec);
2002 return err;
2003 } else if (!err) {
2004 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2005 "from BIOS. Using genenic mode...\n");
2006 }
2007
2008 spec->init_verbs = vt1708B_4ch_volume_init_verbs;
2009
2010 spec->stream_name_analog = "VT1708B Analog";
2011 spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
2012 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
2013
2014 spec->stream_name_digital = "VT1708B Digital";
2015 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
2016 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
2017
2018 if (!spec->adc_nids && spec->input_mux) {
2019 spec->adc_nids = vt1708B_adc_nids;
2020 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
2021 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
2022 spec->num_mixers++;
2023 }
2024
2025 codec->patch_ops = via_patch_ops;
2026
2027 codec->patch_ops.init = via_auto_init;
2028#ifdef CONFIG_SND_HDA_POWER_SAVE
2029 spec->loopback.amplist = vt1708B_loopbacks;
2030#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01002031
2032 return 0;
2033}
2034
Harald Welted949cac2008-09-09 15:56:01 +08002035/* Patch for VT1708S */
2036
2037/* capture mixer elements */
2038static struct snd_kcontrol_new vt1708S_capture_mixer[] = {
2039 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
2040 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
2041 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
2042 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
2043 HDA_CODEC_VOLUME("Mic Boost", 0x1A, 0x0, HDA_INPUT),
2044 HDA_CODEC_VOLUME("Front Mic Boost", 0x1E, 0x0, HDA_INPUT),
2045 {
2046 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2047 /* The multiple "Capture Source" controls confuse alsamixer
2048 * So call somewhat different..
2049 */
2050 /* .name = "Capture Source", */
2051 .name = "Input Source",
2052 .count = 1,
2053 .info = via_mux_enum_info,
2054 .get = via_mux_enum_get,
2055 .put = via_mux_enum_put,
2056 },
2057 { } /* end */
2058};
2059
2060static struct hda_verb vt1708S_volume_init_verbs[] = {
2061 /* Unmute ADC0-1 and set the default input to mic-in */
2062 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2063 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2064
2065 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the
2066 * analog-loopback mixer widget */
2067 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2068 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2069 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2070 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2071 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2072 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2073
2074 /* Setup default input of PW4 to MW0 */
2075 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
2076 /* PW9 Output enable */
2077 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2078 { }
2079};
2080
2081static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
2082 .substreams = 2,
2083 .channels_min = 2,
2084 .channels_max = 8,
2085 .nid = 0x10, /* NID to query formats and rates */
2086 .ops = {
2087 .open = via_playback_pcm_open,
2088 .prepare = via_playback_pcm_prepare,
2089 .cleanup = via_playback_pcm_cleanup
2090 },
2091};
2092
2093static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
2094 .substreams = 2,
2095 .channels_min = 2,
2096 .channels_max = 2,
2097 .nid = 0x13, /* NID to query formats and rates */
2098 .ops = {
2099 .prepare = via_capture_pcm_prepare,
2100 .cleanup = via_capture_pcm_cleanup
2101 },
2102};
2103
2104static struct hda_pcm_stream vt1708S_pcm_digital_playback = {
2105 .substreams = 1,
2106 .channels_min = 2,
2107 .channels_max = 2,
2108 /* NID is set in via_build_pcms */
2109 .ops = {
2110 .open = via_dig_playback_pcm_open,
2111 .close = via_dig_playback_pcm_close,
2112 .prepare = via_dig_playback_pcm_prepare
2113 },
2114};
2115
2116/* fill in the dac_nids table from the parsed pin configuration */
2117static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
2118 const struct auto_pin_cfg *cfg)
2119{
2120 int i;
2121 hda_nid_t nid;
2122
2123 spec->multiout.num_dacs = cfg->line_outs;
2124
2125 spec->multiout.dac_nids = spec->private_dac_nids;
2126
2127 for (i = 0; i < 4; i++) {
2128 nid = cfg->line_out_pins[i];
2129 if (nid) {
2130 /* config dac list */
2131 switch (i) {
2132 case AUTO_SEQ_FRONT:
2133 spec->multiout.dac_nids[i] = 0x10;
2134 break;
2135 case AUTO_SEQ_CENLFE:
2136 spec->multiout.dac_nids[i] = 0x24;
2137 break;
2138 case AUTO_SEQ_SURROUND:
2139 spec->multiout.dac_nids[i] = 0x11;
2140 break;
2141 case AUTO_SEQ_SIDE:
2142 spec->multiout.dac_nids[i] = 0x25;
2143 break;
2144 }
2145 }
2146 }
2147
2148 return 0;
2149}
2150
2151/* add playback controls from the parsed DAC table */
2152static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
2153 const struct auto_pin_cfg *cfg)
2154{
2155 char name[32];
2156 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
2157 hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25};
2158 hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27};
2159 hda_nid_t nid, nid_vol, nid_mute;
2160 int i, err;
2161
2162 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2163 nid = cfg->line_out_pins[i];
2164
2165 if (!nid)
2166 continue;
2167
2168 nid_vol = nid_vols[i];
2169 nid_mute = nid_mutes[i];
2170
2171 if (i == AUTO_SEQ_CENLFE) {
2172 /* Center/LFE */
2173 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2174 "Center Playback Volume",
2175 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2176 HDA_OUTPUT));
2177 if (err < 0)
2178 return err;
2179 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2180 "LFE Playback Volume",
2181 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2182 HDA_OUTPUT));
2183 if (err < 0)
2184 return err;
2185 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2186 "Center Playback Switch",
2187 HDA_COMPOSE_AMP_VAL(nid_mute,
2188 1, 0,
2189 HDA_OUTPUT));
2190 if (err < 0)
2191 return err;
2192 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2193 "LFE Playback Switch",
2194 HDA_COMPOSE_AMP_VAL(nid_mute,
2195 2, 0,
2196 HDA_OUTPUT));
2197 if (err < 0)
2198 return err;
2199 } else if (i == AUTO_SEQ_FRONT) {
2200 /* add control to mixer index 0 */
2201 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2202 "Master Front Playback Volume",
2203 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
2204 HDA_INPUT));
2205 if (err < 0)
2206 return err;
2207 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2208 "Master Front Playback Switch",
2209 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
2210 HDA_INPUT));
2211 if (err < 0)
2212 return err;
2213
2214 /* Front */
2215 sprintf(name, "%s Playback Volume", chname[i]);
2216 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2217 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2218 HDA_OUTPUT));
2219 if (err < 0)
2220 return err;
2221 sprintf(name, "%s Playback Switch", chname[i]);
2222 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2223 HDA_COMPOSE_AMP_VAL(nid_mute,
2224 3, 0,
2225 HDA_OUTPUT));
2226 if (err < 0)
2227 return err;
2228 } else {
2229 sprintf(name, "%s Playback Volume", chname[i]);
2230 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2231 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2232 HDA_OUTPUT));
2233 if (err < 0)
2234 return err;
2235 sprintf(name, "%s Playback Switch", chname[i]);
2236 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2237 HDA_COMPOSE_AMP_VAL(nid_mute,
2238 3, 0,
2239 HDA_OUTPUT));
2240 if (err < 0)
2241 return err;
2242 }
2243 }
2244
2245 return 0;
2246}
2247
2248static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2249{
2250 int err;
2251
2252 if (!pin)
2253 return 0;
2254
2255 spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */
2256
2257 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2258 "Headphone Playback Volume",
2259 HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
2260 if (err < 0)
2261 return err;
2262
2263 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2264 "Headphone Playback Switch",
2265 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2266 if (err < 0)
2267 return err;
2268
2269 return 0;
2270}
2271
2272/* create playback/capture controls for input pins */
2273static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
2274 const struct auto_pin_cfg *cfg)
2275{
2276 static char *labels[] = {
2277 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2278 };
2279 struct hda_input_mux *imux = &spec->private_imux;
2280 int i, err, idx = 0;
2281
2282 /* for internal loopback recording select */
2283 imux->items[imux->num_items].label = "Stereo Mixer";
2284 imux->items[imux->num_items].index = 5;
2285 imux->num_items++;
2286
2287 for (i = 0; i < AUTO_PIN_LAST; i++) {
2288 if (!cfg->input_pins[i])
2289 continue;
2290
2291 switch (cfg->input_pins[i]) {
2292 case 0x1a: /* Mic */
2293 idx = 2;
2294 break;
2295
2296 case 0x1b: /* Line In */
2297 idx = 3;
2298 break;
2299
2300 case 0x1e: /* Front Mic */
2301 idx = 4;
2302 break;
2303
2304 case 0x1f: /* CD */
2305 idx = 1;
2306 break;
2307 }
2308 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
2309 idx, 0x16);
2310 if (err < 0)
2311 return err;
2312 imux->items[imux->num_items].label = labels[i];
2313 imux->items[imux->num_items].index = idx-1;
2314 imux->num_items++;
2315 }
2316 return 0;
2317}
2318
2319static int vt1708S_parse_auto_config(struct hda_codec *codec)
2320{
2321 struct via_spec *spec = codec->spec;
2322 int err;
2323 static hda_nid_t vt1708s_ignore[] = {0x21, 0};
2324
2325 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
2326 vt1708s_ignore);
2327 if (err < 0)
2328 return err;
2329 err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg);
2330 if (err < 0)
2331 return err;
2332 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2333 return 0; /* can't find valid BIOS pin config */
2334
2335 err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg);
2336 if (err < 0)
2337 return err;
2338 err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2339 if (err < 0)
2340 return err;
2341 err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
2342 if (err < 0)
2343 return err;
2344
2345 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2346
2347 if (spec->autocfg.dig_out_pin)
2348 spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID;
2349
2350 if (spec->kctl_alloc)
2351 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2352
2353 spec->input_mux = &spec->private_imux;
2354
2355 return 1;
2356}
2357
2358#ifdef CONFIG_SND_HDA_POWER_SAVE
2359static struct hda_amp_list vt1708S_loopbacks[] = {
2360 { 0x16, HDA_INPUT, 1 },
2361 { 0x16, HDA_INPUT, 2 },
2362 { 0x16, HDA_INPUT, 3 },
2363 { 0x16, HDA_INPUT, 4 },
2364 { } /* end */
2365};
2366#endif
2367
2368static int patch_vt1708S(struct hda_codec *codec)
2369{
2370 struct via_spec *spec;
2371 int err;
2372
2373 /* create a codec specific record */
2374 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2375 if (spec == NULL)
2376 return -ENOMEM;
2377
2378 codec->spec = spec;
2379
2380 /* automatic parse from the BIOS config */
2381 err = vt1708S_parse_auto_config(codec);
2382 if (err < 0) {
2383 via_free(codec);
2384 return err;
2385 } else if (!err) {
2386 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2387 "from BIOS. Using genenic mode...\n");
2388 }
2389
2390 spec->init_verbs = vt1708S_volume_init_verbs;
2391
2392 spec->stream_name_analog = "VT1708S Analog";
2393 spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
2394 spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
2395
2396 spec->stream_name_digital = "VT1708S Digital";
2397 spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
2398
2399 if (!spec->adc_nids && spec->input_mux) {
2400 spec->adc_nids = vt1708S_adc_nids;
2401 spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
2402 spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
2403 spec->num_mixers++;
2404 }
2405
2406 codec->patch_ops = via_patch_ops;
2407
2408 codec->patch_ops.init = via_auto_init;
2409
2410#ifdef CONFIG_SND_HDA_POWER_SAVE
2411 spec->loopback.amplist = vt1708S_loopbacks;
2412#endif
2413
2414 return 0;
2415}
2416
2417/* Patch for VT1702 */
2418
2419/* capture mixer elements */
2420static struct snd_kcontrol_new vt1702_capture_mixer[] = {
2421 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
2422 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
2423 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
2424 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT),
2425 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT),
2426 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT),
2427 HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0,
2428 HDA_INPUT),
2429 {
2430 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2431 /* The multiple "Capture Source" controls confuse alsamixer
2432 * So call somewhat different..
2433 */
2434 /* .name = "Capture Source", */
2435 .name = "Input Source",
2436 .count = 1,
2437 .info = via_mux_enum_info,
2438 .get = via_mux_enum_get,
2439 .put = via_mux_enum_put,
2440 },
2441 { } /* end */
2442};
2443
2444static struct hda_verb vt1702_volume_init_verbs[] = {
2445 /*
2446 * Unmute ADC0-1 and set the default input to mic-in
2447 */
2448 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2449 {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2450 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2451
2452
2453 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2454 * mixer widget
2455 */
2456 /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */
2457 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2458 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2459 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2460 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2461 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2462
2463 /* Setup default input of PW4 to MW0 */
2464 {0x17, AC_VERB_SET_CONNECT_SEL, 0x1},
2465 /* PW6 PW7 Output enable */
2466 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2467 {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2468 { }
2469};
2470
2471static struct hda_pcm_stream vt1702_pcm_analog_playback = {
2472 .substreams = 1,
2473 .channels_min = 2,
2474 .channels_max = 2,
2475 .nid = 0x10, /* NID to query formats and rates */
2476 .ops = {
2477 .open = via_playback_pcm_open,
2478 .prepare = via_playback_pcm_prepare,
2479 .cleanup = via_playback_pcm_cleanup
2480 },
2481};
2482
2483static struct hda_pcm_stream vt1702_pcm_analog_capture = {
2484 .substreams = 3,
2485 .channels_min = 2,
2486 .channels_max = 2,
2487 .nid = 0x12, /* NID to query formats and rates */
2488 .ops = {
2489 .prepare = via_capture_pcm_prepare,
2490 .cleanup = via_capture_pcm_cleanup
2491 },
2492};
2493
2494static struct hda_pcm_stream vt1702_pcm_digital_playback = {
2495 .substreams = 1,
2496 .channels_min = 2,
2497 .channels_max = 2,
2498 /* NID is set in via_build_pcms */
2499 .ops = {
2500 .open = via_dig_playback_pcm_open,
2501 .close = via_dig_playback_pcm_close,
2502 .prepare = via_dig_playback_pcm_prepare
2503 },
2504};
2505
2506/* fill in the dac_nids table from the parsed pin configuration */
2507static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
2508 const struct auto_pin_cfg *cfg)
2509{
2510 spec->multiout.num_dacs = 1;
2511 spec->multiout.dac_nids = spec->private_dac_nids;
2512
2513 if (cfg->line_out_pins[0]) {
2514 /* config dac list */
2515 spec->multiout.dac_nids[0] = 0x10;
2516 }
2517
2518 return 0;
2519}
2520
2521/* add playback controls from the parsed DAC table */
2522static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
2523 const struct auto_pin_cfg *cfg)
2524{
2525 int err;
2526
2527 if (!cfg->line_out_pins[0])
2528 return -1;
2529
2530 /* add control to mixer index 0 */
2531 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2532 "Master Front Playback Volume",
2533 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
2534 if (err < 0)
2535 return err;
2536 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2537 "Master Front Playback Switch",
2538 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
2539 if (err < 0)
2540 return err;
2541
2542 /* Front */
2543 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2544 "Front Playback Volume",
2545 HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT));
2546 if (err < 0)
2547 return err;
2548 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2549 "Front Playback Switch",
2550 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT));
2551 if (err < 0)
2552 return err;
2553
2554 return 0;
2555}
2556
2557static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2558{
2559 int err;
2560
2561 if (!pin)
2562 return 0;
2563
2564 spec->multiout.hp_nid = 0x1D;
2565
2566 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2567 "Headphone Playback Volume",
2568 HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT));
2569 if (err < 0)
2570 return err;
2571
2572 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2573 "Headphone Playback Switch",
2574 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2575 if (err < 0)
2576 return err;
2577
2578 return 0;
2579}
2580
2581/* create playback/capture controls for input pins */
2582static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
2583 const struct auto_pin_cfg *cfg)
2584{
2585 static char *labels[] = {
2586 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2587 };
2588 struct hda_input_mux *imux = &spec->private_imux;
2589 int i, err, idx = 0;
2590
2591 /* for internal loopback recording select */
2592 imux->items[imux->num_items].label = "Stereo Mixer";
2593 imux->items[imux->num_items].index = 3;
2594 imux->num_items++;
2595
2596 for (i = 0; i < AUTO_PIN_LAST; i++) {
2597 if (!cfg->input_pins[i])
2598 continue;
2599
2600 switch (cfg->input_pins[i]) {
2601 case 0x14: /* Mic */
2602 idx = 1;
2603 break;
2604
2605 case 0x15: /* Line In */
2606 idx = 2;
2607 break;
2608
2609 case 0x18: /* Front Mic */
2610 idx = 3;
2611 break;
2612 }
2613 err = via_new_analog_input(spec, cfg->input_pins[i],
2614 labels[i], idx, 0x1A);
2615 if (err < 0)
2616 return err;
2617 imux->items[imux->num_items].label = labels[i];
2618 imux->items[imux->num_items].index = idx-1;
2619 imux->num_items++;
2620 }
2621 return 0;
2622}
2623
2624static int vt1702_parse_auto_config(struct hda_codec *codec)
2625{
2626 struct via_spec *spec = codec->spec;
2627 int err;
2628 static hda_nid_t vt1702_ignore[] = {0x1C, 0};
2629
2630 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
2631 vt1702_ignore);
2632 if (err < 0)
2633 return err;
2634 err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg);
2635 if (err < 0)
2636 return err;
2637 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2638 return 0; /* can't find valid BIOS pin config */
2639
2640 err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg);
2641 if (err < 0)
2642 return err;
2643 err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2644 if (err < 0)
2645 return err;
2646 err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
2647 if (err < 0)
2648 return err;
2649
2650 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2651
2652 if (spec->autocfg.dig_out_pin)
2653 spec->multiout.dig_out_nid = VT1702_DIGOUT_NID;
2654
2655 if (spec->kctl_alloc)
2656 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2657
2658 spec->input_mux = &spec->private_imux;
2659
2660 return 1;
2661}
2662
2663#ifdef CONFIG_SND_HDA_POWER_SAVE
2664static struct hda_amp_list vt1702_loopbacks[] = {
2665 { 0x1A, HDA_INPUT, 1 },
2666 { 0x1A, HDA_INPUT, 2 },
2667 { 0x1A, HDA_INPUT, 3 },
2668 { 0x1A, HDA_INPUT, 4 },
2669 { } /* end */
2670};
2671#endif
2672
2673static int patch_vt1702(struct hda_codec *codec)
2674{
2675 struct via_spec *spec;
2676 int err;
2677 unsigned int response;
2678 unsigned char control;
2679
2680 /* create a codec specific record */
2681 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2682 if (spec == NULL)
2683 return -ENOMEM;
2684
2685 codec->spec = spec;
2686
2687 /* automatic parse from the BIOS config */
2688 err = vt1702_parse_auto_config(codec);
2689 if (err < 0) {
2690 via_free(codec);
2691 return err;
2692 } else if (!err) {
2693 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2694 "from BIOS. Using genenic mode...\n");
2695 }
2696
2697 spec->init_verbs = vt1702_volume_init_verbs;
2698
2699 spec->stream_name_analog = "VT1702 Analog";
2700 spec->stream_analog_playback = &vt1702_pcm_analog_playback;
2701 spec->stream_analog_capture = &vt1702_pcm_analog_capture;
2702
2703 spec->stream_name_digital = "VT1702 Digital";
2704 spec->stream_digital_playback = &vt1702_pcm_digital_playback;
2705
2706 if (!spec->adc_nids && spec->input_mux) {
2707 spec->adc_nids = vt1702_adc_nids;
2708 spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
2709 spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
2710 spec->num_mixers++;
2711 }
2712
2713 codec->patch_ops = via_patch_ops;
2714
2715 codec->patch_ops.init = via_auto_init;
2716
2717#ifdef CONFIG_SND_HDA_POWER_SAVE
2718 spec->loopback.amplist = vt1702_loopbacks;
2719#endif
2720
2721 /* Open backdoor */
2722 response = snd_hda_codec_read(codec, codec->afg, 0, 0xF8C, 0);
2723 control = (unsigned char)(response & 0xff);
2724 control |= 0x3;
2725 snd_hda_codec_write(codec, codec->afg, 0, 0xF88, control);
2726
2727 /* Enable GPIO 0&1 for volume&mute control */
2728 /* Enable GPIO 2 for DMIC-DATA */
2729 response = snd_hda_codec_read(codec, codec->afg, 0, 0xF84, 0);
2730 control = (unsigned char)((response >> 16) & 0x3f);
2731 snd_hda_codec_write(codec, codec->afg, 0, 0xF82, control);
2732
2733 return 0;
2734}
2735
Joseph Chanc577b8a2006-11-29 15:29:40 +01002736/*
2737 * patch entries
2738 */
2739struct hda_codec_preset snd_hda_preset_via[] = {
2740 { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708},
2741 { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708},
2742 { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708},
2743 { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708},
Josepch Chanf7278fd2007-12-13 16:40:40 +01002744 { .id = 0x1106E710, .name = "VIA VT1709 10-Ch",
2745 .patch = patch_vt1709_10ch},
2746 { .id = 0x1106E711, .name = "VIA VT1709 10-Ch",
2747 .patch = patch_vt1709_10ch},
2748 { .id = 0x1106E712, .name = "VIA VT1709 10-Ch",
2749 .patch = patch_vt1709_10ch},
2750 { .id = 0x1106E713, .name = "VIA VT1709 10-Ch",
2751 .patch = patch_vt1709_10ch},
2752 { .id = 0x1106E714, .name = "VIA VT1709 6-Ch",
2753 .patch = patch_vt1709_6ch},
2754 { .id = 0x1106E715, .name = "VIA VT1709 6-Ch",
2755 .patch = patch_vt1709_6ch},
2756 { .id = 0x1106E716, .name = "VIA VT1709 6-Ch",
2757 .patch = patch_vt1709_6ch},
2758 { .id = 0x1106E717, .name = "VIA VT1709 6-Ch",
2759 .patch = patch_vt1709_6ch},
2760 { .id = 0x1106E720, .name = "VIA VT1708B 8-Ch",
2761 .patch = patch_vt1708B_8ch},
2762 { .id = 0x1106E721, .name = "VIA VT1708B 8-Ch",
2763 .patch = patch_vt1708B_8ch},
2764 { .id = 0x1106E722, .name = "VIA VT1708B 8-Ch",
2765 .patch = patch_vt1708B_8ch},
2766 { .id = 0x1106E723, .name = "VIA VT1708B 8-Ch",
2767 .patch = patch_vt1708B_8ch},
2768 { .id = 0x1106E724, .name = "VIA VT1708B 4-Ch",
2769 .patch = patch_vt1708B_4ch},
2770 { .id = 0x1106E725, .name = "VIA VT1708B 4-Ch",
2771 .patch = patch_vt1708B_4ch},
2772 { .id = 0x1106E726, .name = "VIA VT1708B 4-Ch",
2773 .patch = patch_vt1708B_4ch},
2774 { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch",
2775 .patch = patch_vt1708B_4ch},
Harald Welted949cac2008-09-09 15:56:01 +08002776 { .id = 0x11060397, .name = "VIA VT1708S",
2777 .patch = patch_vt1708S},
2778 { .id = 0x11061397, .name = "VIA VT1708S",
2779 .patch = patch_vt1708S},
2780 { .id = 0x11062397, .name = "VIA VT1708S",
2781 .patch = patch_vt1708S},
2782 { .id = 0x11063397, .name = "VIA VT1708S",
2783 .patch = patch_vt1708S},
2784 { .id = 0x11064397, .name = "VIA VT1708S",
2785 .patch = patch_vt1708S},
2786 { .id = 0x11065397, .name = "VIA VT1708S",
2787 .patch = patch_vt1708S},
2788 { .id = 0x11066397, .name = "VIA VT1708S",
2789 .patch = patch_vt1708S},
2790 { .id = 0x11067397, .name = "VIA VT1708S",
2791 .patch = patch_vt1708S},
2792 { .id = 0x11060398, .name = "VIA VT1702",
2793 .patch = patch_vt1702},
2794 { .id = 0x11061398, .name = "VIA VT1702",
2795 .patch = patch_vt1702},
2796 { .id = 0x11062398, .name = "VIA VT1702",
2797 .patch = patch_vt1702},
2798 { .id = 0x11063398, .name = "VIA VT1702",
2799 .patch = patch_vt1702},
2800 { .id = 0x11064398, .name = "VIA VT1702",
2801 .patch = patch_vt1702},
2802 { .id = 0x11065398, .name = "VIA VT1702",
2803 .patch = patch_vt1702},
2804 { .id = 0x11066398, .name = "VIA VT1702",
2805 .patch = patch_vt1702},
2806 { .id = 0x11067398, .name = "VIA VT1702",
2807 .patch = patch_vt1702},
Joseph Chanc577b8a2006-11-29 15:29:40 +01002808 {} /* terminator */
2809};