aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorJoseph Chan <josephchan@via.com.tw>2006-11-29 09:29:40 -0500
committerJaroslav Kysela <perex@suse.cz>2007-02-09 03:02:15 -0500
commitc577b8a16fd19a33a8865ca6451287d284a0faf6 (patch)
treefbd2e8d8778827aaf90652db94bda075ff01c22f /sound/pci/hda
parent6c5cfd9d9d312b279adf9226b7e664f6f4c4cfc7 (diff)
[ALSA] hda-codec - Add support for VIA VT1708(A) HD audio codec
This patch is VIA first release for HD audio codec, VT1708(A) and it provides geneneral HD audio driver features. Signed-off-by: Joseph Chan <josephchan@via.com.tw> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/Makefile3
-rw-r--r--sound/pci/hda/hda_codec.c1
-rw-r--r--sound/pci/hda/hda_patch.h3
-rw-r--r--sound/pci/hda/patch_via.c1396
4 files changed, 1402 insertions, 1 deletions
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 148140bb86bd..60d7b05a204a 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -7,7 +7,8 @@ snd-hda-codec-objs := hda_codec.o \
7 patch_sigmatel.o \ 7 patch_sigmatel.o \
8 patch_si3054.o \ 8 patch_si3054.o \
9 patch_atihdmi.o \ 9 patch_atihdmi.o \
10 patch_conexant.o 10 patch_conexant.o \
11 patch_via.o
11ifdef CONFIG_PROC_FS 12ifdef CONFIG_PROC_FS
12snd-hda-codec-objs += hda_proc.o 13snd-hda-codec-objs += hda_proc.o
13endif 14endif
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index c07d5db6b050..e14faf5d5053 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -52,6 +52,7 @@ struct hda_vendor_id {
52static struct hda_vendor_id hda_vendor_ids[] = { 52static struct hda_vendor_id hda_vendor_ids[] = {
53 { 0x10ec, "Realtek" }, 53 { 0x10ec, "Realtek" },
54 { 0x1057, "Motorola" }, 54 { 0x1057, "Motorola" },
55 { 0x1106, "VIA" },
55 { 0x11d4, "Analog Devices" }, 56 { 0x11d4, "Analog Devices" },
56 { 0x13f6, "C-Media" }, 57 { 0x13f6, "C-Media" },
57 { 0x14f1, "Conexant" }, 58 { 0x14f1, "Conexant" },
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h
index 5904ecd88a50..9f9e9ae44a9d 100644
--- a/sound/pci/hda/hda_patch.h
+++ b/sound/pci/hda/hda_patch.h
@@ -16,6 +16,8 @@ extern struct hda_codec_preset snd_hda_preset_si3054[];
16extern struct hda_codec_preset snd_hda_preset_atihdmi[]; 16extern struct hda_codec_preset snd_hda_preset_atihdmi[];
17/* Conexant audio codec */ 17/* Conexant audio codec */
18extern struct hda_codec_preset snd_hda_preset_conexant[]; 18extern struct hda_codec_preset snd_hda_preset_conexant[];
19/* VIA codecs */
20extern struct hda_codec_preset snd_hda_preset_via[];
19 21
20static const struct hda_codec_preset *hda_preset_tables[] = { 22static const struct hda_codec_preset *hda_preset_tables[] = {
21 snd_hda_preset_realtek, 23 snd_hda_preset_realtek,
@@ -25,5 +27,6 @@ static const struct hda_codec_preset *hda_preset_tables[] = {
25 snd_hda_preset_si3054, 27 snd_hda_preset_si3054,
26 snd_hda_preset_atihdmi, 28 snd_hda_preset_atihdmi,
27 snd_hda_preset_conexant, 29 snd_hda_preset_conexant,
30 snd_hda_preset_via,
28 NULL 31 NULL
29}; 32};
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
new file mode 100644
index 000000000000..4c839b031729
--- /dev/null
+++ b/sound/pci/hda/patch_via.c
@@ -0,0 +1,1396 @@
1/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for VIA VT1708 codec
5 *
6 * Copyright (c) 2006 Lydia Wang <lydiawang@viatech.com>
7 * Takashi Iwai <tiwai@suse.de>
8 *
9 * This driver is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This driver is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24/* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */
25/* */
26/* 2006-03-03 Lydia Wang Create the basic patch to support VT1708 codec */
27/* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */
28/* 2006-08-02 Lydia Wang Add support to VT1709 codec */
29/* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */
30/* */
31/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
32
33
34#include <sound/driver.h>
35#include <linux/init.h>
36#include <linux/delay.h>
37#include <linux/slab.h>
38#include <linux/pci.h>
39#include <sound/core.h>
40#include "hda_codec.h"
41#include "hda_local.h"
42
43
44/* amp values */
45#define AMP_VAL_IDX_SHIFT 19
46#define AMP_VAL_IDX_MASK (0x0f<<19)
47
48#define NUM_CONTROL_ALLOC 32
49#define NUM_VERB_ALLOC 32
50
51/* Pin Widget NID */
52#define VT1708_HP_NID 0x13
53#define VT1708_DIGOUT_NID 0x14
54#define VT1708_DIGIN_NID 0x16
55
56#define VT1709_HP_DAC_NID 0x28
57#define VT1709_DIGOUT_NID 0x13
58#define VT1709_DIGIN_NID 0x17
59
60#define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b)
61#define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713)
62#define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717)
63
64
65enum {
66 VIA_CTL_WIDGET_VOL,
67 VIA_CTL_WIDGET_MUTE,
68};
69
70enum {
71 AUTO_SEQ_FRONT,
72 AUTO_SEQ_SURROUND,
73 AUTO_SEQ_CENLFE,
74 AUTO_SEQ_SIDE
75};
76
77static struct snd_kcontrol_new vt1708_control_templates[] = {
78 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
79 HDA_CODEC_MUTE(NULL, 0, 0, 0),
80};
81
82
83struct via_spec {
84 /* codec parameterization */
85 struct snd_kcontrol_new *mixers[3];
86 unsigned int num_mixers;
87
88 struct hda_verb *init_verbs;
89
90 char *stream_name_analog;
91 struct hda_pcm_stream *stream_analog_playback;
92 struct hda_pcm_stream *stream_analog_capture;
93
94 char *stream_name_digital;
95 struct hda_pcm_stream *stream_digital_playback;
96 struct hda_pcm_stream *stream_digital_capture;
97
98 /* playback */
99 struct hda_multi_out multiout;
100
101 /* capture */
102 unsigned int num_adc_nids;
103 hda_nid_t *adc_nids;
104 hda_nid_t dig_in_nid;
105
106 /* capture source */
107 const struct hda_input_mux *input_mux;
108 unsigned int cur_mux[3];
109
110 /* PCM information */
111 struct hda_pcm pcm_rec[2];
112
113 /* dynamic controls, init_verbs and input_mux */
114 struct auto_pin_cfg autocfg;
115 unsigned int num_kctl_alloc, num_kctl_used;
116 struct snd_kcontrol_new *kctl_alloc;
117 struct hda_input_mux private_imux;
118 hda_nid_t private_dac_nids[4];
119};
120
121static hda_nid_t vt1708_adc_nids[2] = {
122 /* ADC1-2 */
123 0x15, 0x27
124};
125
126static hda_nid_t vt1709_adc_nids[3] = {
127 /* ADC1-2 */
128 0x14, 0x15, 0x16
129};
130
131/* add dynamic controls */
132static int via_add_control(struct via_spec *spec, int type, const char *name,
133 unsigned long val)
134{
135 struct snd_kcontrol_new *knew;
136
137 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
138 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
139
140 /* array + terminator */
141 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
142 if (!knew)
143 return -ENOMEM;
144 if (spec->kctl_alloc) {
145 memcpy(knew, spec->kctl_alloc,
146 sizeof(*knew) * spec->num_kctl_alloc);
147 kfree(spec->kctl_alloc);
148 }
149 spec->kctl_alloc = knew;
150 spec->num_kctl_alloc = num;
151 }
152
153 knew = &spec->kctl_alloc[spec->num_kctl_used];
154 *knew = vt1708_control_templates[type];
155 knew->name = kstrdup(name, GFP_KERNEL);
156
157 if (!knew->name)
158 return -ENOMEM;
159 knew->private_value = val;
160 spec->num_kctl_used++;
161 return 0;
162}
163
164/* create input playback/capture controls for the given pin */
165static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
166 const char *ctlname, int idx, int mix_nid)
167{
168 char name[32];
169 int err;
170
171 sprintf(name, "%s Playback Volume", ctlname);
172 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
173 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
174 if (err < 0)
175 return err;
176 sprintf(name, "%s Playback Switch", ctlname);
177 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
178 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
179 if (err < 0)
180 return err;
181 return 0;
182}
183
184static void via_auto_set_output_and_unmute(struct hda_codec *codec,
185 hda_nid_t nid, int pin_type,
186 int dac_idx)
187{
188 /* set as output */
189 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
190 pin_type);
191 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
192 AMP_OUT_UNMUTE);
193}
194
195
196static void via_auto_init_multi_out(struct hda_codec *codec)
197{
198 struct via_spec *spec = codec->spec;
199 int i;
200
201 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
202 hda_nid_t nid = spec->autocfg.line_out_pins[i];
203 if (nid)
204 via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
205 }
206}
207
208static void via_auto_init_hp_out(struct hda_codec *codec)
209{
210 struct via_spec *spec = codec->spec;
211 hda_nid_t pin;
212
213 pin = spec->autocfg.hp_pins[0];
214 if (pin) /* connect to front */
215 via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
216}
217
218static void via_auto_init_analog_input(struct hda_codec *codec)
219{
220 struct via_spec *spec = codec->spec;
221 int i;
222
223 for (i = 0; i < AUTO_PIN_LAST; i++) {
224 hda_nid_t nid = spec->autocfg.input_pins[i];
225
226 snd_hda_codec_write(codec, nid, 0,
227 AC_VERB_SET_PIN_WIDGET_CONTROL,
228 (i <= AUTO_PIN_FRONT_MIC ?
229 PIN_VREF50 : PIN_IN));
230
231 }
232}
233/*
234 * input MUX handling
235 */
236static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
237 struct snd_ctl_elem_info *uinfo)
238{
239 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
240 struct via_spec *spec = codec->spec;
241 return snd_hda_input_mux_info(spec->input_mux, uinfo);
242}
243
244static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
245 struct snd_ctl_elem_value *ucontrol)
246{
247 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
248 struct via_spec *spec = codec->spec;
249 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
250
251 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
252 return 0;
253}
254
255static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
256 struct snd_ctl_elem_value *ucontrol)
257{
258 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
259 struct via_spec *spec = codec->spec;
260 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
261 unsigned int vendor_id = codec->vendor_id;
262
263 /* AIW0 lydia 060801 add for correct sw0 input select */
264 if (IS_VT1708_VENDORID(vendor_id) && (adc_idx == 0))
265 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
266 0x18, &spec->cur_mux[adc_idx]);
267 else if ((IS_VT1709_10CH_VENDORID(vendor_id) ||
268 IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0) )
269 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
270 0x19, &spec->cur_mux[adc_idx]);
271 else
272 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
273 spec->adc_nids[adc_idx],
274 &spec->cur_mux[adc_idx]);
275}
276
277/* capture mixer elements */
278static struct snd_kcontrol_new vt1708_capture_mixer[] = {
279 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
280 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
281 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
282 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
283 {
284 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
285 /* The multiple "Capture Source" controls confuse alsamixer
286 * So call somewhat different..
287 * FIXME: the controls appear in the "playback" view!
288 */
289 /* .name = "Capture Source", */
290 .name = "Input Source",
291 .count = 1,
292 .info = via_mux_enum_info,
293 .get = via_mux_enum_get,
294 .put = via_mux_enum_put,
295 },
296 { } /* end */
297};
298/*
299 * generic initialization of ADC, input mixers and output mixers
300 */
301static struct hda_verb vt1708_volume_init_verbs[] = {
302 /*
303 * Unmute ADC0-1 and set the default input to mic-in
304 */
305 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
306 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
307
308
309 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
310 * mixer widget
311 */
312 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
313 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
314 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
315 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
316 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
317 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
318
319 /*
320 * Set up output mixers (0x19 - 0x1b)
321 */
322 /* set vol=0 to output mixers */
323 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
324 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
325 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
326
327 /* Setup default input to PW4 */
328 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
329 /* Set mic as default input of sw0 */
330 {0x18, AC_VERB_SET_CONNECT_SEL, 0x2},
331 /* PW9 Output enable */
332 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
333};
334
335static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
336 struct hda_codec *codec,
337 struct snd_pcm_substream *substream)
338{
339 struct via_spec *spec = codec->spec;
340 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
341}
342
343static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
344 struct hda_codec *codec,
345 unsigned int stream_tag,
346 unsigned int format,
347 struct snd_pcm_substream *substream)
348{
349 struct via_spec *spec = codec->spec;
350 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
351 stream_tag, format, substream);
352}
353
354static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
355 struct hda_codec *codec,
356 struct snd_pcm_substream *substream)
357{
358 struct via_spec *spec = codec->spec;
359 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
360}
361
362/*
363 * Digital out
364 */
365static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
366 struct hda_codec *codec,
367 struct snd_pcm_substream *substream)
368{
369 struct via_spec *spec = codec->spec;
370 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
371}
372
373static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
374 struct hda_codec *codec,
375 struct snd_pcm_substream *substream)
376{
377 struct via_spec *spec = codec->spec;
378 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
379}
380
381/*
382 * Analog capture
383 */
384static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
385 struct hda_codec *codec,
386 unsigned int stream_tag,
387 unsigned int format,
388 struct snd_pcm_substream *substream)
389{
390 struct via_spec *spec = codec->spec;
391
392 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
393 stream_tag, 0, format);
394 return 0;
395}
396
397static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
398 struct hda_codec *codec,
399 struct snd_pcm_substream *substream)
400{
401 struct via_spec *spec = codec->spec;
402 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
403 0, 0, 0);
404 return 0;
405}
406
407static struct hda_pcm_stream vt1708_pcm_analog_playback = {
408 .substreams = 1,
409 .channels_min = 2,
410 .channels_max = 8,
411 .nid = 0x10, /* NID to query formats and rates */
412 .ops = {
413 .open = via_playback_pcm_open,
414 .prepare = via_playback_pcm_prepare,
415 .cleanup = via_playback_pcm_cleanup
416 },
417};
418
419static struct hda_pcm_stream vt1708_pcm_analog_capture = {
420 .substreams = 2,
421 .channels_min = 2,
422 .channels_max = 2,
423 .nid = 0x15, /* NID to query formats and rates */
424 .ops = {
425 .prepare = via_capture_pcm_prepare,
426 .cleanup = via_capture_pcm_cleanup
427 },
428};
429
430static struct hda_pcm_stream vt1708_pcm_digital_playback = {
431 .substreams = 1,
432 .channels_min = 2,
433 .channels_max = 2,
434 /* NID is set in via_build_pcms */
435 .ops = {
436 .open = via_dig_playback_pcm_open,
437 .close = via_dig_playback_pcm_close
438 },
439};
440
441static struct hda_pcm_stream vt1708_pcm_digital_capture = {
442 .substreams = 1,
443 .channels_min = 2,
444 .channels_max = 2,
445};
446
447static int via_build_controls(struct hda_codec *codec)
448{
449 struct via_spec *spec = codec->spec;
450 int err;
451 int i;
452
453 for (i = 0; i < spec->num_mixers; i++) {
454 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
455 if (err < 0)
456 return err;
457 }
458
459 if (spec->multiout.dig_out_nid) {
460 err = snd_hda_create_spdif_out_ctls(codec,
461 spec->multiout.dig_out_nid);
462 if (err < 0)
463 return err;
464 }
465 if (spec->dig_in_nid) {
466 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
467 if (err < 0)
468 return err;
469 }
470 return 0;
471}
472
473static int via_build_pcms(struct hda_codec *codec)
474{
475 struct via_spec *spec = codec->spec;
476 struct hda_pcm *info = spec->pcm_rec;
477
478 codec->num_pcms = 1;
479 codec->pcm_info = info;
480
481 info->name = spec->stream_name_analog;
482 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
483 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
484 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
485 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
486
487 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
488 spec->multiout.max_channels;
489
490 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
491 codec->num_pcms++;
492 info++;
493 info->name = spec->stream_name_digital;
494 if (spec->multiout.dig_out_nid) {
495 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
496 *(spec->stream_digital_playback);
497 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
498 spec->multiout.dig_out_nid;
499 }
500 if (spec->dig_in_nid) {
501 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
502 *(spec->stream_digital_capture);
503 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
504 spec->dig_in_nid;
505 }
506 }
507
508 return 0;
509}
510
511static void via_free(struct hda_codec *codec)
512{
513 struct via_spec *spec = codec->spec;
514 unsigned int i;
515
516 if (!spec)
517 return;
518
519 if (spec->kctl_alloc) {
520 for (i = 0; i < spec->num_kctl_used; i++)
521 kfree(spec->kctl_alloc[i].name);
522 kfree(spec->kctl_alloc);
523 }
524
525 kfree(codec->spec);
526}
527
528static int via_init(struct hda_codec *codec)
529{
530 struct via_spec *spec = codec->spec;
531 snd_hda_sequence_write(codec, spec->init_verbs);
532 return 0;
533}
534
535#ifdef CONFIG_PM
536/*
537 * resume
538 */
539static int via_resume(struct hda_codec *codec)
540{
541 struct via_spec *spec = codec->spec;
542 int i;
543
544 via_init(codec);
545 for (i = 0; i < spec->num_mixers; i++)
546 snd_hda_resume_ctls(codec, spec->mixers[i]);
547 if (spec->multiout.dig_out_nid)
548 snd_hda_resume_spdif_out(codec);
549 if (spec->dig_in_nid)
550 snd_hda_resume_spdif_in(codec);
551
552 return 0;
553}
554#endif
555
556/*
557 */
558static struct hda_codec_ops via_patch_ops = {
559 .build_controls = via_build_controls,
560 .build_pcms = via_build_pcms,
561 .init = via_init,
562 .free = via_free,
563#ifdef CONFIG_PM
564 .resume = via_resume,
565#endif
566};
567
568/* fill in the dac_nids table from the parsed pin configuration */
569static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
570 const struct auto_pin_cfg *cfg)
571{
572 int i;
573 hda_nid_t nid;
574
575 spec->multiout.num_dacs = cfg->line_outs;
576
577 spec->multiout.dac_nids = spec->private_dac_nids;
578
579 for(i = 0; i < 4; i++) {
580 nid = cfg->line_out_pins[i];
581 if (nid) {
582 /* config dac list */
583 switch (i) {
584 case AUTO_SEQ_FRONT:
585 spec->multiout.dac_nids[i] = 0x10;
586 break;
587 case AUTO_SEQ_CENLFE:
588 spec->multiout.dac_nids[i] = 0x12;
589 break;
590 case AUTO_SEQ_SURROUND:
591 spec->multiout.dac_nids[i] = 0x13;
592 break;
593 case AUTO_SEQ_SIDE:
594 spec->multiout.dac_nids[i] = 0x11;
595 break;
596 }
597 }
598 }
599
600 return 0;
601}
602
603/* add playback controls from the parsed DAC table */
604static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
605 const struct auto_pin_cfg *cfg)
606{
607 char name[32];
608 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
609 hda_nid_t nid, nid_vol = 0;
610 int i, err;
611
612 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
613 nid = cfg->line_out_pins[i];
614
615 if (!nid)
616 continue;
617
618 if (i != AUTO_SEQ_FRONT)
619 nid_vol = 0x1b - i + 1;
620
621 if (i == AUTO_SEQ_CENLFE) {
622 /* Center/LFE */
623 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
624 "Center Playback Volume",
625 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
626 if (err < 0)
627 return err;
628 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
629 "LFE Playback Volume",
630 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
631 if (err < 0)
632 return err;
633 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
634 "Center Playback Switch",
635 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
636 if (err < 0)
637 return err;
638 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
639 "LFE Playback Switch",
640 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
641 if (err < 0)
642 return err;
643 } else if (i == AUTO_SEQ_FRONT){
644 /* add control to mixer index 0 */
645 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
646 "Master Front Playback Volume",
647 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT));
648 if (err < 0)
649 return err;
650 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
651 "Master Front Playback Switch",
652 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT));
653 if (err < 0)
654 return err;
655
656 /* add control to PW3 */
657 sprintf(name, "%s Playback Volume", chname[i]);
658 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
659 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
660 if (err < 0)
661 return err;
662 sprintf(name, "%s Playback Switch", chname[i]);
663 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
664 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
665 if (err < 0)
666 return err;
667 } else {
668 sprintf(name, "%s Playback Volume", chname[i]);
669 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
670 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
671 if (err < 0)
672 return err;
673 sprintf(name, "%s Playback Switch", chname[i]);
674 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
675 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
676 if (err < 0)
677 return err;
678 }
679 }
680
681 return 0;
682}
683
684static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
685{
686 int err;
687
688 if (!pin)
689 return 0;
690
691 spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
692
693 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
694 "Headphone Playback Volume",
695 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
696 if (err < 0)
697 return err;
698 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
699 "Headphone Playback Switch",
700 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
701 if (err < 0)
702 return err;
703
704 return 0;
705}
706
707/* create playback/capture controls for input pins */
708static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
709 const struct auto_pin_cfg *cfg)
710{
711 static char *labels[] = {
712 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
713 };
714 struct hda_input_mux *imux = &spec->private_imux;
715 int i, err, idx = 0;
716
717 /* for internal loopback recording select */
718 imux->items[imux->num_items].label = "Stereo Mixer";
719 imux->items[imux->num_items].index = idx;
720 imux->num_items++;
721
722 for (i = 0; i < AUTO_PIN_LAST; i++) {
723 if (!cfg->input_pins[i])
724 continue;
725
726 switch (cfg->input_pins[i]) {
727 case 0x1d: /* Mic */
728 idx = 2;
729 break;
730
731 case 0x1e: /* Line In */
732 idx = 3;
733 break;
734
735 case 0x21: /* Front Mic */
736 idx = 4;
737 break;
738
739 case 0x24: /* CD */
740 idx = 1;
741 break;
742 }
743 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
744 idx, 0x17);
745 if (err < 0)
746 return err;
747 imux->items[imux->num_items].label = labels[i];
748 imux->items[imux->num_items].index = idx;
749 imux->num_items++;
750 }
751 return 0;
752}
753
754static int vt1708_parse_auto_config(struct hda_codec *codec)
755{
756 struct via_spec *spec = codec->spec;
757 int err;
758
759 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
760 if (err < 0)
761 return err;
762 err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
763 if (err < 0)
764 return err;
765 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
766 return 0; /* can't find valid BIOS pin config */
767
768 err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
769 if (err < 0)
770 return err;
771 err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
772 if (err < 0)
773 return err;
774 err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
775 if (err < 0)
776 return err;
777
778 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
779
780 if (spec->autocfg.dig_out_pin)
781 spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
782 if (spec->autocfg.dig_in_pin)
783 spec->dig_in_nid = VT1708_DIGIN_NID;
784
785 if (spec->kctl_alloc)
786 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
787
788 spec->init_verbs = vt1708_volume_init_verbs;
789
790 spec->input_mux = &spec->private_imux;
791
792 return 1;
793}
794
795/* init callback for auto-configuration model -- overriding the default init */
796static int via_auto_init(struct hda_codec *codec)
797{
798 via_init(codec);
799 via_auto_init_multi_out(codec);
800 via_auto_init_hp_out(codec);
801 via_auto_init_analog_input(codec);
802 return 0;
803}
804
805static int patch_vt1708(struct hda_codec *codec)
806{
807 struct via_spec *spec;
808 int err;
809
810 /* create a codec specific record */
811 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
812 if (spec == NULL)
813 return -ENOMEM;
814
815 codec->spec = spec;
816
817 /* automatic parse from the BIOS config */
818 err = vt1708_parse_auto_config(codec);
819 if (err < 0) {
820 via_free(codec);
821 return err;
822 } else if (!err) {
823 printk(KERN_INFO "hda_codec: Cannot set up configuration "
824 "from BIOS. Using genenic mode...\n");
825 }
826
827
828 spec->stream_name_analog = "VT1708 Analog";
829 spec->stream_analog_playback = &vt1708_pcm_analog_playback;
830 spec->stream_analog_capture = &vt1708_pcm_analog_capture;
831
832 spec->stream_name_digital = "VT1708 Digital";
833 spec->stream_digital_playback = &vt1708_pcm_digital_playback;
834 spec->stream_digital_capture = &vt1708_pcm_digital_capture;
835
836
837 if (!spec->adc_nids && spec->input_mux) {
838 spec->adc_nids = vt1708_adc_nids;
839 spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
840 spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
841 spec->num_mixers++;
842 }
843
844 codec->patch_ops = via_patch_ops;
845
846 codec->patch_ops.init = via_auto_init;
847
848 return 0;
849}
850
851/* capture mixer elements */
852static struct snd_kcontrol_new vt1709_capture_mixer[] = {
853 HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
854 HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
855 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
856 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
857 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
858 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
859 {
860 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
861 /* The multiple "Capture Source" controls confuse alsamixer
862 * So call somewhat different..
863 * FIXME: the controls appear in the "playback" view!
864 */
865 /* .name = "Capture Source", */
866 .name = "Input Source",
867 .count = 1,
868 .info = via_mux_enum_info,
869 .get = via_mux_enum_get,
870 .put = via_mux_enum_put,
871 },
872 { } /* end */
873};
874
875/*
876 * generic initialization of ADC, input mixers and output mixers
877 */
878static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
879 /*
880 * Unmute ADC0-2 and set the default input to mic-in
881 */
882 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
883 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
884 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
885
886
887 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
888 * mixer widget
889 */
890 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
891 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
892 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
893 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
894 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
895 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
896
897 /*
898 * Set up output selector (0x1a, 0x1b, 0x29)
899 */
900 /* set vol=0 to output mixers */
901 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
902 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
903 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
904
905 /*
906 * Unmute PW3 and PW4
907 */
908 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
909 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
910
911 /* Set input of PW4 as AOW4 */
912 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
913 /* Set mic as default input of sw0 */
914 {0x19, AC_VERB_SET_CONNECT_SEL, 0x2},
915 /* PW9 Output enable */
916 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
917 { }
918};
919
920static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
921 .substreams = 1,
922 .channels_min = 2,
923 .channels_max = 10,
924 .nid = 0x10, /* NID to query formats and rates */
925 .ops = {
926 .open = via_playback_pcm_open,
927 .prepare = via_playback_pcm_prepare,
928 .cleanup = via_playback_pcm_cleanup
929 },
930};
931
932static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
933 .substreams = 1,
934 .channels_min = 2,
935 .channels_max = 6,
936 .nid = 0x10, /* NID to query formats and rates */
937 .ops = {
938 .open = via_playback_pcm_open,
939 .prepare = via_playback_pcm_prepare,
940 .cleanup = via_playback_pcm_cleanup
941 },
942};
943
944static struct hda_pcm_stream vt1709_pcm_analog_capture = {
945 .substreams = 2,
946 .channels_min = 2,
947 .channels_max = 2,
948 .nid = 0x14, /* NID to query formats and rates */
949 .ops = {
950 .prepare = via_capture_pcm_prepare,
951 .cleanup = via_capture_pcm_cleanup
952 },
953};
954
955static struct hda_pcm_stream vt1709_pcm_digital_playback = {
956 .substreams = 1,
957 .channels_min = 2,
958 .channels_max = 2,
959 /* NID is set in via_build_pcms */
960 .ops = {
961 .open = via_dig_playback_pcm_open,
962 .close = via_dig_playback_pcm_close
963 },
964};
965
966static struct hda_pcm_stream vt1709_pcm_digital_capture = {
967 .substreams = 1,
968 .channels_min = 2,
969 .channels_max = 2,
970};
971
972static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
973 const struct auto_pin_cfg *cfg)
974{
975 int i;
976 hda_nid_t nid;
977
978 if (cfg->line_outs == 4) /* 10 channels */
979 spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
980 else if (cfg->line_outs == 3) /* 6 channels */
981 spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
982
983 spec->multiout.dac_nids = spec->private_dac_nids;
984
985 if (cfg->line_outs == 4) { /* 10 channels */
986 for (i = 0; i < cfg->line_outs; i++) {
987 nid = cfg->line_out_pins[i];
988 if (nid) {
989 /* config dac list */
990 switch (i) {
991 case AUTO_SEQ_FRONT:
992 /* AOW0 */
993 spec->multiout.dac_nids[i] = 0x10;
994 break;
995 case AUTO_SEQ_CENLFE:
996 /* AOW2 */
997 spec->multiout.dac_nids[i] = 0x12;
998 break;
999 case AUTO_SEQ_SURROUND:
1000 /* AOW3 */
1001 spec->multiout.dac_nids[i] = 0x27;
1002 break;
1003 case AUTO_SEQ_SIDE:
1004 /* AOW1 */
1005 spec->multiout.dac_nids[i] = 0x11;
1006 break;
1007 default:
1008 break;
1009 }
1010 }
1011 }
1012 spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
1013
1014 } else if (cfg->line_outs == 3) { /* 6 channels */
1015 for(i = 0; i < cfg->line_outs; i++) {
1016 nid = cfg->line_out_pins[i];
1017 if (nid) {
1018 /* config dac list */
1019 switch(i) {
1020 case AUTO_SEQ_FRONT:
1021 /* AOW0 */
1022 spec->multiout.dac_nids[i] = 0x10;
1023 break;
1024 case AUTO_SEQ_CENLFE:
1025 /* AOW2 */
1026 spec->multiout.dac_nids[i] = 0x12;
1027 break;
1028 case AUTO_SEQ_SURROUND:
1029 /* AOW1 */
1030 spec->multiout.dac_nids[i] = 0x11;
1031 break;
1032 default:
1033 break;
1034 }
1035 }
1036 }
1037 }
1038
1039 return 0;
1040}
1041
1042/* add playback controls from the parsed DAC table */
1043static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
1044 const struct auto_pin_cfg *cfg)
1045{
1046 char name[32];
1047 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1048 hda_nid_t nid = 0;
1049 int i, err;
1050
1051 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1052 nid = cfg->line_out_pins[i];
1053
1054 if (!nid)
1055 continue;
1056
1057 if (i == AUTO_SEQ_CENLFE) {
1058 /* Center/LFE */
1059 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1060 "Center Playback Volume",
1061 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT));
1062 if (err < 0)
1063 return err;
1064 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1065 "LFE Playback Volume",
1066 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT));
1067 if (err < 0)
1068 return err;
1069 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1070 "Center Playback Switch",
1071 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT));
1072 if (err < 0)
1073 return err;
1074 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1075 "LFE Playback Switch",
1076 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT));
1077 if (err < 0)
1078 return err;
1079 } else if (i == AUTO_SEQ_FRONT){
1080 /* add control to mixer index 0 */
1081 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1082 "Master Front Playback Volume",
1083 HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT));
1084 if (err < 0)
1085 return err;
1086 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1087 "Master Front Playback Switch",
1088 HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT));
1089 if (err < 0)
1090 return err;
1091
1092 /* add control to PW3 */
1093 sprintf(name, "%s Playback Volume", chname[i]);
1094 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1095 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
1096 if (err < 0)
1097 return err;
1098 sprintf(name, "%s Playback Switch", chname[i]);
1099 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1100 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
1101 if (err < 0)
1102 return err;
1103 } else if (i == AUTO_SEQ_SURROUND) {
1104 sprintf(name, "%s Playback Volume", chname[i]);
1105 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1106 HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT));
1107 if (err < 0)
1108 return err;
1109 sprintf(name, "%s Playback Switch", chname[i]);
1110 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1111 HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT));
1112 if (err < 0)
1113 return err;
1114 } else if (i == AUTO_SEQ_SIDE) {
1115 sprintf(name, "%s Playback Volume", chname[i]);
1116 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
1117 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT));
1118 if (err < 0)
1119 return err;
1120 sprintf(name, "%s Playback Switch", chname[i]);
1121 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
1122 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT));
1123 if (err < 0)
1124 return err;
1125 }
1126 }
1127
1128 return 0;
1129}
1130
1131static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1132{
1133 int err;
1134
1135 if (!pin)
1136 return 0;
1137
1138 if (spec->multiout.num_dacs == 5) /* 10 channels */
1139 spec->multiout.hp_nid = VT1709_HP_DAC_NID;
1140 else if (spec->multiout.num_dacs == 3) /* 6 channels */
1141 spec->multiout.hp_nid = 0;
1142
1143 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1144 "Headphone Playback Volume",
1145 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1146 if (err < 0)
1147 return err;
1148 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1149 "Headphone Playback Switch",
1150 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1151 if (err < 0)
1152 return err;
1153
1154 return 0;
1155}
1156
1157/* create playback/capture controls for input pins */
1158static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
1159 const struct auto_pin_cfg *cfg)
1160{
1161 static char *labels[] = {
1162 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1163 };
1164 struct hda_input_mux *imux = &spec->private_imux;
1165 int i, err, idx = 0;
1166
1167 /* for internal loopback recording select */
1168 imux->items[imux->num_items].label = "Stereo Mixer";
1169 imux->items[imux->num_items].index = idx;
1170 imux->num_items++;
1171
1172 for (i = 0; i < AUTO_PIN_LAST; i++) {
1173 if (!cfg->input_pins[i])
1174 continue;
1175
1176 switch (cfg->input_pins[i]) {
1177 case 0x1d: /* Mic */
1178 idx = 2;
1179 break;
1180
1181 case 0x1e: /* Line In */
1182 idx = 3;
1183 break;
1184
1185 case 0x21: /* Front Mic */
1186 idx = 4;
1187 break;
1188
1189 case 0x23: /* CD */
1190 idx = 1;
1191 break;
1192 }
1193 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
1194 idx, 0x18);
1195 if (err < 0)
1196 return err;
1197 imux->items[imux->num_items].label = labels[i];
1198 imux->items[imux->num_items].index = idx;
1199 imux->num_items++;
1200 }
1201 return 0;
1202}
1203
1204static int vt1709_parse_auto_config(struct hda_codec *codec)
1205{
1206 struct via_spec *spec = codec->spec;
1207 int err;
1208
1209 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1210 if (err < 0)
1211 return err;
1212 err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
1213 if (err < 0)
1214 return err;
1215 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1216 return 0; /* can't find valid BIOS pin config */
1217
1218 err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
1219 if (err < 0)
1220 return err;
1221 err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1222 if (err < 0)
1223 return err;
1224 err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
1225 if (err < 0)
1226 return err;
1227
1228 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1229
1230 if (spec->autocfg.dig_out_pin)
1231 spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
1232 if (spec->autocfg.dig_in_pin)
1233 spec->dig_in_nid = VT1709_DIGIN_NID;
1234
1235 if (spec->kctl_alloc)
1236 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
1237
1238 spec->input_mux = &spec->private_imux;
1239
1240 return 1;
1241}
1242
1243static int patch_vt1709_10ch(struct hda_codec *codec)
1244{
1245 struct via_spec *spec;
1246 int err;
1247
1248 /* create a codec specific record */
1249 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
1250 if (spec == NULL)
1251 return -ENOMEM;
1252
1253 codec->spec = spec;
1254
1255 err = vt1709_parse_auto_config(codec);
1256 if (err < 0) {
1257 via_free(codec);
1258 return err;
1259 } else if (!err) {
1260 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
1261 "Using genenic mode...\n");
1262 }
1263
1264 spec->init_verbs = vt1709_10ch_volume_init_verbs;
1265
1266 spec->stream_name_analog = "VT1709 Analog";
1267 spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
1268 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1269
1270 spec->stream_name_digital = "VT1709 Digital";
1271 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1272 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1273
1274
1275 if (!spec->adc_nids && spec->input_mux) {
1276 spec->adc_nids = vt1709_adc_nids;
1277 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
1278 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1279 spec->num_mixers++;
1280 }
1281
1282 codec->patch_ops = via_patch_ops;
1283
1284 codec->patch_ops.init = via_auto_init;
1285
1286 return 0;
1287}
1288/*
1289 * generic initialization of ADC, input mixers and output mixers
1290 */
1291static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
1292 /*
1293 * Unmute ADC0-2 and set the default input to mic-in
1294 */
1295 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1296 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1297 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1298
1299
1300 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1301 * mixer widget
1302 */
1303 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1304 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1305 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1306 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1307 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1308 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1309
1310 /*
1311 * Set up output selector (0x1a, 0x1b, 0x29)
1312 */
1313 /* set vol=0 to output mixers */
1314 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1315 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1316 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1317
1318 /*
1319 * Unmute PW3 and PW4
1320 */
1321 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1322 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1323
1324 /* Set input of PW4 as MW0 */
1325 {0x20, AC_VERB_SET_CONNECT_SEL, 0},
1326 /* Set mic as default input of sw0 */
1327 {0x19, AC_VERB_SET_CONNECT_SEL, 0x2},
1328 /* PW9 Output enable */
1329 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1330 { }
1331};
1332
1333static int patch_vt1709_6ch(struct hda_codec *codec)
1334{
1335 struct via_spec *spec;
1336 int err;
1337
1338 /* create a codec specific record */
1339 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
1340 if (spec == NULL)
1341 return -ENOMEM;
1342
1343 codec->spec = spec;
1344
1345 err = vt1709_parse_auto_config(codec);
1346 if (err < 0) {
1347 via_free(codec);
1348 return err;
1349 } else if (!err) {
1350 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
1351 "Using genenic mode...\n");
1352 }
1353
1354 spec->init_verbs = vt1709_6ch_volume_init_verbs;
1355
1356 spec->stream_name_analog = "VT1709 Analog";
1357 spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
1358 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1359
1360 spec->stream_name_digital = "VT1709 Digital";
1361 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1362 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1363
1364
1365 if (!spec->adc_nids && spec->input_mux) {
1366 spec->adc_nids = vt1709_adc_nids;
1367 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
1368 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1369 spec->num_mixers++;
1370 }
1371
1372 codec->patch_ops = via_patch_ops;
1373
1374 codec->patch_ops.init = via_auto_init;
1375
1376 return 0;
1377}
1378
1379/*
1380 * patch entries
1381 */
1382struct hda_codec_preset snd_hda_preset_via[] = {
1383 { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708},
1384 { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708},
1385 { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708},
1386 { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708},
1387 { .id = 0x1106E710, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
1388 { .id = 0x1106E711, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
1389 { .id = 0x1106E712, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
1390 { .id = 0x1106E713, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
1391 { .id = 0x1106E714, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
1392 { .id = 0x1106E715, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
1393 { .id = 0x1106E716, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
1394 { .id = 0x1106E717, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
1395 {} /* terminator */
1396};