blob: e62698984287bf83610c14c9e844845866bf09fc [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 */
Harald Welted7426322008-09-15 22:43:23 +080038/* 2008-09-15 Logan Li Add VT1708S Mic Boost workaround/backdoor */
Joseph Chanc577b8a2006-11-29 15:29:40 +010039/* */
40/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
41
42
Joseph Chanc577b8a2006-11-29 15:29:40 +010043#include <linux/init.h>
44#include <linux/delay.h>
45#include <linux/slab.h>
Joseph Chanc577b8a2006-11-29 15:29:40 +010046#include <sound/core.h>
Harald Welte0aa62ae2008-09-09 15:58:27 +080047#include <sound/asoundef.h>
Joseph Chanc577b8a2006-11-29 15:29:40 +010048#include "hda_codec.h"
49#include "hda_local.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
Joseph Chanc577b8a2006-11-29 15:29:40 +010055/* Pin Widget NID */
56#define VT1708_HP_NID 0x13
57#define VT1708_DIGOUT_NID 0x14
58#define VT1708_DIGIN_NID 0x16
Josepch Chanf7278fd2007-12-13 16:40:40 +010059#define VT1708_DIGIN_PIN 0x26
Harald Welted949cac2008-09-09 15:56:01 +080060#define VT1708_HP_PIN_NID 0x20
61#define VT1708_CD_PIN_NID 0x24
Joseph Chanc577b8a2006-11-29 15:29:40 +010062
63#define VT1709_HP_DAC_NID 0x28
64#define VT1709_DIGOUT_NID 0x13
65#define VT1709_DIGIN_NID 0x17
Josepch Chanf7278fd2007-12-13 16:40:40 +010066#define VT1709_DIGIN_PIN 0x25
67
68#define VT1708B_HP_NID 0x25
69#define VT1708B_DIGOUT_NID 0x12
70#define VT1708B_DIGIN_NID 0x15
71#define VT1708B_DIGIN_PIN 0x21
Joseph Chanc577b8a2006-11-29 15:29:40 +010072
Harald Welted949cac2008-09-09 15:56:01 +080073#define VT1708S_HP_NID 0x25
74#define VT1708S_DIGOUT_NID 0x12
75
76#define VT1702_HP_NID 0x17
77#define VT1702_DIGOUT_NID 0x11
78
Harald Welted7426322008-09-15 22:43:23 +080079enum VIA_HDA_CODEC {
80 UNKNOWN = -1,
81 VT1708,
82 VT1709_10CH,
83 VT1709_6CH,
84 VT1708B_8CH,
85 VT1708B_4CH,
86 VT1708S,
Lydia Wang518bf3b2009-10-10 19:07:29 +080087 VT1708BCE,
Harald Welted7426322008-09-15 22:43:23 +080088 VT1702,
89 CODEC_TYPES,
90};
91
Lydia Wang744ff5f2009-10-10 19:07:26 +080092static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
Harald Welted7426322008-09-15 22:43:23 +080093{
Lydia Wang744ff5f2009-10-10 19:07:26 +080094 u32 vendor_id = codec->vendor_id;
Harald Welted7426322008-09-15 22:43:23 +080095 u16 ven_id = vendor_id >> 16;
96 u16 dev_id = vendor_id & 0xffff;
97 enum VIA_HDA_CODEC codec_type;
98
99 /* get codec type */
100 if (ven_id != 0x1106)
101 codec_type = UNKNOWN;
102 else if (dev_id >= 0x1708 && dev_id <= 0x170b)
103 codec_type = VT1708;
104 else if (dev_id >= 0xe710 && dev_id <= 0xe713)
105 codec_type = VT1709_10CH;
106 else if (dev_id >= 0xe714 && dev_id <= 0xe717)
107 codec_type = VT1709_6CH;
Lydia Wang518bf3b2009-10-10 19:07:29 +0800108 else if (dev_id >= 0xe720 && dev_id <= 0xe723) {
Harald Welted7426322008-09-15 22:43:23 +0800109 codec_type = VT1708B_8CH;
Lydia Wang518bf3b2009-10-10 19:07:29 +0800110 if (snd_hda_param_read(codec, 0x16, AC_PAR_CONNLIST_LEN) == 0x7)
111 codec_type = VT1708BCE;
112 } else if (dev_id >= 0xe724 && dev_id <= 0xe727)
Harald Welted7426322008-09-15 22:43:23 +0800113 codec_type = VT1708B_4CH;
114 else if ((dev_id & 0xfff) == 0x397
115 && (dev_id >> 12) < 8)
116 codec_type = VT1708S;
117 else if ((dev_id & 0xfff) == 0x398
118 && (dev_id >> 12) < 8)
119 codec_type = VT1702;
120 else
121 codec_type = UNKNOWN;
122 return codec_type;
123};
124
Harald Welte69e52a82008-09-09 15:57:32 +0800125#define VIA_HP_EVENT 0x01
126#define VIA_GPIO_EVENT 0x02
127
Joseph Chanc577b8a2006-11-29 15:29:40 +0100128enum {
129 VIA_CTL_WIDGET_VOL,
130 VIA_CTL_WIDGET_MUTE,
131};
132
133enum {
Harald Welteeb14a462008-09-09 15:40:38 +0800134 AUTO_SEQ_FRONT = 0,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100135 AUTO_SEQ_SURROUND,
136 AUTO_SEQ_CENLFE,
137 AUTO_SEQ_SIDE
138};
139
Harald Welted7426322008-09-15 22:43:23 +0800140/* Some VT1708S based boards gets the micboost setting wrong, so we have
141 * to apply some brute-force and re-write the TLV's by software. */
142static int mic_boost_tlv(struct snd_kcontrol *kcontrol, int op_flag,
143 unsigned int size, unsigned int __user *_tlv)
144{
145 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
146 hda_nid_t nid = get_amp_nid(kcontrol);
147
Lydia Wang744ff5f2009-10-10 19:07:26 +0800148 if (get_codec_type(codec) == VT1708S
Harald Welted7426322008-09-15 22:43:23 +0800149 && (nid == 0x1a || nid == 0x1e)) {
150 if (size < 4 * sizeof(unsigned int))
151 return -ENOMEM;
152 if (put_user(1, _tlv)) /* SNDRV_CTL_TLVT_DB_SCALE */
153 return -EFAULT;
154 if (put_user(2 * sizeof(unsigned int), _tlv + 1))
155 return -EFAULT;
156 if (put_user(0, _tlv + 2)) /* offset = 0 */
157 return -EFAULT;
158 if (put_user(1000, _tlv + 3)) /* step size = 10 dB */
159 return -EFAULT;
160 }
161 return 0;
162}
163
164static int mic_boost_volume_info(struct snd_kcontrol *kcontrol,
165 struct snd_ctl_elem_info *uinfo)
166{
167 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
168 hda_nid_t nid = get_amp_nid(kcontrol);
169
Lydia Wang744ff5f2009-10-10 19:07:26 +0800170 if (get_codec_type(codec) == VT1708S
Harald Welted7426322008-09-15 22:43:23 +0800171 && (nid == 0x1a || nid == 0x1e)) {
172 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
173 uinfo->count = 2;
174 uinfo->value.integer.min = 0;
175 uinfo->value.integer.max = 3;
176 }
177 return 0;
178}
179
Joseph Chanc577b8a2006-11-29 15:29:40 +0100180static struct snd_kcontrol_new vt1708_control_templates[] = {
181 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
182 HDA_CODEC_MUTE(NULL, 0, 0, 0),
183};
184
185
186struct via_spec {
187 /* codec parameterization */
188 struct snd_kcontrol_new *mixers[3];
189 unsigned int num_mixers;
190
Harald Welte69e52a82008-09-09 15:57:32 +0800191 struct hda_verb *init_verbs[5];
192 unsigned int num_iverbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100193
194 char *stream_name_analog;
195 struct hda_pcm_stream *stream_analog_playback;
196 struct hda_pcm_stream *stream_analog_capture;
197
198 char *stream_name_digital;
199 struct hda_pcm_stream *stream_digital_playback;
200 struct hda_pcm_stream *stream_digital_capture;
201
202 /* playback */
203 struct hda_multi_out multiout;
Takashi Iwai9da29272009-05-07 16:31:14 +0200204 hda_nid_t slave_dig_outs[2];
Joseph Chanc577b8a2006-11-29 15:29:40 +0100205
206 /* capture */
207 unsigned int num_adc_nids;
208 hda_nid_t *adc_nids;
Takashi Iwai337b9d02009-07-07 18:18:59 +0200209 hda_nid_t mux_nids[3];
Joseph Chanc577b8a2006-11-29 15:29:40 +0100210 hda_nid_t dig_in_nid;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +0200211 hda_nid_t dig_in_pin;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100212
213 /* capture source */
214 const struct hda_input_mux *input_mux;
215 unsigned int cur_mux[3];
216
217 /* PCM information */
Harald Welte98aa34c2008-09-09 16:02:09 +0800218 struct hda_pcm pcm_rec[3];
Joseph Chanc577b8a2006-11-29 15:29:40 +0100219
220 /* dynamic controls, init_verbs and input_mux */
221 struct auto_pin_cfg autocfg;
Takashi Iwai603c4012008-07-30 15:01:44 +0200222 struct snd_array kctls;
Harald Welte0aa62ae2008-09-09 15:58:27 +0800223 struct hda_input_mux private_imux[2];
Takashi Iwai41923e42007-10-22 17:20:10 +0200224 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwaicb53c622007-08-10 17:21:45 +0200225
Harald Welte0aa62ae2008-09-09 15:58:27 +0800226 /* HP mode source */
227 const struct hda_input_mux *hp_mux;
228 unsigned int hp_independent_mode;
229
Lydia Wang518bf3b2009-10-10 19:07:29 +0800230 enum VIA_HDA_CODEC codec_type;
231
Takashi Iwaicb53c622007-08-10 17:21:45 +0200232#ifdef CONFIG_SND_HDA_POWER_SAVE
233 struct hda_loopback_check loopback;
234#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +0100235};
236
237static hda_nid_t vt1708_adc_nids[2] = {
238 /* ADC1-2 */
239 0x15, 0x27
240};
241
242static hda_nid_t vt1709_adc_nids[3] = {
243 /* ADC1-2 */
244 0x14, 0x15, 0x16
245};
246
Josepch Chanf7278fd2007-12-13 16:40:40 +0100247static hda_nid_t vt1708B_adc_nids[2] = {
248 /* ADC1-2 */
249 0x13, 0x14
250};
251
Harald Welted949cac2008-09-09 15:56:01 +0800252static hda_nid_t vt1708S_adc_nids[2] = {
253 /* ADC1-2 */
254 0x13, 0x14
255};
256
257static hda_nid_t vt1702_adc_nids[3] = {
258 /* ADC1-2 */
259 0x12, 0x20, 0x1F
260};
261
Joseph Chanc577b8a2006-11-29 15:29:40 +0100262/* add dynamic controls */
263static int via_add_control(struct via_spec *spec, int type, const char *name,
264 unsigned long val)
265{
266 struct snd_kcontrol_new *knew;
267
Takashi Iwai603c4012008-07-30 15:01:44 +0200268 snd_array_init(&spec->kctls, sizeof(*knew), 32);
269 knew = snd_array_new(&spec->kctls);
270 if (!knew)
271 return -ENOMEM;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100272 *knew = vt1708_control_templates[type];
273 knew->name = kstrdup(name, GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100274 if (!knew->name)
275 return -ENOMEM;
276 knew->private_value = val;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100277 return 0;
278}
279
Takashi Iwai603c4012008-07-30 15:01:44 +0200280static void via_free_kctls(struct hda_codec *codec)
281{
282 struct via_spec *spec = codec->spec;
283
284 if (spec->kctls.list) {
285 struct snd_kcontrol_new *kctl = spec->kctls.list;
286 int i;
287 for (i = 0; i < spec->kctls.used; i++)
288 kfree(kctl[i].name);
289 }
290 snd_array_free(&spec->kctls);
291}
292
Joseph Chanc577b8a2006-11-29 15:29:40 +0100293/* create input playback/capture controls for the given pin */
294static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
295 const char *ctlname, int idx, int mix_nid)
296{
297 char name[32];
298 int err;
299
300 sprintf(name, "%s Playback Volume", ctlname);
301 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
302 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
303 if (err < 0)
304 return err;
305 sprintf(name, "%s Playback Switch", ctlname);
306 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
307 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
308 if (err < 0)
309 return err;
310 return 0;
311}
312
313static void via_auto_set_output_and_unmute(struct hda_codec *codec,
314 hda_nid_t nid, int pin_type,
315 int dac_idx)
316{
317 /* set as output */
318 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
319 pin_type);
320 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
321 AMP_OUT_UNMUTE);
Takashi Iwaid3a11e62009-07-07 13:43:35 +0200322 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
323 snd_hda_codec_write(codec, nid, 0,
324 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100325}
326
327
328static void via_auto_init_multi_out(struct hda_codec *codec)
329{
330 struct via_spec *spec = codec->spec;
331 int i;
332
333 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
334 hda_nid_t nid = spec->autocfg.line_out_pins[i];
335 if (nid)
336 via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
337 }
338}
339
340static void via_auto_init_hp_out(struct hda_codec *codec)
341{
342 struct via_spec *spec = codec->spec;
343 hda_nid_t pin;
344
345 pin = spec->autocfg.hp_pins[0];
346 if (pin) /* connect to front */
347 via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
348}
349
350static void via_auto_init_analog_input(struct hda_codec *codec)
351{
352 struct via_spec *spec = codec->spec;
353 int i;
354
355 for (i = 0; i < AUTO_PIN_LAST; i++) {
356 hda_nid_t nid = spec->autocfg.input_pins[i];
357
358 snd_hda_codec_write(codec, nid, 0,
359 AC_VERB_SET_PIN_WIDGET_CONTROL,
360 (i <= AUTO_PIN_FRONT_MIC ?
361 PIN_VREF50 : PIN_IN));
362
363 }
364}
365/*
366 * input MUX handling
367 */
368static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
369 struct snd_ctl_elem_info *uinfo)
370{
371 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
372 struct via_spec *spec = codec->spec;
373 return snd_hda_input_mux_info(spec->input_mux, uinfo);
374}
375
376static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
377 struct snd_ctl_elem_value *ucontrol)
378{
379 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
380 struct via_spec *spec = codec->spec;
381 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
382
383 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
384 return 0;
385}
386
387static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
388 struct snd_ctl_elem_value *ucontrol)
389{
390 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
391 struct via_spec *spec = codec->spec;
392 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100393
Takashi Iwai337b9d02009-07-07 18:18:59 +0200394 if (!spec->mux_nids[adc_idx])
395 return -EINVAL;
396 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
397 spec->mux_nids[adc_idx],
398 &spec->cur_mux[adc_idx]);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100399}
400
Harald Welte0aa62ae2008-09-09 15:58:27 +0800401static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
402 struct snd_ctl_elem_info *uinfo)
403{
404 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
405 struct via_spec *spec = codec->spec;
406 return snd_hda_input_mux_info(spec->hp_mux, uinfo);
407}
408
409static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
410 struct snd_ctl_elem_value *ucontrol)
411{
412 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
413 struct via_spec *spec = codec->spec;
414 hda_nid_t nid = spec->autocfg.hp_pins[0];
415 unsigned int pinsel = snd_hda_codec_read(codec, nid, 0,
416 AC_VERB_GET_CONNECT_SEL,
417 0x00);
418
419 ucontrol->value.enumerated.item[0] = pinsel;
420
421 return 0;
422}
423
424static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
425 struct snd_ctl_elem_value *ucontrol)
426{
427 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
428 struct via_spec *spec = codec->spec;
429 hda_nid_t nid = spec->autocfg.hp_pins[0];
430 unsigned int pinsel = ucontrol->value.enumerated.item[0];
431 unsigned int con_nid = snd_hda_codec_read(codec, nid, 0,
432 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
433
434 if (con_nid == spec->multiout.hp_nid) {
435 if (pinsel == 0) {
436 if (!spec->hp_independent_mode) {
437 if (spec->multiout.num_dacs > 1)
438 spec->multiout.num_dacs -= 1;
439 spec->hp_independent_mode = 1;
440 }
441 } else if (pinsel == 1) {
442 if (spec->hp_independent_mode) {
443 if (spec->multiout.num_dacs > 1)
444 spec->multiout.num_dacs += 1;
445 spec->hp_independent_mode = 0;
446 }
447 }
448 } else {
449 if (pinsel == 0) {
450 if (spec->hp_independent_mode) {
451 if (spec->multiout.num_dacs > 1)
452 spec->multiout.num_dacs += 1;
453 spec->hp_independent_mode = 0;
454 }
455 } else if (pinsel == 1) {
456 if (!spec->hp_independent_mode) {
457 if (spec->multiout.num_dacs > 1)
458 spec->multiout.num_dacs -= 1;
459 spec->hp_independent_mode = 1;
460 }
461 }
462 }
463 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL,
464 pinsel);
465
466 if (spec->multiout.hp_nid &&
467 spec->multiout.hp_nid != spec->multiout.dac_nids[HDA_FRONT])
468 snd_hda_codec_setup_stream(codec,
469 spec->multiout.hp_nid,
470 0, 0, 0);
471
472 return 0;
473}
474
475static struct snd_kcontrol_new via_hp_mixer[] = {
476 {
477 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
478 .name = "Independent HP",
479 .count = 1,
480 .info = via_independent_hp_info,
481 .get = via_independent_hp_get,
482 .put = via_independent_hp_put,
483 },
484 { } /* end */
485};
486
Joseph Chanc577b8a2006-11-29 15:29:40 +0100487/* capture mixer elements */
488static struct snd_kcontrol_new vt1708_capture_mixer[] = {
489 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
490 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
491 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
492 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
493 {
494 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
495 /* The multiple "Capture Source" controls confuse alsamixer
496 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +0100497 */
498 /* .name = "Capture Source", */
499 .name = "Input Source",
500 .count = 1,
501 .info = via_mux_enum_info,
502 .get = via_mux_enum_get,
503 .put = via_mux_enum_put,
504 },
505 { } /* end */
506};
507/*
508 * generic initialization of ADC, input mixers and output mixers
509 */
510static struct hda_verb vt1708_volume_init_verbs[] = {
511 /*
512 * Unmute ADC0-1 and set the default input to mic-in
513 */
514 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
515 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
516
517
Josepch Chanf7278fd2007-12-13 16:40:40 +0100518 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +0100519 * mixer widget
520 */
521 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +0100522 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
523 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
524 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
525 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
526 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100527
528 /*
529 * Set up output mixers (0x19 - 0x1b)
530 */
531 /* set vol=0 to output mixers */
532 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
533 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
534 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
535
536 /* Setup default input to PW4 */
537 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100538 /* PW9 Output enable */
539 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Josepch Chanf7278fd2007-12-13 16:40:40 +0100540 { }
Joseph Chanc577b8a2006-11-29 15:29:40 +0100541};
542
543static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
544 struct hda_codec *codec,
545 struct snd_pcm_substream *substream)
546{
547 struct via_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +0100548 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
549 hinfo);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100550}
551
552static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
553 struct hda_codec *codec,
554 unsigned int stream_tag,
555 unsigned int format,
556 struct snd_pcm_substream *substream)
557{
558 struct via_spec *spec = codec->spec;
559 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
560 stream_tag, format, substream);
561}
562
563static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
564 struct hda_codec *codec,
565 struct snd_pcm_substream *substream)
566{
567 struct via_spec *spec = codec->spec;
568 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
569}
570
Harald Welte0aa62ae2008-09-09 15:58:27 +0800571
572static void playback_multi_pcm_prep_0(struct hda_codec *codec,
573 unsigned int stream_tag,
574 unsigned int format,
575 struct snd_pcm_substream *substream)
576{
577 struct via_spec *spec = codec->spec;
578 struct hda_multi_out *mout = &spec->multiout;
579 hda_nid_t *nids = mout->dac_nids;
580 int chs = substream->runtime->channels;
581 int i;
582
583 mutex_lock(&codec->spdif_mutex);
584 if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
585 if (chs == 2 &&
586 snd_hda_is_supported_format(codec, mout->dig_out_nid,
587 format) &&
588 !(codec->spdif_status & IEC958_AES0_NONAUDIO)) {
589 mout->dig_out_used = HDA_DIG_ANALOG_DUP;
590 /* turn off SPDIF once; otherwise the IEC958 bits won't
591 * be updated */
592 if (codec->spdif_ctls & AC_DIG1_ENABLE)
593 snd_hda_codec_write(codec, mout->dig_out_nid, 0,
594 AC_VERB_SET_DIGI_CONVERT_1,
595 codec->spdif_ctls &
596 ~AC_DIG1_ENABLE & 0xff);
597 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
598 stream_tag, 0, format);
599 /* turn on again (if needed) */
600 if (codec->spdif_ctls & AC_DIG1_ENABLE)
601 snd_hda_codec_write(codec, mout->dig_out_nid, 0,
602 AC_VERB_SET_DIGI_CONVERT_1,
603 codec->spdif_ctls & 0xff);
604 } else {
605 mout->dig_out_used = 0;
606 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
607 0, 0, 0);
608 }
609 }
610 mutex_unlock(&codec->spdif_mutex);
611
612 /* front */
613 snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag,
614 0, format);
615
616 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
617 !spec->hp_independent_mode)
618 /* headphone out will just decode front left/right (stereo) */
619 snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag,
620 0, format);
621
622 /* extra outputs copied from front */
623 for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
624 if (mout->extra_out_nid[i])
625 snd_hda_codec_setup_stream(codec,
626 mout->extra_out_nid[i],
627 stream_tag, 0, format);
628
629 /* surrounds */
630 for (i = 1; i < mout->num_dacs; i++) {
631 if (chs >= (i + 1) * 2) /* independent out */
632 snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
633 i * 2, format);
634 else /* copy front */
635 snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
636 0, format);
637 }
638}
639
640static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
641 struct hda_codec *codec,
642 unsigned int stream_tag,
643 unsigned int format,
644 struct snd_pcm_substream *substream)
645{
646 struct via_spec *spec = codec->spec;
647 struct hda_multi_out *mout = &spec->multiout;
648 hda_nid_t *nids = mout->dac_nids;
649
650 if (substream->number == 0)
651 playback_multi_pcm_prep_0(codec, stream_tag, format,
652 substream);
653 else {
654 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
655 spec->hp_independent_mode)
656 snd_hda_codec_setup_stream(codec, mout->hp_nid,
657 stream_tag, 0, format);
658 }
659
660 return 0;
661}
662
663static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
664 struct hda_codec *codec,
665 struct snd_pcm_substream *substream)
666{
667 struct via_spec *spec = codec->spec;
668 struct hda_multi_out *mout = &spec->multiout;
669 hda_nid_t *nids = mout->dac_nids;
670 int i;
671
672 if (substream->number == 0) {
673 for (i = 0; i < mout->num_dacs; i++)
674 snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
675
676 if (mout->hp_nid && !spec->hp_independent_mode)
677 snd_hda_codec_setup_stream(codec, mout->hp_nid,
678 0, 0, 0);
679
680 for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
681 if (mout->extra_out_nid[i])
682 snd_hda_codec_setup_stream(codec,
683 mout->extra_out_nid[i],
684 0, 0, 0);
685 mutex_lock(&codec->spdif_mutex);
686 if (mout->dig_out_nid &&
687 mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
688 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
689 0, 0, 0);
690 mout->dig_out_used = 0;
691 }
692 mutex_unlock(&codec->spdif_mutex);
693 } else {
694 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
695 spec->hp_independent_mode)
696 snd_hda_codec_setup_stream(codec, mout->hp_nid,
697 0, 0, 0);
698 }
699
700 return 0;
701}
702
Joseph Chanc577b8a2006-11-29 15:29:40 +0100703/*
704 * Digital out
705 */
706static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
707 struct hda_codec *codec,
708 struct snd_pcm_substream *substream)
709{
710 struct via_spec *spec = codec->spec;
711 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
712}
713
714static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
715 struct hda_codec *codec,
716 struct snd_pcm_substream *substream)
717{
718 struct via_spec *spec = codec->spec;
719 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
720}
721
Harald Welte5691ec72008-09-15 22:42:26 +0800722static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
Harald Welte98aa34c2008-09-09 16:02:09 +0800723 struct hda_codec *codec,
724 unsigned int stream_tag,
725 unsigned int format,
726 struct snd_pcm_substream *substream)
727{
728 struct via_spec *spec = codec->spec;
Takashi Iwai9da29272009-05-07 16:31:14 +0200729 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
730 stream_tag, format, substream);
731}
Harald Welte5691ec72008-09-15 22:42:26 +0800732
Takashi Iwai9da29272009-05-07 16:31:14 +0200733static int via_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
734 struct hda_codec *codec,
735 struct snd_pcm_substream *substream)
736{
737 struct via_spec *spec = codec->spec;
738 snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
Harald Welte98aa34c2008-09-09 16:02:09 +0800739 return 0;
740}
741
Joseph Chanc577b8a2006-11-29 15:29:40 +0100742/*
743 * Analog capture
744 */
745static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
746 struct hda_codec *codec,
747 unsigned int stream_tag,
748 unsigned int format,
749 struct snd_pcm_substream *substream)
750{
751 struct via_spec *spec = codec->spec;
752
753 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
754 stream_tag, 0, format);
755 return 0;
756}
757
758static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
759 struct hda_codec *codec,
760 struct snd_pcm_substream *substream)
761{
762 struct via_spec *spec = codec->spec;
Takashi Iwai888afa12008-03-18 09:57:50 +0100763 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100764 return 0;
765}
766
767static struct hda_pcm_stream vt1708_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +0800768 .substreams = 2,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100769 .channels_min = 2,
770 .channels_max = 8,
771 .nid = 0x10, /* NID to query formats and rates */
772 .ops = {
773 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +0800774 .prepare = via_playback_multi_pcm_prepare,
775 .cleanup = via_playback_multi_pcm_cleanup
Joseph Chanc577b8a2006-11-29 15:29:40 +0100776 },
777};
778
Takashi Iwaibc9b562382008-05-23 17:50:27 +0200779static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
780 .substreams = 1,
781 .channels_min = 2,
782 .channels_max = 8,
783 .nid = 0x10, /* NID to query formats and rates */
784 /* We got noisy outputs on the right channel on VT1708 when
785 * 24bit samples are used. Until any workaround is found,
786 * disable the 24bit format, so far.
787 */
788 .formats = SNDRV_PCM_FMTBIT_S16_LE,
789 .ops = {
790 .open = via_playback_pcm_open,
791 .prepare = via_playback_pcm_prepare,
792 .cleanup = via_playback_pcm_cleanup
793 },
794};
795
Joseph Chanc577b8a2006-11-29 15:29:40 +0100796static struct hda_pcm_stream vt1708_pcm_analog_capture = {
797 .substreams = 2,
798 .channels_min = 2,
799 .channels_max = 2,
800 .nid = 0x15, /* NID to query formats and rates */
801 .ops = {
802 .prepare = via_capture_pcm_prepare,
803 .cleanup = via_capture_pcm_cleanup
804 },
805};
806
807static struct hda_pcm_stream vt1708_pcm_digital_playback = {
808 .substreams = 1,
809 .channels_min = 2,
810 .channels_max = 2,
811 /* NID is set in via_build_pcms */
812 .ops = {
813 .open = via_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +0200814 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +0200815 .prepare = via_dig_playback_pcm_prepare,
816 .cleanup = via_dig_playback_pcm_cleanup
Joseph Chanc577b8a2006-11-29 15:29:40 +0100817 },
818};
819
820static struct hda_pcm_stream vt1708_pcm_digital_capture = {
821 .substreams = 1,
822 .channels_min = 2,
823 .channels_max = 2,
824};
825
826static int via_build_controls(struct hda_codec *codec)
827{
828 struct via_spec *spec = codec->spec;
829 int err;
830 int i;
831
832 for (i = 0; i < spec->num_mixers; i++) {
833 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
834 if (err < 0)
835 return err;
836 }
837
838 if (spec->multiout.dig_out_nid) {
839 err = snd_hda_create_spdif_out_ctls(codec,
840 spec->multiout.dig_out_nid);
841 if (err < 0)
842 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +0100843 err = snd_hda_create_spdif_share_sw(codec,
844 &spec->multiout);
845 if (err < 0)
846 return err;
847 spec->multiout.share_spdif = 1;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100848 }
849 if (spec->dig_in_nid) {
850 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
851 if (err < 0)
852 return err;
853 }
Takashi Iwai603c4012008-07-30 15:01:44 +0200854 via_free_kctls(codec); /* no longer needed */
Joseph Chanc577b8a2006-11-29 15:29:40 +0100855 return 0;
856}
857
858static int via_build_pcms(struct hda_codec *codec)
859{
860 struct via_spec *spec = codec->spec;
861 struct hda_pcm *info = spec->pcm_rec;
862
863 codec->num_pcms = 1;
864 codec->pcm_info = info;
865
866 info->name = spec->stream_name_analog;
867 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
868 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
869 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
870 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
871
872 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
873 spec->multiout.max_channels;
874
875 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
876 codec->num_pcms++;
877 info++;
878 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +0100879 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100880 if (spec->multiout.dig_out_nid) {
881 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
882 *(spec->stream_digital_playback);
883 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
884 spec->multiout.dig_out_nid;
885 }
886 if (spec->dig_in_nid) {
887 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
888 *(spec->stream_digital_capture);
889 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
890 spec->dig_in_nid;
891 }
892 }
893
894 return 0;
895}
896
897static void via_free(struct hda_codec *codec)
898{
899 struct via_spec *spec = codec->spec;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100900
901 if (!spec)
902 return;
903
Takashi Iwai603c4012008-07-30 15:01:44 +0200904 via_free_kctls(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100905 kfree(codec->spec);
906}
907
Harald Welte69e52a82008-09-09 15:57:32 +0800908/* mute internal speaker if HP is plugged */
909static void via_hp_automute(struct hda_codec *codec)
910{
911 unsigned int present;
912 struct via_spec *spec = codec->spec;
913
914 present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
915 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
916 snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
917 HDA_OUTPUT, 0, HDA_AMP_MUTE,
918 present ? HDA_AMP_MUTE : 0);
919}
920
921static void via_gpio_control(struct hda_codec *codec)
922{
923 unsigned int gpio_data;
924 unsigned int vol_counter;
925 unsigned int vol;
926 unsigned int master_vol;
927
928 struct via_spec *spec = codec->spec;
929
930 gpio_data = snd_hda_codec_read(codec, codec->afg, 0,
931 AC_VERB_GET_GPIO_DATA, 0) & 0x03;
932
933 vol_counter = (snd_hda_codec_read(codec, codec->afg, 0,
934 0xF84, 0) & 0x3F0000) >> 16;
935
936 vol = vol_counter & 0x1F;
937 master_vol = snd_hda_codec_read(codec, 0x1A, 0,
938 AC_VERB_GET_AMP_GAIN_MUTE,
939 AC_AMP_GET_INPUT);
940
941 if (gpio_data == 0x02) {
942 /* unmute line out */
943 snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
944 HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
945
946 if (vol_counter & 0x20) {
947 /* decrease volume */
948 if (vol > master_vol)
949 vol = master_vol;
950 snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT,
951 0, HDA_AMP_VOLMASK,
952 master_vol-vol);
953 } else {
954 /* increase volume */
955 snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, 0,
956 HDA_AMP_VOLMASK,
957 ((master_vol+vol) > 0x2A) ? 0x2A :
958 (master_vol+vol));
959 }
960 } else if (!(gpio_data & 0x02)) {
961 /* mute line out */
962 snd_hda_codec_amp_stereo(codec,
963 spec->autocfg.line_out_pins[0],
964 HDA_OUTPUT, 0, HDA_AMP_MUTE,
965 HDA_AMP_MUTE);
966 }
967}
968
969/* unsolicited event for jack sensing */
970static void via_unsol_event(struct hda_codec *codec,
971 unsigned int res)
972{
973 res >>= 26;
974 if (res == VIA_HP_EVENT)
975 via_hp_automute(codec);
976 else if (res == VIA_GPIO_EVENT)
977 via_gpio_control(codec);
978}
979
Joseph Chanc577b8a2006-11-29 15:29:40 +0100980static int via_init(struct hda_codec *codec)
981{
982 struct via_spec *spec = codec->spec;
Harald Welte69e52a82008-09-09 15:57:32 +0800983 int i;
984 for (i = 0; i < spec->num_iverbs; i++)
985 snd_hda_sequence_write(codec, spec->init_verbs[i]);
986
Lydia Wang518bf3b2009-10-10 19:07:29 +0800987 spec->codec_type = get_codec_type(codec);
988 if (spec->codec_type == VT1708BCE)
989 spec->codec_type = VT1708S; /* VT1708BCE & VT1708S are almost
990 same */
Josepch Chanf7278fd2007-12-13 16:40:40 +0100991 /* Lydia Add for EAPD enable */
992 if (!spec->dig_in_nid) { /* No Digital In connection */
Takashi Iwai55d1d6c2009-07-07 13:39:03 +0200993 if (spec->dig_in_pin) {
994 snd_hda_codec_write(codec, spec->dig_in_pin, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100995 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +0100996 PIN_OUT);
Takashi Iwai55d1d6c2009-07-07 13:39:03 +0200997 snd_hda_codec_write(codec, spec->dig_in_pin, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +0100998 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
999 }
Takashi Iwai12b74c82008-01-15 12:39:38 +01001000 } else /* enable SPDIF-input pin */
1001 snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
1002 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
Josepch Chanf7278fd2007-12-13 16:40:40 +01001003
Takashi Iwai9da29272009-05-07 16:31:14 +02001004 /* assign slave outs */
1005 if (spec->slave_dig_outs[0])
1006 codec->slave_dig_outs = spec->slave_dig_outs;
Harald Welte5691ec72008-09-15 22:42:26 +08001007
Joseph Chanc577b8a2006-11-29 15:29:40 +01001008 return 0;
1009}
1010
Takashi Iwaicb53c622007-08-10 17:21:45 +02001011#ifdef CONFIG_SND_HDA_POWER_SAVE
1012static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
1013{
1014 struct via_spec *spec = codec->spec;
1015 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
1016}
1017#endif
1018
Joseph Chanc577b8a2006-11-29 15:29:40 +01001019/*
1020 */
1021static struct hda_codec_ops via_patch_ops = {
1022 .build_controls = via_build_controls,
1023 .build_pcms = via_build_pcms,
1024 .init = via_init,
1025 .free = via_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02001026#ifdef CONFIG_SND_HDA_POWER_SAVE
1027 .check_power_status = via_check_power_status,
1028#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001029};
1030
1031/* fill in the dac_nids table from the parsed pin configuration */
1032static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
1033 const struct auto_pin_cfg *cfg)
1034{
1035 int i;
1036 hda_nid_t nid;
1037
1038 spec->multiout.num_dacs = cfg->line_outs;
1039
1040 spec->multiout.dac_nids = spec->private_dac_nids;
1041
1042 for(i = 0; i < 4; i++) {
1043 nid = cfg->line_out_pins[i];
1044 if (nid) {
1045 /* config dac list */
1046 switch (i) {
1047 case AUTO_SEQ_FRONT:
1048 spec->multiout.dac_nids[i] = 0x10;
1049 break;
1050 case AUTO_SEQ_CENLFE:
1051 spec->multiout.dac_nids[i] = 0x12;
1052 break;
1053 case AUTO_SEQ_SURROUND:
Harald Weltefb4cb772008-09-09 15:53:36 +08001054 spec->multiout.dac_nids[i] = 0x11;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001055 break;
1056 case AUTO_SEQ_SIDE:
Harald Weltefb4cb772008-09-09 15:53:36 +08001057 spec->multiout.dac_nids[i] = 0x13;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001058 break;
1059 }
1060 }
1061 }
1062
1063 return 0;
1064}
1065
1066/* add playback controls from the parsed DAC table */
1067static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
1068 const struct auto_pin_cfg *cfg)
1069{
1070 char name[32];
1071 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1072 hda_nid_t nid, nid_vol = 0;
1073 int i, err;
1074
1075 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1076 nid = cfg->line_out_pins[i];
1077
1078 if (!nid)
1079 continue;
1080
1081 if (i != AUTO_SEQ_FRONT)
Harald Weltefb4cb772008-09-09 15:53:36 +08001082 nid_vol = 0x18 + i;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001083
1084 if (i == AUTO_SEQ_CENLFE) {
1085 /* Center/LFE */
1086 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001087 "Center Playback Volume",
1088 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1089 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001090 if (err < 0)
1091 return err;
1092 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1093 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001094 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1095 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001096 if (err < 0)
1097 return err;
1098 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1099 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001100 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1101 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001102 if (err < 0)
1103 return err;
1104 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1105 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001106 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1107 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001108 if (err < 0)
1109 return err;
1110 } else if (i == AUTO_SEQ_FRONT){
1111 /* add control to mixer index 0 */
1112 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1113 "Master Front Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001114 HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
1115 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001116 if (err < 0)
1117 return err;
1118 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1119 "Master Front Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001120 HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
1121 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001122 if (err < 0)
1123 return err;
1124
1125 /* add control to PW3 */
1126 sprintf(name, "%s Playback Volume", chname[i]);
1127 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001128 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1129 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001130 if (err < 0)
1131 return err;
1132 sprintf(name, "%s Playback Switch", chname[i]);
1133 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001134 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1135 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001136 if (err < 0)
1137 return err;
1138 } else {
1139 sprintf(name, "%s Playback Volume", chname[i]);
1140 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001141 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1142 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001143 if (err < 0)
1144 return err;
1145 sprintf(name, "%s Playback Switch", chname[i]);
1146 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001147 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1148 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001149 if (err < 0)
1150 return err;
1151 }
1152 }
1153
1154 return 0;
1155}
1156
Harald Welte0aa62ae2008-09-09 15:58:27 +08001157static void create_hp_imux(struct via_spec *spec)
1158{
1159 int i;
1160 struct hda_input_mux *imux = &spec->private_imux[1];
1161 static const char *texts[] = { "OFF", "ON", NULL};
1162
1163 /* for hp mode select */
1164 i = 0;
1165 while (texts[i] != NULL) {
1166 imux->items[imux->num_items].label = texts[i];
1167 imux->items[imux->num_items].index = i;
1168 imux->num_items++;
1169 i++;
1170 }
1171
1172 spec->hp_mux = &spec->private_imux[1];
1173}
1174
Joseph Chanc577b8a2006-11-29 15:29:40 +01001175static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1176{
1177 int err;
1178
1179 if (!pin)
1180 return 0;
1181
1182 spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
1183
1184 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1185 "Headphone Playback Volume",
1186 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1187 if (err < 0)
1188 return err;
1189 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1190 "Headphone Playback Switch",
1191 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1192 if (err < 0)
1193 return err;
1194
Harald Welte0aa62ae2008-09-09 15:58:27 +08001195 create_hp_imux(spec);
1196
Joseph Chanc577b8a2006-11-29 15:29:40 +01001197 return 0;
1198}
1199
1200/* create playback/capture controls for input pins */
1201static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
1202 const struct auto_pin_cfg *cfg)
1203{
1204 static char *labels[] = {
1205 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1206 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08001207 struct hda_input_mux *imux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01001208 int i, err, idx = 0;
1209
1210 /* for internal loopback recording select */
1211 imux->items[imux->num_items].label = "Stereo Mixer";
1212 imux->items[imux->num_items].index = idx;
1213 imux->num_items++;
1214
1215 for (i = 0; i < AUTO_PIN_LAST; i++) {
1216 if (!cfg->input_pins[i])
1217 continue;
1218
1219 switch (cfg->input_pins[i]) {
1220 case 0x1d: /* Mic */
1221 idx = 2;
1222 break;
1223
1224 case 0x1e: /* Line In */
1225 idx = 3;
1226 break;
1227
1228 case 0x21: /* Front Mic */
1229 idx = 4;
1230 break;
1231
1232 case 0x24: /* CD */
1233 idx = 1;
1234 break;
1235 }
1236 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
1237 idx, 0x17);
1238 if (err < 0)
1239 return err;
1240 imux->items[imux->num_items].label = labels[i];
1241 imux->items[imux->num_items].index = idx;
1242 imux->num_items++;
1243 }
1244 return 0;
1245}
1246
Takashi Iwaicb53c622007-08-10 17:21:45 +02001247#ifdef CONFIG_SND_HDA_POWER_SAVE
1248static struct hda_amp_list vt1708_loopbacks[] = {
1249 { 0x17, HDA_INPUT, 1 },
1250 { 0x17, HDA_INPUT, 2 },
1251 { 0x17, HDA_INPUT, 3 },
1252 { 0x17, HDA_INPUT, 4 },
1253 { } /* end */
1254};
1255#endif
1256
Harald Welte76d9b0d2008-09-09 15:50:37 +08001257static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
1258{
1259 unsigned int def_conf;
1260 unsigned char seqassoc;
1261
Takashi Iwai2f334f92009-02-20 14:37:42 +01001262 def_conf = snd_hda_codec_get_pincfg(codec, nid);
Harald Welte76d9b0d2008-09-09 15:50:37 +08001263 seqassoc = (unsigned char) get_defcfg_association(def_conf);
1264 seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
1265 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) {
1266 if (seqassoc == 0xff) {
1267 def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
Takashi Iwai2f334f92009-02-20 14:37:42 +01001268 snd_hda_codec_set_pincfg(codec, nid, def_conf);
Harald Welte76d9b0d2008-09-09 15:50:37 +08001269 }
1270 }
1271
1272 return;
1273}
1274
Joseph Chanc577b8a2006-11-29 15:29:40 +01001275static int vt1708_parse_auto_config(struct hda_codec *codec)
1276{
1277 struct via_spec *spec = codec->spec;
1278 int err;
1279
Harald Welte76d9b0d2008-09-09 15:50:37 +08001280 /* Add HP and CD pin config connect bit re-config action */
1281 vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
1282 vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
1283
Joseph Chanc577b8a2006-11-29 15:29:40 +01001284 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1285 if (err < 0)
1286 return err;
1287 err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
1288 if (err < 0)
1289 return err;
1290 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1291 return 0; /* can't find valid BIOS pin config */
1292
1293 err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
1294 if (err < 0)
1295 return err;
1296 err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1297 if (err < 0)
1298 return err;
1299 err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
1300 if (err < 0)
1301 return err;
1302
1303 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1304
Takashi Iwai0852d7a2009-02-11 11:35:15 +01001305 if (spec->autocfg.dig_outs)
Joseph Chanc577b8a2006-11-29 15:29:40 +01001306 spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02001307 spec->dig_in_pin = VT1708_DIGIN_PIN;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001308 if (spec->autocfg.dig_in_pin)
1309 spec->dig_in_nid = VT1708_DIGIN_NID;
1310
Takashi Iwai603c4012008-07-30 15:01:44 +02001311 if (spec->kctls.list)
1312 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001313
Harald Welte69e52a82008-09-09 15:57:32 +08001314 spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001315
Harald Welte0aa62ae2008-09-09 15:58:27 +08001316 spec->input_mux = &spec->private_imux[0];
1317
Harald Weltef8fdd492008-09-15 22:41:31 +08001318 if (spec->hp_mux)
1319 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001320
1321 return 1;
1322}
1323
1324/* init callback for auto-configuration model -- overriding the default init */
1325static int via_auto_init(struct hda_codec *codec)
1326{
1327 via_init(codec);
1328 via_auto_init_multi_out(codec);
1329 via_auto_init_hp_out(codec);
1330 via_auto_init_analog_input(codec);
1331 return 0;
1332}
1333
Takashi Iwai337b9d02009-07-07 18:18:59 +02001334static int get_mux_nids(struct hda_codec *codec)
1335{
1336 struct via_spec *spec = codec->spec;
1337 hda_nid_t nid, conn[8];
1338 unsigned int type;
1339 int i, n;
1340
1341 for (i = 0; i < spec->num_adc_nids; i++) {
1342 nid = spec->adc_nids[i];
1343 while (nid) {
Takashi Iwaia22d5432009-07-27 12:54:26 +02001344 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai1c55d522009-07-08 07:45:46 +02001345 if (type == AC_WID_PIN)
1346 break;
Takashi Iwai337b9d02009-07-07 18:18:59 +02001347 n = snd_hda_get_connections(codec, nid, conn,
1348 ARRAY_SIZE(conn));
1349 if (n <= 0)
1350 break;
1351 if (n > 1) {
1352 spec->mux_nids[i] = nid;
1353 break;
1354 }
1355 nid = conn[0];
1356 }
1357 }
Takashi Iwai1c55d522009-07-08 07:45:46 +02001358 return 0;
Takashi Iwai337b9d02009-07-07 18:18:59 +02001359}
1360
Joseph Chanc577b8a2006-11-29 15:29:40 +01001361static int patch_vt1708(struct hda_codec *codec)
1362{
1363 struct via_spec *spec;
1364 int err;
1365
1366 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08001367 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001368 if (spec == NULL)
1369 return -ENOMEM;
1370
1371 codec->spec = spec;
1372
1373 /* automatic parse from the BIOS config */
1374 err = vt1708_parse_auto_config(codec);
1375 if (err < 0) {
1376 via_free(codec);
1377 return err;
1378 } else if (!err) {
1379 printk(KERN_INFO "hda_codec: Cannot set up configuration "
1380 "from BIOS. Using genenic mode...\n");
1381 }
1382
1383
1384 spec->stream_name_analog = "VT1708 Analog";
1385 spec->stream_analog_playback = &vt1708_pcm_analog_playback;
Takashi Iwaibc9b562382008-05-23 17:50:27 +02001386 /* disable 32bit format on VT1708 */
1387 if (codec->vendor_id == 0x11061708)
1388 spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001389 spec->stream_analog_capture = &vt1708_pcm_analog_capture;
1390
1391 spec->stream_name_digital = "VT1708 Digital";
1392 spec->stream_digital_playback = &vt1708_pcm_digital_playback;
1393 spec->stream_digital_capture = &vt1708_pcm_digital_capture;
1394
1395
1396 if (!spec->adc_nids && spec->input_mux) {
1397 spec->adc_nids = vt1708_adc_nids;
1398 spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
Takashi Iwai0f67a612009-08-31 08:12:29 +02001399 get_mux_nids(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001400 spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
1401 spec->num_mixers++;
1402 }
1403
1404 codec->patch_ops = via_patch_ops;
1405
1406 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001407#ifdef CONFIG_SND_HDA_POWER_SAVE
1408 spec->loopback.amplist = vt1708_loopbacks;
1409#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001410
1411 return 0;
1412}
1413
1414/* capture mixer elements */
1415static struct snd_kcontrol_new vt1709_capture_mixer[] = {
1416 HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
1417 HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
1418 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
1419 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
1420 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
1421 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
1422 {
1423 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1424 /* The multiple "Capture Source" controls confuse alsamixer
1425 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +01001426 */
1427 /* .name = "Capture Source", */
1428 .name = "Input Source",
1429 .count = 1,
1430 .info = via_mux_enum_info,
1431 .get = via_mux_enum_get,
1432 .put = via_mux_enum_put,
1433 },
1434 { } /* end */
1435};
1436
Harald Welte69e52a82008-09-09 15:57:32 +08001437static struct hda_verb vt1709_uniwill_init_verbs[] = {
1438 {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
1439 { }
1440};
1441
Joseph Chanc577b8a2006-11-29 15:29:40 +01001442/*
1443 * generic initialization of ADC, input mixers and output mixers
1444 */
1445static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
1446 /*
1447 * Unmute ADC0-2 and set the default input to mic-in
1448 */
1449 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1450 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1451 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1452
1453
Josepch Chanf7278fd2007-12-13 16:40:40 +01001454 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +01001455 * mixer widget
1456 */
1457 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +01001458 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1459 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1460 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1461 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1462 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001463
1464 /*
1465 * Set up output selector (0x1a, 0x1b, 0x29)
1466 */
1467 /* set vol=0 to output mixers */
1468 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1469 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1470 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1471
1472 /*
1473 * Unmute PW3 and PW4
1474 */
1475 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1476 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1477
1478 /* Set input of PW4 as AOW4 */
1479 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001480 /* PW9 Output enable */
1481 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1482 { }
1483};
1484
1485static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
1486 .substreams = 1,
1487 .channels_min = 2,
1488 .channels_max = 10,
1489 .nid = 0x10, /* NID to query formats and rates */
1490 .ops = {
1491 .open = via_playback_pcm_open,
1492 .prepare = via_playback_pcm_prepare,
1493 .cleanup = via_playback_pcm_cleanup
1494 },
1495};
1496
1497static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
1498 .substreams = 1,
1499 .channels_min = 2,
1500 .channels_max = 6,
1501 .nid = 0x10, /* NID to query formats and rates */
1502 .ops = {
1503 .open = via_playback_pcm_open,
1504 .prepare = via_playback_pcm_prepare,
1505 .cleanup = via_playback_pcm_cleanup
1506 },
1507};
1508
1509static struct hda_pcm_stream vt1709_pcm_analog_capture = {
1510 .substreams = 2,
1511 .channels_min = 2,
1512 .channels_max = 2,
1513 .nid = 0x14, /* NID to query formats and rates */
1514 .ops = {
1515 .prepare = via_capture_pcm_prepare,
1516 .cleanup = via_capture_pcm_cleanup
1517 },
1518};
1519
1520static struct hda_pcm_stream vt1709_pcm_digital_playback = {
1521 .substreams = 1,
1522 .channels_min = 2,
1523 .channels_max = 2,
1524 /* NID is set in via_build_pcms */
1525 .ops = {
1526 .open = via_dig_playback_pcm_open,
1527 .close = via_dig_playback_pcm_close
1528 },
1529};
1530
1531static struct hda_pcm_stream vt1709_pcm_digital_capture = {
1532 .substreams = 1,
1533 .channels_min = 2,
1534 .channels_max = 2,
1535};
1536
1537static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
1538 const struct auto_pin_cfg *cfg)
1539{
1540 int i;
1541 hda_nid_t nid;
1542
1543 if (cfg->line_outs == 4) /* 10 channels */
1544 spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
1545 else if (cfg->line_outs == 3) /* 6 channels */
1546 spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
1547
1548 spec->multiout.dac_nids = spec->private_dac_nids;
1549
1550 if (cfg->line_outs == 4) { /* 10 channels */
1551 for (i = 0; i < cfg->line_outs; i++) {
1552 nid = cfg->line_out_pins[i];
1553 if (nid) {
1554 /* config dac list */
1555 switch (i) {
1556 case AUTO_SEQ_FRONT:
1557 /* AOW0 */
1558 spec->multiout.dac_nids[i] = 0x10;
1559 break;
1560 case AUTO_SEQ_CENLFE:
1561 /* AOW2 */
1562 spec->multiout.dac_nids[i] = 0x12;
1563 break;
1564 case AUTO_SEQ_SURROUND:
1565 /* AOW3 */
Harald Weltefb4cb772008-09-09 15:53:36 +08001566 spec->multiout.dac_nids[i] = 0x11;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001567 break;
1568 case AUTO_SEQ_SIDE:
1569 /* AOW1 */
Harald Weltefb4cb772008-09-09 15:53:36 +08001570 spec->multiout.dac_nids[i] = 0x27;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001571 break;
1572 default:
1573 break;
1574 }
1575 }
1576 }
1577 spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
1578
1579 } else if (cfg->line_outs == 3) { /* 6 channels */
1580 for(i = 0; i < cfg->line_outs; i++) {
1581 nid = cfg->line_out_pins[i];
1582 if (nid) {
1583 /* config dac list */
1584 switch(i) {
1585 case AUTO_SEQ_FRONT:
1586 /* AOW0 */
1587 spec->multiout.dac_nids[i] = 0x10;
1588 break;
1589 case AUTO_SEQ_CENLFE:
1590 /* AOW2 */
1591 spec->multiout.dac_nids[i] = 0x12;
1592 break;
1593 case AUTO_SEQ_SURROUND:
1594 /* AOW1 */
1595 spec->multiout.dac_nids[i] = 0x11;
1596 break;
1597 default:
1598 break;
1599 }
1600 }
1601 }
1602 }
1603
1604 return 0;
1605}
1606
1607/* add playback controls from the parsed DAC table */
1608static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
1609 const struct auto_pin_cfg *cfg)
1610{
1611 char name[32];
1612 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1613 hda_nid_t nid = 0;
1614 int i, err;
1615
1616 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1617 nid = cfg->line_out_pins[i];
1618
1619 if (!nid)
1620 continue;
1621
1622 if (i == AUTO_SEQ_CENLFE) {
1623 /* Center/LFE */
1624 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1625 "Center Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001626 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
1627 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001628 if (err < 0)
1629 return err;
1630 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1631 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001632 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
1633 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001634 if (err < 0)
1635 return err;
1636 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1637 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001638 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
1639 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001640 if (err < 0)
1641 return err;
1642 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1643 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001644 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
1645 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001646 if (err < 0)
1647 return err;
1648 } else if (i == AUTO_SEQ_FRONT){
1649 /* add control to mixer index 0 */
1650 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1651 "Master Front Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001652 HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
1653 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001654 if (err < 0)
1655 return err;
1656 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1657 "Master Front Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001658 HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
1659 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001660 if (err < 0)
1661 return err;
1662
1663 /* add control to PW3 */
1664 sprintf(name, "%s Playback Volume", chname[i]);
1665 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001666 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1667 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001668 if (err < 0)
1669 return err;
1670 sprintf(name, "%s Playback Switch", chname[i]);
1671 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001672 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1673 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001674 if (err < 0)
1675 return err;
1676 } else if (i == AUTO_SEQ_SURROUND) {
1677 sprintf(name, "%s Playback Volume", chname[i]);
1678 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001679 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001680 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001681 if (err < 0)
1682 return err;
1683 sprintf(name, "%s Playback Switch", chname[i]);
1684 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001685 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001686 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001687 if (err < 0)
1688 return err;
1689 } else if (i == AUTO_SEQ_SIDE) {
1690 sprintf(name, "%s Playback Volume", chname[i]);
1691 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001692 HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001693 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001694 if (err < 0)
1695 return err;
1696 sprintf(name, "%s Playback Switch", chname[i]);
1697 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001698 HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001699 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001700 if (err < 0)
1701 return err;
1702 }
1703 }
1704
1705 return 0;
1706}
1707
1708static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1709{
1710 int err;
1711
1712 if (!pin)
1713 return 0;
1714
1715 if (spec->multiout.num_dacs == 5) /* 10 channels */
1716 spec->multiout.hp_nid = VT1709_HP_DAC_NID;
1717 else if (spec->multiout.num_dacs == 3) /* 6 channels */
1718 spec->multiout.hp_nid = 0;
1719
1720 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1721 "Headphone Playback Volume",
1722 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1723 if (err < 0)
1724 return err;
1725 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1726 "Headphone Playback Switch",
1727 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1728 if (err < 0)
1729 return err;
1730
1731 return 0;
1732}
1733
1734/* create playback/capture controls for input pins */
1735static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
1736 const struct auto_pin_cfg *cfg)
1737{
1738 static char *labels[] = {
1739 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1740 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08001741 struct hda_input_mux *imux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01001742 int i, err, idx = 0;
1743
1744 /* for internal loopback recording select */
1745 imux->items[imux->num_items].label = "Stereo Mixer";
1746 imux->items[imux->num_items].index = idx;
1747 imux->num_items++;
1748
1749 for (i = 0; i < AUTO_PIN_LAST; i++) {
1750 if (!cfg->input_pins[i])
1751 continue;
1752
1753 switch (cfg->input_pins[i]) {
1754 case 0x1d: /* Mic */
1755 idx = 2;
1756 break;
1757
1758 case 0x1e: /* Line In */
1759 idx = 3;
1760 break;
1761
1762 case 0x21: /* Front Mic */
1763 idx = 4;
1764 break;
1765
1766 case 0x23: /* CD */
1767 idx = 1;
1768 break;
1769 }
1770 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
1771 idx, 0x18);
1772 if (err < 0)
1773 return err;
1774 imux->items[imux->num_items].label = labels[i];
1775 imux->items[imux->num_items].index = idx;
1776 imux->num_items++;
1777 }
1778 return 0;
1779}
1780
1781static int vt1709_parse_auto_config(struct hda_codec *codec)
1782{
1783 struct via_spec *spec = codec->spec;
1784 int err;
1785
1786 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1787 if (err < 0)
1788 return err;
1789 err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
1790 if (err < 0)
1791 return err;
1792 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1793 return 0; /* can't find valid BIOS pin config */
1794
1795 err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
1796 if (err < 0)
1797 return err;
1798 err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1799 if (err < 0)
1800 return err;
1801 err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
1802 if (err < 0)
1803 return err;
1804
1805 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1806
Takashi Iwai0852d7a2009-02-11 11:35:15 +01001807 if (spec->autocfg.dig_outs)
Joseph Chanc577b8a2006-11-29 15:29:40 +01001808 spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02001809 spec->dig_in_pin = VT1709_DIGIN_PIN;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001810 if (spec->autocfg.dig_in_pin)
1811 spec->dig_in_nid = VT1709_DIGIN_NID;
1812
Takashi Iwai603c4012008-07-30 15:01:44 +02001813 if (spec->kctls.list)
1814 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001815
Harald Welte0aa62ae2008-09-09 15:58:27 +08001816 spec->input_mux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01001817
Harald Weltef8fdd492008-09-15 22:41:31 +08001818 if (spec->hp_mux)
1819 spec->mixers[spec->num_mixers++] = via_hp_mixer;
1820
Joseph Chanc577b8a2006-11-29 15:29:40 +01001821 return 1;
1822}
1823
Takashi Iwaicb53c622007-08-10 17:21:45 +02001824#ifdef CONFIG_SND_HDA_POWER_SAVE
1825static struct hda_amp_list vt1709_loopbacks[] = {
1826 { 0x18, HDA_INPUT, 1 },
1827 { 0x18, HDA_INPUT, 2 },
1828 { 0x18, HDA_INPUT, 3 },
1829 { 0x18, HDA_INPUT, 4 },
1830 { } /* end */
1831};
1832#endif
1833
Joseph Chanc577b8a2006-11-29 15:29:40 +01001834static int patch_vt1709_10ch(struct hda_codec *codec)
1835{
1836 struct via_spec *spec;
1837 int err;
1838
1839 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08001840 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001841 if (spec == NULL)
1842 return -ENOMEM;
1843
1844 codec->spec = spec;
1845
1846 err = vt1709_parse_auto_config(codec);
1847 if (err < 0) {
1848 via_free(codec);
1849 return err;
1850 } else if (!err) {
1851 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
1852 "Using genenic mode...\n");
1853 }
1854
Harald Welte69e52a82008-09-09 15:57:32 +08001855 spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs;
1856 spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001857
1858 spec->stream_name_analog = "VT1709 Analog";
1859 spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
1860 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1861
1862 spec->stream_name_digital = "VT1709 Digital";
1863 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1864 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1865
1866
1867 if (!spec->adc_nids && spec->input_mux) {
1868 spec->adc_nids = vt1709_adc_nids;
1869 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02001870 get_mux_nids(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001871 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1872 spec->num_mixers++;
1873 }
1874
1875 codec->patch_ops = via_patch_ops;
1876
1877 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08001878 codec->patch_ops.unsol_event = via_unsol_event;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001879#ifdef CONFIG_SND_HDA_POWER_SAVE
1880 spec->loopback.amplist = vt1709_loopbacks;
1881#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001882
1883 return 0;
1884}
1885/*
1886 * generic initialization of ADC, input mixers and output mixers
1887 */
1888static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
1889 /*
1890 * Unmute ADC0-2 and set the default input to mic-in
1891 */
1892 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1893 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1894 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1895
1896
1897 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1898 * mixer widget
1899 */
1900 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
1901 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1902 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1903 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1904 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1905 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1906
1907 /*
1908 * Set up output selector (0x1a, 0x1b, 0x29)
1909 */
1910 /* set vol=0 to output mixers */
1911 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1912 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1913 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1914
1915 /*
1916 * Unmute PW3 and PW4
1917 */
1918 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1919 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1920
1921 /* Set input of PW4 as MW0 */
1922 {0x20, AC_VERB_SET_CONNECT_SEL, 0},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001923 /* PW9 Output enable */
1924 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1925 { }
1926};
1927
1928static int patch_vt1709_6ch(struct hda_codec *codec)
1929{
1930 struct via_spec *spec;
1931 int err;
1932
1933 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08001934 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001935 if (spec == NULL)
1936 return -ENOMEM;
1937
1938 codec->spec = spec;
1939
1940 err = vt1709_parse_auto_config(codec);
1941 if (err < 0) {
1942 via_free(codec);
1943 return err;
1944 } else if (!err) {
1945 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
1946 "Using genenic mode...\n");
1947 }
1948
Harald Welte69e52a82008-09-09 15:57:32 +08001949 spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs;
1950 spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001951
1952 spec->stream_name_analog = "VT1709 Analog";
1953 spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
1954 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
1955
1956 spec->stream_name_digital = "VT1709 Digital";
1957 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
1958 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
1959
1960
1961 if (!spec->adc_nids && spec->input_mux) {
1962 spec->adc_nids = vt1709_adc_nids;
1963 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02001964 get_mux_nids(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001965 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
1966 spec->num_mixers++;
1967 }
1968
1969 codec->patch_ops = via_patch_ops;
1970
1971 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08001972 codec->patch_ops.unsol_event = via_unsol_event;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001973#ifdef CONFIG_SND_HDA_POWER_SAVE
1974 spec->loopback.amplist = vt1709_loopbacks;
1975#endif
Josepch Chanf7278fd2007-12-13 16:40:40 +01001976 return 0;
1977}
1978
1979/* capture mixer elements */
1980static struct snd_kcontrol_new vt1708B_capture_mixer[] = {
1981 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
1982 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
1983 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
1984 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
1985 {
1986 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1987 /* The multiple "Capture Source" controls confuse alsamixer
1988 * So call somewhat different..
Josepch Chanf7278fd2007-12-13 16:40:40 +01001989 */
1990 /* .name = "Capture Source", */
1991 .name = "Input Source",
1992 .count = 1,
1993 .info = via_mux_enum_info,
1994 .get = via_mux_enum_get,
1995 .put = via_mux_enum_put,
1996 },
1997 { } /* end */
1998};
1999/*
2000 * generic initialization of ADC, input mixers and output mixers
2001 */
2002static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
2003 /*
2004 * Unmute ADC0-1 and set the default input to mic-in
2005 */
2006 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2007 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2008
2009
2010 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2011 * mixer widget
2012 */
2013 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2014 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2015 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2016 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2017 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2018 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2019
2020 /*
2021 * Set up output mixers
2022 */
2023 /* set vol=0 to output mixers */
2024 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2025 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2026 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2027
2028 /* Setup default input to PW4 */
2029 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1},
2030 /* PW9 Output enable */
2031 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2032 /* PW10 Input enable */
2033 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
2034 { }
2035};
2036
2037static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
2038 /*
2039 * Unmute ADC0-1 and set the default input to mic-in
2040 */
2041 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2042 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2043
2044
2045 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2046 * mixer widget
2047 */
2048 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2049 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2050 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2051 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2052 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2053 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2054
2055 /*
2056 * Set up output mixers
2057 */
2058 /* set vol=0 to output mixers */
2059 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2060 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2061 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2062
2063 /* Setup default input of PW4 to MW0 */
2064 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
2065 /* PW9 Output enable */
2066 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2067 /* PW10 Input enable */
2068 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
2069 { }
2070};
2071
Harald Welte69e52a82008-09-09 15:57:32 +08002072static struct hda_verb vt1708B_uniwill_init_verbs[] = {
2073 {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
2074 { }
2075};
2076
Josepch Chanf7278fd2007-12-13 16:40:40 +01002077static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08002078 .substreams = 2,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002079 .channels_min = 2,
2080 .channels_max = 8,
2081 .nid = 0x10, /* NID to query formats and rates */
2082 .ops = {
2083 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08002084 .prepare = via_playback_multi_pcm_prepare,
2085 .cleanup = via_playback_multi_pcm_cleanup
Josepch Chanf7278fd2007-12-13 16:40:40 +01002086 },
2087};
2088
2089static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08002090 .substreams = 2,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002091 .channels_min = 2,
2092 .channels_max = 4,
2093 .nid = 0x10, /* NID to query formats and rates */
2094 .ops = {
2095 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08002096 .prepare = via_playback_multi_pcm_prepare,
2097 .cleanup = via_playback_multi_pcm_cleanup
Josepch Chanf7278fd2007-12-13 16:40:40 +01002098 },
2099};
2100
2101static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
2102 .substreams = 2,
2103 .channels_min = 2,
2104 .channels_max = 2,
2105 .nid = 0x13, /* NID to query formats and rates */
2106 .ops = {
2107 .prepare = via_capture_pcm_prepare,
2108 .cleanup = via_capture_pcm_cleanup
2109 },
2110};
2111
2112static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
2113 .substreams = 1,
2114 .channels_min = 2,
2115 .channels_max = 2,
2116 /* NID is set in via_build_pcms */
2117 .ops = {
2118 .open = via_dig_playback_pcm_open,
2119 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02002120 .prepare = via_dig_playback_pcm_prepare,
2121 .cleanup = via_dig_playback_pcm_cleanup
Josepch Chanf7278fd2007-12-13 16:40:40 +01002122 },
2123};
2124
2125static struct hda_pcm_stream vt1708B_pcm_digital_capture = {
2126 .substreams = 1,
2127 .channels_min = 2,
2128 .channels_max = 2,
2129};
2130
2131/* fill in the dac_nids table from the parsed pin configuration */
2132static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
2133 const struct auto_pin_cfg *cfg)
2134{
2135 int i;
2136 hda_nid_t nid;
2137
2138 spec->multiout.num_dacs = cfg->line_outs;
2139
2140 spec->multiout.dac_nids = spec->private_dac_nids;
2141
2142 for (i = 0; i < 4; i++) {
2143 nid = cfg->line_out_pins[i];
2144 if (nid) {
2145 /* config dac list */
2146 switch (i) {
2147 case AUTO_SEQ_FRONT:
2148 spec->multiout.dac_nids[i] = 0x10;
2149 break;
2150 case AUTO_SEQ_CENLFE:
2151 spec->multiout.dac_nids[i] = 0x24;
2152 break;
2153 case AUTO_SEQ_SURROUND:
Harald Weltefb4cb772008-09-09 15:53:36 +08002154 spec->multiout.dac_nids[i] = 0x11;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002155 break;
2156 case AUTO_SEQ_SIDE:
Harald Weltefb4cb772008-09-09 15:53:36 +08002157 spec->multiout.dac_nids[i] = 0x25;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002158 break;
2159 }
2160 }
2161 }
2162
2163 return 0;
2164}
2165
2166/* add playback controls from the parsed DAC table */
2167static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
2168 const struct auto_pin_cfg *cfg)
2169{
2170 char name[32];
2171 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
Harald Weltefb4cb772008-09-09 15:53:36 +08002172 hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27};
Josepch Chanf7278fd2007-12-13 16:40:40 +01002173 hda_nid_t nid, nid_vol = 0;
2174 int i, err;
2175
2176 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2177 nid = cfg->line_out_pins[i];
2178
2179 if (!nid)
2180 continue;
2181
2182 nid_vol = nid_vols[i];
2183
2184 if (i == AUTO_SEQ_CENLFE) {
2185 /* Center/LFE */
2186 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2187 "Center Playback Volume",
2188 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2189 HDA_OUTPUT));
2190 if (err < 0)
2191 return err;
2192 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2193 "LFE Playback Volume",
2194 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2195 HDA_OUTPUT));
2196 if (err < 0)
2197 return err;
2198 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2199 "Center Playback Switch",
2200 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2201 HDA_OUTPUT));
2202 if (err < 0)
2203 return err;
2204 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2205 "LFE Playback Switch",
2206 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2207 HDA_OUTPUT));
2208 if (err < 0)
2209 return err;
2210 } else if (i == AUTO_SEQ_FRONT) {
2211 /* add control to mixer index 0 */
2212 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2213 "Master Front Playback Volume",
2214 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2215 HDA_INPUT));
2216 if (err < 0)
2217 return err;
2218 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2219 "Master Front Playback Switch",
2220 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2221 HDA_INPUT));
2222 if (err < 0)
2223 return err;
2224
2225 /* add control to PW3 */
2226 sprintf(name, "%s Playback Volume", chname[i]);
2227 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2228 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2229 HDA_OUTPUT));
2230 if (err < 0)
2231 return err;
2232 sprintf(name, "%s Playback Switch", chname[i]);
2233 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2234 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2235 HDA_OUTPUT));
2236 if (err < 0)
2237 return err;
2238 } else {
2239 sprintf(name, "%s Playback Volume", chname[i]);
2240 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2241 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2242 HDA_OUTPUT));
2243 if (err < 0)
2244 return err;
2245 sprintf(name, "%s Playback Switch", chname[i]);
2246 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2247 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2248 HDA_OUTPUT));
2249 if (err < 0)
2250 return err;
2251 }
2252 }
2253
2254 return 0;
2255}
2256
2257static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2258{
2259 int err;
2260
2261 if (!pin)
2262 return 0;
2263
2264 spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
2265
2266 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2267 "Headphone Playback Volume",
2268 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2269 if (err < 0)
2270 return err;
2271 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2272 "Headphone Playback Switch",
2273 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2274 if (err < 0)
2275 return err;
2276
Harald Welte0aa62ae2008-09-09 15:58:27 +08002277 create_hp_imux(spec);
2278
Josepch Chanf7278fd2007-12-13 16:40:40 +01002279 return 0;
2280}
2281
2282/* create playback/capture controls for input pins */
2283static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
2284 const struct auto_pin_cfg *cfg)
2285{
2286 static char *labels[] = {
2287 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2288 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08002289 struct hda_input_mux *imux = &spec->private_imux[0];
Josepch Chanf7278fd2007-12-13 16:40:40 +01002290 int i, err, idx = 0;
2291
2292 /* for internal loopback recording select */
2293 imux->items[imux->num_items].label = "Stereo Mixer";
2294 imux->items[imux->num_items].index = idx;
2295 imux->num_items++;
2296
2297 for (i = 0; i < AUTO_PIN_LAST; i++) {
2298 if (!cfg->input_pins[i])
2299 continue;
2300
2301 switch (cfg->input_pins[i]) {
2302 case 0x1a: /* Mic */
2303 idx = 2;
2304 break;
2305
2306 case 0x1b: /* Line In */
2307 idx = 3;
2308 break;
2309
2310 case 0x1e: /* Front Mic */
2311 idx = 4;
2312 break;
2313
2314 case 0x1f: /* CD */
2315 idx = 1;
2316 break;
2317 }
2318 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
2319 idx, 0x16);
2320 if (err < 0)
2321 return err;
2322 imux->items[imux->num_items].label = labels[i];
2323 imux->items[imux->num_items].index = idx;
2324 imux->num_items++;
2325 }
2326 return 0;
2327}
2328
2329static int vt1708B_parse_auto_config(struct hda_codec *codec)
2330{
2331 struct via_spec *spec = codec->spec;
2332 int err;
2333
2334 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
2335 if (err < 0)
2336 return err;
2337 err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg);
2338 if (err < 0)
2339 return err;
2340 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2341 return 0; /* can't find valid BIOS pin config */
2342
2343 err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg);
2344 if (err < 0)
2345 return err;
2346 err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2347 if (err < 0)
2348 return err;
2349 err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
2350 if (err < 0)
2351 return err;
2352
2353 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2354
Takashi Iwai0852d7a2009-02-11 11:35:15 +01002355 if (spec->autocfg.dig_outs)
Josepch Chanf7278fd2007-12-13 16:40:40 +01002356 spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02002357 spec->dig_in_pin = VT1708B_DIGIN_PIN;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002358 if (spec->autocfg.dig_in_pin)
2359 spec->dig_in_nid = VT1708B_DIGIN_NID;
2360
Takashi Iwai603c4012008-07-30 15:01:44 +02002361 if (spec->kctls.list)
2362 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002363
Harald Welte0aa62ae2008-09-09 15:58:27 +08002364 spec->input_mux = &spec->private_imux[0];
2365
Harald Weltef8fdd492008-09-15 22:41:31 +08002366 if (spec->hp_mux)
2367 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002368
2369 return 1;
2370}
2371
2372#ifdef CONFIG_SND_HDA_POWER_SAVE
2373static struct hda_amp_list vt1708B_loopbacks[] = {
2374 { 0x16, HDA_INPUT, 1 },
2375 { 0x16, HDA_INPUT, 2 },
2376 { 0x16, HDA_INPUT, 3 },
2377 { 0x16, HDA_INPUT, 4 },
2378 { } /* end */
2379};
2380#endif
Lydia Wang518bf3b2009-10-10 19:07:29 +08002381static int patch_vt1708S(struct hda_codec *codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002382static int patch_vt1708B_8ch(struct hda_codec *codec)
2383{
2384 struct via_spec *spec;
2385 int err;
2386
Lydia Wang518bf3b2009-10-10 19:07:29 +08002387 if (get_codec_type(codec) == VT1708BCE)
2388 return patch_vt1708S(codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002389 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08002390 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002391 if (spec == NULL)
2392 return -ENOMEM;
2393
2394 codec->spec = spec;
2395
2396 /* automatic parse from the BIOS config */
2397 err = vt1708B_parse_auto_config(codec);
2398 if (err < 0) {
2399 via_free(codec);
2400 return err;
2401 } else if (!err) {
2402 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2403 "from BIOS. Using genenic mode...\n");
2404 }
2405
Harald Welte69e52a82008-09-09 15:57:32 +08002406 spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs;
2407 spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002408
2409 spec->stream_name_analog = "VT1708B Analog";
2410 spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
2411 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
2412
2413 spec->stream_name_digital = "VT1708B Digital";
2414 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
2415 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
2416
2417 if (!spec->adc_nids && spec->input_mux) {
2418 spec->adc_nids = vt1708B_adc_nids;
2419 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02002420 get_mux_nids(codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002421 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
2422 spec->num_mixers++;
2423 }
2424
2425 codec->patch_ops = via_patch_ops;
2426
2427 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08002428 codec->patch_ops.unsol_event = via_unsol_event;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002429#ifdef CONFIG_SND_HDA_POWER_SAVE
2430 spec->loopback.amplist = vt1708B_loopbacks;
2431#endif
2432
2433 return 0;
2434}
2435
2436static int patch_vt1708B_4ch(struct hda_codec *codec)
2437{
2438 struct via_spec *spec;
2439 int err;
2440
2441 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08002442 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002443 if (spec == NULL)
2444 return -ENOMEM;
2445
2446 codec->spec = spec;
2447
2448 /* automatic parse from the BIOS config */
2449 err = vt1708B_parse_auto_config(codec);
2450 if (err < 0) {
2451 via_free(codec);
2452 return err;
2453 } else if (!err) {
2454 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2455 "from BIOS. Using genenic mode...\n");
2456 }
2457
Harald Welte69e52a82008-09-09 15:57:32 +08002458 spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs;
2459 spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002460
2461 spec->stream_name_analog = "VT1708B Analog";
2462 spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
2463 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
2464
2465 spec->stream_name_digital = "VT1708B Digital";
2466 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
2467 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
2468
2469 if (!spec->adc_nids && spec->input_mux) {
2470 spec->adc_nids = vt1708B_adc_nids;
2471 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02002472 get_mux_nids(codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002473 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
2474 spec->num_mixers++;
2475 }
2476
2477 codec->patch_ops = via_patch_ops;
2478
2479 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08002480 codec->patch_ops.unsol_event = via_unsol_event;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002481#ifdef CONFIG_SND_HDA_POWER_SAVE
2482 spec->loopback.amplist = vt1708B_loopbacks;
2483#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01002484
2485 return 0;
2486}
2487
Harald Welted949cac2008-09-09 15:56:01 +08002488/* Patch for VT1708S */
2489
Harald Welted7426322008-09-15 22:43:23 +08002490/* VT1708S software backdoor based override for buggy hardware micboost
2491 * setting */
2492#define MIC_BOOST_VOLUME(xname, nid) { \
2493 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2494 .name = xname, \
2495 .index = 0, \
2496 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
2497 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
2498 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
2499 .info = mic_boost_volume_info, \
2500 .get = snd_hda_mixer_amp_volume_get, \
2501 .put = snd_hda_mixer_amp_volume_put, \
2502 .tlv = { .c = mic_boost_tlv }, \
2503 .private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT) }
2504
Harald Welted949cac2008-09-09 15:56:01 +08002505/* capture mixer elements */
2506static struct snd_kcontrol_new vt1708S_capture_mixer[] = {
2507 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
2508 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
2509 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
2510 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
Harald Welted7426322008-09-15 22:43:23 +08002511 MIC_BOOST_VOLUME("Mic Boost Capture Volume", 0x1A),
2512 MIC_BOOST_VOLUME("Front Mic Boost Capture Volume", 0x1E),
Harald Welted949cac2008-09-09 15:56:01 +08002513 {
2514 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2515 /* The multiple "Capture Source" controls confuse alsamixer
2516 * So call somewhat different..
2517 */
2518 /* .name = "Capture Source", */
2519 .name = "Input Source",
2520 .count = 1,
2521 .info = via_mux_enum_info,
2522 .get = via_mux_enum_get,
2523 .put = via_mux_enum_put,
2524 },
2525 { } /* end */
2526};
2527
2528static struct hda_verb vt1708S_volume_init_verbs[] = {
2529 /* Unmute ADC0-1 and set the default input to mic-in */
2530 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2531 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2532
2533 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the
2534 * analog-loopback mixer widget */
2535 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2536 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2537 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2538 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2539 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2540 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2541
2542 /* Setup default input of PW4 to MW0 */
2543 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
Harald Welte5691ec72008-09-15 22:42:26 +08002544 /* PW9, PW10 Output enable */
Harald Welted949cac2008-09-09 15:56:01 +08002545 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Harald Welte5691ec72008-09-15 22:42:26 +08002546 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Harald Welted7426322008-09-15 22:43:23 +08002547 /* Enable Mic Boost Volume backdoor */
2548 {0x1, 0xf98, 0x1},
Harald Welted949cac2008-09-09 15:56:01 +08002549 { }
2550};
2551
Harald Welte69e52a82008-09-09 15:57:32 +08002552static struct hda_verb vt1708S_uniwill_init_verbs[] = {
2553 {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
2554 { }
2555};
2556
Harald Welted949cac2008-09-09 15:56:01 +08002557static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
2558 .substreams = 2,
2559 .channels_min = 2,
2560 .channels_max = 8,
2561 .nid = 0x10, /* NID to query formats and rates */
2562 .ops = {
2563 .open = via_playback_pcm_open,
2564 .prepare = via_playback_pcm_prepare,
2565 .cleanup = via_playback_pcm_cleanup
2566 },
2567};
2568
2569static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
2570 .substreams = 2,
2571 .channels_min = 2,
2572 .channels_max = 2,
2573 .nid = 0x13, /* NID to query formats and rates */
2574 .ops = {
2575 .prepare = via_capture_pcm_prepare,
2576 .cleanup = via_capture_pcm_cleanup
2577 },
2578};
2579
2580static struct hda_pcm_stream vt1708S_pcm_digital_playback = {
Takashi Iwai9da29272009-05-07 16:31:14 +02002581 .substreams = 1,
Harald Welted949cac2008-09-09 15:56:01 +08002582 .channels_min = 2,
2583 .channels_max = 2,
2584 /* NID is set in via_build_pcms */
2585 .ops = {
2586 .open = via_dig_playback_pcm_open,
2587 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02002588 .prepare = via_dig_playback_pcm_prepare,
2589 .cleanup = via_dig_playback_pcm_cleanup
Harald Welted949cac2008-09-09 15:56:01 +08002590 },
2591};
2592
2593/* fill in the dac_nids table from the parsed pin configuration */
2594static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
2595 const struct auto_pin_cfg *cfg)
2596{
2597 int i;
2598 hda_nid_t nid;
2599
2600 spec->multiout.num_dacs = cfg->line_outs;
2601
2602 spec->multiout.dac_nids = spec->private_dac_nids;
2603
2604 for (i = 0; i < 4; i++) {
2605 nid = cfg->line_out_pins[i];
2606 if (nid) {
2607 /* config dac list */
2608 switch (i) {
2609 case AUTO_SEQ_FRONT:
2610 spec->multiout.dac_nids[i] = 0x10;
2611 break;
2612 case AUTO_SEQ_CENLFE:
2613 spec->multiout.dac_nids[i] = 0x24;
2614 break;
2615 case AUTO_SEQ_SURROUND:
2616 spec->multiout.dac_nids[i] = 0x11;
2617 break;
2618 case AUTO_SEQ_SIDE:
2619 spec->multiout.dac_nids[i] = 0x25;
2620 break;
2621 }
2622 }
2623 }
2624
2625 return 0;
2626}
2627
2628/* add playback controls from the parsed DAC table */
2629static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
2630 const struct auto_pin_cfg *cfg)
2631{
2632 char name[32];
2633 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
2634 hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25};
2635 hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27};
2636 hda_nid_t nid, nid_vol, nid_mute;
2637 int i, err;
2638
2639 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2640 nid = cfg->line_out_pins[i];
2641
2642 if (!nid)
2643 continue;
2644
2645 nid_vol = nid_vols[i];
2646 nid_mute = nid_mutes[i];
2647
2648 if (i == AUTO_SEQ_CENLFE) {
2649 /* Center/LFE */
2650 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2651 "Center Playback Volume",
2652 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2653 HDA_OUTPUT));
2654 if (err < 0)
2655 return err;
2656 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2657 "LFE Playback Volume",
2658 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2659 HDA_OUTPUT));
2660 if (err < 0)
2661 return err;
2662 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2663 "Center Playback Switch",
2664 HDA_COMPOSE_AMP_VAL(nid_mute,
2665 1, 0,
2666 HDA_OUTPUT));
2667 if (err < 0)
2668 return err;
2669 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2670 "LFE Playback Switch",
2671 HDA_COMPOSE_AMP_VAL(nid_mute,
2672 2, 0,
2673 HDA_OUTPUT));
2674 if (err < 0)
2675 return err;
2676 } else if (i == AUTO_SEQ_FRONT) {
2677 /* add control to mixer index 0 */
2678 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2679 "Master Front Playback Volume",
2680 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
2681 HDA_INPUT));
2682 if (err < 0)
2683 return err;
2684 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2685 "Master Front Playback Switch",
2686 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
2687 HDA_INPUT));
2688 if (err < 0)
2689 return err;
2690
2691 /* Front */
2692 sprintf(name, "%s Playback Volume", chname[i]);
2693 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2694 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2695 HDA_OUTPUT));
2696 if (err < 0)
2697 return err;
2698 sprintf(name, "%s Playback Switch", chname[i]);
2699 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2700 HDA_COMPOSE_AMP_VAL(nid_mute,
2701 3, 0,
2702 HDA_OUTPUT));
2703 if (err < 0)
2704 return err;
2705 } else {
2706 sprintf(name, "%s Playback Volume", chname[i]);
2707 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2708 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2709 HDA_OUTPUT));
2710 if (err < 0)
2711 return err;
2712 sprintf(name, "%s Playback Switch", chname[i]);
2713 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2714 HDA_COMPOSE_AMP_VAL(nid_mute,
2715 3, 0,
2716 HDA_OUTPUT));
2717 if (err < 0)
2718 return err;
2719 }
2720 }
2721
2722 return 0;
2723}
2724
2725static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2726{
2727 int err;
2728
2729 if (!pin)
2730 return 0;
2731
2732 spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */
2733
2734 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2735 "Headphone Playback Volume",
2736 HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
2737 if (err < 0)
2738 return err;
2739
2740 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2741 "Headphone Playback Switch",
2742 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2743 if (err < 0)
2744 return err;
2745
Harald Welte0aa62ae2008-09-09 15:58:27 +08002746 create_hp_imux(spec);
2747
Harald Welted949cac2008-09-09 15:56:01 +08002748 return 0;
2749}
2750
2751/* create playback/capture controls for input pins */
2752static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
2753 const struct auto_pin_cfg *cfg)
2754{
2755 static char *labels[] = {
2756 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2757 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08002758 struct hda_input_mux *imux = &spec->private_imux[0];
Harald Welted949cac2008-09-09 15:56:01 +08002759 int i, err, idx = 0;
2760
2761 /* for internal loopback recording select */
2762 imux->items[imux->num_items].label = "Stereo Mixer";
2763 imux->items[imux->num_items].index = 5;
2764 imux->num_items++;
2765
2766 for (i = 0; i < AUTO_PIN_LAST; i++) {
2767 if (!cfg->input_pins[i])
2768 continue;
2769
2770 switch (cfg->input_pins[i]) {
2771 case 0x1a: /* Mic */
2772 idx = 2;
2773 break;
2774
2775 case 0x1b: /* Line In */
2776 idx = 3;
2777 break;
2778
2779 case 0x1e: /* Front Mic */
2780 idx = 4;
2781 break;
2782
2783 case 0x1f: /* CD */
2784 idx = 1;
2785 break;
2786 }
2787 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
2788 idx, 0x16);
2789 if (err < 0)
2790 return err;
2791 imux->items[imux->num_items].label = labels[i];
2792 imux->items[imux->num_items].index = idx-1;
2793 imux->num_items++;
2794 }
2795 return 0;
2796}
2797
Takashi Iwai9da29272009-05-07 16:31:14 +02002798/* fill out digital output widgets; one for master and one for slave outputs */
2799static void fill_dig_outs(struct hda_codec *codec)
2800{
2801 struct via_spec *spec = codec->spec;
2802 int i;
2803
2804 for (i = 0; i < spec->autocfg.dig_outs; i++) {
2805 hda_nid_t nid;
2806 int conn;
2807
2808 nid = spec->autocfg.dig_out_pins[i];
2809 if (!nid)
2810 continue;
2811 conn = snd_hda_get_connections(codec, nid, &nid, 1);
2812 if (conn < 1)
2813 continue;
2814 if (!spec->multiout.dig_out_nid)
2815 spec->multiout.dig_out_nid = nid;
2816 else {
2817 spec->slave_dig_outs[0] = nid;
2818 break; /* at most two dig outs */
2819 }
2820 }
2821}
2822
Harald Welted949cac2008-09-09 15:56:01 +08002823static int vt1708S_parse_auto_config(struct hda_codec *codec)
2824{
2825 struct via_spec *spec = codec->spec;
2826 int err;
Harald Welted949cac2008-09-09 15:56:01 +08002827
Takashi Iwai9da29272009-05-07 16:31:14 +02002828 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
Harald Welted949cac2008-09-09 15:56:01 +08002829 if (err < 0)
2830 return err;
2831 err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg);
2832 if (err < 0)
2833 return err;
2834 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2835 return 0; /* can't find valid BIOS pin config */
2836
2837 err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg);
2838 if (err < 0)
2839 return err;
2840 err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2841 if (err < 0)
2842 return err;
2843 err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
2844 if (err < 0)
2845 return err;
2846
2847 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2848
Takashi Iwai9da29272009-05-07 16:31:14 +02002849 fill_dig_outs(codec);
Harald Welte98aa34c2008-09-09 16:02:09 +08002850
Takashi Iwai603c4012008-07-30 15:01:44 +02002851 if (spec->kctls.list)
2852 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Harald Welted949cac2008-09-09 15:56:01 +08002853
Harald Welte0aa62ae2008-09-09 15:58:27 +08002854 spec->input_mux = &spec->private_imux[0];
2855
Harald Weltef8fdd492008-09-15 22:41:31 +08002856 if (spec->hp_mux)
2857 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08002858
2859 return 1;
2860}
2861
2862#ifdef CONFIG_SND_HDA_POWER_SAVE
2863static struct hda_amp_list vt1708S_loopbacks[] = {
2864 { 0x16, HDA_INPUT, 1 },
2865 { 0x16, HDA_INPUT, 2 },
2866 { 0x16, HDA_INPUT, 3 },
2867 { 0x16, HDA_INPUT, 4 },
2868 { } /* end */
2869};
2870#endif
2871
2872static int patch_vt1708S(struct hda_codec *codec)
2873{
2874 struct via_spec *spec;
2875 int err;
2876
2877 /* create a codec specific record */
2878 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2879 if (spec == NULL)
2880 return -ENOMEM;
2881
2882 codec->spec = spec;
2883
2884 /* automatic parse from the BIOS config */
2885 err = vt1708S_parse_auto_config(codec);
2886 if (err < 0) {
2887 via_free(codec);
2888 return err;
2889 } else if (!err) {
2890 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2891 "from BIOS. Using genenic mode...\n");
2892 }
2893
Harald Welte69e52a82008-09-09 15:57:32 +08002894 spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
2895 spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs;
Harald Welted949cac2008-09-09 15:56:01 +08002896
2897 spec->stream_name_analog = "VT1708S Analog";
2898 spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
2899 spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
2900
2901 spec->stream_name_digital = "VT1708S Digital";
2902 spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
2903
2904 if (!spec->adc_nids && spec->input_mux) {
2905 spec->adc_nids = vt1708S_adc_nids;
2906 spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02002907 get_mux_nids(codec);
Harald Welted949cac2008-09-09 15:56:01 +08002908 spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
2909 spec->num_mixers++;
2910 }
2911
2912 codec->patch_ops = via_patch_ops;
2913
2914 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08002915 codec->patch_ops.unsol_event = via_unsol_event;
Harald Welted949cac2008-09-09 15:56:01 +08002916#ifdef CONFIG_SND_HDA_POWER_SAVE
2917 spec->loopback.amplist = vt1708S_loopbacks;
2918#endif
2919
Lydia Wang518bf3b2009-10-10 19:07:29 +08002920 /* correct names for VT1708BCE */
2921 if (get_codec_type(codec) == VT1708BCE) {
2922 kfree(codec->chip_name);
2923 codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
2924 snprintf(codec->bus->card->mixername,
2925 sizeof(codec->bus->card->mixername),
2926 "%s %s", codec->vendor_name, codec->chip_name);
2927 spec->stream_name_analog = "VT1708BCE Analog";
2928 spec->stream_name_digital = "VT1708BCE Digital";
2929 }
Harald Welted949cac2008-09-09 15:56:01 +08002930 return 0;
2931}
2932
2933/* Patch for VT1702 */
2934
2935/* capture mixer elements */
2936static struct snd_kcontrol_new vt1702_capture_mixer[] = {
2937 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
2938 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
2939 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
2940 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT),
2941 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT),
2942 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT),
2943 HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0,
2944 HDA_INPUT),
2945 {
2946 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2947 /* The multiple "Capture Source" controls confuse alsamixer
2948 * So call somewhat different..
2949 */
2950 /* .name = "Capture Source", */
2951 .name = "Input Source",
2952 .count = 1,
2953 .info = via_mux_enum_info,
2954 .get = via_mux_enum_get,
2955 .put = via_mux_enum_put,
2956 },
2957 { } /* end */
2958};
2959
2960static struct hda_verb vt1702_volume_init_verbs[] = {
2961 /*
2962 * Unmute ADC0-1 and set the default input to mic-in
2963 */
2964 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2965 {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2966 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2967
2968
2969 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2970 * mixer widget
2971 */
2972 /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */
2973 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2974 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2975 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2976 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2977 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2978
2979 /* Setup default input of PW4 to MW0 */
2980 {0x17, AC_VERB_SET_CONNECT_SEL, 0x1},
2981 /* PW6 PW7 Output enable */
2982 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2983 {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2984 { }
2985};
2986
Harald Welte69e52a82008-09-09 15:57:32 +08002987static struct hda_verb vt1702_uniwill_init_verbs[] = {
2988 {0x01, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_GPIO_EVENT},
2989 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
2990 { }
2991};
2992
Harald Welted949cac2008-09-09 15:56:01 +08002993static struct hda_pcm_stream vt1702_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08002994 .substreams = 2,
Harald Welted949cac2008-09-09 15:56:01 +08002995 .channels_min = 2,
2996 .channels_max = 2,
2997 .nid = 0x10, /* NID to query formats and rates */
2998 .ops = {
2999 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08003000 .prepare = via_playback_multi_pcm_prepare,
3001 .cleanup = via_playback_multi_pcm_cleanup
Harald Welted949cac2008-09-09 15:56:01 +08003002 },
3003};
3004
3005static struct hda_pcm_stream vt1702_pcm_analog_capture = {
3006 .substreams = 3,
3007 .channels_min = 2,
3008 .channels_max = 2,
3009 .nid = 0x12, /* NID to query formats and rates */
3010 .ops = {
3011 .prepare = via_capture_pcm_prepare,
3012 .cleanup = via_capture_pcm_cleanup
3013 },
3014};
3015
3016static struct hda_pcm_stream vt1702_pcm_digital_playback = {
Harald Welte5691ec72008-09-15 22:42:26 +08003017 .substreams = 2,
Harald Welted949cac2008-09-09 15:56:01 +08003018 .channels_min = 2,
3019 .channels_max = 2,
3020 /* NID is set in via_build_pcms */
3021 .ops = {
3022 .open = via_dig_playback_pcm_open,
3023 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02003024 .prepare = via_dig_playback_pcm_prepare,
3025 .cleanup = via_dig_playback_pcm_cleanup
Harald Welted949cac2008-09-09 15:56:01 +08003026 },
3027};
3028
3029/* fill in the dac_nids table from the parsed pin configuration */
3030static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
3031 const struct auto_pin_cfg *cfg)
3032{
3033 spec->multiout.num_dacs = 1;
3034 spec->multiout.dac_nids = spec->private_dac_nids;
3035
3036 if (cfg->line_out_pins[0]) {
3037 /* config dac list */
3038 spec->multiout.dac_nids[0] = 0x10;
3039 }
3040
3041 return 0;
3042}
3043
3044/* add playback controls from the parsed DAC table */
3045static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
3046 const struct auto_pin_cfg *cfg)
3047{
3048 int err;
3049
3050 if (!cfg->line_out_pins[0])
3051 return -1;
3052
3053 /* add control to mixer index 0 */
3054 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3055 "Master Front Playback Volume",
3056 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
3057 if (err < 0)
3058 return err;
3059 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3060 "Master Front Playback Switch",
3061 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
3062 if (err < 0)
3063 return err;
3064
3065 /* Front */
3066 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3067 "Front Playback Volume",
3068 HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT));
3069 if (err < 0)
3070 return err;
3071 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3072 "Front Playback Switch",
3073 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT));
3074 if (err < 0)
3075 return err;
3076
3077 return 0;
3078}
3079
3080static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
3081{
3082 int err;
3083
3084 if (!pin)
3085 return 0;
3086
3087 spec->multiout.hp_nid = 0x1D;
3088
3089 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3090 "Headphone Playback Volume",
3091 HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT));
3092 if (err < 0)
3093 return err;
3094
3095 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3096 "Headphone Playback Switch",
3097 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3098 if (err < 0)
3099 return err;
3100
Harald Welte0aa62ae2008-09-09 15:58:27 +08003101 create_hp_imux(spec);
3102
Harald Welted949cac2008-09-09 15:56:01 +08003103 return 0;
3104}
3105
3106/* create playback/capture controls for input pins */
3107static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
3108 const struct auto_pin_cfg *cfg)
3109{
3110 static char *labels[] = {
3111 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
3112 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08003113 struct hda_input_mux *imux = &spec->private_imux[0];
Harald Welted949cac2008-09-09 15:56:01 +08003114 int i, err, idx = 0;
3115
3116 /* for internal loopback recording select */
3117 imux->items[imux->num_items].label = "Stereo Mixer";
3118 imux->items[imux->num_items].index = 3;
3119 imux->num_items++;
3120
3121 for (i = 0; i < AUTO_PIN_LAST; i++) {
3122 if (!cfg->input_pins[i])
3123 continue;
3124
3125 switch (cfg->input_pins[i]) {
3126 case 0x14: /* Mic */
3127 idx = 1;
3128 break;
3129
3130 case 0x15: /* Line In */
3131 idx = 2;
3132 break;
3133
3134 case 0x18: /* Front Mic */
3135 idx = 3;
3136 break;
3137 }
3138 err = via_new_analog_input(spec, cfg->input_pins[i],
3139 labels[i], idx, 0x1A);
3140 if (err < 0)
3141 return err;
3142 imux->items[imux->num_items].label = labels[i];
3143 imux->items[imux->num_items].index = idx-1;
3144 imux->num_items++;
3145 }
3146 return 0;
3147}
3148
3149static int vt1702_parse_auto_config(struct hda_codec *codec)
3150{
3151 struct via_spec *spec = codec->spec;
3152 int err;
Harald Welted949cac2008-09-09 15:56:01 +08003153
Takashi Iwai9da29272009-05-07 16:31:14 +02003154 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
Harald Welted949cac2008-09-09 15:56:01 +08003155 if (err < 0)
3156 return err;
3157 err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg);
3158 if (err < 0)
3159 return err;
3160 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
3161 return 0; /* can't find valid BIOS pin config */
3162
3163 err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg);
3164 if (err < 0)
3165 return err;
3166 err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
3167 if (err < 0)
3168 return err;
Lydia Wangc2c02ea2009-10-10 19:07:32 +08003169 /* limit AA path volume to 0 dB */
3170 snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT,
3171 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
3172 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3173 (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3174 (1 << AC_AMPCAP_MUTE_SHIFT));
Harald Welted949cac2008-09-09 15:56:01 +08003175 err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
3176 if (err < 0)
3177 return err;
3178
3179 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3180
Takashi Iwai9da29272009-05-07 16:31:14 +02003181 fill_dig_outs(codec);
Harald Welte98aa34c2008-09-09 16:02:09 +08003182
Takashi Iwai603c4012008-07-30 15:01:44 +02003183 if (spec->kctls.list)
3184 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Harald Welted949cac2008-09-09 15:56:01 +08003185
Harald Welte0aa62ae2008-09-09 15:58:27 +08003186 spec->input_mux = &spec->private_imux[0];
3187
Harald Weltef8fdd492008-09-15 22:41:31 +08003188 if (spec->hp_mux)
3189 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08003190
3191 return 1;
3192}
3193
3194#ifdef CONFIG_SND_HDA_POWER_SAVE
3195static struct hda_amp_list vt1702_loopbacks[] = {
3196 { 0x1A, HDA_INPUT, 1 },
3197 { 0x1A, HDA_INPUT, 2 },
3198 { 0x1A, HDA_INPUT, 3 },
3199 { 0x1A, HDA_INPUT, 4 },
3200 { } /* end */
3201};
3202#endif
3203
3204static int patch_vt1702(struct hda_codec *codec)
3205{
3206 struct via_spec *spec;
3207 int err;
3208 unsigned int response;
3209 unsigned char control;
3210
3211 /* create a codec specific record */
3212 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3213 if (spec == NULL)
3214 return -ENOMEM;
3215
3216 codec->spec = spec;
3217
3218 /* automatic parse from the BIOS config */
3219 err = vt1702_parse_auto_config(codec);
3220 if (err < 0) {
3221 via_free(codec);
3222 return err;
3223 } else if (!err) {
3224 printk(KERN_INFO "hda_codec: Cannot set up configuration "
3225 "from BIOS. Using genenic mode...\n");
3226 }
3227
Harald Welte69e52a82008-09-09 15:57:32 +08003228 spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs;
3229 spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs;
Harald Welted949cac2008-09-09 15:56:01 +08003230
3231 spec->stream_name_analog = "VT1702 Analog";
3232 spec->stream_analog_playback = &vt1702_pcm_analog_playback;
3233 spec->stream_analog_capture = &vt1702_pcm_analog_capture;
3234
3235 spec->stream_name_digital = "VT1702 Digital";
3236 spec->stream_digital_playback = &vt1702_pcm_digital_playback;
3237
3238 if (!spec->adc_nids && spec->input_mux) {
3239 spec->adc_nids = vt1702_adc_nids;
3240 spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02003241 get_mux_nids(codec);
Harald Welted949cac2008-09-09 15:56:01 +08003242 spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
3243 spec->num_mixers++;
3244 }
3245
3246 codec->patch_ops = via_patch_ops;
3247
3248 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003249 codec->patch_ops.unsol_event = via_unsol_event;
Harald Welted949cac2008-09-09 15:56:01 +08003250#ifdef CONFIG_SND_HDA_POWER_SAVE
3251 spec->loopback.amplist = vt1702_loopbacks;
3252#endif
3253
3254 /* Open backdoor */
3255 response = snd_hda_codec_read(codec, codec->afg, 0, 0xF8C, 0);
3256 control = (unsigned char)(response & 0xff);
3257 control |= 0x3;
3258 snd_hda_codec_write(codec, codec->afg, 0, 0xF88, control);
3259
3260 /* Enable GPIO 0&1 for volume&mute control */
3261 /* Enable GPIO 2 for DMIC-DATA */
3262 response = snd_hda_codec_read(codec, codec->afg, 0, 0xF84, 0);
3263 control = (unsigned char)((response >> 16) & 0x3f);
3264 snd_hda_codec_write(codec, codec->afg, 0, 0xF82, control);
3265
3266 return 0;
3267}
3268
Joseph Chanc577b8a2006-11-29 15:29:40 +01003269/*
3270 * patch entries
3271 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +01003272static struct hda_codec_preset snd_hda_preset_via[] = {
Takashi Iwai3218c172008-12-18 09:17:56 +01003273 { .id = 0x11061708, .name = "VT1708", .patch = patch_vt1708},
3274 { .id = 0x11061709, .name = "VT1708", .patch = patch_vt1708},
3275 { .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708},
3276 { .id = 0x1106170b, .name = "VT1708", .patch = patch_vt1708},
3277 { .id = 0x1106e710, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003278 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003279 { .id = 0x1106e711, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003280 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003281 { .id = 0x1106e712, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003282 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003283 { .id = 0x1106e713, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003284 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003285 { .id = 0x1106e714, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003286 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003287 { .id = 0x1106e715, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003288 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003289 { .id = 0x1106e716, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003290 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003291 { .id = 0x1106e717, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003292 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003293 { .id = 0x1106e720, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003294 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003295 { .id = 0x1106e721, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003296 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003297 { .id = 0x1106e722, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003298 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003299 { .id = 0x1106e723, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003300 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003301 { .id = 0x1106e724, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003302 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003303 { .id = 0x1106e725, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003304 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003305 { .id = 0x1106e726, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003306 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003307 { .id = 0x1106e727, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003308 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003309 { .id = 0x11060397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08003310 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01003311 { .id = 0x11061397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08003312 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01003313 { .id = 0x11062397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08003314 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01003315 { .id = 0x11063397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08003316 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01003317 { .id = 0x11064397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08003318 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01003319 { .id = 0x11065397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08003320 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01003321 { .id = 0x11066397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08003322 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01003323 { .id = 0x11067397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08003324 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01003325 { .id = 0x11060398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08003326 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01003327 { .id = 0x11061398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08003328 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01003329 { .id = 0x11062398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08003330 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01003331 { .id = 0x11063398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08003332 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01003333 { .id = 0x11064398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08003334 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01003335 { .id = 0x11065398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08003336 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01003337 { .id = 0x11066398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08003338 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01003339 { .id = 0x11067398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08003340 .patch = patch_vt1702},
Joseph Chanc577b8a2006-11-29 15:29:40 +01003341 {} /* terminator */
3342};
Takashi Iwai1289e9e2008-11-27 15:47:11 +01003343
3344MODULE_ALIAS("snd-hda-codec-id:1106*");
3345
3346static struct hda_codec_preset_list via_list = {
3347 .preset = snd_hda_preset_via,
3348 .owner = THIS_MODULE,
3349};
3350
3351MODULE_LICENSE("GPL");
3352MODULE_DESCRIPTION("VIA HD-audio codec");
3353
3354static int __init patch_via_init(void)
3355{
3356 return snd_hda_add_codec_preset(&via_list);
3357}
3358
3359static void __exit patch_via_exit(void)
3360{
3361 snd_hda_delete_codec_preset(&via_list);
3362}
3363
3364module_init(patch_via_init)
3365module_exit(patch_via_exit)