blob: 4e4d2c5b261f060cec3e3af70ea854a349cc31a6 [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 */
Harald Welte69e52a82008-09-09 15:57:32 +080035/* 2008-04-09 Lydia Wang Add mute front speaker when HP plugin */
Harald Welte0aa62ae2008-09-09 15:58:27 +080036/* 2008-04-09 Lydia Wang Add Independent HP feature */
Joseph Chanc577b8a2006-11-29 15:29:40 +010037/* */
38/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
39
40
Joseph Chanc577b8a2006-11-29 15:29:40 +010041#include <linux/init.h>
42#include <linux/delay.h>
43#include <linux/slab.h>
Joseph Chanc577b8a2006-11-29 15:29:40 +010044#include <sound/core.h>
Harald Welte0aa62ae2008-09-09 15:58:27 +080045#include <sound/asoundef.h>
Joseph Chanc577b8a2006-11-29 15:29:40 +010046#include "hda_codec.h"
47#include "hda_local.h"
Harvey Harrison3c9a3202008-02-29 11:59:26 +010048#include "hda_patch.h"
Joseph Chanc577b8a2006-11-29 15:29:40 +010049
50/* amp values */
51#define AMP_VAL_IDX_SHIFT 19
52#define AMP_VAL_IDX_MASK (0x0f<<19)
53
54#define NUM_CONTROL_ALLOC 32
55#define NUM_VERB_ALLOC 32
56
57/* Pin Widget NID */
58#define VT1708_HP_NID 0x13
59#define VT1708_DIGOUT_NID 0x14
60#define VT1708_DIGIN_NID 0x16
Josepch Chanf7278fd2007-12-13 16:40:40 +010061#define VT1708_DIGIN_PIN 0x26
Harald Welted949cac2008-09-09 15:56:01 +080062#define VT1708_HP_PIN_NID 0x20
63#define VT1708_CD_PIN_NID 0x24
Joseph Chanc577b8a2006-11-29 15:29:40 +010064
65#define VT1709_HP_DAC_NID 0x28
66#define VT1709_DIGOUT_NID 0x13
67#define VT1709_DIGIN_NID 0x17
Josepch Chanf7278fd2007-12-13 16:40:40 +010068#define VT1709_DIGIN_PIN 0x25
69
70#define VT1708B_HP_NID 0x25
71#define VT1708B_DIGOUT_NID 0x12
72#define VT1708B_DIGIN_NID 0x15
73#define VT1708B_DIGIN_PIN 0x21
Joseph Chanc577b8a2006-11-29 15:29:40 +010074
Harald Welted949cac2008-09-09 15:56:01 +080075#define VT1708S_HP_NID 0x25
76#define VT1708S_DIGOUT_NID 0x12
77
78#define VT1702_HP_NID 0x17
79#define VT1702_DIGOUT_NID 0x11
80
Joseph Chanc577b8a2006-11-29 15:29:40 +010081#define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b)
82#define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713)
83#define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717)
Josepch Chanf7278fd2007-12-13 16:40:40 +010084#define IS_VT1708B_8CH_VENDORID(x) ((x) >= 0x1106e720 && (x) <= 0x1106e723)
85#define IS_VT1708B_4CH_VENDORID(x) ((x) >= 0x1106e724 && (x) <= 0x1106e727)
Harald Welted949cac2008-09-09 15:56:01 +080086#define IS_VT1708S_VENDORID(x) ((x) >= 0x11060397 && (x) <= 0x11067397)
87#define IS_VT1702_VENDORID(x) ((x) >= 0x11060398 && (x) <= 0x11067398)
Joseph Chanc577b8a2006-11-29 15:29:40 +010088
Harald Welte69e52a82008-09-09 15:57:32 +080089#define VIA_HP_EVENT 0x01
90#define VIA_GPIO_EVENT 0x02
91
Joseph Chanc577b8a2006-11-29 15:29:40 +010092enum {
93 VIA_CTL_WIDGET_VOL,
94 VIA_CTL_WIDGET_MUTE,
95};
96
97enum {
Harald Welteeb14a462008-09-09 15:40:38 +080098 AUTO_SEQ_FRONT = 0,
Joseph Chanc577b8a2006-11-29 15:29:40 +010099 AUTO_SEQ_SURROUND,
100 AUTO_SEQ_CENLFE,
101 AUTO_SEQ_SIDE
102};
103
104static struct snd_kcontrol_new vt1708_control_templates[] = {
105 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
106 HDA_CODEC_MUTE(NULL, 0, 0, 0),
107};
108
109
110struct via_spec {
111 /* codec parameterization */
112 struct snd_kcontrol_new *mixers[3];
113 unsigned int num_mixers;
114
Harald Welte69e52a82008-09-09 15:57:32 +0800115 struct hda_verb *init_verbs[5];
116 unsigned int num_iverbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100117
118 char *stream_name_analog;
119 struct hda_pcm_stream *stream_analog_playback;
120 struct hda_pcm_stream *stream_analog_capture;
121
122 char *stream_name_digital;
123 struct hda_pcm_stream *stream_digital_playback;
124 struct hda_pcm_stream *stream_digital_capture;
125
126 /* playback */
127 struct hda_multi_out multiout;
128
129 /* capture */
130 unsigned int num_adc_nids;
131 hda_nid_t *adc_nids;
132 hda_nid_t dig_in_nid;
133
134 /* capture source */
135 const struct hda_input_mux *input_mux;
136 unsigned int cur_mux[3];
137
138 /* PCM information */
139 struct hda_pcm pcm_rec[2];
140
141 /* dynamic controls, init_verbs and input_mux */
142 struct auto_pin_cfg autocfg;
143 unsigned int num_kctl_alloc, num_kctl_used;
144 struct snd_kcontrol_new *kctl_alloc;
Harald Welte0aa62ae2008-09-09 15:58:27 +0800145 struct hda_input_mux private_imux[2];
Takashi Iwai41923e42007-10-22 17:20:10 +0200146 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwaicb53c622007-08-10 17:21:45 +0200147
Harald Welte0aa62ae2008-09-09 15:58:27 +0800148 /* HP mode source */
149 const struct hda_input_mux *hp_mux;
150 unsigned int hp_independent_mode;
151
Takashi Iwaicb53c622007-08-10 17:21:45 +0200152#ifdef CONFIG_SND_HDA_POWER_SAVE
153 struct hda_loopback_check loopback;
154#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +0100155};
156
157static hda_nid_t vt1708_adc_nids[2] = {
158 /* ADC1-2 */
159 0x15, 0x27
160};
161
162static hda_nid_t vt1709_adc_nids[3] = {
163 /* ADC1-2 */
164 0x14, 0x15, 0x16
165};
166
Josepch Chanf7278fd2007-12-13 16:40:40 +0100167static hda_nid_t vt1708B_adc_nids[2] = {
168 /* ADC1-2 */
169 0x13, 0x14
170};
171
Harald Welted949cac2008-09-09 15:56:01 +0800172static hda_nid_t vt1708S_adc_nids[2] = {
173 /* ADC1-2 */
174 0x13, 0x14
175};
176
177static hda_nid_t vt1702_adc_nids[3] = {
178 /* ADC1-2 */
179 0x12, 0x20, 0x1F
180};
181
Joseph Chanc577b8a2006-11-29 15:29:40 +0100182/* add dynamic controls */
183static int via_add_control(struct via_spec *spec, int type, const char *name,
184 unsigned long val)
185{
186 struct snd_kcontrol_new *knew;
187
188 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
189 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
190
191 /* array + terminator */
192 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
193 if (!knew)
194 return -ENOMEM;
195 if (spec->kctl_alloc) {
196 memcpy(knew, spec->kctl_alloc,
197 sizeof(*knew) * spec->num_kctl_alloc);
198 kfree(spec->kctl_alloc);
199 }
200 spec->kctl_alloc = knew;
201 spec->num_kctl_alloc = num;
202 }
203
204 knew = &spec->kctl_alloc[spec->num_kctl_used];
205 *knew = vt1708_control_templates[type];
206 knew->name = kstrdup(name, GFP_KERNEL);
207
208 if (!knew->name)
209 return -ENOMEM;
210 knew->private_value = val;
211 spec->num_kctl_used++;
212 return 0;
213}
214
215/* create input playback/capture controls for the given pin */
216static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
217 const char *ctlname, int idx, int mix_nid)
218{
219 char name[32];
220 int err;
221
222 sprintf(name, "%s Playback Volume", ctlname);
223 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
224 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
225 if (err < 0)
226 return err;
227 sprintf(name, "%s Playback Switch", ctlname);
228 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
229 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
230 if (err < 0)
231 return err;
232 return 0;
233}
234
235static void via_auto_set_output_and_unmute(struct hda_codec *codec,
236 hda_nid_t nid, int pin_type,
237 int dac_idx)
238{
239 /* set as output */
240 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
241 pin_type);
242 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
243 AMP_OUT_UNMUTE);
244}
245
246
247static void via_auto_init_multi_out(struct hda_codec *codec)
248{
249 struct via_spec *spec = codec->spec;
250 int i;
251
252 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
253 hda_nid_t nid = spec->autocfg.line_out_pins[i];
254 if (nid)
255 via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
256 }
257}
258
259static void via_auto_init_hp_out(struct hda_codec *codec)
260{
261 struct via_spec *spec = codec->spec;
262 hda_nid_t pin;
263
264 pin = spec->autocfg.hp_pins[0];
265 if (pin) /* connect to front */
266 via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
267}
268
269static void via_auto_init_analog_input(struct hda_codec *codec)
270{
271 struct via_spec *spec = codec->spec;
272 int i;
273
274 for (i = 0; i < AUTO_PIN_LAST; i++) {
275 hda_nid_t nid = spec->autocfg.input_pins[i];
276
277 snd_hda_codec_write(codec, nid, 0,
278 AC_VERB_SET_PIN_WIDGET_CONTROL,
279 (i <= AUTO_PIN_FRONT_MIC ?
280 PIN_VREF50 : PIN_IN));
281
282 }
283}
284/*
285 * input MUX handling
286 */
287static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
288 struct snd_ctl_elem_info *uinfo)
289{
290 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
291 struct via_spec *spec = codec->spec;
292 return snd_hda_input_mux_info(spec->input_mux, uinfo);
293}
294
295static int via_mux_enum_get(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
302 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
303 return 0;
304}
305
306static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
307 struct snd_ctl_elem_value *ucontrol)
308{
309 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
310 struct via_spec *spec = codec->spec;
311 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
312 unsigned int vendor_id = codec->vendor_id;
313
314 /* AIW0 lydia 060801 add for correct sw0 input select */
315 if (IS_VT1708_VENDORID(vendor_id) && (adc_idx == 0))
316 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
317 0x18, &spec->cur_mux[adc_idx]);
318 else if ((IS_VT1709_10CH_VENDORID(vendor_id) ||
Harald Welteeb14a462008-09-09 15:40:38 +0800319 IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0))
Joseph Chanc577b8a2006-11-29 15:29:40 +0100320 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
321 0x19, &spec->cur_mux[adc_idx]);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100322 else if ((IS_VT1708B_8CH_VENDORID(vendor_id) ||
Harald Welteeb14a462008-09-09 15:40:38 +0800323 IS_VT1708B_4CH_VENDORID(vendor_id)) && (adc_idx == 0))
Josepch Chanf7278fd2007-12-13 16:40:40 +0100324 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
325 0x17, &spec->cur_mux[adc_idx]);
Harald Welted949cac2008-09-09 15:56:01 +0800326 else if (IS_VT1702_VENDORID(vendor_id) && (adc_idx == 0))
327 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
328 0x13, &spec->cur_mux[adc_idx]);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100329 else
330 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
331 spec->adc_nids[adc_idx],
332 &spec->cur_mux[adc_idx]);
333}
334
Harald Welte0aa62ae2008-09-09 15:58:27 +0800335static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
336 struct snd_ctl_elem_info *uinfo)
337{
338 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
339 struct via_spec *spec = codec->spec;
340 return snd_hda_input_mux_info(spec->hp_mux, uinfo);
341}
342
343static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
344 struct snd_ctl_elem_value *ucontrol)
345{
346 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
347 struct via_spec *spec = codec->spec;
348 hda_nid_t nid = spec->autocfg.hp_pins[0];
349 unsigned int pinsel = snd_hda_codec_read(codec, nid, 0,
350 AC_VERB_GET_CONNECT_SEL,
351 0x00);
352
353 ucontrol->value.enumerated.item[0] = pinsel;
354
355 return 0;
356}
357
358static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
359 struct snd_ctl_elem_value *ucontrol)
360{
361 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
362 struct via_spec *spec = codec->spec;
363 hda_nid_t nid = spec->autocfg.hp_pins[0];
364 unsigned int pinsel = ucontrol->value.enumerated.item[0];
365 unsigned int con_nid = snd_hda_codec_read(codec, nid, 0,
366 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
367
368 if (con_nid == spec->multiout.hp_nid) {
369 if (pinsel == 0) {
370 if (!spec->hp_independent_mode) {
371 if (spec->multiout.num_dacs > 1)
372 spec->multiout.num_dacs -= 1;
373 spec->hp_independent_mode = 1;
374 }
375 } else if (pinsel == 1) {
376 if (spec->hp_independent_mode) {
377 if (spec->multiout.num_dacs > 1)
378 spec->multiout.num_dacs += 1;
379 spec->hp_independent_mode = 0;
380 }
381 }
382 } else {
383 if (pinsel == 0) {
384 if (spec->hp_independent_mode) {
385 if (spec->multiout.num_dacs > 1)
386 spec->multiout.num_dacs += 1;
387 spec->hp_independent_mode = 0;
388 }
389 } else if (pinsel == 1) {
390 if (!spec->hp_independent_mode) {
391 if (spec->multiout.num_dacs > 1)
392 spec->multiout.num_dacs -= 1;
393 spec->hp_independent_mode = 1;
394 }
395 }
396 }
397 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL,
398 pinsel);
399
400 if (spec->multiout.hp_nid &&
401 spec->multiout.hp_nid != spec->multiout.dac_nids[HDA_FRONT])
402 snd_hda_codec_setup_stream(codec,
403 spec->multiout.hp_nid,
404 0, 0, 0);
405
406 return 0;
407}
408
409static struct snd_kcontrol_new via_hp_mixer[] = {
410 {
411 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
412 .name = "Independent HP",
413 .count = 1,
414 .info = via_independent_hp_info,
415 .get = via_independent_hp_get,
416 .put = via_independent_hp_put,
417 },
418 { } /* end */
419};
420
Joseph Chanc577b8a2006-11-29 15:29:40 +0100421/* capture mixer elements */
422static struct snd_kcontrol_new vt1708_capture_mixer[] = {
423 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
424 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
425 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
426 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
427 {
428 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
429 /* The multiple "Capture Source" controls confuse alsamixer
430 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +0100431 */
432 /* .name = "Capture Source", */
433 .name = "Input Source",
434 .count = 1,
435 .info = via_mux_enum_info,
436 .get = via_mux_enum_get,
437 .put = via_mux_enum_put,
438 },
439 { } /* end */
440};
441/*
442 * generic initialization of ADC, input mixers and output mixers
443 */
444static struct hda_verb vt1708_volume_init_verbs[] = {
445 /*
446 * Unmute ADC0-1 and set the default input to mic-in
447 */
448 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
449 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
450
451
Josepch Chanf7278fd2007-12-13 16:40:40 +0100452 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +0100453 * mixer widget
454 */
455 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +0100456 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
457 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
458 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
459 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
460 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100461
462 /*
463 * Set up output mixers (0x19 - 0x1b)
464 */
465 /* set vol=0 to output mixers */
466 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
467 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
468 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
469
470 /* Setup default input to PW4 */
471 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100472 /* PW9 Output enable */
473 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Josepch Chanf7278fd2007-12-13 16:40:40 +0100474 { }
Joseph Chanc577b8a2006-11-29 15:29:40 +0100475};
476
477static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
478 struct hda_codec *codec,
479 struct snd_pcm_substream *substream)
480{
481 struct via_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +0100482 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
483 hinfo);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100484}
485
486static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
487 struct hda_codec *codec,
488 unsigned int stream_tag,
489 unsigned int format,
490 struct snd_pcm_substream *substream)
491{
492 struct via_spec *spec = codec->spec;
493 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
494 stream_tag, format, substream);
495}
496
497static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
498 struct hda_codec *codec,
499 struct snd_pcm_substream *substream)
500{
501 struct via_spec *spec = codec->spec;
502 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
503}
504
Harald Welte0aa62ae2008-09-09 15:58:27 +0800505
506static void playback_multi_pcm_prep_0(struct hda_codec *codec,
507 unsigned int stream_tag,
508 unsigned int format,
509 struct snd_pcm_substream *substream)
510{
511 struct via_spec *spec = codec->spec;
512 struct hda_multi_out *mout = &spec->multiout;
513 hda_nid_t *nids = mout->dac_nids;
514 int chs = substream->runtime->channels;
515 int i;
516
517 mutex_lock(&codec->spdif_mutex);
518 if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
519 if (chs == 2 &&
520 snd_hda_is_supported_format(codec, mout->dig_out_nid,
521 format) &&
522 !(codec->spdif_status & IEC958_AES0_NONAUDIO)) {
523 mout->dig_out_used = HDA_DIG_ANALOG_DUP;
524 /* turn off SPDIF once; otherwise the IEC958 bits won't
525 * be updated */
526 if (codec->spdif_ctls & AC_DIG1_ENABLE)
527 snd_hda_codec_write(codec, mout->dig_out_nid, 0,
528 AC_VERB_SET_DIGI_CONVERT_1,
529 codec->spdif_ctls &
530 ~AC_DIG1_ENABLE & 0xff);
531 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
532 stream_tag, 0, format);
533 /* turn on again (if needed) */
534 if (codec->spdif_ctls & AC_DIG1_ENABLE)
535 snd_hda_codec_write(codec, mout->dig_out_nid, 0,
536 AC_VERB_SET_DIGI_CONVERT_1,
537 codec->spdif_ctls & 0xff);
538 } else {
539 mout->dig_out_used = 0;
540 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
541 0, 0, 0);
542 }
543 }
544 mutex_unlock(&codec->spdif_mutex);
545
546 /* front */
547 snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag,
548 0, format);
549
550 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
551 !spec->hp_independent_mode)
552 /* headphone out will just decode front left/right (stereo) */
553 snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag,
554 0, format);
555
556 /* extra outputs copied from front */
557 for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
558 if (mout->extra_out_nid[i])
559 snd_hda_codec_setup_stream(codec,
560 mout->extra_out_nid[i],
561 stream_tag, 0, format);
562
563 /* surrounds */
564 for (i = 1; i < mout->num_dacs; i++) {
565 if (chs >= (i + 1) * 2) /* independent out */
566 snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
567 i * 2, format);
568 else /* copy front */
569 snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
570 0, format);
571 }
572}
573
574static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
575 struct hda_codec *codec,
576 unsigned int stream_tag,
577 unsigned int format,
578 struct snd_pcm_substream *substream)
579{
580 struct via_spec *spec = codec->spec;
581 struct hda_multi_out *mout = &spec->multiout;
582 hda_nid_t *nids = mout->dac_nids;
583
584 if (substream->number == 0)
585 playback_multi_pcm_prep_0(codec, stream_tag, format,
586 substream);
587 else {
588 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
589 spec->hp_independent_mode)
590 snd_hda_codec_setup_stream(codec, mout->hp_nid,
591 stream_tag, 0, format);
592 }
593
594 return 0;
595}
596
597static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
598 struct hda_codec *codec,
599 struct snd_pcm_substream *substream)
600{
601 struct via_spec *spec = codec->spec;
602 struct hda_multi_out *mout = &spec->multiout;
603 hda_nid_t *nids = mout->dac_nids;
604 int i;
605
606 if (substream->number == 0) {
607 for (i = 0; i < mout->num_dacs; i++)
608 snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
609
610 if (mout->hp_nid && !spec->hp_independent_mode)
611 snd_hda_codec_setup_stream(codec, mout->hp_nid,
612 0, 0, 0);
613
614 for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
615 if (mout->extra_out_nid[i])
616 snd_hda_codec_setup_stream(codec,
617 mout->extra_out_nid[i],
618 0, 0, 0);
619 mutex_lock(&codec->spdif_mutex);
620 if (mout->dig_out_nid &&
621 mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
622 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
623 0, 0, 0);
624 mout->dig_out_used = 0;
625 }
626 mutex_unlock(&codec->spdif_mutex);
627 } else {
628 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
629 spec->hp_independent_mode)
630 snd_hda_codec_setup_stream(codec, mout->hp_nid,
631 0, 0, 0);
632 }
633
634 return 0;
635}
636
Joseph Chanc577b8a2006-11-29 15:29:40 +0100637/*
638 * Digital out
639 */
640static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
641 struct hda_codec *codec,
642 struct snd_pcm_substream *substream)
643{
644 struct via_spec *spec = codec->spec;
645 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
646}
647
648static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
649 struct hda_codec *codec,
650 struct snd_pcm_substream *substream)
651{
652 struct via_spec *spec = codec->spec;
653 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
654}
655
Takashi Iwai6b97eb42007-04-05 14:51:48 +0200656static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
657 struct hda_codec *codec,
658 unsigned int stream_tag,
659 unsigned int format,
660 struct snd_pcm_substream *substream)
661{
662 struct via_spec *spec = codec->spec;
663 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
664 stream_tag, format, substream);
665}
666
Joseph Chanc577b8a2006-11-29 15:29:40 +0100667/*
668 * Analog capture
669 */
670static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
671 struct hda_codec *codec,
672 unsigned int stream_tag,
673 unsigned int format,
674 struct snd_pcm_substream *substream)
675{
676 struct via_spec *spec = codec->spec;
677
678 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
679 stream_tag, 0, format);
680 return 0;
681}
682
683static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
684 struct hda_codec *codec,
685 struct snd_pcm_substream *substream)
686{
687 struct via_spec *spec = codec->spec;
Takashi Iwai888afa12008-03-18 09:57:50 +0100688 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100689 return 0;
690}
691
692static struct hda_pcm_stream vt1708_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +0800693 .substreams = 2,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100694 .channels_min = 2,
695 .channels_max = 8,
696 .nid = 0x10, /* NID to query formats and rates */
697 .ops = {
698 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +0800699 .prepare = via_playback_multi_pcm_prepare,
700 .cleanup = via_playback_multi_pcm_cleanup
Joseph Chanc577b8a2006-11-29 15:29:40 +0100701 },
702};
703
Takashi Iwaibc9b5622008-05-23 17:50:27 +0200704static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
705 .substreams = 1,
706 .channels_min = 2,
707 .channels_max = 8,
708 .nid = 0x10, /* NID to query formats and rates */
709 /* We got noisy outputs on the right channel on VT1708 when
710 * 24bit samples are used. Until any workaround is found,
711 * disable the 24bit format, so far.
712 */
713 .formats = SNDRV_PCM_FMTBIT_S16_LE,
714 .ops = {
715 .open = via_playback_pcm_open,
716 .prepare = via_playback_pcm_prepare,
717 .cleanup = via_playback_pcm_cleanup
718 },
719};
720
Joseph Chanc577b8a2006-11-29 15:29:40 +0100721static struct hda_pcm_stream vt1708_pcm_analog_capture = {
722 .substreams = 2,
723 .channels_min = 2,
724 .channels_max = 2,
725 .nid = 0x15, /* NID to query formats and rates */
726 .ops = {
727 .prepare = via_capture_pcm_prepare,
728 .cleanup = via_capture_pcm_cleanup
729 },
730};
731
732static struct hda_pcm_stream vt1708_pcm_digital_playback = {
733 .substreams = 1,
734 .channels_min = 2,
735 .channels_max = 2,
736 /* NID is set in via_build_pcms */
737 .ops = {
738 .open = via_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +0200739 .close = via_dig_playback_pcm_close,
740 .prepare = via_dig_playback_pcm_prepare
Joseph Chanc577b8a2006-11-29 15:29:40 +0100741 },
742};
743
744static struct hda_pcm_stream vt1708_pcm_digital_capture = {
745 .substreams = 1,
746 .channels_min = 2,
747 .channels_max = 2,
748};
749
750static int via_build_controls(struct hda_codec *codec)
751{
752 struct via_spec *spec = codec->spec;
753 int err;
754 int i;
755
756 for (i = 0; i < spec->num_mixers; i++) {
757 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
758 if (err < 0)
759 return err;
760 }
761
762 if (spec->multiout.dig_out_nid) {
763 err = snd_hda_create_spdif_out_ctls(codec,
764 spec->multiout.dig_out_nid);
765 if (err < 0)
766 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +0100767 err = snd_hda_create_spdif_share_sw(codec,
768 &spec->multiout);
769 if (err < 0)
770 return err;
771 spec->multiout.share_spdif = 1;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100772 }
773 if (spec->dig_in_nid) {
774 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
775 if (err < 0)
776 return err;
777 }
778 return 0;
779}
780
781static int via_build_pcms(struct hda_codec *codec)
782{
783 struct via_spec *spec = codec->spec;
784 struct hda_pcm *info = spec->pcm_rec;
785
786 codec->num_pcms = 1;
787 codec->pcm_info = info;
788
789 info->name = spec->stream_name_analog;
790 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
791 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
792 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
793 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
794
795 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
796 spec->multiout.max_channels;
797
798 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
799 codec->num_pcms++;
800 info++;
801 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +0100802 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100803 if (spec->multiout.dig_out_nid) {
804 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
805 *(spec->stream_digital_playback);
806 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
807 spec->multiout.dig_out_nid;
808 }
809 if (spec->dig_in_nid) {
810 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
811 *(spec->stream_digital_capture);
812 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
813 spec->dig_in_nid;
814 }
815 }
816
817 return 0;
818}
819
820static void via_free(struct hda_codec *codec)
821{
822 struct via_spec *spec = codec->spec;
823 unsigned int i;
824
825 if (!spec)
826 return;
827
828 if (spec->kctl_alloc) {
829 for (i = 0; i < spec->num_kctl_used; i++)
830 kfree(spec->kctl_alloc[i].name);
831 kfree(spec->kctl_alloc);
832 }
833
834 kfree(codec->spec);
835}
836
Harald Welte69e52a82008-09-09 15:57:32 +0800837/* mute internal speaker if HP is plugged */
838static void via_hp_automute(struct hda_codec *codec)
839{
840 unsigned int present;
841 struct via_spec *spec = codec->spec;
842
843 present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
844 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
845 snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
846 HDA_OUTPUT, 0, HDA_AMP_MUTE,
847 present ? HDA_AMP_MUTE : 0);
848}
849
850static void via_gpio_control(struct hda_codec *codec)
851{
852 unsigned int gpio_data;
853 unsigned int vol_counter;
854 unsigned int vol;
855 unsigned int master_vol;
856
857 struct via_spec *spec = codec->spec;
858
859 gpio_data = snd_hda_codec_read(codec, codec->afg, 0,
860 AC_VERB_GET_GPIO_DATA, 0) & 0x03;
861
862 vol_counter = (snd_hda_codec_read(codec, codec->afg, 0,
863 0xF84, 0) & 0x3F0000) >> 16;
864
865 vol = vol_counter & 0x1F;
866 master_vol = snd_hda_codec_read(codec, 0x1A, 0,
867 AC_VERB_GET_AMP_GAIN_MUTE,
868 AC_AMP_GET_INPUT);
869
870 if (gpio_data == 0x02) {
871 /* unmute line out */
872 snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
873 HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
874
875 if (vol_counter & 0x20) {
876 /* decrease volume */
877 if (vol > master_vol)
878 vol = master_vol;
879 snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT,
880 0, HDA_AMP_VOLMASK,
881 master_vol-vol);
882 } else {
883 /* increase volume */
884 snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, 0,
885 HDA_AMP_VOLMASK,
886 ((master_vol+vol) > 0x2A) ? 0x2A :
887 (master_vol+vol));
888 }
889 } else if (!(gpio_data & 0x02)) {
890 /* mute line out */
891 snd_hda_codec_amp_stereo(codec,
892 spec->autocfg.line_out_pins[0],
893 HDA_OUTPUT, 0, HDA_AMP_MUTE,
894 HDA_AMP_MUTE);
895 }
896}
897
898/* unsolicited event for jack sensing */
899static void via_unsol_event(struct hda_codec *codec,
900 unsigned int res)
901{
902 res >>= 26;
903 if (res == VIA_HP_EVENT)
904 via_hp_automute(codec);
905 else if (res == VIA_GPIO_EVENT)
906 via_gpio_control(codec);
907}
908
Joseph Chanc577b8a2006-11-29 15:29:40 +0100909static int via_init(struct hda_codec *codec)
910{
911 struct via_spec *spec = codec->spec;
Harald Welte69e52a82008-09-09 15:57:32 +0800912 int i;
913 for (i = 0; i < spec->num_iverbs; i++)
914 snd_hda_sequence_write(codec, spec->init_verbs[i]);
915
Josepch Chanf7278fd2007-12-13 16:40:40 +0100916 /* Lydia Add for EAPD enable */
917 if (!spec->dig_in_nid) { /* No Digital In connection */
918 if (IS_VT1708_VENDORID(codec->vendor_id)) {
919 snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
920 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100921 PIN_OUT);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100922 snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
923 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
924 } else if (IS_VT1709_10CH_VENDORID(codec->vendor_id) ||
925 IS_VT1709_6CH_VENDORID(codec->vendor_id)) {
926 snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
927 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100928 PIN_OUT);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100929 snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
930 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
931 } else if (IS_VT1708B_8CH_VENDORID(codec->vendor_id) ||
932 IS_VT1708B_4CH_VENDORID(codec->vendor_id)) {
933 snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
934 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100935 PIN_OUT);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100936 snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
937 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
938 }
Takashi Iwai12b74c82008-01-15 12:39:38 +0100939 } else /* enable SPDIF-input pin */
940 snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
941 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100942
Joseph Chanc577b8a2006-11-29 15:29:40 +0100943 return 0;
944}
945
Takashi Iwaicb53c622007-08-10 17:21:45 +0200946#ifdef CONFIG_SND_HDA_POWER_SAVE
947static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
948{
949 struct via_spec *spec = codec->spec;
950 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
951}
952#endif
953
Joseph Chanc577b8a2006-11-29 15:29:40 +0100954/*
955 */
956static struct hda_codec_ops via_patch_ops = {
957 .build_controls = via_build_controls,
958 .build_pcms = via_build_pcms,
959 .init = via_init,
960 .free = via_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +0200961#ifdef CONFIG_SND_HDA_POWER_SAVE
962 .check_power_status = via_check_power_status,
963#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +0100964};
965
966/* fill in the dac_nids table from the parsed pin configuration */
967static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
968 const struct auto_pin_cfg *cfg)
969{
970 int i;
971 hda_nid_t nid;
972
973 spec->multiout.num_dacs = cfg->line_outs;
974
975 spec->multiout.dac_nids = spec->private_dac_nids;
976
977 for(i = 0; i < 4; i++) {
978 nid = cfg->line_out_pins[i];
979 if (nid) {
980 /* config dac list */
981 switch (i) {
982 case AUTO_SEQ_FRONT:
983 spec->multiout.dac_nids[i] = 0x10;
984 break;
985 case AUTO_SEQ_CENLFE:
986 spec->multiout.dac_nids[i] = 0x12;
987 break;
988 case AUTO_SEQ_SURROUND:
Harald Weltefb4cb772008-09-09 15:53:36 +0800989 spec->multiout.dac_nids[i] = 0x11;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100990 break;
991 case AUTO_SEQ_SIDE:
Harald Weltefb4cb772008-09-09 15:53:36 +0800992 spec->multiout.dac_nids[i] = 0x13;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100993 break;
994 }
995 }
996 }
997
998 return 0;
999}
1000
1001/* add playback controls from the parsed DAC table */
1002static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
1003 const struct auto_pin_cfg *cfg)
1004{
1005 char name[32];
1006 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1007 hda_nid_t nid, nid_vol = 0;
1008 int i, err;
1009
1010 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1011 nid = cfg->line_out_pins[i];
1012
1013 if (!nid)
1014 continue;
1015
1016 if (i != AUTO_SEQ_FRONT)
Harald Weltefb4cb772008-09-09 15:53:36 +08001017 nid_vol = 0x18 + i;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001018
1019 if (i == AUTO_SEQ_CENLFE) {
1020 /* Center/LFE */
1021 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001022 "Center Playback Volume",
1023 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1024 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001025 if (err < 0)
1026 return err;
1027 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1028 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001029 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1030 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001031 if (err < 0)
1032 return err;
1033 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1034 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001035 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1036 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001037 if (err < 0)
1038 return err;
1039 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1040 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001041 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1042 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001043 if (err < 0)
1044 return err;
1045 } else if (i == AUTO_SEQ_FRONT){
1046 /* add control to mixer index 0 */
1047 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1048 "Master Front Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001049 HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
1050 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001051 if (err < 0)
1052 return err;
1053 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1054 "Master Front Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001055 HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
1056 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001057 if (err < 0)
1058 return err;
1059
1060 /* add control to PW3 */
1061 sprintf(name, "%s Playback Volume", chname[i]);
1062 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001063 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1064 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001065 if (err < 0)
1066 return err;
1067 sprintf(name, "%s Playback Switch", chname[i]);
1068 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001069 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1070 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001071 if (err < 0)
1072 return err;
1073 } else {
1074 sprintf(name, "%s Playback Volume", chname[i]);
1075 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001076 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1077 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001078 if (err < 0)
1079 return err;
1080 sprintf(name, "%s Playback Switch", chname[i]);
1081 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001082 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1083 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001084 if (err < 0)
1085 return err;
1086 }
1087 }
1088
1089 return 0;
1090}
1091
Harald Welte0aa62ae2008-09-09 15:58:27 +08001092static void create_hp_imux(struct via_spec *spec)
1093{
1094 int i;
1095 struct hda_input_mux *imux = &spec->private_imux[1];
1096 static const char *texts[] = { "OFF", "ON", NULL};
1097
1098 /* for hp mode select */
1099 i = 0;
1100 while (texts[i] != NULL) {
1101 imux->items[imux->num_items].label = texts[i];
1102 imux->items[imux->num_items].index = i;
1103 imux->num_items++;
1104 i++;
1105 }
1106
1107 spec->hp_mux = &spec->private_imux[1];
1108}
1109
Joseph Chanc577b8a2006-11-29 15:29:40 +01001110static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1111{
1112 int err;
1113
1114 if (!pin)
1115 return 0;
1116
1117 spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
1118
1119 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1120 "Headphone Playback Volume",
1121 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1122 if (err < 0)
1123 return err;
1124 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1125 "Headphone Playback Switch",
1126 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1127 if (err < 0)
1128 return err;
1129
Harald Welte0aa62ae2008-09-09 15:58:27 +08001130 create_hp_imux(spec);
1131
Joseph Chanc577b8a2006-11-29 15:29:40 +01001132 return 0;
1133}
1134
1135/* create playback/capture controls for input pins */
1136static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
1137 const struct auto_pin_cfg *cfg)
1138{
1139 static char *labels[] = {
1140 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1141 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08001142 struct hda_input_mux *imux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01001143 int i, err, idx = 0;
1144
1145 /* for internal loopback recording select */
1146 imux->items[imux->num_items].label = "Stereo Mixer";
1147 imux->items[imux->num_items].index = idx;
1148 imux->num_items++;
1149
1150 for (i = 0; i < AUTO_PIN_LAST; i++) {
1151 if (!cfg->input_pins[i])
1152 continue;
1153
1154 switch (cfg->input_pins[i]) {
1155 case 0x1d: /* Mic */
1156 idx = 2;
1157 break;
1158
1159 case 0x1e: /* Line In */
1160 idx = 3;
1161 break;
1162
1163 case 0x21: /* Front Mic */
1164 idx = 4;
1165 break;
1166
1167 case 0x24: /* CD */
1168 idx = 1;
1169 break;
1170 }
1171 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
1172 idx, 0x17);
1173 if (err < 0)
1174 return err;
1175 imux->items[imux->num_items].label = labels[i];
1176 imux->items[imux->num_items].index = idx;
1177 imux->num_items++;
1178 }
1179 return 0;
1180}
1181
Takashi Iwaicb53c622007-08-10 17:21:45 +02001182#ifdef CONFIG_SND_HDA_POWER_SAVE
1183static struct hda_amp_list vt1708_loopbacks[] = {
1184 { 0x17, HDA_INPUT, 1 },
1185 { 0x17, HDA_INPUT, 2 },
1186 { 0x17, HDA_INPUT, 3 },
1187 { 0x17, HDA_INPUT, 4 },
1188 { } /* end */
1189};
1190#endif
1191
Harald Welte76d9b0d2008-09-09 15:50:37 +08001192static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
1193{
1194 unsigned int def_conf;
1195 unsigned char seqassoc;
1196
1197 def_conf = snd_hda_codec_read(codec, nid, 0,
1198 AC_VERB_GET_CONFIG_DEFAULT, 0);
1199 seqassoc = (unsigned char) get_defcfg_association(def_conf);
1200 seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
1201 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) {
1202 if (seqassoc == 0xff) {
1203 def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
1204 snd_hda_codec_write(codec, nid, 0,
1205 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1206 def_conf >> 24);
1207 }
1208 }
1209
1210 return;
1211}
1212
Joseph Chanc577b8a2006-11-29 15:29:40 +01001213static int vt1708_parse_auto_config(struct hda_codec *codec)
1214{
1215 struct via_spec *spec = codec->spec;
1216 int err;
1217
Harald Welte76d9b0d2008-09-09 15:50:37 +08001218 /* Add HP and CD pin config connect bit re-config action */
1219 vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
1220 vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
1221
Joseph Chanc577b8a2006-11-29 15:29:40 +01001222 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1223 if (err < 0)
1224 return err;
1225 err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
1226 if (err < 0)
1227 return err;
1228 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1229 return 0; /* can't find valid BIOS pin config */
1230
1231 err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
1232 if (err < 0)
1233 return err;
1234 err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1235 if (err < 0)
1236 return err;
1237 err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
1238 if (err < 0)
1239 return err;
1240
1241 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1242
1243 if (spec->autocfg.dig_out_pin)
1244 spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
1245 if (spec->autocfg.dig_in_pin)
1246 spec->dig_in_nid = VT1708_DIGIN_NID;
1247
1248 if (spec->kctl_alloc)
1249 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
1250
Harald Welte69e52a82008-09-09 15:57:32 +08001251 spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001252
Harald Welte0aa62ae2008-09-09 15:58:27 +08001253 spec->input_mux = &spec->private_imux[0];
1254
1255 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001256
1257 return 1;
1258}
1259
1260/* init callback for auto-configuration model -- overriding the default init */
1261static int via_auto_init(struct hda_codec *codec)
1262{
1263 via_init(codec);
1264 via_auto_init_multi_out(codec);
1265 via_auto_init_hp_out(codec);
1266 via_auto_init_analog_input(codec);
1267 return 0;
1268}
1269
1270static int patch_vt1708(struct hda_codec *codec)
1271{
1272 struct via_spec *spec;
1273 int err;
1274
1275 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08001276 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001277 if (spec == NULL)
1278 return -ENOMEM;
1279
1280 codec->spec = spec;
1281
1282 /* automatic parse from the BIOS config */
1283 err = vt1708_parse_auto_config(codec);
1284 if (err < 0) {
1285 via_free(codec);
1286 return err;
1287 } else if (!err) {
1288 printk(KERN_INFO "hda_codec: Cannot set up configuration "
1289 "from BIOS. Using genenic mode...\n");
1290 }
1291
1292
1293 spec->stream_name_analog = "VT1708 Analog";
1294 spec->stream_analog_playback = &vt1708_pcm_analog_playback;
Takashi Iwaibc9b5622008-05-23 17:50:27 +02001295 /* disable 32bit format on VT1708 */
1296 if (codec->vendor_id == 0x11061708)
1297 spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001298 spec->stream_analog_capture = &vt1708_pcm_analog_capture;
1299
1300 spec->stream_name_digital = "VT1708 Digital";
1301 spec->stream_digital_playback = &vt1708_pcm_digital_playback;
1302 spec->stream_digital_capture = &vt1708_pcm_digital_capture;
1303
1304
1305 if (!spec->adc_nids && spec->input_mux) {
1306 spec->adc_nids = vt1708_adc_nids;
1307 spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
1308 spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
1309 spec->num_mixers++;
1310 }
1311
1312 codec->patch_ops = via_patch_ops;
1313
1314 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001315#ifdef CONFIG_SND_HDA_POWER_SAVE
1316 spec->loopback.amplist = vt1708_loopbacks;
1317#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001318
1319 return 0;
1320}
1321
1322/* capture mixer elements */
1323static struct snd_kcontrol_new vt1709_capture_mixer[] = {
1324 HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
1325 HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
1326 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
1327 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
1328 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
1329 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
1330 {
1331 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1332 /* The multiple "Capture Source" controls confuse alsamixer
1333 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +01001334 */
1335 /* .name = "Capture Source", */
1336 .name = "Input Source",
1337 .count = 1,
1338 .info = via_mux_enum_info,
1339 .get = via_mux_enum_get,
1340 .put = via_mux_enum_put,
1341 },
1342 { } /* end */
1343};
1344
Harald Welte69e52a82008-09-09 15:57:32 +08001345static struct hda_verb vt1709_uniwill_init_verbs[] = {
1346 {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
1347 { }
1348};
1349
Joseph Chanc577b8a2006-11-29 15:29:40 +01001350/*
1351 * generic initialization of ADC, input mixers and output mixers
1352 */
1353static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
1354 /*
1355 * Unmute ADC0-2 and set the default input to mic-in
1356 */
1357 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1358 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1359 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1360
1361
Josepch Chanf7278fd2007-12-13 16:40:40 +01001362 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +01001363 * mixer widget
1364 */
1365 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +01001366 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1367 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1368 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1369 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1370 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001371
1372 /*
1373 * Set up output selector (0x1a, 0x1b, 0x29)
1374 */
1375 /* set vol=0 to output mixers */
1376 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1377 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1378 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1379
1380 /*
1381 * Unmute PW3 and PW4
1382 */
1383 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1384 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1385
1386 /* Set input of PW4 as AOW4 */
1387 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001388 /* PW9 Output enable */
1389 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1390 { }
1391};
1392
1393static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
1394 .substreams = 1,
1395 .channels_min = 2,
1396 .channels_max = 10,
1397 .nid = 0x10, /* NID to query formats and rates */
1398 .ops = {
1399 .open = via_playback_pcm_open,
1400 .prepare = via_playback_pcm_prepare,
1401 .cleanup = via_playback_pcm_cleanup
1402 },
1403};
1404
1405static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
1406 .substreams = 1,
1407 .channels_min = 2,
1408 .channels_max = 6,
1409 .nid = 0x10, /* NID to query formats and rates */
1410 .ops = {
1411 .open = via_playback_pcm_open,
1412 .prepare = via_playback_pcm_prepare,
1413 .cleanup = via_playback_pcm_cleanup
1414 },
1415};
1416
1417static struct hda_pcm_stream vt1709_pcm_analog_capture = {
1418 .substreams = 2,
1419 .channels_min = 2,
1420 .channels_max = 2,
1421 .nid = 0x14, /* NID to query formats and rates */
1422 .ops = {
1423 .prepare = via_capture_pcm_prepare,
1424 .cleanup = via_capture_pcm_cleanup
1425 },
1426};
1427
1428static struct hda_pcm_stream vt1709_pcm_digital_playback = {
1429 .substreams = 1,
1430 .channels_min = 2,
1431 .channels_max = 2,
1432 /* NID is set in via_build_pcms */
1433 .ops = {
1434 .open = via_dig_playback_pcm_open,
1435 .close = via_dig_playback_pcm_close
1436 },
1437};
1438
1439static struct hda_pcm_stream vt1709_pcm_digital_capture = {
1440 .substreams = 1,
1441 .channels_min = 2,
1442 .channels_max = 2,
1443};
1444
1445static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
1446 const struct auto_pin_cfg *cfg)
1447{
1448 int i;
1449 hda_nid_t nid;
1450
1451 if (cfg->line_outs == 4) /* 10 channels */
1452 spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
1453 else if (cfg->line_outs == 3) /* 6 channels */
1454 spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
1455
1456 spec->multiout.dac_nids = spec->private_dac_nids;
1457
1458 if (cfg->line_outs == 4) { /* 10 channels */
1459 for (i = 0; i < cfg->line_outs; i++) {
1460 nid = cfg->line_out_pins[i];
1461 if (nid) {
1462 /* config dac list */
1463 switch (i) {
1464 case AUTO_SEQ_FRONT:
1465 /* AOW0 */
1466 spec->multiout.dac_nids[i] = 0x10;
1467 break;
1468 case AUTO_SEQ_CENLFE:
1469 /* AOW2 */
1470 spec->multiout.dac_nids[i] = 0x12;
1471 break;
1472 case AUTO_SEQ_SURROUND:
1473 /* AOW3 */
Harald Weltefb4cb772008-09-09 15:53:36 +08001474 spec->multiout.dac_nids[i] = 0x11;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001475 break;
1476 case AUTO_SEQ_SIDE:
1477 /* AOW1 */
Harald Weltefb4cb772008-09-09 15:53:36 +08001478 spec->multiout.dac_nids[i] = 0x27;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001479 break;
1480 default:
1481 break;
1482 }
1483 }
1484 }
1485 spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
1486
1487 } else if (cfg->line_outs == 3) { /* 6 channels */
1488 for(i = 0; i < cfg->line_outs; i++) {
1489 nid = cfg->line_out_pins[i];
1490 if (nid) {
1491 /* config dac list */
1492 switch(i) {
1493 case AUTO_SEQ_FRONT:
1494 /* AOW0 */
1495 spec->multiout.dac_nids[i] = 0x10;
1496 break;
1497 case AUTO_SEQ_CENLFE:
1498 /* AOW2 */
1499 spec->multiout.dac_nids[i] = 0x12;
1500 break;
1501 case AUTO_SEQ_SURROUND:
1502 /* AOW1 */
1503 spec->multiout.dac_nids[i] = 0x11;
1504 break;
1505 default:
1506 break;
1507 }
1508 }
1509 }
1510 }
1511
1512 return 0;
1513}
1514
1515/* add playback controls from the parsed DAC table */
1516static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
1517 const struct auto_pin_cfg *cfg)
1518{
1519 char name[32];
1520 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1521 hda_nid_t nid = 0;
1522 int i, err;
1523
1524 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1525 nid = cfg->line_out_pins[i];
1526
1527 if (!nid)
1528 continue;
1529
1530 if (i == AUTO_SEQ_CENLFE) {
1531 /* Center/LFE */
1532 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1533 "Center Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001534 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
1535 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001536 if (err < 0)
1537 return err;
1538 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1539 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001540 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
1541 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001542 if (err < 0)
1543 return err;
1544 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1545 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001546 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
1547 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001548 if (err < 0)
1549 return err;
1550 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1551 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001552 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
1553 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001554 if (err < 0)
1555 return err;
1556 } else if (i == AUTO_SEQ_FRONT){
1557 /* add control to mixer index 0 */
1558 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1559 "Master Front Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001560 HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
1561 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001562 if (err < 0)
1563 return err;
1564 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1565 "Master Front Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001566 HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
1567 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001568 if (err < 0)
1569 return err;
1570
1571 /* add control to PW3 */
1572 sprintf(name, "%s Playback Volume", chname[i]);
1573 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001574 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1575 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001576 if (err < 0)
1577 return err;
1578 sprintf(name, "%s Playback Switch", chname[i]);
1579 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001580 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1581 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001582 if (err < 0)
1583 return err;
1584 } else if (i == AUTO_SEQ_SURROUND) {
1585 sprintf(name, "%s Playback Volume", chname[i]);
1586 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001587 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001588 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001589 if (err < 0)
1590 return err;
1591 sprintf(name, "%s Playback Switch", chname[i]);
1592 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001593 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001594 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001595 if (err < 0)
1596 return err;
1597 } else if (i == AUTO_SEQ_SIDE) {
1598 sprintf(name, "%s Playback Volume", chname[i]);
1599 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001600 HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001601 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001602 if (err < 0)
1603 return err;
1604 sprintf(name, "%s Playback Switch", chname[i]);
1605 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001606 HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001607 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001608 if (err < 0)
1609 return err;
1610 }
1611 }
1612
1613 return 0;
1614}
1615
1616static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1617{
1618 int err;
1619
1620 if (!pin)
1621 return 0;
1622
1623 if (spec->multiout.num_dacs == 5) /* 10 channels */
1624 spec->multiout.hp_nid = VT1709_HP_DAC_NID;
1625 else if (spec->multiout.num_dacs == 3) /* 6 channels */
1626 spec->multiout.hp_nid = 0;
1627
1628 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1629 "Headphone Playback Volume",
1630 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1631 if (err < 0)
1632 return err;
1633 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1634 "Headphone Playback Switch",
1635 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1636 if (err < 0)
1637 return err;
1638
1639 return 0;
1640}
1641
1642/* create playback/capture controls for input pins */
1643static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
1644 const struct auto_pin_cfg *cfg)
1645{
1646 static char *labels[] = {
1647 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1648 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08001649 struct hda_input_mux *imux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01001650 int i, err, idx = 0;
1651
1652 /* for internal loopback recording select */
1653 imux->items[imux->num_items].label = "Stereo Mixer";
1654 imux->items[imux->num_items].index = idx;
1655 imux->num_items++;
1656
1657 for (i = 0; i < AUTO_PIN_LAST; i++) {
1658 if (!cfg->input_pins[i])
1659 continue;
1660
1661 switch (cfg->input_pins[i]) {
1662 case 0x1d: /* Mic */
1663 idx = 2;
1664 break;
1665
1666 case 0x1e: /* Line In */
1667 idx = 3;
1668 break;
1669
1670 case 0x21: /* Front Mic */
1671 idx = 4;
1672 break;
1673
1674 case 0x23: /* CD */
1675 idx = 1;
1676 break;
1677 }
1678 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
1679 idx, 0x18);
1680 if (err < 0)
1681 return err;
1682 imux->items[imux->num_items].label = labels[i];
1683 imux->items[imux->num_items].index = idx;
1684 imux->num_items++;
1685 }
1686 return 0;
1687}
1688
1689static int vt1709_parse_auto_config(struct hda_codec *codec)
1690{
1691 struct via_spec *spec = codec->spec;
1692 int err;
1693
1694 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1695 if (err < 0)
1696 return err;
1697 err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
1698 if (err < 0)
1699 return err;
1700 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1701 return 0; /* can't find valid BIOS pin config */
1702
1703 err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
1704 if (err < 0)
1705 return err;
1706 err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1707 if (err < 0)
1708 return err;
1709 err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
1710 if (err < 0)
1711 return err;
1712
1713 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1714
1715 if (spec->autocfg.dig_out_pin)
1716 spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
1717 if (spec->autocfg.dig_in_pin)
1718 spec->dig_in_nid = VT1709_DIGIN_NID;
1719
1720 if (spec->kctl_alloc)
1721 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
1722
Harald Welte0aa62ae2008-09-09 15:58:27 +08001723 spec->input_mux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01001724
1725 return 1;
1726}
1727
Takashi Iwaicb53c622007-08-10 17:21:45 +02001728#ifdef CONFIG_SND_HDA_POWER_SAVE
1729static struct hda_amp_list vt1709_loopbacks[] = {
1730 { 0x18, HDA_INPUT, 1 },
1731 { 0x18, HDA_INPUT, 2 },
1732 { 0x18, HDA_INPUT, 3 },
1733 { 0x18, HDA_INPUT, 4 },
1734 { } /* end */
1735};
1736#endif
1737
Joseph Chanc577b8a2006-11-29 15:29:40 +01001738static int patch_vt1709_10ch(struct hda_codec *codec)
1739{
1740 struct via_spec *spec;
1741 int err;
1742
1743 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08001744 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001745 if (spec == NULL)
1746 return -ENOMEM;
1747
1748 codec->spec = spec;
1749
1750 err = vt1709_parse_auto_config(codec);
1751 if (err < 0) {
1752 via_free(codec);
1753 return err;
1754 } else if (!err) {
1755 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
1756 "Using genenic mode...\n");
1757 }
1758
Harald Welte69e52a82008-09-09 15:57:32 +08001759 spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs;
1760 spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001761
1762 spec->stream_name_analog = "VT1709 Analog";
1763 spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
1764 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1765
1766 spec->stream_name_digital = "VT1709 Digital";
1767 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1768 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1769
1770
1771 if (!spec->adc_nids && spec->input_mux) {
1772 spec->adc_nids = vt1709_adc_nids;
1773 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
1774 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1775 spec->num_mixers++;
1776 }
1777
1778 codec->patch_ops = via_patch_ops;
1779
1780 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08001781 codec->patch_ops.unsol_event = via_unsol_event;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001782#ifdef CONFIG_SND_HDA_POWER_SAVE
1783 spec->loopback.amplist = vt1709_loopbacks;
1784#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001785
1786 return 0;
1787}
1788/*
1789 * generic initialization of ADC, input mixers and output mixers
1790 */
1791static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
1792 /*
1793 * Unmute ADC0-2 and set the default input to mic-in
1794 */
1795 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1796 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1797 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1798
1799
1800 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1801 * mixer widget
1802 */
1803 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1804 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1805 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1806 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1807 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1808 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1809
1810 /*
1811 * Set up output selector (0x1a, 0x1b, 0x29)
1812 */
1813 /* set vol=0 to output mixers */
1814 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1815 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1816 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1817
1818 /*
1819 * Unmute PW3 and PW4
1820 */
1821 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1822 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1823
1824 /* Set input of PW4 as MW0 */
1825 {0x20, AC_VERB_SET_CONNECT_SEL, 0},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001826 /* PW9 Output enable */
1827 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1828 { }
1829};
1830
1831static int patch_vt1709_6ch(struct hda_codec *codec)
1832{
1833 struct via_spec *spec;
1834 int err;
1835
1836 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08001837 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001838 if (spec == NULL)
1839 return -ENOMEM;
1840
1841 codec->spec = spec;
1842
1843 err = vt1709_parse_auto_config(codec);
1844 if (err < 0) {
1845 via_free(codec);
1846 return err;
1847 } else if (!err) {
1848 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
1849 "Using genenic mode...\n");
1850 }
1851
Harald Welte69e52a82008-09-09 15:57:32 +08001852 spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs;
1853 spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001854
1855 spec->stream_name_analog = "VT1709 Analog";
1856 spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
1857 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1858
1859 spec->stream_name_digital = "VT1709 Digital";
1860 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1861 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1862
1863
1864 if (!spec->adc_nids && spec->input_mux) {
1865 spec->adc_nids = vt1709_adc_nids;
1866 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
1867 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1868 spec->num_mixers++;
1869 }
1870
1871 codec->patch_ops = via_patch_ops;
1872
1873 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08001874 codec->patch_ops.unsol_event = via_unsol_event;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001875#ifdef CONFIG_SND_HDA_POWER_SAVE
1876 spec->loopback.amplist = vt1709_loopbacks;
1877#endif
Josepch Chanf7278fd2007-12-13 16:40:40 +01001878 return 0;
1879}
1880
1881/* capture mixer elements */
1882static struct snd_kcontrol_new vt1708B_capture_mixer[] = {
1883 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
1884 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
1885 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
1886 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
1887 {
1888 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1889 /* The multiple "Capture Source" controls confuse alsamixer
1890 * So call somewhat different..
Josepch Chanf7278fd2007-12-13 16:40:40 +01001891 */
1892 /* .name = "Capture Source", */
1893 .name = "Input Source",
1894 .count = 1,
1895 .info = via_mux_enum_info,
1896 .get = via_mux_enum_get,
1897 .put = via_mux_enum_put,
1898 },
1899 { } /* end */
1900};
1901/*
1902 * generic initialization of ADC, input mixers and output mixers
1903 */
1904static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
1905 /*
1906 * Unmute ADC0-1 and set the default input to mic-in
1907 */
1908 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1909 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1910
1911
1912 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1913 * mixer widget
1914 */
1915 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1916 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1917 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1918 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1919 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1920 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1921
1922 /*
1923 * Set up output mixers
1924 */
1925 /* set vol=0 to output mixers */
1926 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1927 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1928 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1929
1930 /* Setup default input to PW4 */
1931 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1},
1932 /* PW9 Output enable */
1933 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1934 /* PW10 Input enable */
1935 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
1936 { }
1937};
1938
1939static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
1940 /*
1941 * Unmute ADC0-1 and set the default input to mic-in
1942 */
1943 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1944 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1945
1946
1947 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1948 * mixer widget
1949 */
1950 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1951 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1952 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1953 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1954 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1955 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1956
1957 /*
1958 * Set up output mixers
1959 */
1960 /* set vol=0 to output mixers */
1961 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1962 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1963 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1964
1965 /* Setup default input of PW4 to MW0 */
1966 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
1967 /* PW9 Output enable */
1968 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1969 /* PW10 Input enable */
1970 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
1971 { }
1972};
1973
Harald Welte69e52a82008-09-09 15:57:32 +08001974static struct hda_verb vt1708B_uniwill_init_verbs[] = {
1975 {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
1976 { }
1977};
1978
Josepch Chanf7278fd2007-12-13 16:40:40 +01001979static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08001980 .substreams = 2,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001981 .channels_min = 2,
1982 .channels_max = 8,
1983 .nid = 0x10, /* NID to query formats and rates */
1984 .ops = {
1985 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08001986 .prepare = via_playback_multi_pcm_prepare,
1987 .cleanup = via_playback_multi_pcm_cleanup
Josepch Chanf7278fd2007-12-13 16:40:40 +01001988 },
1989};
1990
1991static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08001992 .substreams = 2,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001993 .channels_min = 2,
1994 .channels_max = 4,
1995 .nid = 0x10, /* NID to query formats and rates */
1996 .ops = {
1997 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08001998 .prepare = via_playback_multi_pcm_prepare,
1999 .cleanup = via_playback_multi_pcm_cleanup
Josepch Chanf7278fd2007-12-13 16:40:40 +01002000 },
2001};
2002
2003static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
2004 .substreams = 2,
2005 .channels_min = 2,
2006 .channels_max = 2,
2007 .nid = 0x13, /* NID to query formats and rates */
2008 .ops = {
2009 .prepare = via_capture_pcm_prepare,
2010 .cleanup = via_capture_pcm_cleanup
2011 },
2012};
2013
2014static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
2015 .substreams = 1,
2016 .channels_min = 2,
2017 .channels_max = 2,
2018 /* NID is set in via_build_pcms */
2019 .ops = {
2020 .open = via_dig_playback_pcm_open,
2021 .close = via_dig_playback_pcm_close,
2022 .prepare = via_dig_playback_pcm_prepare
2023 },
2024};
2025
2026static struct hda_pcm_stream vt1708B_pcm_digital_capture = {
2027 .substreams = 1,
2028 .channels_min = 2,
2029 .channels_max = 2,
2030};
2031
2032/* fill in the dac_nids table from the parsed pin configuration */
2033static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
2034 const struct auto_pin_cfg *cfg)
2035{
2036 int i;
2037 hda_nid_t nid;
2038
2039 spec->multiout.num_dacs = cfg->line_outs;
2040
2041 spec->multiout.dac_nids = spec->private_dac_nids;
2042
2043 for (i = 0; i < 4; i++) {
2044 nid = cfg->line_out_pins[i];
2045 if (nid) {
2046 /* config dac list */
2047 switch (i) {
2048 case AUTO_SEQ_FRONT:
2049 spec->multiout.dac_nids[i] = 0x10;
2050 break;
2051 case AUTO_SEQ_CENLFE:
2052 spec->multiout.dac_nids[i] = 0x24;
2053 break;
2054 case AUTO_SEQ_SURROUND:
Harald Weltefb4cb772008-09-09 15:53:36 +08002055 spec->multiout.dac_nids[i] = 0x11;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002056 break;
2057 case AUTO_SEQ_SIDE:
Harald Weltefb4cb772008-09-09 15:53:36 +08002058 spec->multiout.dac_nids[i] = 0x25;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002059 break;
2060 }
2061 }
2062 }
2063
2064 return 0;
2065}
2066
2067/* add playback controls from the parsed DAC table */
2068static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
2069 const struct auto_pin_cfg *cfg)
2070{
2071 char name[32];
2072 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
Harald Weltefb4cb772008-09-09 15:53:36 +08002073 hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27};
Josepch Chanf7278fd2007-12-13 16:40:40 +01002074 hda_nid_t nid, nid_vol = 0;
2075 int i, err;
2076
2077 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2078 nid = cfg->line_out_pins[i];
2079
2080 if (!nid)
2081 continue;
2082
2083 nid_vol = nid_vols[i];
2084
2085 if (i == AUTO_SEQ_CENLFE) {
2086 /* Center/LFE */
2087 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2088 "Center Playback Volume",
2089 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2090 HDA_OUTPUT));
2091 if (err < 0)
2092 return err;
2093 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2094 "LFE Playback Volume",
2095 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2096 HDA_OUTPUT));
2097 if (err < 0)
2098 return err;
2099 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2100 "Center Playback Switch",
2101 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2102 HDA_OUTPUT));
2103 if (err < 0)
2104 return err;
2105 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2106 "LFE Playback Switch",
2107 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2108 HDA_OUTPUT));
2109 if (err < 0)
2110 return err;
2111 } else if (i == AUTO_SEQ_FRONT) {
2112 /* add control to mixer index 0 */
2113 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2114 "Master Front Playback Volume",
2115 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2116 HDA_INPUT));
2117 if (err < 0)
2118 return err;
2119 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2120 "Master Front Playback Switch",
2121 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2122 HDA_INPUT));
2123 if (err < 0)
2124 return err;
2125
2126 /* add control to PW3 */
2127 sprintf(name, "%s Playback Volume", chname[i]);
2128 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2129 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2130 HDA_OUTPUT));
2131 if (err < 0)
2132 return err;
2133 sprintf(name, "%s Playback Switch", chname[i]);
2134 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2135 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2136 HDA_OUTPUT));
2137 if (err < 0)
2138 return err;
2139 } else {
2140 sprintf(name, "%s Playback Volume", chname[i]);
2141 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2142 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2143 HDA_OUTPUT));
2144 if (err < 0)
2145 return err;
2146 sprintf(name, "%s Playback Switch", chname[i]);
2147 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2148 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2149 HDA_OUTPUT));
2150 if (err < 0)
2151 return err;
2152 }
2153 }
2154
2155 return 0;
2156}
2157
2158static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2159{
2160 int err;
2161
2162 if (!pin)
2163 return 0;
2164
2165 spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
2166
2167 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2168 "Headphone Playback Volume",
2169 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2170 if (err < 0)
2171 return err;
2172 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2173 "Headphone Playback Switch",
2174 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2175 if (err < 0)
2176 return err;
2177
Harald Welte0aa62ae2008-09-09 15:58:27 +08002178 create_hp_imux(spec);
2179
Josepch Chanf7278fd2007-12-13 16:40:40 +01002180 return 0;
2181}
2182
2183/* create playback/capture controls for input pins */
2184static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
2185 const struct auto_pin_cfg *cfg)
2186{
2187 static char *labels[] = {
2188 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2189 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08002190 struct hda_input_mux *imux = &spec->private_imux[0];
Josepch Chanf7278fd2007-12-13 16:40:40 +01002191 int i, err, idx = 0;
2192
2193 /* for internal loopback recording select */
2194 imux->items[imux->num_items].label = "Stereo Mixer";
2195 imux->items[imux->num_items].index = idx;
2196 imux->num_items++;
2197
2198 for (i = 0; i < AUTO_PIN_LAST; i++) {
2199 if (!cfg->input_pins[i])
2200 continue;
2201
2202 switch (cfg->input_pins[i]) {
2203 case 0x1a: /* Mic */
2204 idx = 2;
2205 break;
2206
2207 case 0x1b: /* Line In */
2208 idx = 3;
2209 break;
2210
2211 case 0x1e: /* Front Mic */
2212 idx = 4;
2213 break;
2214
2215 case 0x1f: /* CD */
2216 idx = 1;
2217 break;
2218 }
2219 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
2220 idx, 0x16);
2221 if (err < 0)
2222 return err;
2223 imux->items[imux->num_items].label = labels[i];
2224 imux->items[imux->num_items].index = idx;
2225 imux->num_items++;
2226 }
2227 return 0;
2228}
2229
2230static int vt1708B_parse_auto_config(struct hda_codec *codec)
2231{
2232 struct via_spec *spec = codec->spec;
2233 int err;
2234
2235 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
2236 if (err < 0)
2237 return err;
2238 err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg);
2239 if (err < 0)
2240 return err;
2241 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2242 return 0; /* can't find valid BIOS pin config */
2243
2244 err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg);
2245 if (err < 0)
2246 return err;
2247 err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2248 if (err < 0)
2249 return err;
2250 err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
2251 if (err < 0)
2252 return err;
2253
2254 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2255
2256 if (spec->autocfg.dig_out_pin)
2257 spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
2258 if (spec->autocfg.dig_in_pin)
2259 spec->dig_in_nid = VT1708B_DIGIN_NID;
2260
2261 if (spec->kctl_alloc)
2262 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2263
Harald Welte0aa62ae2008-09-09 15:58:27 +08002264 spec->input_mux = &spec->private_imux[0];
2265
2266 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002267
2268 return 1;
2269}
2270
2271#ifdef CONFIG_SND_HDA_POWER_SAVE
2272static struct hda_amp_list vt1708B_loopbacks[] = {
2273 { 0x16, HDA_INPUT, 1 },
2274 { 0x16, HDA_INPUT, 2 },
2275 { 0x16, HDA_INPUT, 3 },
2276 { 0x16, HDA_INPUT, 4 },
2277 { } /* end */
2278};
2279#endif
2280
2281static int patch_vt1708B_8ch(struct hda_codec *codec)
2282{
2283 struct via_spec *spec;
2284 int err;
2285
2286 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08002287 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002288 if (spec == NULL)
2289 return -ENOMEM;
2290
2291 codec->spec = spec;
2292
2293 /* automatic parse from the BIOS config */
2294 err = vt1708B_parse_auto_config(codec);
2295 if (err < 0) {
2296 via_free(codec);
2297 return err;
2298 } else if (!err) {
2299 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2300 "from BIOS. Using genenic mode...\n");
2301 }
2302
Harald Welte69e52a82008-09-09 15:57:32 +08002303 spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs;
2304 spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002305
2306 spec->stream_name_analog = "VT1708B Analog";
2307 spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
2308 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
2309
2310 spec->stream_name_digital = "VT1708B Digital";
2311 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
2312 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
2313
2314 if (!spec->adc_nids && spec->input_mux) {
2315 spec->adc_nids = vt1708B_adc_nids;
2316 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
2317 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
2318 spec->num_mixers++;
2319 }
2320
2321 codec->patch_ops = via_patch_ops;
2322
2323 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08002324 codec->patch_ops.unsol_event = via_unsol_event;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002325#ifdef CONFIG_SND_HDA_POWER_SAVE
2326 spec->loopback.amplist = vt1708B_loopbacks;
2327#endif
2328
2329 return 0;
2330}
2331
2332static int patch_vt1708B_4ch(struct hda_codec *codec)
2333{
2334 struct via_spec *spec;
2335 int err;
2336
2337 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08002338 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002339 if (spec == NULL)
2340 return -ENOMEM;
2341
2342 codec->spec = spec;
2343
2344 /* automatic parse from the BIOS config */
2345 err = vt1708B_parse_auto_config(codec);
2346 if (err < 0) {
2347 via_free(codec);
2348 return err;
2349 } else if (!err) {
2350 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2351 "from BIOS. Using genenic mode...\n");
2352 }
2353
Harald Welte69e52a82008-09-09 15:57:32 +08002354 spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs;
2355 spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002356
2357 spec->stream_name_analog = "VT1708B Analog";
2358 spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
2359 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
2360
2361 spec->stream_name_digital = "VT1708B Digital";
2362 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
2363 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
2364
2365 if (!spec->adc_nids && spec->input_mux) {
2366 spec->adc_nids = vt1708B_adc_nids;
2367 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
2368 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
2369 spec->num_mixers++;
2370 }
2371
2372 codec->patch_ops = via_patch_ops;
2373
2374 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08002375 codec->patch_ops.unsol_event = via_unsol_event;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002376#ifdef CONFIG_SND_HDA_POWER_SAVE
2377 spec->loopback.amplist = vt1708B_loopbacks;
2378#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01002379
2380 return 0;
2381}
2382
Harald Welted949cac2008-09-09 15:56:01 +08002383/* Patch for VT1708S */
2384
2385/* capture mixer elements */
2386static struct snd_kcontrol_new vt1708S_capture_mixer[] = {
2387 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
2388 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
2389 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
2390 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
2391 HDA_CODEC_VOLUME("Mic Boost", 0x1A, 0x0, HDA_INPUT),
2392 HDA_CODEC_VOLUME("Front Mic Boost", 0x1E, 0x0, HDA_INPUT),
2393 {
2394 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2395 /* The multiple "Capture Source" controls confuse alsamixer
2396 * So call somewhat different..
2397 */
2398 /* .name = "Capture Source", */
2399 .name = "Input Source",
2400 .count = 1,
2401 .info = via_mux_enum_info,
2402 .get = via_mux_enum_get,
2403 .put = via_mux_enum_put,
2404 },
2405 { } /* end */
2406};
2407
2408static struct hda_verb vt1708S_volume_init_verbs[] = {
2409 /* Unmute ADC0-1 and set the default input to mic-in */
2410 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2411 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2412
2413 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the
2414 * analog-loopback mixer widget */
2415 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2416 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2417 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2418 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2419 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2420 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2421
2422 /* Setup default input of PW4 to MW0 */
2423 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
2424 /* PW9 Output enable */
2425 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2426 { }
2427};
2428
Harald Welte69e52a82008-09-09 15:57:32 +08002429static struct hda_verb vt1708S_uniwill_init_verbs[] = {
2430 {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
2431 { }
2432};
2433
Harald Welted949cac2008-09-09 15:56:01 +08002434static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
2435 .substreams = 2,
2436 .channels_min = 2,
2437 .channels_max = 8,
2438 .nid = 0x10, /* NID to query formats and rates */
2439 .ops = {
2440 .open = via_playback_pcm_open,
2441 .prepare = via_playback_pcm_prepare,
2442 .cleanup = via_playback_pcm_cleanup
2443 },
2444};
2445
2446static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
2447 .substreams = 2,
2448 .channels_min = 2,
2449 .channels_max = 2,
2450 .nid = 0x13, /* NID to query formats and rates */
2451 .ops = {
2452 .prepare = via_capture_pcm_prepare,
2453 .cleanup = via_capture_pcm_cleanup
2454 },
2455};
2456
2457static struct hda_pcm_stream vt1708S_pcm_digital_playback = {
2458 .substreams = 1,
2459 .channels_min = 2,
2460 .channels_max = 2,
2461 /* NID is set in via_build_pcms */
2462 .ops = {
2463 .open = via_dig_playback_pcm_open,
2464 .close = via_dig_playback_pcm_close,
2465 .prepare = via_dig_playback_pcm_prepare
2466 },
2467};
2468
2469/* fill in the dac_nids table from the parsed pin configuration */
2470static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
2471 const struct auto_pin_cfg *cfg)
2472{
2473 int i;
2474 hda_nid_t nid;
2475
2476 spec->multiout.num_dacs = cfg->line_outs;
2477
2478 spec->multiout.dac_nids = spec->private_dac_nids;
2479
2480 for (i = 0; i < 4; i++) {
2481 nid = cfg->line_out_pins[i];
2482 if (nid) {
2483 /* config dac list */
2484 switch (i) {
2485 case AUTO_SEQ_FRONT:
2486 spec->multiout.dac_nids[i] = 0x10;
2487 break;
2488 case AUTO_SEQ_CENLFE:
2489 spec->multiout.dac_nids[i] = 0x24;
2490 break;
2491 case AUTO_SEQ_SURROUND:
2492 spec->multiout.dac_nids[i] = 0x11;
2493 break;
2494 case AUTO_SEQ_SIDE:
2495 spec->multiout.dac_nids[i] = 0x25;
2496 break;
2497 }
2498 }
2499 }
2500
2501 return 0;
2502}
2503
2504/* add playback controls from the parsed DAC table */
2505static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
2506 const struct auto_pin_cfg *cfg)
2507{
2508 char name[32];
2509 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
2510 hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25};
2511 hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27};
2512 hda_nid_t nid, nid_vol, nid_mute;
2513 int i, err;
2514
2515 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2516 nid = cfg->line_out_pins[i];
2517
2518 if (!nid)
2519 continue;
2520
2521 nid_vol = nid_vols[i];
2522 nid_mute = nid_mutes[i];
2523
2524 if (i == AUTO_SEQ_CENLFE) {
2525 /* Center/LFE */
2526 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2527 "Center Playback Volume",
2528 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2529 HDA_OUTPUT));
2530 if (err < 0)
2531 return err;
2532 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2533 "LFE Playback Volume",
2534 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2535 HDA_OUTPUT));
2536 if (err < 0)
2537 return err;
2538 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2539 "Center Playback Switch",
2540 HDA_COMPOSE_AMP_VAL(nid_mute,
2541 1, 0,
2542 HDA_OUTPUT));
2543 if (err < 0)
2544 return err;
2545 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2546 "LFE Playback Switch",
2547 HDA_COMPOSE_AMP_VAL(nid_mute,
2548 2, 0,
2549 HDA_OUTPUT));
2550 if (err < 0)
2551 return err;
2552 } else if (i == AUTO_SEQ_FRONT) {
2553 /* add control to mixer index 0 */
2554 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2555 "Master Front Playback Volume",
2556 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
2557 HDA_INPUT));
2558 if (err < 0)
2559 return err;
2560 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2561 "Master Front Playback Switch",
2562 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
2563 HDA_INPUT));
2564 if (err < 0)
2565 return err;
2566
2567 /* Front */
2568 sprintf(name, "%s Playback Volume", chname[i]);
2569 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2570 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2571 HDA_OUTPUT));
2572 if (err < 0)
2573 return err;
2574 sprintf(name, "%s Playback Switch", chname[i]);
2575 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2576 HDA_COMPOSE_AMP_VAL(nid_mute,
2577 3, 0,
2578 HDA_OUTPUT));
2579 if (err < 0)
2580 return err;
2581 } else {
2582 sprintf(name, "%s Playback Volume", chname[i]);
2583 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2584 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2585 HDA_OUTPUT));
2586 if (err < 0)
2587 return err;
2588 sprintf(name, "%s Playback Switch", chname[i]);
2589 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2590 HDA_COMPOSE_AMP_VAL(nid_mute,
2591 3, 0,
2592 HDA_OUTPUT));
2593 if (err < 0)
2594 return err;
2595 }
2596 }
2597
2598 return 0;
2599}
2600
2601static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2602{
2603 int err;
2604
2605 if (!pin)
2606 return 0;
2607
2608 spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */
2609
2610 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2611 "Headphone Playback Volume",
2612 HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
2613 if (err < 0)
2614 return err;
2615
2616 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2617 "Headphone Playback Switch",
2618 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2619 if (err < 0)
2620 return err;
2621
Harald Welte0aa62ae2008-09-09 15:58:27 +08002622 create_hp_imux(spec);
2623
Harald Welted949cac2008-09-09 15:56:01 +08002624 return 0;
2625}
2626
2627/* create playback/capture controls for input pins */
2628static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
2629 const struct auto_pin_cfg *cfg)
2630{
2631 static char *labels[] = {
2632 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2633 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08002634 struct hda_input_mux *imux = &spec->private_imux[0];
Harald Welted949cac2008-09-09 15:56:01 +08002635 int i, err, idx = 0;
2636
2637 /* for internal loopback recording select */
2638 imux->items[imux->num_items].label = "Stereo Mixer";
2639 imux->items[imux->num_items].index = 5;
2640 imux->num_items++;
2641
2642 for (i = 0; i < AUTO_PIN_LAST; i++) {
2643 if (!cfg->input_pins[i])
2644 continue;
2645
2646 switch (cfg->input_pins[i]) {
2647 case 0x1a: /* Mic */
2648 idx = 2;
2649 break;
2650
2651 case 0x1b: /* Line In */
2652 idx = 3;
2653 break;
2654
2655 case 0x1e: /* Front Mic */
2656 idx = 4;
2657 break;
2658
2659 case 0x1f: /* CD */
2660 idx = 1;
2661 break;
2662 }
2663 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
2664 idx, 0x16);
2665 if (err < 0)
2666 return err;
2667 imux->items[imux->num_items].label = labels[i];
2668 imux->items[imux->num_items].index = idx-1;
2669 imux->num_items++;
2670 }
2671 return 0;
2672}
2673
2674static int vt1708S_parse_auto_config(struct hda_codec *codec)
2675{
2676 struct via_spec *spec = codec->spec;
2677 int err;
2678 static hda_nid_t vt1708s_ignore[] = {0x21, 0};
2679
2680 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
2681 vt1708s_ignore);
2682 if (err < 0)
2683 return err;
2684 err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg);
2685 if (err < 0)
2686 return err;
2687 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2688 return 0; /* can't find valid BIOS pin config */
2689
2690 err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg);
2691 if (err < 0)
2692 return err;
2693 err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2694 if (err < 0)
2695 return err;
2696 err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
2697 if (err < 0)
2698 return err;
2699
2700 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2701
2702 if (spec->autocfg.dig_out_pin)
2703 spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID;
2704
2705 if (spec->kctl_alloc)
2706 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2707
Harald Welte0aa62ae2008-09-09 15:58:27 +08002708 spec->input_mux = &spec->private_imux[0];
2709
2710 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08002711
2712 return 1;
2713}
2714
2715#ifdef CONFIG_SND_HDA_POWER_SAVE
2716static struct hda_amp_list vt1708S_loopbacks[] = {
2717 { 0x16, HDA_INPUT, 1 },
2718 { 0x16, HDA_INPUT, 2 },
2719 { 0x16, HDA_INPUT, 3 },
2720 { 0x16, HDA_INPUT, 4 },
2721 { } /* end */
2722};
2723#endif
2724
2725static int patch_vt1708S(struct hda_codec *codec)
2726{
2727 struct via_spec *spec;
2728 int err;
2729
2730 /* create a codec specific record */
2731 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2732 if (spec == NULL)
2733 return -ENOMEM;
2734
2735 codec->spec = spec;
2736
2737 /* automatic parse from the BIOS config */
2738 err = vt1708S_parse_auto_config(codec);
2739 if (err < 0) {
2740 via_free(codec);
2741 return err;
2742 } else if (!err) {
2743 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2744 "from BIOS. Using genenic mode...\n");
2745 }
2746
Harald Welte69e52a82008-09-09 15:57:32 +08002747 spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
2748 spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs;
Harald Welted949cac2008-09-09 15:56:01 +08002749
2750 spec->stream_name_analog = "VT1708S Analog";
2751 spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
2752 spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
2753
2754 spec->stream_name_digital = "VT1708S Digital";
2755 spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
2756
2757 if (!spec->adc_nids && spec->input_mux) {
2758 spec->adc_nids = vt1708S_adc_nids;
2759 spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
2760 spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
2761 spec->num_mixers++;
2762 }
2763
2764 codec->patch_ops = via_patch_ops;
2765
2766 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08002767 codec->patch_ops.unsol_event = via_unsol_event;
Harald Welted949cac2008-09-09 15:56:01 +08002768#ifdef CONFIG_SND_HDA_POWER_SAVE
2769 spec->loopback.amplist = vt1708S_loopbacks;
2770#endif
2771
2772 return 0;
2773}
2774
2775/* Patch for VT1702 */
2776
2777/* capture mixer elements */
2778static struct snd_kcontrol_new vt1702_capture_mixer[] = {
2779 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
2780 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
2781 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
2782 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT),
2783 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT),
2784 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT),
2785 HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0,
2786 HDA_INPUT),
2787 {
2788 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2789 /* The multiple "Capture Source" controls confuse alsamixer
2790 * So call somewhat different..
2791 */
2792 /* .name = "Capture Source", */
2793 .name = "Input Source",
2794 .count = 1,
2795 .info = via_mux_enum_info,
2796 .get = via_mux_enum_get,
2797 .put = via_mux_enum_put,
2798 },
2799 { } /* end */
2800};
2801
2802static struct hda_verb vt1702_volume_init_verbs[] = {
2803 /*
2804 * Unmute ADC0-1 and set the default input to mic-in
2805 */
2806 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2807 {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2808 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2809
2810
2811 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2812 * mixer widget
2813 */
2814 /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */
2815 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2816 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2817 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2818 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2819 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2820
2821 /* Setup default input of PW4 to MW0 */
2822 {0x17, AC_VERB_SET_CONNECT_SEL, 0x1},
2823 /* PW6 PW7 Output enable */
2824 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2825 {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2826 { }
2827};
2828
Harald Welte69e52a82008-09-09 15:57:32 +08002829static struct hda_verb vt1702_uniwill_init_verbs[] = {
2830 {0x01, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_GPIO_EVENT},
2831 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
2832 { }
2833};
2834
Harald Welted949cac2008-09-09 15:56:01 +08002835static struct hda_pcm_stream vt1702_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08002836 .substreams = 2,
Harald Welted949cac2008-09-09 15:56:01 +08002837 .channels_min = 2,
2838 .channels_max = 2,
2839 .nid = 0x10, /* NID to query formats and rates */
2840 .ops = {
2841 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08002842 .prepare = via_playback_multi_pcm_prepare,
2843 .cleanup = via_playback_multi_pcm_cleanup
Harald Welted949cac2008-09-09 15:56:01 +08002844 },
2845};
2846
2847static struct hda_pcm_stream vt1702_pcm_analog_capture = {
2848 .substreams = 3,
2849 .channels_min = 2,
2850 .channels_max = 2,
2851 .nid = 0x12, /* NID to query formats and rates */
2852 .ops = {
2853 .prepare = via_capture_pcm_prepare,
2854 .cleanup = via_capture_pcm_cleanup
2855 },
2856};
2857
2858static struct hda_pcm_stream vt1702_pcm_digital_playback = {
2859 .substreams = 1,
2860 .channels_min = 2,
2861 .channels_max = 2,
2862 /* NID is set in via_build_pcms */
2863 .ops = {
2864 .open = via_dig_playback_pcm_open,
2865 .close = via_dig_playback_pcm_close,
2866 .prepare = via_dig_playback_pcm_prepare
2867 },
2868};
2869
2870/* fill in the dac_nids table from the parsed pin configuration */
2871static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
2872 const struct auto_pin_cfg *cfg)
2873{
2874 spec->multiout.num_dacs = 1;
2875 spec->multiout.dac_nids = spec->private_dac_nids;
2876
2877 if (cfg->line_out_pins[0]) {
2878 /* config dac list */
2879 spec->multiout.dac_nids[0] = 0x10;
2880 }
2881
2882 return 0;
2883}
2884
2885/* add playback controls from the parsed DAC table */
2886static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
2887 const struct auto_pin_cfg *cfg)
2888{
2889 int err;
2890
2891 if (!cfg->line_out_pins[0])
2892 return -1;
2893
2894 /* add control to mixer index 0 */
2895 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2896 "Master Front Playback Volume",
2897 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
2898 if (err < 0)
2899 return err;
2900 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2901 "Master Front Playback Switch",
2902 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
2903 if (err < 0)
2904 return err;
2905
2906 /* Front */
2907 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2908 "Front Playback Volume",
2909 HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT));
2910 if (err < 0)
2911 return err;
2912 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2913 "Front Playback Switch",
2914 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT));
2915 if (err < 0)
2916 return err;
2917
2918 return 0;
2919}
2920
2921static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2922{
2923 int err;
2924
2925 if (!pin)
2926 return 0;
2927
2928 spec->multiout.hp_nid = 0x1D;
2929
2930 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2931 "Headphone Playback Volume",
2932 HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT));
2933 if (err < 0)
2934 return err;
2935
2936 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2937 "Headphone Playback Switch",
2938 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2939 if (err < 0)
2940 return err;
2941
Harald Welte0aa62ae2008-09-09 15:58:27 +08002942 create_hp_imux(spec);
2943
Harald Welted949cac2008-09-09 15:56:01 +08002944 return 0;
2945}
2946
2947/* create playback/capture controls for input pins */
2948static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
2949 const struct auto_pin_cfg *cfg)
2950{
2951 static char *labels[] = {
2952 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2953 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08002954 struct hda_input_mux *imux = &spec->private_imux[0];
Harald Welted949cac2008-09-09 15:56:01 +08002955 int i, err, idx = 0;
2956
2957 /* for internal loopback recording select */
2958 imux->items[imux->num_items].label = "Stereo Mixer";
2959 imux->items[imux->num_items].index = 3;
2960 imux->num_items++;
2961
2962 for (i = 0; i < AUTO_PIN_LAST; i++) {
2963 if (!cfg->input_pins[i])
2964 continue;
2965
2966 switch (cfg->input_pins[i]) {
2967 case 0x14: /* Mic */
2968 idx = 1;
2969 break;
2970
2971 case 0x15: /* Line In */
2972 idx = 2;
2973 break;
2974
2975 case 0x18: /* Front Mic */
2976 idx = 3;
2977 break;
2978 }
2979 err = via_new_analog_input(spec, cfg->input_pins[i],
2980 labels[i], idx, 0x1A);
2981 if (err < 0)
2982 return err;
2983 imux->items[imux->num_items].label = labels[i];
2984 imux->items[imux->num_items].index = idx-1;
2985 imux->num_items++;
2986 }
2987 return 0;
2988}
2989
2990static int vt1702_parse_auto_config(struct hda_codec *codec)
2991{
2992 struct via_spec *spec = codec->spec;
2993 int err;
2994 static hda_nid_t vt1702_ignore[] = {0x1C, 0};
2995
2996 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
2997 vt1702_ignore);
2998 if (err < 0)
2999 return err;
3000 err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg);
3001 if (err < 0)
3002 return err;
3003 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
3004 return 0; /* can't find valid BIOS pin config */
3005
3006 err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg);
3007 if (err < 0)
3008 return err;
3009 err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
3010 if (err < 0)
3011 return err;
3012 err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
3013 if (err < 0)
3014 return err;
3015
3016 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3017
3018 if (spec->autocfg.dig_out_pin)
3019 spec->multiout.dig_out_nid = VT1702_DIGOUT_NID;
3020
3021 if (spec->kctl_alloc)
3022 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3023
Harald Welte0aa62ae2008-09-09 15:58:27 +08003024 spec->input_mux = &spec->private_imux[0];
3025
3026 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08003027
3028 return 1;
3029}
3030
3031#ifdef CONFIG_SND_HDA_POWER_SAVE
3032static struct hda_amp_list vt1702_loopbacks[] = {
3033 { 0x1A, HDA_INPUT, 1 },
3034 { 0x1A, HDA_INPUT, 2 },
3035 { 0x1A, HDA_INPUT, 3 },
3036 { 0x1A, HDA_INPUT, 4 },
3037 { } /* end */
3038};
3039#endif
3040
3041static int patch_vt1702(struct hda_codec *codec)
3042{
3043 struct via_spec *spec;
3044 int err;
3045 unsigned int response;
3046 unsigned char control;
3047
3048 /* create a codec specific record */
3049 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3050 if (spec == NULL)
3051 return -ENOMEM;
3052
3053 codec->spec = spec;
3054
3055 /* automatic parse from the BIOS config */
3056 err = vt1702_parse_auto_config(codec);
3057 if (err < 0) {
3058 via_free(codec);
3059 return err;
3060 } else if (!err) {
3061 printk(KERN_INFO "hda_codec: Cannot set up configuration "
3062 "from BIOS. Using genenic mode...\n");
3063 }
3064
Harald Welte69e52a82008-09-09 15:57:32 +08003065 spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs;
3066 spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs;
Harald Welted949cac2008-09-09 15:56:01 +08003067
3068 spec->stream_name_analog = "VT1702 Analog";
3069 spec->stream_analog_playback = &vt1702_pcm_analog_playback;
3070 spec->stream_analog_capture = &vt1702_pcm_analog_capture;
3071
3072 spec->stream_name_digital = "VT1702 Digital";
3073 spec->stream_digital_playback = &vt1702_pcm_digital_playback;
3074
3075 if (!spec->adc_nids && spec->input_mux) {
3076 spec->adc_nids = vt1702_adc_nids;
3077 spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
3078 spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
3079 spec->num_mixers++;
3080 }
3081
3082 codec->patch_ops = via_patch_ops;
3083
3084 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003085 codec->patch_ops.unsol_event = via_unsol_event;
Harald Welted949cac2008-09-09 15:56:01 +08003086#ifdef CONFIG_SND_HDA_POWER_SAVE
3087 spec->loopback.amplist = vt1702_loopbacks;
3088#endif
3089
3090 /* Open backdoor */
3091 response = snd_hda_codec_read(codec, codec->afg, 0, 0xF8C, 0);
3092 control = (unsigned char)(response & 0xff);
3093 control |= 0x3;
3094 snd_hda_codec_write(codec, codec->afg, 0, 0xF88, control);
3095
3096 /* Enable GPIO 0&1 for volume&mute control */
3097 /* Enable GPIO 2 for DMIC-DATA */
3098 response = snd_hda_codec_read(codec, codec->afg, 0, 0xF84, 0);
3099 control = (unsigned char)((response >> 16) & 0x3f);
3100 snd_hda_codec_write(codec, codec->afg, 0, 0xF82, control);
3101
3102 return 0;
3103}
3104
Joseph Chanc577b8a2006-11-29 15:29:40 +01003105/*
3106 * patch entries
3107 */
3108struct hda_codec_preset snd_hda_preset_via[] = {
3109 { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708},
3110 { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708},
3111 { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708},
3112 { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708},
Josepch Chanf7278fd2007-12-13 16:40:40 +01003113 { .id = 0x1106E710, .name = "VIA VT1709 10-Ch",
3114 .patch = patch_vt1709_10ch},
3115 { .id = 0x1106E711, .name = "VIA VT1709 10-Ch",
3116 .patch = patch_vt1709_10ch},
3117 { .id = 0x1106E712, .name = "VIA VT1709 10-Ch",
3118 .patch = patch_vt1709_10ch},
3119 { .id = 0x1106E713, .name = "VIA VT1709 10-Ch",
3120 .patch = patch_vt1709_10ch},
3121 { .id = 0x1106E714, .name = "VIA VT1709 6-Ch",
3122 .patch = patch_vt1709_6ch},
3123 { .id = 0x1106E715, .name = "VIA VT1709 6-Ch",
3124 .patch = patch_vt1709_6ch},
3125 { .id = 0x1106E716, .name = "VIA VT1709 6-Ch",
3126 .patch = patch_vt1709_6ch},
3127 { .id = 0x1106E717, .name = "VIA VT1709 6-Ch",
3128 .patch = patch_vt1709_6ch},
3129 { .id = 0x1106E720, .name = "VIA VT1708B 8-Ch",
3130 .patch = patch_vt1708B_8ch},
3131 { .id = 0x1106E721, .name = "VIA VT1708B 8-Ch",
3132 .patch = patch_vt1708B_8ch},
3133 { .id = 0x1106E722, .name = "VIA VT1708B 8-Ch",
3134 .patch = patch_vt1708B_8ch},
3135 { .id = 0x1106E723, .name = "VIA VT1708B 8-Ch",
3136 .patch = patch_vt1708B_8ch},
3137 { .id = 0x1106E724, .name = "VIA VT1708B 4-Ch",
3138 .patch = patch_vt1708B_4ch},
3139 { .id = 0x1106E725, .name = "VIA VT1708B 4-Ch",
3140 .patch = patch_vt1708B_4ch},
3141 { .id = 0x1106E726, .name = "VIA VT1708B 4-Ch",
3142 .patch = patch_vt1708B_4ch},
3143 { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch",
3144 .patch = patch_vt1708B_4ch},
Harald Welted949cac2008-09-09 15:56:01 +08003145 { .id = 0x11060397, .name = "VIA VT1708S",
3146 .patch = patch_vt1708S},
3147 { .id = 0x11061397, .name = "VIA VT1708S",
3148 .patch = patch_vt1708S},
3149 { .id = 0x11062397, .name = "VIA VT1708S",
3150 .patch = patch_vt1708S},
3151 { .id = 0x11063397, .name = "VIA VT1708S",
3152 .patch = patch_vt1708S},
3153 { .id = 0x11064397, .name = "VIA VT1708S",
3154 .patch = patch_vt1708S},
3155 { .id = 0x11065397, .name = "VIA VT1708S",
3156 .patch = patch_vt1708S},
3157 { .id = 0x11066397, .name = "VIA VT1708S",
3158 .patch = patch_vt1708S},
3159 { .id = 0x11067397, .name = "VIA VT1708S",
3160 .patch = patch_vt1708S},
3161 { .id = 0x11060398, .name = "VIA VT1702",
3162 .patch = patch_vt1702},
3163 { .id = 0x11061398, .name = "VIA VT1702",
3164 .patch = patch_vt1702},
3165 { .id = 0x11062398, .name = "VIA VT1702",
3166 .patch = patch_vt1702},
3167 { .id = 0x11063398, .name = "VIA VT1702",
3168 .patch = patch_vt1702},
3169 { .id = 0x11064398, .name = "VIA VT1702",
3170 .patch = patch_vt1702},
3171 { .id = 0x11065398, .name = "VIA VT1702",
3172 .patch = patch_vt1702},
3173 { .id = 0x11066398, .name = "VIA VT1702",
3174 .patch = patch_vt1702},
3175 { .id = 0x11067398, .name = "VIA VT1702",
3176 .patch = patch_vt1702},
Joseph Chanc577b8a2006-11-29 15:29:40 +01003177 {} /* terminator */
3178};