blob: 59a173e88128e3109c7a19c234ae6a8e18417867 [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 */
Harald Welte98aa34c2008-09-09 16:02:09 +080037/* 2008-05-28 Lydia Wang Add second S/PDIF Out support for VT1702 */
Joseph Chanc577b8a2006-11-29 15:29:40 +010038/* */
39/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
40
41
Joseph Chanc577b8a2006-11-29 15:29:40 +010042#include <linux/init.h>
43#include <linux/delay.h>
44#include <linux/slab.h>
Joseph Chanc577b8a2006-11-29 15:29:40 +010045#include <sound/core.h>
Harald Welte0aa62ae2008-09-09 15:58:27 +080046#include <sound/asoundef.h>
Joseph Chanc577b8a2006-11-29 15:29:40 +010047#include "hda_codec.h"
48#include "hda_local.h"
Harvey Harrison3c9a3202008-02-29 11:59:26 +010049#include "hda_patch.h"
Joseph Chanc577b8a2006-11-29 15:29:40 +010050
51/* amp values */
52#define AMP_VAL_IDX_SHIFT 19
53#define AMP_VAL_IDX_MASK (0x0f<<19)
54
55#define NUM_CONTROL_ALLOC 32
56#define NUM_VERB_ALLOC 32
57
58/* Pin Widget NID */
59#define VT1708_HP_NID 0x13
60#define VT1708_DIGOUT_NID 0x14
61#define VT1708_DIGIN_NID 0x16
Josepch Chanf7278fd2007-12-13 16:40:40 +010062#define VT1708_DIGIN_PIN 0x26
Harald Welted949cac2008-09-09 15:56:01 +080063#define VT1708_HP_PIN_NID 0x20
64#define VT1708_CD_PIN_NID 0x24
Joseph Chanc577b8a2006-11-29 15:29:40 +010065
66#define VT1709_HP_DAC_NID 0x28
67#define VT1709_DIGOUT_NID 0x13
68#define VT1709_DIGIN_NID 0x17
Josepch Chanf7278fd2007-12-13 16:40:40 +010069#define VT1709_DIGIN_PIN 0x25
70
71#define VT1708B_HP_NID 0x25
72#define VT1708B_DIGOUT_NID 0x12
73#define VT1708B_DIGIN_NID 0x15
74#define VT1708B_DIGIN_PIN 0x21
Joseph Chanc577b8a2006-11-29 15:29:40 +010075
Harald Welted949cac2008-09-09 15:56:01 +080076#define VT1708S_HP_NID 0x25
77#define VT1708S_DIGOUT_NID 0x12
78
79#define VT1702_HP_NID 0x17
80#define VT1702_DIGOUT_NID 0x11
81
Joseph Chanc577b8a2006-11-29 15:29:40 +010082#define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b)
83#define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713)
84#define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717)
Josepch Chanf7278fd2007-12-13 16:40:40 +010085#define IS_VT1708B_8CH_VENDORID(x) ((x) >= 0x1106e720 && (x) <= 0x1106e723)
86#define IS_VT1708B_4CH_VENDORID(x) ((x) >= 0x1106e724 && (x) <= 0x1106e727)
Harald Welted949cac2008-09-09 15:56:01 +080087#define IS_VT1708S_VENDORID(x) ((x) >= 0x11060397 && (x) <= 0x11067397)
88#define IS_VT1702_VENDORID(x) ((x) >= 0x11060398 && (x) <= 0x11067398)
Joseph Chanc577b8a2006-11-29 15:29:40 +010089
Harald Welte69e52a82008-09-09 15:57:32 +080090#define VIA_HP_EVENT 0x01
91#define VIA_GPIO_EVENT 0x02
92
Joseph Chanc577b8a2006-11-29 15:29:40 +010093enum {
94 VIA_CTL_WIDGET_VOL,
95 VIA_CTL_WIDGET_MUTE,
96};
97
98enum {
Harald Welteeb14a462008-09-09 15:40:38 +080099 AUTO_SEQ_FRONT = 0,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100100 AUTO_SEQ_SURROUND,
101 AUTO_SEQ_CENLFE,
102 AUTO_SEQ_SIDE
103};
104
105static struct snd_kcontrol_new vt1708_control_templates[] = {
106 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
107 HDA_CODEC_MUTE(NULL, 0, 0, 0),
108};
109
110
111struct via_spec {
112 /* codec parameterization */
113 struct snd_kcontrol_new *mixers[3];
114 unsigned int num_mixers;
115
Harald Welte69e52a82008-09-09 15:57:32 +0800116 struct hda_verb *init_verbs[5];
117 unsigned int num_iverbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100118
119 char *stream_name_analog;
120 struct hda_pcm_stream *stream_analog_playback;
121 struct hda_pcm_stream *stream_analog_capture;
122
123 char *stream_name_digital;
124 struct hda_pcm_stream *stream_digital_playback;
125 struct hda_pcm_stream *stream_digital_capture;
126
127 /* playback */
128 struct hda_multi_out multiout;
Harald Welte98aa34c2008-09-09 16:02:09 +0800129 hda_nid_t extra_dig_out_nid;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100130
131 /* capture */
132 unsigned int num_adc_nids;
133 hda_nid_t *adc_nids;
134 hda_nid_t dig_in_nid;
135
136 /* capture source */
137 const struct hda_input_mux *input_mux;
138 unsigned int cur_mux[3];
139
140 /* PCM information */
Harald Welte98aa34c2008-09-09 16:02:09 +0800141 struct hda_pcm pcm_rec[3];
Joseph Chanc577b8a2006-11-29 15:29:40 +0100142
143 /* dynamic controls, init_verbs and input_mux */
144 struct auto_pin_cfg autocfg;
145 unsigned int num_kctl_alloc, num_kctl_used;
146 struct snd_kcontrol_new *kctl_alloc;
Harald Welte0aa62ae2008-09-09 15:58:27 +0800147 struct hda_input_mux private_imux[2];
Takashi Iwai41923e42007-10-22 17:20:10 +0200148 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwaicb53c622007-08-10 17:21:45 +0200149
Harald Welte0aa62ae2008-09-09 15:58:27 +0800150 /* HP mode source */
151 const struct hda_input_mux *hp_mux;
152 unsigned int hp_independent_mode;
153
Takashi Iwaicb53c622007-08-10 17:21:45 +0200154#ifdef CONFIG_SND_HDA_POWER_SAVE
155 struct hda_loopback_check loopback;
156#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +0100157};
158
159static hda_nid_t vt1708_adc_nids[2] = {
160 /* ADC1-2 */
161 0x15, 0x27
162};
163
164static hda_nid_t vt1709_adc_nids[3] = {
165 /* ADC1-2 */
166 0x14, 0x15, 0x16
167};
168
Josepch Chanf7278fd2007-12-13 16:40:40 +0100169static hda_nid_t vt1708B_adc_nids[2] = {
170 /* ADC1-2 */
171 0x13, 0x14
172};
173
Harald Welted949cac2008-09-09 15:56:01 +0800174static hda_nid_t vt1708S_adc_nids[2] = {
175 /* ADC1-2 */
176 0x13, 0x14
177};
178
179static hda_nid_t vt1702_adc_nids[3] = {
180 /* ADC1-2 */
181 0x12, 0x20, 0x1F
182};
183
Joseph Chanc577b8a2006-11-29 15:29:40 +0100184/* add dynamic controls */
185static int via_add_control(struct via_spec *spec, int type, const char *name,
186 unsigned long val)
187{
188 struct snd_kcontrol_new *knew;
189
190 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
191 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
192
193 /* array + terminator */
194 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
195 if (!knew)
196 return -ENOMEM;
197 if (spec->kctl_alloc) {
198 memcpy(knew, spec->kctl_alloc,
199 sizeof(*knew) * spec->num_kctl_alloc);
200 kfree(spec->kctl_alloc);
201 }
202 spec->kctl_alloc = knew;
203 spec->num_kctl_alloc = num;
204 }
205
206 knew = &spec->kctl_alloc[spec->num_kctl_used];
207 *knew = vt1708_control_templates[type];
208 knew->name = kstrdup(name, GFP_KERNEL);
209
210 if (!knew->name)
211 return -ENOMEM;
212 knew->private_value = val;
213 spec->num_kctl_used++;
214 return 0;
215}
216
217/* create input playback/capture controls for the given pin */
218static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
219 const char *ctlname, int idx, int mix_nid)
220{
221 char name[32];
222 int err;
223
224 sprintf(name, "%s Playback Volume", ctlname);
225 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
226 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
227 if (err < 0)
228 return err;
229 sprintf(name, "%s Playback Switch", ctlname);
230 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
231 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
232 if (err < 0)
233 return err;
234 return 0;
235}
236
237static void via_auto_set_output_and_unmute(struct hda_codec *codec,
238 hda_nid_t nid, int pin_type,
239 int dac_idx)
240{
241 /* set as output */
242 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
243 pin_type);
244 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
245 AMP_OUT_UNMUTE);
246}
247
248
249static void via_auto_init_multi_out(struct hda_codec *codec)
250{
251 struct via_spec *spec = codec->spec;
252 int i;
253
254 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
255 hda_nid_t nid = spec->autocfg.line_out_pins[i];
256 if (nid)
257 via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
258 }
259}
260
261static void via_auto_init_hp_out(struct hda_codec *codec)
262{
263 struct via_spec *spec = codec->spec;
264 hda_nid_t pin;
265
266 pin = spec->autocfg.hp_pins[0];
267 if (pin) /* connect to front */
268 via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
269}
270
271static void via_auto_init_analog_input(struct hda_codec *codec)
272{
273 struct via_spec *spec = codec->spec;
274 int i;
275
276 for (i = 0; i < AUTO_PIN_LAST; i++) {
277 hda_nid_t nid = spec->autocfg.input_pins[i];
278
279 snd_hda_codec_write(codec, nid, 0,
280 AC_VERB_SET_PIN_WIDGET_CONTROL,
281 (i <= AUTO_PIN_FRONT_MIC ?
282 PIN_VREF50 : PIN_IN));
283
284 }
285}
286/*
287 * input MUX handling
288 */
289static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
290 struct snd_ctl_elem_info *uinfo)
291{
292 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
293 struct via_spec *spec = codec->spec;
294 return snd_hda_input_mux_info(spec->input_mux, uinfo);
295}
296
297static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
298 struct snd_ctl_elem_value *ucontrol)
299{
300 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
301 struct via_spec *spec = codec->spec;
302 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
303
304 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
305 return 0;
306}
307
308static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
309 struct snd_ctl_elem_value *ucontrol)
310{
311 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
312 struct via_spec *spec = codec->spec;
313 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
314 unsigned int vendor_id = codec->vendor_id;
315
316 /* AIW0 lydia 060801 add for correct sw0 input select */
317 if (IS_VT1708_VENDORID(vendor_id) && (adc_idx == 0))
318 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
319 0x18, &spec->cur_mux[adc_idx]);
320 else if ((IS_VT1709_10CH_VENDORID(vendor_id) ||
Harald Welteeb14a462008-09-09 15:40:38 +0800321 IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0))
Joseph Chanc577b8a2006-11-29 15:29:40 +0100322 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
323 0x19, &spec->cur_mux[adc_idx]);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100324 else if ((IS_VT1708B_8CH_VENDORID(vendor_id) ||
Harald Welteeb14a462008-09-09 15:40:38 +0800325 IS_VT1708B_4CH_VENDORID(vendor_id)) && (adc_idx == 0))
Josepch Chanf7278fd2007-12-13 16:40:40 +0100326 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
327 0x17, &spec->cur_mux[adc_idx]);
Harald Welted949cac2008-09-09 15:56:01 +0800328 else if (IS_VT1702_VENDORID(vendor_id) && (adc_idx == 0))
329 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
330 0x13, &spec->cur_mux[adc_idx]);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100331 else
332 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
333 spec->adc_nids[adc_idx],
334 &spec->cur_mux[adc_idx]);
335}
336
Harald Welte0aa62ae2008-09-09 15:58:27 +0800337static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
338 struct snd_ctl_elem_info *uinfo)
339{
340 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
341 struct via_spec *spec = codec->spec;
342 return snd_hda_input_mux_info(spec->hp_mux, uinfo);
343}
344
345static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
346 struct snd_ctl_elem_value *ucontrol)
347{
348 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
349 struct via_spec *spec = codec->spec;
350 hda_nid_t nid = spec->autocfg.hp_pins[0];
351 unsigned int pinsel = snd_hda_codec_read(codec, nid, 0,
352 AC_VERB_GET_CONNECT_SEL,
353 0x00);
354
355 ucontrol->value.enumerated.item[0] = pinsel;
356
357 return 0;
358}
359
360static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
361 struct snd_ctl_elem_value *ucontrol)
362{
363 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
364 struct via_spec *spec = codec->spec;
365 hda_nid_t nid = spec->autocfg.hp_pins[0];
366 unsigned int pinsel = ucontrol->value.enumerated.item[0];
367 unsigned int con_nid = snd_hda_codec_read(codec, nid, 0,
368 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
369
370 if (con_nid == spec->multiout.hp_nid) {
371 if (pinsel == 0) {
372 if (!spec->hp_independent_mode) {
373 if (spec->multiout.num_dacs > 1)
374 spec->multiout.num_dacs -= 1;
375 spec->hp_independent_mode = 1;
376 }
377 } else if (pinsel == 1) {
378 if (spec->hp_independent_mode) {
379 if (spec->multiout.num_dacs > 1)
380 spec->multiout.num_dacs += 1;
381 spec->hp_independent_mode = 0;
382 }
383 }
384 } else {
385 if (pinsel == 0) {
386 if (spec->hp_independent_mode) {
387 if (spec->multiout.num_dacs > 1)
388 spec->multiout.num_dacs += 1;
389 spec->hp_independent_mode = 0;
390 }
391 } else if (pinsel == 1) {
392 if (!spec->hp_independent_mode) {
393 if (spec->multiout.num_dacs > 1)
394 spec->multiout.num_dacs -= 1;
395 spec->hp_independent_mode = 1;
396 }
397 }
398 }
399 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL,
400 pinsel);
401
402 if (spec->multiout.hp_nid &&
403 spec->multiout.hp_nid != spec->multiout.dac_nids[HDA_FRONT])
404 snd_hda_codec_setup_stream(codec,
405 spec->multiout.hp_nid,
406 0, 0, 0);
407
408 return 0;
409}
410
411static struct snd_kcontrol_new via_hp_mixer[] = {
412 {
413 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
414 .name = "Independent HP",
415 .count = 1,
416 .info = via_independent_hp_info,
417 .get = via_independent_hp_get,
418 .put = via_independent_hp_put,
419 },
420 { } /* end */
421};
422
Joseph Chanc577b8a2006-11-29 15:29:40 +0100423/* capture mixer elements */
424static struct snd_kcontrol_new vt1708_capture_mixer[] = {
425 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
426 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
427 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
428 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
429 {
430 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
431 /* The multiple "Capture Source" controls confuse alsamixer
432 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +0100433 */
434 /* .name = "Capture Source", */
435 .name = "Input Source",
436 .count = 1,
437 .info = via_mux_enum_info,
438 .get = via_mux_enum_get,
439 .put = via_mux_enum_put,
440 },
441 { } /* end */
442};
443/*
444 * generic initialization of ADC, input mixers and output mixers
445 */
446static struct hda_verb vt1708_volume_init_verbs[] = {
447 /*
448 * Unmute ADC0-1 and set the default input to mic-in
449 */
450 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
451 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
452
453
Josepch Chanf7278fd2007-12-13 16:40:40 +0100454 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +0100455 * mixer widget
456 */
457 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +0100458 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
459 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
460 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
461 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
462 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100463
464 /*
465 * Set up output mixers (0x19 - 0x1b)
466 */
467 /* set vol=0 to output mixers */
468 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
469 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
470 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
471
472 /* Setup default input to PW4 */
473 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100474 /* PW9 Output enable */
475 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Josepch Chanf7278fd2007-12-13 16:40:40 +0100476 { }
Joseph Chanc577b8a2006-11-29 15:29:40 +0100477};
478
479static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
480 struct hda_codec *codec,
481 struct snd_pcm_substream *substream)
482{
483 struct via_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +0100484 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
485 hinfo);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100486}
487
488static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
489 struct hda_codec *codec,
490 unsigned int stream_tag,
491 unsigned int format,
492 struct snd_pcm_substream *substream)
493{
494 struct via_spec *spec = codec->spec;
495 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
496 stream_tag, format, substream);
497}
498
499static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
500 struct hda_codec *codec,
501 struct snd_pcm_substream *substream)
502{
503 struct via_spec *spec = codec->spec;
504 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
505}
506
Harald Welte0aa62ae2008-09-09 15:58:27 +0800507
508static void playback_multi_pcm_prep_0(struct hda_codec *codec,
509 unsigned int stream_tag,
510 unsigned int format,
511 struct snd_pcm_substream *substream)
512{
513 struct via_spec *spec = codec->spec;
514 struct hda_multi_out *mout = &spec->multiout;
515 hda_nid_t *nids = mout->dac_nids;
516 int chs = substream->runtime->channels;
517 int i;
518
519 mutex_lock(&codec->spdif_mutex);
520 if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
521 if (chs == 2 &&
522 snd_hda_is_supported_format(codec, mout->dig_out_nid,
523 format) &&
524 !(codec->spdif_status & IEC958_AES0_NONAUDIO)) {
525 mout->dig_out_used = HDA_DIG_ANALOG_DUP;
526 /* turn off SPDIF once; otherwise the IEC958 bits won't
527 * be updated */
528 if (codec->spdif_ctls & AC_DIG1_ENABLE)
529 snd_hda_codec_write(codec, mout->dig_out_nid, 0,
530 AC_VERB_SET_DIGI_CONVERT_1,
531 codec->spdif_ctls &
532 ~AC_DIG1_ENABLE & 0xff);
533 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
534 stream_tag, 0, format);
535 /* turn on again (if needed) */
536 if (codec->spdif_ctls & AC_DIG1_ENABLE)
537 snd_hda_codec_write(codec, mout->dig_out_nid, 0,
538 AC_VERB_SET_DIGI_CONVERT_1,
539 codec->spdif_ctls & 0xff);
540 } else {
541 mout->dig_out_used = 0;
542 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
543 0, 0, 0);
544 }
545 }
546 mutex_unlock(&codec->spdif_mutex);
547
548 /* front */
549 snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag,
550 0, format);
551
552 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
553 !spec->hp_independent_mode)
554 /* headphone out will just decode front left/right (stereo) */
555 snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag,
556 0, format);
557
558 /* extra outputs copied from front */
559 for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
560 if (mout->extra_out_nid[i])
561 snd_hda_codec_setup_stream(codec,
562 mout->extra_out_nid[i],
563 stream_tag, 0, format);
564
565 /* surrounds */
566 for (i = 1; i < mout->num_dacs; i++) {
567 if (chs >= (i + 1) * 2) /* independent out */
568 snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
569 i * 2, format);
570 else /* copy front */
571 snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
572 0, format);
573 }
574}
575
576static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
577 struct hda_codec *codec,
578 unsigned int stream_tag,
579 unsigned int format,
580 struct snd_pcm_substream *substream)
581{
582 struct via_spec *spec = codec->spec;
583 struct hda_multi_out *mout = &spec->multiout;
584 hda_nid_t *nids = mout->dac_nids;
585
586 if (substream->number == 0)
587 playback_multi_pcm_prep_0(codec, stream_tag, format,
588 substream);
589 else {
590 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
591 spec->hp_independent_mode)
592 snd_hda_codec_setup_stream(codec, mout->hp_nid,
593 stream_tag, 0, format);
594 }
595
596 return 0;
597}
598
599static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
600 struct hda_codec *codec,
601 struct snd_pcm_substream *substream)
602{
603 struct via_spec *spec = codec->spec;
604 struct hda_multi_out *mout = &spec->multiout;
605 hda_nid_t *nids = mout->dac_nids;
606 int i;
607
608 if (substream->number == 0) {
609 for (i = 0; i < mout->num_dacs; i++)
610 snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
611
612 if (mout->hp_nid && !spec->hp_independent_mode)
613 snd_hda_codec_setup_stream(codec, mout->hp_nid,
614 0, 0, 0);
615
616 for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
617 if (mout->extra_out_nid[i])
618 snd_hda_codec_setup_stream(codec,
619 mout->extra_out_nid[i],
620 0, 0, 0);
621 mutex_lock(&codec->spdif_mutex);
622 if (mout->dig_out_nid &&
623 mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
624 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
625 0, 0, 0);
626 mout->dig_out_used = 0;
627 }
628 mutex_unlock(&codec->spdif_mutex);
629 } else {
630 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
631 spec->hp_independent_mode)
632 snd_hda_codec_setup_stream(codec, mout->hp_nid,
633 0, 0, 0);
634 }
635
636 return 0;
637}
638
Joseph Chanc577b8a2006-11-29 15:29:40 +0100639/*
640 * Digital out
641 */
642static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
643 struct hda_codec *codec,
644 struct snd_pcm_substream *substream)
645{
646 struct via_spec *spec = codec->spec;
647 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
648}
649
650static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
651 struct hda_codec *codec,
652 struct snd_pcm_substream *substream)
653{
654 struct via_spec *spec = codec->spec;
655 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
656}
657
Harald Welte98aa34c2008-09-09 16:02:09 +0800658/* setup SPDIF output stream */
659static void setup_dig_playback_stream(struct hda_codec *codec, hda_nid_t nid,
660 unsigned int stream_tag, unsigned int format)
661{
662 /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
663 if (codec->spdif_ctls & AC_DIG1_ENABLE)
664 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
665 codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
666 snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
667 /* turn on again (if needed) */
668 if (codec->spdif_ctls & AC_DIG1_ENABLE)
669 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
670 codec->spdif_ctls & 0xff);
671}
672
Harald Welte5691ec72008-09-15 22:42:26 +0800673static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
Harald Welte98aa34c2008-09-09 16:02:09 +0800674 struct hda_codec *codec,
675 unsigned int stream_tag,
676 unsigned int format,
677 struct snd_pcm_substream *substream)
678{
679 struct via_spec *spec = codec->spec;
Harald Welte5691ec72008-09-15 22:42:26 +0800680 hda_nid_t nid;
681
682 /* 1st or 2nd S/PDIF */
683 if (substream->number == 0)
684 nid = spec->multiout.dig_out_nid;
685 else if (substream->number == 1)
686 nid = spec->extra_dig_out_nid;
687 else
688 return -1;
Harald Welte98aa34c2008-09-09 16:02:09 +0800689
690 mutex_lock(&codec->spdif_mutex);
Harald Welte5691ec72008-09-15 22:42:26 +0800691 setup_dig_playback_stream(codec, nid, stream_tag, format);
Harald Welte98aa34c2008-09-09 16:02:09 +0800692 mutex_unlock(&codec->spdif_mutex);
693 return 0;
694}
695
Joseph Chanc577b8a2006-11-29 15:29:40 +0100696/*
697 * Analog capture
698 */
699static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
700 struct hda_codec *codec,
701 unsigned int stream_tag,
702 unsigned int format,
703 struct snd_pcm_substream *substream)
704{
705 struct via_spec *spec = codec->spec;
706
707 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
708 stream_tag, 0, format);
709 return 0;
710}
711
712static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
713 struct hda_codec *codec,
714 struct snd_pcm_substream *substream)
715{
716 struct via_spec *spec = codec->spec;
Takashi Iwai888afa12008-03-18 09:57:50 +0100717 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100718 return 0;
719}
720
721static struct hda_pcm_stream vt1708_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +0800722 .substreams = 2,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100723 .channels_min = 2,
724 .channels_max = 8,
725 .nid = 0x10, /* NID to query formats and rates */
726 .ops = {
727 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +0800728 .prepare = via_playback_multi_pcm_prepare,
729 .cleanup = via_playback_multi_pcm_cleanup
Joseph Chanc577b8a2006-11-29 15:29:40 +0100730 },
731};
732
Takashi Iwaibc9b5622008-05-23 17:50:27 +0200733static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
734 .substreams = 1,
735 .channels_min = 2,
736 .channels_max = 8,
737 .nid = 0x10, /* NID to query formats and rates */
738 /* We got noisy outputs on the right channel on VT1708 when
739 * 24bit samples are used. Until any workaround is found,
740 * disable the 24bit format, so far.
741 */
742 .formats = SNDRV_PCM_FMTBIT_S16_LE,
743 .ops = {
744 .open = via_playback_pcm_open,
745 .prepare = via_playback_pcm_prepare,
746 .cleanup = via_playback_pcm_cleanup
747 },
748};
749
Joseph Chanc577b8a2006-11-29 15:29:40 +0100750static struct hda_pcm_stream vt1708_pcm_analog_capture = {
751 .substreams = 2,
752 .channels_min = 2,
753 .channels_max = 2,
754 .nid = 0x15, /* NID to query formats and rates */
755 .ops = {
756 .prepare = via_capture_pcm_prepare,
757 .cleanup = via_capture_pcm_cleanup
758 },
759};
760
761static struct hda_pcm_stream vt1708_pcm_digital_playback = {
762 .substreams = 1,
763 .channels_min = 2,
764 .channels_max = 2,
765 /* NID is set in via_build_pcms */
766 .ops = {
767 .open = via_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +0200768 .close = via_dig_playback_pcm_close,
769 .prepare = via_dig_playback_pcm_prepare
Joseph Chanc577b8a2006-11-29 15:29:40 +0100770 },
771};
772
773static struct hda_pcm_stream vt1708_pcm_digital_capture = {
774 .substreams = 1,
775 .channels_min = 2,
776 .channels_max = 2,
777};
778
779static int via_build_controls(struct hda_codec *codec)
780{
781 struct via_spec *spec = codec->spec;
782 int err;
783 int i;
784
785 for (i = 0; i < spec->num_mixers; i++) {
786 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
787 if (err < 0)
788 return err;
789 }
790
791 if (spec->multiout.dig_out_nid) {
792 err = snd_hda_create_spdif_out_ctls(codec,
793 spec->multiout.dig_out_nid);
794 if (err < 0)
795 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +0100796 err = snd_hda_create_spdif_share_sw(codec,
797 &spec->multiout);
798 if (err < 0)
799 return err;
800 spec->multiout.share_spdif = 1;
Harald Welte98aa34c2008-09-09 16:02:09 +0800801
802 if (spec->extra_dig_out_nid) {
803 err = snd_hda_create_spdif_out_ctls(codec,
804 spec->extra_dig_out_nid);
805 if (err < 0)
806 return err;
807 }
Joseph Chanc577b8a2006-11-29 15:29:40 +0100808 }
809 if (spec->dig_in_nid) {
810 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
811 if (err < 0)
812 return err;
813 }
814 return 0;
815}
816
817static int via_build_pcms(struct hda_codec *codec)
818{
819 struct via_spec *spec = codec->spec;
820 struct hda_pcm *info = spec->pcm_rec;
821
822 codec->num_pcms = 1;
823 codec->pcm_info = info;
824
825 info->name = spec->stream_name_analog;
826 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
827 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
828 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
829 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
830
831 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
832 spec->multiout.max_channels;
833
834 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
835 codec->num_pcms++;
836 info++;
837 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +0100838 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100839 if (spec->multiout.dig_out_nid) {
840 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
841 *(spec->stream_digital_playback);
842 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
843 spec->multiout.dig_out_nid;
844 }
845 if (spec->dig_in_nid) {
846 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
847 *(spec->stream_digital_capture);
848 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
849 spec->dig_in_nid;
850 }
851 }
852
853 return 0;
854}
855
856static void via_free(struct hda_codec *codec)
857{
858 struct via_spec *spec = codec->spec;
859 unsigned int i;
860
861 if (!spec)
862 return;
863
864 if (spec->kctl_alloc) {
865 for (i = 0; i < spec->num_kctl_used; i++)
866 kfree(spec->kctl_alloc[i].name);
867 kfree(spec->kctl_alloc);
868 }
869
870 kfree(codec->spec);
871}
872
Harald Welte69e52a82008-09-09 15:57:32 +0800873/* mute internal speaker if HP is plugged */
874static void via_hp_automute(struct hda_codec *codec)
875{
876 unsigned int present;
877 struct via_spec *spec = codec->spec;
878
879 present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
880 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
881 snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
882 HDA_OUTPUT, 0, HDA_AMP_MUTE,
883 present ? HDA_AMP_MUTE : 0);
884}
885
886static void via_gpio_control(struct hda_codec *codec)
887{
888 unsigned int gpio_data;
889 unsigned int vol_counter;
890 unsigned int vol;
891 unsigned int master_vol;
892
893 struct via_spec *spec = codec->spec;
894
895 gpio_data = snd_hda_codec_read(codec, codec->afg, 0,
896 AC_VERB_GET_GPIO_DATA, 0) & 0x03;
897
898 vol_counter = (snd_hda_codec_read(codec, codec->afg, 0,
899 0xF84, 0) & 0x3F0000) >> 16;
900
901 vol = vol_counter & 0x1F;
902 master_vol = snd_hda_codec_read(codec, 0x1A, 0,
903 AC_VERB_GET_AMP_GAIN_MUTE,
904 AC_AMP_GET_INPUT);
905
906 if (gpio_data == 0x02) {
907 /* unmute line out */
908 snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
909 HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
910
911 if (vol_counter & 0x20) {
912 /* decrease volume */
913 if (vol > master_vol)
914 vol = master_vol;
915 snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT,
916 0, HDA_AMP_VOLMASK,
917 master_vol-vol);
918 } else {
919 /* increase volume */
920 snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, 0,
921 HDA_AMP_VOLMASK,
922 ((master_vol+vol) > 0x2A) ? 0x2A :
923 (master_vol+vol));
924 }
925 } else if (!(gpio_data & 0x02)) {
926 /* mute line out */
927 snd_hda_codec_amp_stereo(codec,
928 spec->autocfg.line_out_pins[0],
929 HDA_OUTPUT, 0, HDA_AMP_MUTE,
930 HDA_AMP_MUTE);
931 }
932}
933
934/* unsolicited event for jack sensing */
935static void via_unsol_event(struct hda_codec *codec,
936 unsigned int res)
937{
938 res >>= 26;
939 if (res == VIA_HP_EVENT)
940 via_hp_automute(codec);
941 else if (res == VIA_GPIO_EVENT)
942 via_gpio_control(codec);
943}
944
Harald Welte5691ec72008-09-15 22:42:26 +0800945static hda_nid_t slave_dig_outs[] = {
946 0,
947};
948
Joseph Chanc577b8a2006-11-29 15:29:40 +0100949static int via_init(struct hda_codec *codec)
950{
951 struct via_spec *spec = codec->spec;
Harald Welte69e52a82008-09-09 15:57:32 +0800952 int i;
953 for (i = 0; i < spec->num_iverbs; i++)
954 snd_hda_sequence_write(codec, spec->init_verbs[i]);
955
Josepch Chanf7278fd2007-12-13 16:40:40 +0100956 /* Lydia Add for EAPD enable */
957 if (!spec->dig_in_nid) { /* No Digital In connection */
958 if (IS_VT1708_VENDORID(codec->vendor_id)) {
959 snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
960 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100961 PIN_OUT);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100962 snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
963 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
964 } else if (IS_VT1709_10CH_VENDORID(codec->vendor_id) ||
965 IS_VT1709_6CH_VENDORID(codec->vendor_id)) {
966 snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
967 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100968 PIN_OUT);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100969 snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
970 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
971 } else if (IS_VT1708B_8CH_VENDORID(codec->vendor_id) ||
972 IS_VT1708B_4CH_VENDORID(codec->vendor_id)) {
973 snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
974 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100975 PIN_OUT);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100976 snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
977 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
978 }
Takashi Iwai12b74c82008-01-15 12:39:38 +0100979 } else /* enable SPDIF-input pin */
980 snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
981 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
Josepch Chanf7278fd2007-12-13 16:40:40 +0100982
Harald Welte5691ec72008-09-15 22:42:26 +0800983 /* no slave outs */
984 codec->slave_dig_outs = slave_dig_outs;
985
Joseph Chanc577b8a2006-11-29 15:29:40 +0100986 return 0;
987}
988
Takashi Iwaicb53c622007-08-10 17:21:45 +0200989#ifdef CONFIG_SND_HDA_POWER_SAVE
990static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
991{
992 struct via_spec *spec = codec->spec;
993 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
994}
995#endif
996
Joseph Chanc577b8a2006-11-29 15:29:40 +0100997/*
998 */
999static struct hda_codec_ops via_patch_ops = {
1000 .build_controls = via_build_controls,
1001 .build_pcms = via_build_pcms,
1002 .init = via_init,
1003 .free = via_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02001004#ifdef CONFIG_SND_HDA_POWER_SAVE
1005 .check_power_status = via_check_power_status,
1006#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001007};
1008
1009/* fill in the dac_nids table from the parsed pin configuration */
1010static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
1011 const struct auto_pin_cfg *cfg)
1012{
1013 int i;
1014 hda_nid_t nid;
1015
1016 spec->multiout.num_dacs = cfg->line_outs;
1017
1018 spec->multiout.dac_nids = spec->private_dac_nids;
1019
1020 for(i = 0; i < 4; i++) {
1021 nid = cfg->line_out_pins[i];
1022 if (nid) {
1023 /* config dac list */
1024 switch (i) {
1025 case AUTO_SEQ_FRONT:
1026 spec->multiout.dac_nids[i] = 0x10;
1027 break;
1028 case AUTO_SEQ_CENLFE:
1029 spec->multiout.dac_nids[i] = 0x12;
1030 break;
1031 case AUTO_SEQ_SURROUND:
Harald Weltefb4cb772008-09-09 15:53:36 +08001032 spec->multiout.dac_nids[i] = 0x11;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001033 break;
1034 case AUTO_SEQ_SIDE:
Harald Weltefb4cb772008-09-09 15:53:36 +08001035 spec->multiout.dac_nids[i] = 0x13;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001036 break;
1037 }
1038 }
1039 }
1040
1041 return 0;
1042}
1043
1044/* add playback controls from the parsed DAC table */
1045static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
1046 const struct auto_pin_cfg *cfg)
1047{
1048 char name[32];
1049 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1050 hda_nid_t nid, nid_vol = 0;
1051 int i, err;
1052
1053 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1054 nid = cfg->line_out_pins[i];
1055
1056 if (!nid)
1057 continue;
1058
1059 if (i != AUTO_SEQ_FRONT)
Harald Weltefb4cb772008-09-09 15:53:36 +08001060 nid_vol = 0x18 + i;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001061
1062 if (i == AUTO_SEQ_CENLFE) {
1063 /* Center/LFE */
1064 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001065 "Center Playback Volume",
1066 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1067 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001068 if (err < 0)
1069 return err;
1070 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1071 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001072 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1073 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001074 if (err < 0)
1075 return err;
1076 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1077 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001078 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1079 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001080 if (err < 0)
1081 return err;
1082 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1083 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001084 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1085 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001086 if (err < 0)
1087 return err;
1088 } else if (i == AUTO_SEQ_FRONT){
1089 /* add control to mixer index 0 */
1090 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1091 "Master Front Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001092 HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
1093 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001094 if (err < 0)
1095 return err;
1096 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1097 "Master Front Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001098 HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
1099 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001100 if (err < 0)
1101 return err;
1102
1103 /* add control to PW3 */
1104 sprintf(name, "%s Playback Volume", chname[i]);
1105 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001106 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1107 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001108 if (err < 0)
1109 return err;
1110 sprintf(name, "%s Playback Switch", chname[i]);
1111 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001112 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1113 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001114 if (err < 0)
1115 return err;
1116 } else {
1117 sprintf(name, "%s Playback Volume", chname[i]);
1118 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001119 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1120 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001121 if (err < 0)
1122 return err;
1123 sprintf(name, "%s Playback Switch", chname[i]);
1124 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001125 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1126 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001127 if (err < 0)
1128 return err;
1129 }
1130 }
1131
1132 return 0;
1133}
1134
Harald Welte0aa62ae2008-09-09 15:58:27 +08001135static void create_hp_imux(struct via_spec *spec)
1136{
1137 int i;
1138 struct hda_input_mux *imux = &spec->private_imux[1];
1139 static const char *texts[] = { "OFF", "ON", NULL};
1140
1141 /* for hp mode select */
1142 i = 0;
1143 while (texts[i] != NULL) {
1144 imux->items[imux->num_items].label = texts[i];
1145 imux->items[imux->num_items].index = i;
1146 imux->num_items++;
1147 i++;
1148 }
1149
1150 spec->hp_mux = &spec->private_imux[1];
1151}
1152
Joseph Chanc577b8a2006-11-29 15:29:40 +01001153static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1154{
1155 int err;
1156
1157 if (!pin)
1158 return 0;
1159
1160 spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
1161
1162 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1163 "Headphone Playback Volume",
1164 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1165 if (err < 0)
1166 return err;
1167 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1168 "Headphone Playback Switch",
1169 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1170 if (err < 0)
1171 return err;
1172
Harald Welte0aa62ae2008-09-09 15:58:27 +08001173 create_hp_imux(spec);
1174
Joseph Chanc577b8a2006-11-29 15:29:40 +01001175 return 0;
1176}
1177
1178/* create playback/capture controls for input pins */
1179static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
1180 const struct auto_pin_cfg *cfg)
1181{
1182 static char *labels[] = {
1183 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1184 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08001185 struct hda_input_mux *imux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01001186 int i, err, idx = 0;
1187
1188 /* for internal loopback recording select */
1189 imux->items[imux->num_items].label = "Stereo Mixer";
1190 imux->items[imux->num_items].index = idx;
1191 imux->num_items++;
1192
1193 for (i = 0; i < AUTO_PIN_LAST; i++) {
1194 if (!cfg->input_pins[i])
1195 continue;
1196
1197 switch (cfg->input_pins[i]) {
1198 case 0x1d: /* Mic */
1199 idx = 2;
1200 break;
1201
1202 case 0x1e: /* Line In */
1203 idx = 3;
1204 break;
1205
1206 case 0x21: /* Front Mic */
1207 idx = 4;
1208 break;
1209
1210 case 0x24: /* CD */
1211 idx = 1;
1212 break;
1213 }
1214 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
1215 idx, 0x17);
1216 if (err < 0)
1217 return err;
1218 imux->items[imux->num_items].label = labels[i];
1219 imux->items[imux->num_items].index = idx;
1220 imux->num_items++;
1221 }
1222 return 0;
1223}
1224
Takashi Iwaicb53c622007-08-10 17:21:45 +02001225#ifdef CONFIG_SND_HDA_POWER_SAVE
1226static struct hda_amp_list vt1708_loopbacks[] = {
1227 { 0x17, HDA_INPUT, 1 },
1228 { 0x17, HDA_INPUT, 2 },
1229 { 0x17, HDA_INPUT, 3 },
1230 { 0x17, HDA_INPUT, 4 },
1231 { } /* end */
1232};
1233#endif
1234
Harald Welte76d9b0d2008-09-09 15:50:37 +08001235static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
1236{
1237 unsigned int def_conf;
1238 unsigned char seqassoc;
1239
1240 def_conf = snd_hda_codec_read(codec, nid, 0,
1241 AC_VERB_GET_CONFIG_DEFAULT, 0);
1242 seqassoc = (unsigned char) get_defcfg_association(def_conf);
1243 seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
1244 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) {
1245 if (seqassoc == 0xff) {
1246 def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
1247 snd_hda_codec_write(codec, nid, 0,
1248 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1249 def_conf >> 24);
1250 }
1251 }
1252
1253 return;
1254}
1255
Joseph Chanc577b8a2006-11-29 15:29:40 +01001256static int vt1708_parse_auto_config(struct hda_codec *codec)
1257{
1258 struct via_spec *spec = codec->spec;
1259 int err;
1260
Harald Welte76d9b0d2008-09-09 15:50:37 +08001261 /* Add HP and CD pin config connect bit re-config action */
1262 vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
1263 vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
1264
Joseph Chanc577b8a2006-11-29 15:29:40 +01001265 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1266 if (err < 0)
1267 return err;
1268 err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
1269 if (err < 0)
1270 return err;
1271 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1272 return 0; /* can't find valid BIOS pin config */
1273
1274 err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
1275 if (err < 0)
1276 return err;
1277 err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1278 if (err < 0)
1279 return err;
1280 err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
1281 if (err < 0)
1282 return err;
1283
1284 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1285
1286 if (spec->autocfg.dig_out_pin)
1287 spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
1288 if (spec->autocfg.dig_in_pin)
1289 spec->dig_in_nid = VT1708_DIGIN_NID;
1290
1291 if (spec->kctl_alloc)
1292 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
1293
Harald Welte69e52a82008-09-09 15:57:32 +08001294 spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001295
Harald Welte0aa62ae2008-09-09 15:58:27 +08001296 spec->input_mux = &spec->private_imux[0];
1297
Harald Weltef8fdd492008-09-15 22:41:31 +08001298 if (spec->hp_mux)
1299 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001300
1301 return 1;
1302}
1303
1304/* init callback for auto-configuration model -- overriding the default init */
1305static int via_auto_init(struct hda_codec *codec)
1306{
1307 via_init(codec);
1308 via_auto_init_multi_out(codec);
1309 via_auto_init_hp_out(codec);
1310 via_auto_init_analog_input(codec);
1311 return 0;
1312}
1313
1314static int patch_vt1708(struct hda_codec *codec)
1315{
1316 struct via_spec *spec;
1317 int err;
1318
1319 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08001320 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001321 if (spec == NULL)
1322 return -ENOMEM;
1323
1324 codec->spec = spec;
1325
1326 /* automatic parse from the BIOS config */
1327 err = vt1708_parse_auto_config(codec);
1328 if (err < 0) {
1329 via_free(codec);
1330 return err;
1331 } else if (!err) {
1332 printk(KERN_INFO "hda_codec: Cannot set up configuration "
1333 "from BIOS. Using genenic mode...\n");
1334 }
1335
1336
1337 spec->stream_name_analog = "VT1708 Analog";
1338 spec->stream_analog_playback = &vt1708_pcm_analog_playback;
Takashi Iwaibc9b5622008-05-23 17:50:27 +02001339 /* disable 32bit format on VT1708 */
1340 if (codec->vendor_id == 0x11061708)
1341 spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001342 spec->stream_analog_capture = &vt1708_pcm_analog_capture;
1343
1344 spec->stream_name_digital = "VT1708 Digital";
1345 spec->stream_digital_playback = &vt1708_pcm_digital_playback;
1346 spec->stream_digital_capture = &vt1708_pcm_digital_capture;
1347
1348
1349 if (!spec->adc_nids && spec->input_mux) {
1350 spec->adc_nids = vt1708_adc_nids;
1351 spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
1352 spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
1353 spec->num_mixers++;
1354 }
1355
1356 codec->patch_ops = via_patch_ops;
1357
1358 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001359#ifdef CONFIG_SND_HDA_POWER_SAVE
1360 spec->loopback.amplist = vt1708_loopbacks;
1361#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001362
1363 return 0;
1364}
1365
1366/* capture mixer elements */
1367static struct snd_kcontrol_new vt1709_capture_mixer[] = {
1368 HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
1369 HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
1370 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
1371 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
1372 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
1373 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
1374 {
1375 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1376 /* The multiple "Capture Source" controls confuse alsamixer
1377 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +01001378 */
1379 /* .name = "Capture Source", */
1380 .name = "Input Source",
1381 .count = 1,
1382 .info = via_mux_enum_info,
1383 .get = via_mux_enum_get,
1384 .put = via_mux_enum_put,
1385 },
1386 { } /* end */
1387};
1388
Harald Welte69e52a82008-09-09 15:57:32 +08001389static struct hda_verb vt1709_uniwill_init_verbs[] = {
1390 {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
1391 { }
1392};
1393
Joseph Chanc577b8a2006-11-29 15:29:40 +01001394/*
1395 * generic initialization of ADC, input mixers and output mixers
1396 */
1397static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
1398 /*
1399 * Unmute ADC0-2 and set the default input to mic-in
1400 */
1401 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1402 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1403 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1404
1405
Josepch Chanf7278fd2007-12-13 16:40:40 +01001406 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +01001407 * mixer widget
1408 */
1409 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +01001410 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1411 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1412 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1413 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1414 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001415
1416 /*
1417 * Set up output selector (0x1a, 0x1b, 0x29)
1418 */
1419 /* set vol=0 to output mixers */
1420 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1421 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1422 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1423
1424 /*
1425 * Unmute PW3 and PW4
1426 */
1427 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1428 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1429
1430 /* Set input of PW4 as AOW4 */
1431 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001432 /* PW9 Output enable */
1433 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1434 { }
1435};
1436
1437static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
1438 .substreams = 1,
1439 .channels_min = 2,
1440 .channels_max = 10,
1441 .nid = 0x10, /* NID to query formats and rates */
1442 .ops = {
1443 .open = via_playback_pcm_open,
1444 .prepare = via_playback_pcm_prepare,
1445 .cleanup = via_playback_pcm_cleanup
1446 },
1447};
1448
1449static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
1450 .substreams = 1,
1451 .channels_min = 2,
1452 .channels_max = 6,
1453 .nid = 0x10, /* NID to query formats and rates */
1454 .ops = {
1455 .open = via_playback_pcm_open,
1456 .prepare = via_playback_pcm_prepare,
1457 .cleanup = via_playback_pcm_cleanup
1458 },
1459};
1460
1461static struct hda_pcm_stream vt1709_pcm_analog_capture = {
1462 .substreams = 2,
1463 .channels_min = 2,
1464 .channels_max = 2,
1465 .nid = 0x14, /* NID to query formats and rates */
1466 .ops = {
1467 .prepare = via_capture_pcm_prepare,
1468 .cleanup = via_capture_pcm_cleanup
1469 },
1470};
1471
1472static struct hda_pcm_stream vt1709_pcm_digital_playback = {
1473 .substreams = 1,
1474 .channels_min = 2,
1475 .channels_max = 2,
1476 /* NID is set in via_build_pcms */
1477 .ops = {
1478 .open = via_dig_playback_pcm_open,
1479 .close = via_dig_playback_pcm_close
1480 },
1481};
1482
1483static struct hda_pcm_stream vt1709_pcm_digital_capture = {
1484 .substreams = 1,
1485 .channels_min = 2,
1486 .channels_max = 2,
1487};
1488
1489static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
1490 const struct auto_pin_cfg *cfg)
1491{
1492 int i;
1493 hda_nid_t nid;
1494
1495 if (cfg->line_outs == 4) /* 10 channels */
1496 spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
1497 else if (cfg->line_outs == 3) /* 6 channels */
1498 spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
1499
1500 spec->multiout.dac_nids = spec->private_dac_nids;
1501
1502 if (cfg->line_outs == 4) { /* 10 channels */
1503 for (i = 0; i < cfg->line_outs; i++) {
1504 nid = cfg->line_out_pins[i];
1505 if (nid) {
1506 /* config dac list */
1507 switch (i) {
1508 case AUTO_SEQ_FRONT:
1509 /* AOW0 */
1510 spec->multiout.dac_nids[i] = 0x10;
1511 break;
1512 case AUTO_SEQ_CENLFE:
1513 /* AOW2 */
1514 spec->multiout.dac_nids[i] = 0x12;
1515 break;
1516 case AUTO_SEQ_SURROUND:
1517 /* AOW3 */
Harald Weltefb4cb772008-09-09 15:53:36 +08001518 spec->multiout.dac_nids[i] = 0x11;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001519 break;
1520 case AUTO_SEQ_SIDE:
1521 /* AOW1 */
Harald Weltefb4cb772008-09-09 15:53:36 +08001522 spec->multiout.dac_nids[i] = 0x27;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001523 break;
1524 default:
1525 break;
1526 }
1527 }
1528 }
1529 spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
1530
1531 } else if (cfg->line_outs == 3) { /* 6 channels */
1532 for(i = 0; i < cfg->line_outs; i++) {
1533 nid = cfg->line_out_pins[i];
1534 if (nid) {
1535 /* config dac list */
1536 switch(i) {
1537 case AUTO_SEQ_FRONT:
1538 /* AOW0 */
1539 spec->multiout.dac_nids[i] = 0x10;
1540 break;
1541 case AUTO_SEQ_CENLFE:
1542 /* AOW2 */
1543 spec->multiout.dac_nids[i] = 0x12;
1544 break;
1545 case AUTO_SEQ_SURROUND:
1546 /* AOW1 */
1547 spec->multiout.dac_nids[i] = 0x11;
1548 break;
1549 default:
1550 break;
1551 }
1552 }
1553 }
1554 }
1555
1556 return 0;
1557}
1558
1559/* add playback controls from the parsed DAC table */
1560static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
1561 const struct auto_pin_cfg *cfg)
1562{
1563 char name[32];
1564 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1565 hda_nid_t nid = 0;
1566 int i, err;
1567
1568 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1569 nid = cfg->line_out_pins[i];
1570
1571 if (!nid)
1572 continue;
1573
1574 if (i == AUTO_SEQ_CENLFE) {
1575 /* Center/LFE */
1576 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1577 "Center Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001578 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
1579 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001580 if (err < 0)
1581 return err;
1582 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1583 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001584 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
1585 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001586 if (err < 0)
1587 return err;
1588 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1589 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001590 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
1591 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001592 if (err < 0)
1593 return err;
1594 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1595 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001596 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
1597 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001598 if (err < 0)
1599 return err;
1600 } else if (i == AUTO_SEQ_FRONT){
1601 /* add control to mixer index 0 */
1602 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1603 "Master Front Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001604 HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
1605 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001606 if (err < 0)
1607 return err;
1608 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1609 "Master Front Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001610 HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
1611 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001612 if (err < 0)
1613 return err;
1614
1615 /* add control to PW3 */
1616 sprintf(name, "%s Playback Volume", chname[i]);
1617 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001618 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1619 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001620 if (err < 0)
1621 return err;
1622 sprintf(name, "%s Playback Switch", chname[i]);
1623 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001624 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1625 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001626 if (err < 0)
1627 return err;
1628 } else if (i == AUTO_SEQ_SURROUND) {
1629 sprintf(name, "%s Playback Volume", chname[i]);
1630 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001631 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001632 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001633 if (err < 0)
1634 return err;
1635 sprintf(name, "%s Playback Switch", chname[i]);
1636 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001637 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001638 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001639 if (err < 0)
1640 return err;
1641 } else if (i == AUTO_SEQ_SIDE) {
1642 sprintf(name, "%s Playback Volume", chname[i]);
1643 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001644 HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001645 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001646 if (err < 0)
1647 return err;
1648 sprintf(name, "%s Playback Switch", chname[i]);
1649 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001650 HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001651 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001652 if (err < 0)
1653 return err;
1654 }
1655 }
1656
1657 return 0;
1658}
1659
1660static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1661{
1662 int err;
1663
1664 if (!pin)
1665 return 0;
1666
1667 if (spec->multiout.num_dacs == 5) /* 10 channels */
1668 spec->multiout.hp_nid = VT1709_HP_DAC_NID;
1669 else if (spec->multiout.num_dacs == 3) /* 6 channels */
1670 spec->multiout.hp_nid = 0;
1671
1672 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1673 "Headphone Playback Volume",
1674 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1675 if (err < 0)
1676 return err;
1677 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1678 "Headphone Playback Switch",
1679 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1680 if (err < 0)
1681 return err;
1682
1683 return 0;
1684}
1685
1686/* create playback/capture controls for input pins */
1687static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
1688 const struct auto_pin_cfg *cfg)
1689{
1690 static char *labels[] = {
1691 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1692 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08001693 struct hda_input_mux *imux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01001694 int i, err, idx = 0;
1695
1696 /* for internal loopback recording select */
1697 imux->items[imux->num_items].label = "Stereo Mixer";
1698 imux->items[imux->num_items].index = idx;
1699 imux->num_items++;
1700
1701 for (i = 0; i < AUTO_PIN_LAST; i++) {
1702 if (!cfg->input_pins[i])
1703 continue;
1704
1705 switch (cfg->input_pins[i]) {
1706 case 0x1d: /* Mic */
1707 idx = 2;
1708 break;
1709
1710 case 0x1e: /* Line In */
1711 idx = 3;
1712 break;
1713
1714 case 0x21: /* Front Mic */
1715 idx = 4;
1716 break;
1717
1718 case 0x23: /* CD */
1719 idx = 1;
1720 break;
1721 }
1722 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
1723 idx, 0x18);
1724 if (err < 0)
1725 return err;
1726 imux->items[imux->num_items].label = labels[i];
1727 imux->items[imux->num_items].index = idx;
1728 imux->num_items++;
1729 }
1730 return 0;
1731}
1732
1733static int vt1709_parse_auto_config(struct hda_codec *codec)
1734{
1735 struct via_spec *spec = codec->spec;
1736 int err;
1737
1738 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1739 if (err < 0)
1740 return err;
1741 err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
1742 if (err < 0)
1743 return err;
1744 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1745 return 0; /* can't find valid BIOS pin config */
1746
1747 err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
1748 if (err < 0)
1749 return err;
1750 err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1751 if (err < 0)
1752 return err;
1753 err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
1754 if (err < 0)
1755 return err;
1756
1757 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1758
1759 if (spec->autocfg.dig_out_pin)
1760 spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
1761 if (spec->autocfg.dig_in_pin)
1762 spec->dig_in_nid = VT1709_DIGIN_NID;
1763
1764 if (spec->kctl_alloc)
1765 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
1766
Harald Welte0aa62ae2008-09-09 15:58:27 +08001767 spec->input_mux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01001768
Harald Weltef8fdd492008-09-15 22:41:31 +08001769 if (spec->hp_mux)
1770 spec->mixers[spec->num_mixers++] = via_hp_mixer;
1771
Joseph Chanc577b8a2006-11-29 15:29:40 +01001772 return 1;
1773}
1774
Takashi Iwaicb53c622007-08-10 17:21:45 +02001775#ifdef CONFIG_SND_HDA_POWER_SAVE
1776static struct hda_amp_list vt1709_loopbacks[] = {
1777 { 0x18, HDA_INPUT, 1 },
1778 { 0x18, HDA_INPUT, 2 },
1779 { 0x18, HDA_INPUT, 3 },
1780 { 0x18, HDA_INPUT, 4 },
1781 { } /* end */
1782};
1783#endif
1784
Joseph Chanc577b8a2006-11-29 15:29:40 +01001785static int patch_vt1709_10ch(struct hda_codec *codec)
1786{
1787 struct via_spec *spec;
1788 int err;
1789
1790 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08001791 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001792 if (spec == NULL)
1793 return -ENOMEM;
1794
1795 codec->spec = spec;
1796
1797 err = vt1709_parse_auto_config(codec);
1798 if (err < 0) {
1799 via_free(codec);
1800 return err;
1801 } else if (!err) {
1802 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
1803 "Using genenic mode...\n");
1804 }
1805
Harald Welte69e52a82008-09-09 15:57:32 +08001806 spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs;
1807 spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001808
1809 spec->stream_name_analog = "VT1709 Analog";
1810 spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
1811 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1812
1813 spec->stream_name_digital = "VT1709 Digital";
1814 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1815 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1816
1817
1818 if (!spec->adc_nids && spec->input_mux) {
1819 spec->adc_nids = vt1709_adc_nids;
1820 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
1821 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1822 spec->num_mixers++;
1823 }
1824
1825 codec->patch_ops = via_patch_ops;
1826
1827 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08001828 codec->patch_ops.unsol_event = via_unsol_event;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001829#ifdef CONFIG_SND_HDA_POWER_SAVE
1830 spec->loopback.amplist = vt1709_loopbacks;
1831#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001832
1833 return 0;
1834}
1835/*
1836 * generic initialization of ADC, input mixers and output mixers
1837 */
1838static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
1839 /*
1840 * Unmute ADC0-2 and set the default input to mic-in
1841 */
1842 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1843 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1844 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1845
1846
1847 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1848 * mixer widget
1849 */
1850 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1851 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1852 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1853 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1854 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1855 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1856
1857 /*
1858 * Set up output selector (0x1a, 0x1b, 0x29)
1859 */
1860 /* set vol=0 to output mixers */
1861 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1862 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1863 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1864
1865 /*
1866 * Unmute PW3 and PW4
1867 */
1868 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1869 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1870
1871 /* Set input of PW4 as MW0 */
1872 {0x20, AC_VERB_SET_CONNECT_SEL, 0},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001873 /* PW9 Output enable */
1874 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1875 { }
1876};
1877
1878static int patch_vt1709_6ch(struct hda_codec *codec)
1879{
1880 struct via_spec *spec;
1881 int err;
1882
1883 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08001884 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001885 if (spec == NULL)
1886 return -ENOMEM;
1887
1888 codec->spec = spec;
1889
1890 err = vt1709_parse_auto_config(codec);
1891 if (err < 0) {
1892 via_free(codec);
1893 return err;
1894 } else if (!err) {
1895 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
1896 "Using genenic mode...\n");
1897 }
1898
Harald Welte69e52a82008-09-09 15:57:32 +08001899 spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs;
1900 spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001901
1902 spec->stream_name_analog = "VT1709 Analog";
1903 spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
1904 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1905
1906 spec->stream_name_digital = "VT1709 Digital";
1907 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1908 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1909
1910
1911 if (!spec->adc_nids && spec->input_mux) {
1912 spec->adc_nids = vt1709_adc_nids;
1913 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
1914 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1915 spec->num_mixers++;
1916 }
1917
1918 codec->patch_ops = via_patch_ops;
1919
1920 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08001921 codec->patch_ops.unsol_event = via_unsol_event;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001922#ifdef CONFIG_SND_HDA_POWER_SAVE
1923 spec->loopback.amplist = vt1709_loopbacks;
1924#endif
Josepch Chanf7278fd2007-12-13 16:40:40 +01001925 return 0;
1926}
1927
1928/* capture mixer elements */
1929static struct snd_kcontrol_new vt1708B_capture_mixer[] = {
1930 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
1931 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
1932 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
1933 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
1934 {
1935 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1936 /* The multiple "Capture Source" controls confuse alsamixer
1937 * So call somewhat different..
Josepch Chanf7278fd2007-12-13 16:40:40 +01001938 */
1939 /* .name = "Capture Source", */
1940 .name = "Input Source",
1941 .count = 1,
1942 .info = via_mux_enum_info,
1943 .get = via_mux_enum_get,
1944 .put = via_mux_enum_put,
1945 },
1946 { } /* end */
1947};
1948/*
1949 * generic initialization of ADC, input mixers and output mixers
1950 */
1951static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
1952 /*
1953 * Unmute ADC0-1 and set the default input to mic-in
1954 */
1955 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1956 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1957
1958
1959 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1960 * mixer widget
1961 */
1962 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1963 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1964 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1965 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1966 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1967 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1968
1969 /*
1970 * Set up output mixers
1971 */
1972 /* set vol=0 to output mixers */
1973 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1974 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1975 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1976
1977 /* Setup default input to PW4 */
1978 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1},
1979 /* PW9 Output enable */
1980 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1981 /* PW10 Input enable */
1982 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
1983 { }
1984};
1985
1986static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
1987 /*
1988 * Unmute ADC0-1 and set the default input to mic-in
1989 */
1990 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1991 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1992
1993
1994 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1995 * mixer widget
1996 */
1997 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1998 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1999 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2000 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2001 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2002 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2003
2004 /*
2005 * Set up output mixers
2006 */
2007 /* set vol=0 to output mixers */
2008 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2009 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2010 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2011
2012 /* Setup default input of PW4 to MW0 */
2013 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
2014 /* PW9 Output enable */
2015 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2016 /* PW10 Input enable */
2017 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
2018 { }
2019};
2020
Harald Welte69e52a82008-09-09 15:57:32 +08002021static struct hda_verb vt1708B_uniwill_init_verbs[] = {
2022 {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
2023 { }
2024};
2025
Josepch Chanf7278fd2007-12-13 16:40:40 +01002026static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08002027 .substreams = 2,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002028 .channels_min = 2,
2029 .channels_max = 8,
2030 .nid = 0x10, /* NID to query formats and rates */
2031 .ops = {
2032 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08002033 .prepare = via_playback_multi_pcm_prepare,
2034 .cleanup = via_playback_multi_pcm_cleanup
Josepch Chanf7278fd2007-12-13 16:40:40 +01002035 },
2036};
2037
2038static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08002039 .substreams = 2,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002040 .channels_min = 2,
2041 .channels_max = 4,
2042 .nid = 0x10, /* NID to query formats and rates */
2043 .ops = {
2044 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08002045 .prepare = via_playback_multi_pcm_prepare,
2046 .cleanup = via_playback_multi_pcm_cleanup
Josepch Chanf7278fd2007-12-13 16:40:40 +01002047 },
2048};
2049
2050static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
2051 .substreams = 2,
2052 .channels_min = 2,
2053 .channels_max = 2,
2054 .nid = 0x13, /* NID to query formats and rates */
2055 .ops = {
2056 .prepare = via_capture_pcm_prepare,
2057 .cleanup = via_capture_pcm_cleanup
2058 },
2059};
2060
2061static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
2062 .substreams = 1,
2063 .channels_min = 2,
2064 .channels_max = 2,
2065 /* NID is set in via_build_pcms */
2066 .ops = {
2067 .open = via_dig_playback_pcm_open,
2068 .close = via_dig_playback_pcm_close,
2069 .prepare = via_dig_playback_pcm_prepare
2070 },
2071};
2072
2073static struct hda_pcm_stream vt1708B_pcm_digital_capture = {
2074 .substreams = 1,
2075 .channels_min = 2,
2076 .channels_max = 2,
2077};
2078
2079/* fill in the dac_nids table from the parsed pin configuration */
2080static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
2081 const struct auto_pin_cfg *cfg)
2082{
2083 int i;
2084 hda_nid_t nid;
2085
2086 spec->multiout.num_dacs = cfg->line_outs;
2087
2088 spec->multiout.dac_nids = spec->private_dac_nids;
2089
2090 for (i = 0; i < 4; i++) {
2091 nid = cfg->line_out_pins[i];
2092 if (nid) {
2093 /* config dac list */
2094 switch (i) {
2095 case AUTO_SEQ_FRONT:
2096 spec->multiout.dac_nids[i] = 0x10;
2097 break;
2098 case AUTO_SEQ_CENLFE:
2099 spec->multiout.dac_nids[i] = 0x24;
2100 break;
2101 case AUTO_SEQ_SURROUND:
Harald Weltefb4cb772008-09-09 15:53:36 +08002102 spec->multiout.dac_nids[i] = 0x11;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002103 break;
2104 case AUTO_SEQ_SIDE:
Harald Weltefb4cb772008-09-09 15:53:36 +08002105 spec->multiout.dac_nids[i] = 0x25;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002106 break;
2107 }
2108 }
2109 }
2110
2111 return 0;
2112}
2113
2114/* add playback controls from the parsed DAC table */
2115static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
2116 const struct auto_pin_cfg *cfg)
2117{
2118 char name[32];
2119 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
Harald Weltefb4cb772008-09-09 15:53:36 +08002120 hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27};
Josepch Chanf7278fd2007-12-13 16:40:40 +01002121 hda_nid_t nid, nid_vol = 0;
2122 int i, err;
2123
2124 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2125 nid = cfg->line_out_pins[i];
2126
2127 if (!nid)
2128 continue;
2129
2130 nid_vol = nid_vols[i];
2131
2132 if (i == AUTO_SEQ_CENLFE) {
2133 /* Center/LFE */
2134 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2135 "Center Playback Volume",
2136 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2137 HDA_OUTPUT));
2138 if (err < 0)
2139 return err;
2140 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2141 "LFE Playback Volume",
2142 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2143 HDA_OUTPUT));
2144 if (err < 0)
2145 return err;
2146 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2147 "Center Playback Switch",
2148 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2149 HDA_OUTPUT));
2150 if (err < 0)
2151 return err;
2152 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2153 "LFE Playback Switch",
2154 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2155 HDA_OUTPUT));
2156 if (err < 0)
2157 return err;
2158 } else if (i == AUTO_SEQ_FRONT) {
2159 /* add control to mixer index 0 */
2160 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2161 "Master Front Playback Volume",
2162 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2163 HDA_INPUT));
2164 if (err < 0)
2165 return err;
2166 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2167 "Master Front Playback Switch",
2168 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2169 HDA_INPUT));
2170 if (err < 0)
2171 return err;
2172
2173 /* add control to PW3 */
2174 sprintf(name, "%s Playback Volume", chname[i]);
2175 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2176 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2177 HDA_OUTPUT));
2178 if (err < 0)
2179 return err;
2180 sprintf(name, "%s Playback Switch", chname[i]);
2181 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2182 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2183 HDA_OUTPUT));
2184 if (err < 0)
2185 return err;
2186 } else {
2187 sprintf(name, "%s Playback Volume", chname[i]);
2188 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2189 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2190 HDA_OUTPUT));
2191 if (err < 0)
2192 return err;
2193 sprintf(name, "%s Playback Switch", chname[i]);
2194 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2195 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2196 HDA_OUTPUT));
2197 if (err < 0)
2198 return err;
2199 }
2200 }
2201
2202 return 0;
2203}
2204
2205static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2206{
2207 int err;
2208
2209 if (!pin)
2210 return 0;
2211
2212 spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
2213
2214 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2215 "Headphone Playback Volume",
2216 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2217 if (err < 0)
2218 return err;
2219 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2220 "Headphone Playback Switch",
2221 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2222 if (err < 0)
2223 return err;
2224
Harald Welte0aa62ae2008-09-09 15:58:27 +08002225 create_hp_imux(spec);
2226
Josepch Chanf7278fd2007-12-13 16:40:40 +01002227 return 0;
2228}
2229
2230/* create playback/capture controls for input pins */
2231static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
2232 const struct auto_pin_cfg *cfg)
2233{
2234 static char *labels[] = {
2235 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2236 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08002237 struct hda_input_mux *imux = &spec->private_imux[0];
Josepch Chanf7278fd2007-12-13 16:40:40 +01002238 int i, err, idx = 0;
2239
2240 /* for internal loopback recording select */
2241 imux->items[imux->num_items].label = "Stereo Mixer";
2242 imux->items[imux->num_items].index = idx;
2243 imux->num_items++;
2244
2245 for (i = 0; i < AUTO_PIN_LAST; i++) {
2246 if (!cfg->input_pins[i])
2247 continue;
2248
2249 switch (cfg->input_pins[i]) {
2250 case 0x1a: /* Mic */
2251 idx = 2;
2252 break;
2253
2254 case 0x1b: /* Line In */
2255 idx = 3;
2256 break;
2257
2258 case 0x1e: /* Front Mic */
2259 idx = 4;
2260 break;
2261
2262 case 0x1f: /* CD */
2263 idx = 1;
2264 break;
2265 }
2266 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
2267 idx, 0x16);
2268 if (err < 0)
2269 return err;
2270 imux->items[imux->num_items].label = labels[i];
2271 imux->items[imux->num_items].index = idx;
2272 imux->num_items++;
2273 }
2274 return 0;
2275}
2276
2277static int vt1708B_parse_auto_config(struct hda_codec *codec)
2278{
2279 struct via_spec *spec = codec->spec;
2280 int err;
2281
2282 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
2283 if (err < 0)
2284 return err;
2285 err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg);
2286 if (err < 0)
2287 return err;
2288 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2289 return 0; /* can't find valid BIOS pin config */
2290
2291 err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg);
2292 if (err < 0)
2293 return err;
2294 err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2295 if (err < 0)
2296 return err;
2297 err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
2298 if (err < 0)
2299 return err;
2300
2301 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2302
2303 if (spec->autocfg.dig_out_pin)
2304 spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
2305 if (spec->autocfg.dig_in_pin)
2306 spec->dig_in_nid = VT1708B_DIGIN_NID;
2307
2308 if (spec->kctl_alloc)
2309 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2310
Harald Welte0aa62ae2008-09-09 15:58:27 +08002311 spec->input_mux = &spec->private_imux[0];
2312
Harald Weltef8fdd492008-09-15 22:41:31 +08002313 if (spec->hp_mux)
2314 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002315
2316 return 1;
2317}
2318
2319#ifdef CONFIG_SND_HDA_POWER_SAVE
2320static struct hda_amp_list vt1708B_loopbacks[] = {
2321 { 0x16, HDA_INPUT, 1 },
2322 { 0x16, HDA_INPUT, 2 },
2323 { 0x16, HDA_INPUT, 3 },
2324 { 0x16, HDA_INPUT, 4 },
2325 { } /* end */
2326};
2327#endif
2328
2329static int patch_vt1708B_8ch(struct hda_codec *codec)
2330{
2331 struct via_spec *spec;
2332 int err;
2333
2334 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08002335 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002336 if (spec == NULL)
2337 return -ENOMEM;
2338
2339 codec->spec = spec;
2340
2341 /* automatic parse from the BIOS config */
2342 err = vt1708B_parse_auto_config(codec);
2343 if (err < 0) {
2344 via_free(codec);
2345 return err;
2346 } else if (!err) {
2347 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2348 "from BIOS. Using genenic mode...\n");
2349 }
2350
Harald Welte69e52a82008-09-09 15:57:32 +08002351 spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs;
2352 spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002353
2354 spec->stream_name_analog = "VT1708B Analog";
2355 spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
2356 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
2357
2358 spec->stream_name_digital = "VT1708B Digital";
2359 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
2360 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
2361
2362 if (!spec->adc_nids && spec->input_mux) {
2363 spec->adc_nids = vt1708B_adc_nids;
2364 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
2365 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
2366 spec->num_mixers++;
2367 }
2368
2369 codec->patch_ops = via_patch_ops;
2370
2371 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08002372 codec->patch_ops.unsol_event = via_unsol_event;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002373#ifdef CONFIG_SND_HDA_POWER_SAVE
2374 spec->loopback.amplist = vt1708B_loopbacks;
2375#endif
2376
2377 return 0;
2378}
2379
2380static int patch_vt1708B_4ch(struct hda_codec *codec)
2381{
2382 struct via_spec *spec;
2383 int err;
2384
2385 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08002386 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002387 if (spec == NULL)
2388 return -ENOMEM;
2389
2390 codec->spec = spec;
2391
2392 /* automatic parse from the BIOS config */
2393 err = vt1708B_parse_auto_config(codec);
2394 if (err < 0) {
2395 via_free(codec);
2396 return err;
2397 } else if (!err) {
2398 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2399 "from BIOS. Using genenic mode...\n");
2400 }
2401
Harald Welte69e52a82008-09-09 15:57:32 +08002402 spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs;
2403 spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002404
2405 spec->stream_name_analog = "VT1708B Analog";
2406 spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
2407 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
2408
2409 spec->stream_name_digital = "VT1708B Digital";
2410 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
2411 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
2412
2413 if (!spec->adc_nids && spec->input_mux) {
2414 spec->adc_nids = vt1708B_adc_nids;
2415 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
2416 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
2417 spec->num_mixers++;
2418 }
2419
2420 codec->patch_ops = via_patch_ops;
2421
2422 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08002423 codec->patch_ops.unsol_event = via_unsol_event;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002424#ifdef CONFIG_SND_HDA_POWER_SAVE
2425 spec->loopback.amplist = vt1708B_loopbacks;
2426#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01002427
2428 return 0;
2429}
2430
Harald Welted949cac2008-09-09 15:56:01 +08002431/* Patch for VT1708S */
2432
2433/* capture mixer elements */
2434static struct snd_kcontrol_new vt1708S_capture_mixer[] = {
2435 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
2436 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
2437 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
2438 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
2439 HDA_CODEC_VOLUME("Mic Boost", 0x1A, 0x0, HDA_INPUT),
2440 HDA_CODEC_VOLUME("Front Mic Boost", 0x1E, 0x0, HDA_INPUT),
2441 {
2442 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2443 /* The multiple "Capture Source" controls confuse alsamixer
2444 * So call somewhat different..
2445 */
2446 /* .name = "Capture Source", */
2447 .name = "Input Source",
2448 .count = 1,
2449 .info = via_mux_enum_info,
2450 .get = via_mux_enum_get,
2451 .put = via_mux_enum_put,
2452 },
2453 { } /* end */
2454};
2455
2456static struct hda_verb vt1708S_volume_init_verbs[] = {
2457 /* Unmute ADC0-1 and set the default input to mic-in */
2458 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2459 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2460
2461 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the
2462 * analog-loopback mixer widget */
2463 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2464 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2465 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2466 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2467 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2468 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2469
2470 /* Setup default input of PW4 to MW0 */
2471 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
Harald Welte5691ec72008-09-15 22:42:26 +08002472 /* PW9, PW10 Output enable */
Harald Welted949cac2008-09-09 15:56:01 +08002473 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Harald Welte5691ec72008-09-15 22:42:26 +08002474 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Harald Welted949cac2008-09-09 15:56:01 +08002475 { }
2476};
2477
Harald Welte69e52a82008-09-09 15:57:32 +08002478static struct hda_verb vt1708S_uniwill_init_verbs[] = {
2479 {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
2480 { }
2481};
2482
Harald Welted949cac2008-09-09 15:56:01 +08002483static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
2484 .substreams = 2,
2485 .channels_min = 2,
2486 .channels_max = 8,
2487 .nid = 0x10, /* NID to query formats and rates */
2488 .ops = {
2489 .open = via_playback_pcm_open,
2490 .prepare = via_playback_pcm_prepare,
2491 .cleanup = via_playback_pcm_cleanup
2492 },
2493};
2494
2495static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
2496 .substreams = 2,
2497 .channels_min = 2,
2498 .channels_max = 2,
2499 .nid = 0x13, /* NID to query formats and rates */
2500 .ops = {
2501 .prepare = via_capture_pcm_prepare,
2502 .cleanup = via_capture_pcm_cleanup
2503 },
2504};
2505
2506static struct hda_pcm_stream vt1708S_pcm_digital_playback = {
Harald Welte5691ec72008-09-15 22:42:26 +08002507 .substreams = 2,
Harald Welted949cac2008-09-09 15:56:01 +08002508 .channels_min = 2,
2509 .channels_max = 2,
2510 /* NID is set in via_build_pcms */
2511 .ops = {
2512 .open = via_dig_playback_pcm_open,
2513 .close = via_dig_playback_pcm_close,
2514 .prepare = via_dig_playback_pcm_prepare
2515 },
2516};
2517
2518/* fill in the dac_nids table from the parsed pin configuration */
2519static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
2520 const struct auto_pin_cfg *cfg)
2521{
2522 int i;
2523 hda_nid_t nid;
2524
2525 spec->multiout.num_dacs = cfg->line_outs;
2526
2527 spec->multiout.dac_nids = spec->private_dac_nids;
2528
2529 for (i = 0; i < 4; i++) {
2530 nid = cfg->line_out_pins[i];
2531 if (nid) {
2532 /* config dac list */
2533 switch (i) {
2534 case AUTO_SEQ_FRONT:
2535 spec->multiout.dac_nids[i] = 0x10;
2536 break;
2537 case AUTO_SEQ_CENLFE:
2538 spec->multiout.dac_nids[i] = 0x24;
2539 break;
2540 case AUTO_SEQ_SURROUND:
2541 spec->multiout.dac_nids[i] = 0x11;
2542 break;
2543 case AUTO_SEQ_SIDE:
2544 spec->multiout.dac_nids[i] = 0x25;
2545 break;
2546 }
2547 }
2548 }
2549
2550 return 0;
2551}
2552
2553/* add playback controls from the parsed DAC table */
2554static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
2555 const struct auto_pin_cfg *cfg)
2556{
2557 char name[32];
2558 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
2559 hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25};
2560 hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27};
2561 hda_nid_t nid, nid_vol, nid_mute;
2562 int i, err;
2563
2564 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2565 nid = cfg->line_out_pins[i];
2566
2567 if (!nid)
2568 continue;
2569
2570 nid_vol = nid_vols[i];
2571 nid_mute = nid_mutes[i];
2572
2573 if (i == AUTO_SEQ_CENLFE) {
2574 /* Center/LFE */
2575 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2576 "Center Playback Volume",
2577 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2578 HDA_OUTPUT));
2579 if (err < 0)
2580 return err;
2581 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2582 "LFE Playback Volume",
2583 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2584 HDA_OUTPUT));
2585 if (err < 0)
2586 return err;
2587 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2588 "Center Playback Switch",
2589 HDA_COMPOSE_AMP_VAL(nid_mute,
2590 1, 0,
2591 HDA_OUTPUT));
2592 if (err < 0)
2593 return err;
2594 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2595 "LFE Playback Switch",
2596 HDA_COMPOSE_AMP_VAL(nid_mute,
2597 2, 0,
2598 HDA_OUTPUT));
2599 if (err < 0)
2600 return err;
2601 } else if (i == AUTO_SEQ_FRONT) {
2602 /* add control to mixer index 0 */
2603 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2604 "Master Front Playback Volume",
2605 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
2606 HDA_INPUT));
2607 if (err < 0)
2608 return err;
2609 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2610 "Master Front Playback Switch",
2611 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
2612 HDA_INPUT));
2613 if (err < 0)
2614 return err;
2615
2616 /* Front */
2617 sprintf(name, "%s Playback Volume", chname[i]);
2618 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2619 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2620 HDA_OUTPUT));
2621 if (err < 0)
2622 return err;
2623 sprintf(name, "%s Playback Switch", chname[i]);
2624 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2625 HDA_COMPOSE_AMP_VAL(nid_mute,
2626 3, 0,
2627 HDA_OUTPUT));
2628 if (err < 0)
2629 return err;
2630 } else {
2631 sprintf(name, "%s Playback Volume", chname[i]);
2632 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2633 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2634 HDA_OUTPUT));
2635 if (err < 0)
2636 return err;
2637 sprintf(name, "%s Playback Switch", chname[i]);
2638 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2639 HDA_COMPOSE_AMP_VAL(nid_mute,
2640 3, 0,
2641 HDA_OUTPUT));
2642 if (err < 0)
2643 return err;
2644 }
2645 }
2646
2647 return 0;
2648}
2649
2650static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2651{
2652 int err;
2653
2654 if (!pin)
2655 return 0;
2656
2657 spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */
2658
2659 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2660 "Headphone Playback Volume",
2661 HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
2662 if (err < 0)
2663 return err;
2664
2665 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2666 "Headphone Playback Switch",
2667 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2668 if (err < 0)
2669 return err;
2670
Harald Welte0aa62ae2008-09-09 15:58:27 +08002671 create_hp_imux(spec);
2672
Harald Welted949cac2008-09-09 15:56:01 +08002673 return 0;
2674}
2675
2676/* create playback/capture controls for input pins */
2677static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
2678 const struct auto_pin_cfg *cfg)
2679{
2680 static char *labels[] = {
2681 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2682 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08002683 struct hda_input_mux *imux = &spec->private_imux[0];
Harald Welted949cac2008-09-09 15:56:01 +08002684 int i, err, idx = 0;
2685
2686 /* for internal loopback recording select */
2687 imux->items[imux->num_items].label = "Stereo Mixer";
2688 imux->items[imux->num_items].index = 5;
2689 imux->num_items++;
2690
2691 for (i = 0; i < AUTO_PIN_LAST; i++) {
2692 if (!cfg->input_pins[i])
2693 continue;
2694
2695 switch (cfg->input_pins[i]) {
2696 case 0x1a: /* Mic */
2697 idx = 2;
2698 break;
2699
2700 case 0x1b: /* Line In */
2701 idx = 3;
2702 break;
2703
2704 case 0x1e: /* Front Mic */
2705 idx = 4;
2706 break;
2707
2708 case 0x1f: /* CD */
2709 idx = 1;
2710 break;
2711 }
2712 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
2713 idx, 0x16);
2714 if (err < 0)
2715 return err;
2716 imux->items[imux->num_items].label = labels[i];
2717 imux->items[imux->num_items].index = idx-1;
2718 imux->num_items++;
2719 }
2720 return 0;
2721}
2722
2723static int vt1708S_parse_auto_config(struct hda_codec *codec)
2724{
2725 struct via_spec *spec = codec->spec;
2726 int err;
2727 static hda_nid_t vt1708s_ignore[] = {0x21, 0};
2728
2729 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
2730 vt1708s_ignore);
2731 if (err < 0)
2732 return err;
2733 err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg);
2734 if (err < 0)
2735 return err;
2736 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2737 return 0; /* can't find valid BIOS pin config */
2738
2739 err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg);
2740 if (err < 0)
2741 return err;
2742 err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2743 if (err < 0)
2744 return err;
2745 err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
2746 if (err < 0)
2747 return err;
2748
2749 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2750
2751 if (spec->autocfg.dig_out_pin)
2752 spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID;
2753
Harald Welte98aa34c2008-09-09 16:02:09 +08002754 spec->extra_dig_out_nid = 0x15;
2755
Harald Welted949cac2008-09-09 15:56:01 +08002756 if (spec->kctl_alloc)
2757 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2758
Harald Welte0aa62ae2008-09-09 15:58:27 +08002759 spec->input_mux = &spec->private_imux[0];
2760
Harald Weltef8fdd492008-09-15 22:41:31 +08002761 if (spec->hp_mux)
2762 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08002763
2764 return 1;
2765}
2766
2767#ifdef CONFIG_SND_HDA_POWER_SAVE
2768static struct hda_amp_list vt1708S_loopbacks[] = {
2769 { 0x16, HDA_INPUT, 1 },
2770 { 0x16, HDA_INPUT, 2 },
2771 { 0x16, HDA_INPUT, 3 },
2772 { 0x16, HDA_INPUT, 4 },
2773 { } /* end */
2774};
2775#endif
2776
2777static int patch_vt1708S(struct hda_codec *codec)
2778{
2779 struct via_spec *spec;
2780 int err;
2781
2782 /* create a codec specific record */
2783 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2784 if (spec == NULL)
2785 return -ENOMEM;
2786
2787 codec->spec = spec;
2788
2789 /* automatic parse from the BIOS config */
2790 err = vt1708S_parse_auto_config(codec);
2791 if (err < 0) {
2792 via_free(codec);
2793 return err;
2794 } else if (!err) {
2795 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2796 "from BIOS. Using genenic mode...\n");
2797 }
2798
Harald Welte69e52a82008-09-09 15:57:32 +08002799 spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
2800 spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs;
Harald Welted949cac2008-09-09 15:56:01 +08002801
2802 spec->stream_name_analog = "VT1708S Analog";
2803 spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
2804 spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
2805
2806 spec->stream_name_digital = "VT1708S Digital";
2807 spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
2808
2809 if (!spec->adc_nids && spec->input_mux) {
2810 spec->adc_nids = vt1708S_adc_nids;
2811 spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
2812 spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
2813 spec->num_mixers++;
2814 }
2815
2816 codec->patch_ops = via_patch_ops;
2817
2818 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08002819 codec->patch_ops.unsol_event = via_unsol_event;
Harald Welted949cac2008-09-09 15:56:01 +08002820#ifdef CONFIG_SND_HDA_POWER_SAVE
2821 spec->loopback.amplist = vt1708S_loopbacks;
2822#endif
2823
2824 return 0;
2825}
2826
2827/* Patch for VT1702 */
2828
2829/* capture mixer elements */
2830static struct snd_kcontrol_new vt1702_capture_mixer[] = {
2831 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
2832 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
2833 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
2834 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT),
2835 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT),
2836 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT),
2837 HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0,
2838 HDA_INPUT),
2839 {
2840 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2841 /* The multiple "Capture Source" controls confuse alsamixer
2842 * So call somewhat different..
2843 */
2844 /* .name = "Capture Source", */
2845 .name = "Input Source",
2846 .count = 1,
2847 .info = via_mux_enum_info,
2848 .get = via_mux_enum_get,
2849 .put = via_mux_enum_put,
2850 },
2851 { } /* end */
2852};
2853
2854static struct hda_verb vt1702_volume_init_verbs[] = {
2855 /*
2856 * Unmute ADC0-1 and set the default input to mic-in
2857 */
2858 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2859 {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2860 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2861
2862
2863 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2864 * mixer widget
2865 */
2866 /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */
2867 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2868 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2869 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2870 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2871 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2872
2873 /* Setup default input of PW4 to MW0 */
2874 {0x17, AC_VERB_SET_CONNECT_SEL, 0x1},
2875 /* PW6 PW7 Output enable */
2876 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2877 {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2878 { }
2879};
2880
Harald Welte69e52a82008-09-09 15:57:32 +08002881static struct hda_verb vt1702_uniwill_init_verbs[] = {
2882 {0x01, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_GPIO_EVENT},
2883 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
2884 { }
2885};
2886
Harald Welted949cac2008-09-09 15:56:01 +08002887static struct hda_pcm_stream vt1702_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08002888 .substreams = 2,
Harald Welted949cac2008-09-09 15:56:01 +08002889 .channels_min = 2,
2890 .channels_max = 2,
2891 .nid = 0x10, /* NID to query formats and rates */
2892 .ops = {
2893 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08002894 .prepare = via_playback_multi_pcm_prepare,
2895 .cleanup = via_playback_multi_pcm_cleanup
Harald Welted949cac2008-09-09 15:56:01 +08002896 },
2897};
2898
2899static struct hda_pcm_stream vt1702_pcm_analog_capture = {
2900 .substreams = 3,
2901 .channels_min = 2,
2902 .channels_max = 2,
2903 .nid = 0x12, /* NID to query formats and rates */
2904 .ops = {
2905 .prepare = via_capture_pcm_prepare,
2906 .cleanup = via_capture_pcm_cleanup
2907 },
2908};
2909
2910static struct hda_pcm_stream vt1702_pcm_digital_playback = {
Harald Welte5691ec72008-09-15 22:42:26 +08002911 .substreams = 2,
Harald Welted949cac2008-09-09 15:56:01 +08002912 .channels_min = 2,
2913 .channels_max = 2,
2914 /* NID is set in via_build_pcms */
2915 .ops = {
2916 .open = via_dig_playback_pcm_open,
2917 .close = via_dig_playback_pcm_close,
2918 .prepare = via_dig_playback_pcm_prepare
2919 },
2920};
2921
2922/* fill in the dac_nids table from the parsed pin configuration */
2923static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
2924 const struct auto_pin_cfg *cfg)
2925{
2926 spec->multiout.num_dacs = 1;
2927 spec->multiout.dac_nids = spec->private_dac_nids;
2928
2929 if (cfg->line_out_pins[0]) {
2930 /* config dac list */
2931 spec->multiout.dac_nids[0] = 0x10;
2932 }
2933
2934 return 0;
2935}
2936
2937/* add playback controls from the parsed DAC table */
2938static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
2939 const struct auto_pin_cfg *cfg)
2940{
2941 int err;
2942
2943 if (!cfg->line_out_pins[0])
2944 return -1;
2945
2946 /* add control to mixer index 0 */
2947 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2948 "Master Front Playback Volume",
2949 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
2950 if (err < 0)
2951 return err;
2952 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2953 "Master Front Playback Switch",
2954 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
2955 if (err < 0)
2956 return err;
2957
2958 /* Front */
2959 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2960 "Front Playback Volume",
2961 HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT));
2962 if (err < 0)
2963 return err;
2964 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2965 "Front Playback Switch",
2966 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT));
2967 if (err < 0)
2968 return err;
2969
2970 return 0;
2971}
2972
2973static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2974{
2975 int err;
2976
2977 if (!pin)
2978 return 0;
2979
2980 spec->multiout.hp_nid = 0x1D;
2981
2982 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2983 "Headphone Playback Volume",
2984 HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT));
2985 if (err < 0)
2986 return err;
2987
2988 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2989 "Headphone Playback Switch",
2990 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2991 if (err < 0)
2992 return err;
2993
Harald Welte0aa62ae2008-09-09 15:58:27 +08002994 create_hp_imux(spec);
2995
Harald Welted949cac2008-09-09 15:56:01 +08002996 return 0;
2997}
2998
2999/* create playback/capture controls for input pins */
3000static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
3001 const struct auto_pin_cfg *cfg)
3002{
3003 static char *labels[] = {
3004 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
3005 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08003006 struct hda_input_mux *imux = &spec->private_imux[0];
Harald Welted949cac2008-09-09 15:56:01 +08003007 int i, err, idx = 0;
3008
3009 /* for internal loopback recording select */
3010 imux->items[imux->num_items].label = "Stereo Mixer";
3011 imux->items[imux->num_items].index = 3;
3012 imux->num_items++;
3013
3014 for (i = 0; i < AUTO_PIN_LAST; i++) {
3015 if (!cfg->input_pins[i])
3016 continue;
3017
3018 switch (cfg->input_pins[i]) {
3019 case 0x14: /* Mic */
3020 idx = 1;
3021 break;
3022
3023 case 0x15: /* Line In */
3024 idx = 2;
3025 break;
3026
3027 case 0x18: /* Front Mic */
3028 idx = 3;
3029 break;
3030 }
3031 err = via_new_analog_input(spec, cfg->input_pins[i],
3032 labels[i], idx, 0x1A);
3033 if (err < 0)
3034 return err;
3035 imux->items[imux->num_items].label = labels[i];
3036 imux->items[imux->num_items].index = idx-1;
3037 imux->num_items++;
3038 }
3039 return 0;
3040}
3041
3042static int vt1702_parse_auto_config(struct hda_codec *codec)
3043{
3044 struct via_spec *spec = codec->spec;
3045 int err;
3046 static hda_nid_t vt1702_ignore[] = {0x1C, 0};
3047
3048 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
3049 vt1702_ignore);
3050 if (err < 0)
3051 return err;
3052 err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg);
3053 if (err < 0)
3054 return err;
3055 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
3056 return 0; /* can't find valid BIOS pin config */
3057
3058 err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg);
3059 if (err < 0)
3060 return err;
3061 err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
3062 if (err < 0)
3063 return err;
3064 err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
3065 if (err < 0)
3066 return err;
3067
3068 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3069
3070 if (spec->autocfg.dig_out_pin)
3071 spec->multiout.dig_out_nid = VT1702_DIGOUT_NID;
3072
Harald Welte98aa34c2008-09-09 16:02:09 +08003073 spec->extra_dig_out_nid = 0x1B;
3074
Harald Welted949cac2008-09-09 15:56:01 +08003075 if (spec->kctl_alloc)
3076 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3077
Harald Welte0aa62ae2008-09-09 15:58:27 +08003078 spec->input_mux = &spec->private_imux[0];
3079
Harald Weltef8fdd492008-09-15 22:41:31 +08003080 if (spec->hp_mux)
3081 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08003082
3083 return 1;
3084}
3085
3086#ifdef CONFIG_SND_HDA_POWER_SAVE
3087static struct hda_amp_list vt1702_loopbacks[] = {
3088 { 0x1A, HDA_INPUT, 1 },
3089 { 0x1A, HDA_INPUT, 2 },
3090 { 0x1A, HDA_INPUT, 3 },
3091 { 0x1A, HDA_INPUT, 4 },
3092 { } /* end */
3093};
3094#endif
3095
3096static int patch_vt1702(struct hda_codec *codec)
3097{
3098 struct via_spec *spec;
3099 int err;
3100 unsigned int response;
3101 unsigned char control;
3102
3103 /* create a codec specific record */
3104 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3105 if (spec == NULL)
3106 return -ENOMEM;
3107
3108 codec->spec = spec;
3109
3110 /* automatic parse from the BIOS config */
3111 err = vt1702_parse_auto_config(codec);
3112 if (err < 0) {
3113 via_free(codec);
3114 return err;
3115 } else if (!err) {
3116 printk(KERN_INFO "hda_codec: Cannot set up configuration "
3117 "from BIOS. Using genenic mode...\n");
3118 }
3119
Harald Welte69e52a82008-09-09 15:57:32 +08003120 spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs;
3121 spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs;
Harald Welted949cac2008-09-09 15:56:01 +08003122
3123 spec->stream_name_analog = "VT1702 Analog";
3124 spec->stream_analog_playback = &vt1702_pcm_analog_playback;
3125 spec->stream_analog_capture = &vt1702_pcm_analog_capture;
3126
3127 spec->stream_name_digital = "VT1702 Digital";
3128 spec->stream_digital_playback = &vt1702_pcm_digital_playback;
3129
3130 if (!spec->adc_nids && spec->input_mux) {
3131 spec->adc_nids = vt1702_adc_nids;
3132 spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
3133 spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
3134 spec->num_mixers++;
3135 }
3136
3137 codec->patch_ops = via_patch_ops;
3138
3139 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003140 codec->patch_ops.unsol_event = via_unsol_event;
Harald Welted949cac2008-09-09 15:56:01 +08003141#ifdef CONFIG_SND_HDA_POWER_SAVE
3142 spec->loopback.amplist = vt1702_loopbacks;
3143#endif
3144
3145 /* Open backdoor */
3146 response = snd_hda_codec_read(codec, codec->afg, 0, 0xF8C, 0);
3147 control = (unsigned char)(response & 0xff);
3148 control |= 0x3;
3149 snd_hda_codec_write(codec, codec->afg, 0, 0xF88, control);
3150
3151 /* Enable GPIO 0&1 for volume&mute control */
3152 /* Enable GPIO 2 for DMIC-DATA */
3153 response = snd_hda_codec_read(codec, codec->afg, 0, 0xF84, 0);
3154 control = (unsigned char)((response >> 16) & 0x3f);
3155 snd_hda_codec_write(codec, codec->afg, 0, 0xF82, control);
3156
3157 return 0;
3158}
3159
Joseph Chanc577b8a2006-11-29 15:29:40 +01003160/*
3161 * patch entries
3162 */
3163struct hda_codec_preset snd_hda_preset_via[] = {
3164 { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708},
3165 { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708},
3166 { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708},
3167 { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708},
Josepch Chanf7278fd2007-12-13 16:40:40 +01003168 { .id = 0x1106E710, .name = "VIA VT1709 10-Ch",
3169 .patch = patch_vt1709_10ch},
3170 { .id = 0x1106E711, .name = "VIA VT1709 10-Ch",
3171 .patch = patch_vt1709_10ch},
3172 { .id = 0x1106E712, .name = "VIA VT1709 10-Ch",
3173 .patch = patch_vt1709_10ch},
3174 { .id = 0x1106E713, .name = "VIA VT1709 10-Ch",
3175 .patch = patch_vt1709_10ch},
3176 { .id = 0x1106E714, .name = "VIA VT1709 6-Ch",
3177 .patch = patch_vt1709_6ch},
3178 { .id = 0x1106E715, .name = "VIA VT1709 6-Ch",
3179 .patch = patch_vt1709_6ch},
3180 { .id = 0x1106E716, .name = "VIA VT1709 6-Ch",
3181 .patch = patch_vt1709_6ch},
3182 { .id = 0x1106E717, .name = "VIA VT1709 6-Ch",
3183 .patch = patch_vt1709_6ch},
3184 { .id = 0x1106E720, .name = "VIA VT1708B 8-Ch",
3185 .patch = patch_vt1708B_8ch},
3186 { .id = 0x1106E721, .name = "VIA VT1708B 8-Ch",
3187 .patch = patch_vt1708B_8ch},
3188 { .id = 0x1106E722, .name = "VIA VT1708B 8-Ch",
3189 .patch = patch_vt1708B_8ch},
3190 { .id = 0x1106E723, .name = "VIA VT1708B 8-Ch",
3191 .patch = patch_vt1708B_8ch},
3192 { .id = 0x1106E724, .name = "VIA VT1708B 4-Ch",
3193 .patch = patch_vt1708B_4ch},
3194 { .id = 0x1106E725, .name = "VIA VT1708B 4-Ch",
3195 .patch = patch_vt1708B_4ch},
3196 { .id = 0x1106E726, .name = "VIA VT1708B 4-Ch",
3197 .patch = patch_vt1708B_4ch},
3198 { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch",
3199 .patch = patch_vt1708B_4ch},
Harald Welted949cac2008-09-09 15:56:01 +08003200 { .id = 0x11060397, .name = "VIA VT1708S",
3201 .patch = patch_vt1708S},
3202 { .id = 0x11061397, .name = "VIA VT1708S",
3203 .patch = patch_vt1708S},
3204 { .id = 0x11062397, .name = "VIA VT1708S",
3205 .patch = patch_vt1708S},
3206 { .id = 0x11063397, .name = "VIA VT1708S",
3207 .patch = patch_vt1708S},
3208 { .id = 0x11064397, .name = "VIA VT1708S",
3209 .patch = patch_vt1708S},
3210 { .id = 0x11065397, .name = "VIA VT1708S",
3211 .patch = patch_vt1708S},
3212 { .id = 0x11066397, .name = "VIA VT1708S",
3213 .patch = patch_vt1708S},
3214 { .id = 0x11067397, .name = "VIA VT1708S",
3215 .patch = patch_vt1708S},
3216 { .id = 0x11060398, .name = "VIA VT1702",
3217 .patch = patch_vt1702},
3218 { .id = 0x11061398, .name = "VIA VT1702",
3219 .patch = patch_vt1702},
3220 { .id = 0x11062398, .name = "VIA VT1702",
3221 .patch = patch_vt1702},
3222 { .id = 0x11063398, .name = "VIA VT1702",
3223 .patch = patch_vt1702},
3224 { .id = 0x11064398, .name = "VIA VT1702",
3225 .patch = patch_vt1702},
3226 { .id = 0x11065398, .name = "VIA VT1702",
3227 .patch = patch_vt1702},
3228 { .id = 0x11066398, .name = "VIA VT1702",
3229 .patch = patch_vt1702},
3230 { .id = 0x11067398, .name = "VIA VT1702",
3231 .patch = patch_vt1702},
Joseph Chanc577b8a2006-11-29 15:29:40 +01003232 {} /* terminator */
3233};