blob: 0da57db3a69145799fc966b45dde7d8b8ac448a1 [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,
Lydia Wangf5271102009-10-10 19:07:35 +0800131 VIA_CTL_WIDGET_ANALOG_MUTE,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100132};
133
134enum {
Harald Welteeb14a462008-09-09 15:40:38 +0800135 AUTO_SEQ_FRONT = 0,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100136 AUTO_SEQ_SURROUND,
137 AUTO_SEQ_CENLFE,
138 AUTO_SEQ_SIDE
139};
140
Harald Welted7426322008-09-15 22:43:23 +0800141/* Some VT1708S based boards gets the micboost setting wrong, so we have
142 * to apply some brute-force and re-write the TLV's by software. */
143static int mic_boost_tlv(struct snd_kcontrol *kcontrol, int op_flag,
144 unsigned int size, unsigned int __user *_tlv)
145{
146 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
147 hda_nid_t nid = get_amp_nid(kcontrol);
148
Lydia Wang744ff5f2009-10-10 19:07:26 +0800149 if (get_codec_type(codec) == VT1708S
Harald Welted7426322008-09-15 22:43:23 +0800150 && (nid == 0x1a || nid == 0x1e)) {
151 if (size < 4 * sizeof(unsigned int))
152 return -ENOMEM;
153 if (put_user(1, _tlv)) /* SNDRV_CTL_TLVT_DB_SCALE */
154 return -EFAULT;
155 if (put_user(2 * sizeof(unsigned int), _tlv + 1))
156 return -EFAULT;
157 if (put_user(0, _tlv + 2)) /* offset = 0 */
158 return -EFAULT;
159 if (put_user(1000, _tlv + 3)) /* step size = 10 dB */
160 return -EFAULT;
161 }
162 return 0;
163}
164
165static int mic_boost_volume_info(struct snd_kcontrol *kcontrol,
166 struct snd_ctl_elem_info *uinfo)
167{
168 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
169 hda_nid_t nid = get_amp_nid(kcontrol);
170
Lydia Wang744ff5f2009-10-10 19:07:26 +0800171 if (get_codec_type(codec) == VT1708S
Harald Welted7426322008-09-15 22:43:23 +0800172 && (nid == 0x1a || nid == 0x1e)) {
173 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
174 uinfo->count = 2;
175 uinfo->value.integer.min = 0;
176 uinfo->value.integer.max = 3;
177 }
178 return 0;
179}
180
Lydia Wangf5271102009-10-10 19:07:35 +0800181static void analog_low_current_mode(struct hda_codec *codec, int stream_idle);
182static void set_jack_power_state(struct hda_codec *codec);
183
184static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
185 struct snd_ctl_elem_value *ucontrol)
186{
187 int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
188 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
189
190 set_jack_power_state(codec);
191 analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1);
192 return change;
193}
194
195/* modify .put = snd_hda_mixer_amp_switch_put */
196#define ANALOG_INPUT_MUTE \
197 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
198 .name = NULL, \
199 .index = 0, \
200 .info = snd_hda_mixer_amp_switch_info, \
201 .get = snd_hda_mixer_amp_switch_get, \
202 .put = analog_input_switch_put, \
203 .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
204
Joseph Chanc577b8a2006-11-29 15:29:40 +0100205static struct snd_kcontrol_new vt1708_control_templates[] = {
206 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
207 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Lydia Wangf5271102009-10-10 19:07:35 +0800208 ANALOG_INPUT_MUTE,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100209};
210
211
212struct via_spec {
213 /* codec parameterization */
214 struct snd_kcontrol_new *mixers[3];
215 unsigned int num_mixers;
216
Harald Welte69e52a82008-09-09 15:57:32 +0800217 struct hda_verb *init_verbs[5];
218 unsigned int num_iverbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100219
220 char *stream_name_analog;
221 struct hda_pcm_stream *stream_analog_playback;
222 struct hda_pcm_stream *stream_analog_capture;
223
224 char *stream_name_digital;
225 struct hda_pcm_stream *stream_digital_playback;
226 struct hda_pcm_stream *stream_digital_capture;
227
228 /* playback */
229 struct hda_multi_out multiout;
Takashi Iwai9da29272009-05-07 16:31:14 +0200230 hda_nid_t slave_dig_outs[2];
Joseph Chanc577b8a2006-11-29 15:29:40 +0100231
232 /* capture */
233 unsigned int num_adc_nids;
234 hda_nid_t *adc_nids;
Takashi Iwai337b9d02009-07-07 18:18:59 +0200235 hda_nid_t mux_nids[3];
Joseph Chanc577b8a2006-11-29 15:29:40 +0100236 hda_nid_t dig_in_nid;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +0200237 hda_nid_t dig_in_pin;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100238
239 /* capture source */
240 const struct hda_input_mux *input_mux;
241 unsigned int cur_mux[3];
242
243 /* PCM information */
Harald Welte98aa34c2008-09-09 16:02:09 +0800244 struct hda_pcm pcm_rec[3];
Joseph Chanc577b8a2006-11-29 15:29:40 +0100245
246 /* dynamic controls, init_verbs and input_mux */
247 struct auto_pin_cfg autocfg;
Takashi Iwai603c4012008-07-30 15:01:44 +0200248 struct snd_array kctls;
Harald Welte0aa62ae2008-09-09 15:58:27 +0800249 struct hda_input_mux private_imux[2];
Takashi Iwai41923e42007-10-22 17:20:10 +0200250 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwaicb53c622007-08-10 17:21:45 +0200251
Harald Welte0aa62ae2008-09-09 15:58:27 +0800252 /* HP mode source */
253 const struct hda_input_mux *hp_mux;
254 unsigned int hp_independent_mode;
255
Lydia Wang518bf3b2009-10-10 19:07:29 +0800256 enum VIA_HDA_CODEC codec_type;
257
Takashi Iwaicb53c622007-08-10 17:21:45 +0200258#ifdef CONFIG_SND_HDA_POWER_SAVE
259 struct hda_loopback_check loopback;
260#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +0100261};
262
263static hda_nid_t vt1708_adc_nids[2] = {
264 /* ADC1-2 */
265 0x15, 0x27
266};
267
268static hda_nid_t vt1709_adc_nids[3] = {
269 /* ADC1-2 */
270 0x14, 0x15, 0x16
271};
272
Josepch Chanf7278fd2007-12-13 16:40:40 +0100273static hda_nid_t vt1708B_adc_nids[2] = {
274 /* ADC1-2 */
275 0x13, 0x14
276};
277
Harald Welted949cac2008-09-09 15:56:01 +0800278static hda_nid_t vt1708S_adc_nids[2] = {
279 /* ADC1-2 */
280 0x13, 0x14
281};
282
283static hda_nid_t vt1702_adc_nids[3] = {
284 /* ADC1-2 */
285 0x12, 0x20, 0x1F
286};
287
Joseph Chanc577b8a2006-11-29 15:29:40 +0100288/* add dynamic controls */
289static int via_add_control(struct via_spec *spec, int type, const char *name,
290 unsigned long val)
291{
292 struct snd_kcontrol_new *knew;
293
Takashi Iwai603c4012008-07-30 15:01:44 +0200294 snd_array_init(&spec->kctls, sizeof(*knew), 32);
295 knew = snd_array_new(&spec->kctls);
296 if (!knew)
297 return -ENOMEM;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100298 *knew = vt1708_control_templates[type];
299 knew->name = kstrdup(name, GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100300 if (!knew->name)
301 return -ENOMEM;
302 knew->private_value = val;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100303 return 0;
304}
305
Takashi Iwai603c4012008-07-30 15:01:44 +0200306static void via_free_kctls(struct hda_codec *codec)
307{
308 struct via_spec *spec = codec->spec;
309
310 if (spec->kctls.list) {
311 struct snd_kcontrol_new *kctl = spec->kctls.list;
312 int i;
313 for (i = 0; i < spec->kctls.used; i++)
314 kfree(kctl[i].name);
315 }
316 snd_array_free(&spec->kctls);
317}
318
Joseph Chanc577b8a2006-11-29 15:29:40 +0100319/* create input playback/capture controls for the given pin */
Lydia Wang9510e8d2009-10-10 19:07:39 +0800320static int via_new_analog_input(struct via_spec *spec, const char *ctlname,
321 int idx, int mix_nid)
Joseph Chanc577b8a2006-11-29 15:29:40 +0100322{
323 char name[32];
324 int err;
325
326 sprintf(name, "%s Playback Volume", ctlname);
327 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
328 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
329 if (err < 0)
330 return err;
331 sprintf(name, "%s Playback Switch", ctlname);
Lydia Wangf5271102009-10-10 19:07:35 +0800332 err = via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100333 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
334 if (err < 0)
335 return err;
336 return 0;
337}
338
339static void via_auto_set_output_and_unmute(struct hda_codec *codec,
340 hda_nid_t nid, int pin_type,
341 int dac_idx)
342{
343 /* set as output */
344 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
345 pin_type);
346 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
347 AMP_OUT_UNMUTE);
Takashi Iwaid3a11e62009-07-07 13:43:35 +0200348 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
349 snd_hda_codec_write(codec, nid, 0,
350 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100351}
352
353
354static void via_auto_init_multi_out(struct hda_codec *codec)
355{
356 struct via_spec *spec = codec->spec;
357 int i;
358
359 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
360 hda_nid_t nid = spec->autocfg.line_out_pins[i];
361 if (nid)
362 via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
363 }
364}
365
366static void via_auto_init_hp_out(struct hda_codec *codec)
367{
368 struct via_spec *spec = codec->spec;
369 hda_nid_t pin;
370
371 pin = spec->autocfg.hp_pins[0];
372 if (pin) /* connect to front */
373 via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
374}
375
376static void via_auto_init_analog_input(struct hda_codec *codec)
377{
378 struct via_spec *spec = codec->spec;
379 int i;
380
381 for (i = 0; i < AUTO_PIN_LAST; i++) {
382 hda_nid_t nid = spec->autocfg.input_pins[i];
383
384 snd_hda_codec_write(codec, nid, 0,
385 AC_VERB_SET_PIN_WIDGET_CONTROL,
386 (i <= AUTO_PIN_FRONT_MIC ?
387 PIN_VREF50 : PIN_IN));
388
389 }
390}
Lydia Wangf5271102009-10-10 19:07:35 +0800391
392static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
393 unsigned int *affected_parm)
394{
395 unsigned parm;
396 unsigned def_conf = snd_hda_codec_get_pincfg(codec, nid);
397 unsigned no_presence = (def_conf & AC_DEFCFG_MISC)
398 >> AC_DEFCFG_MISC_SHIFT
399 & AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */
400 unsigned present = snd_hda_codec_read(codec, nid, 0,
401 AC_VERB_GET_PIN_SENSE, 0) >> 31;
402
403 if ((no_presence || present) && get_defcfg_connect(def_conf)
404 != AC_JACK_PORT_NONE) {
405 *affected_parm = AC_PWRST_D0; /* if it's connected */
406 parm = AC_PWRST_D0;
407 } else
408 parm = AC_PWRST_D3;
409
410 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
411}
412
413static void set_jack_power_state(struct hda_codec *codec)
414{
415 struct via_spec *spec = codec->spec;
416 int imux_is_smixer;
417 unsigned int parm;
418
419 if (spec->codec_type == VT1702) {
420 imux_is_smixer = snd_hda_codec_read(
421 codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
422 /* inputs */
423 /* PW 1/2/5 (14h/15h/18h) */
424 parm = AC_PWRST_D3;
425 set_pin_power_state(codec, 0x14, &parm);
426 set_pin_power_state(codec, 0x15, &parm);
427 set_pin_power_state(codec, 0x18, &parm);
428 if (imux_is_smixer)
429 parm = AC_PWRST_D0; /* SW0 = stereo mixer (idx 3) */
430 /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
431 snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
432 parm);
433 snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE,
434 parm);
435 snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
436 parm);
437 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE,
438 parm);
439
440 /* outputs */
441 /* PW 3/4 (16h/17h) */
442 parm = AC_PWRST_D3;
443 set_pin_power_state(codec, 0x16, &parm);
444 set_pin_power_state(codec, 0x17, &parm);
445 /* MW0 (1ah), AOW 0/1 (10h/1dh) */
446 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
447 imux_is_smixer ? AC_PWRST_D0 : parm);
448 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
449 parm);
450 snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE,
451 parm);
452 } else if (spec->codec_type == VT1708B_8CH
453 || spec->codec_type == VT1708B_4CH
454 || spec->codec_type == VT1708S) {
455 /* SW0 (17h) = stereo mixer */
456 int is_8ch = spec->codec_type != VT1708B_4CH;
457 imux_is_smixer = snd_hda_codec_read(
458 codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
459 == ((spec->codec_type == VT1708S) ? 5 : 0);
460 /* inputs */
461 /* PW 1/2/5 (1ah/1bh/1eh) */
462 parm = AC_PWRST_D3;
463 set_pin_power_state(codec, 0x1a, &parm);
464 set_pin_power_state(codec, 0x1b, &parm);
465 set_pin_power_state(codec, 0x1e, &parm);
466 if (imux_is_smixer)
467 parm = AC_PWRST_D0;
468 /* SW0 (17h), AIW 0/1 (13h/14h) */
469 snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
470 parm);
471 snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
472 parm);
473 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
474 parm);
475
476 /* outputs */
477 /* PW0 (19h), SW1 (18h), AOW1 (11h) */
478 parm = AC_PWRST_D3;
479 set_pin_power_state(codec, 0x19, &parm);
480 snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
481 parm);
482 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
483 parm);
484
485 /* PW6 (22h), SW2 (26h), AOW2 (24h) */
486 if (is_8ch) {
487 parm = AC_PWRST_D3;
488 set_pin_power_state(codec, 0x22, &parm);
489 snd_hda_codec_write(codec, 0x26, 0,
490 AC_VERB_SET_POWER_STATE, parm);
491 snd_hda_codec_write(codec, 0x24, 0,
492 AC_VERB_SET_POWER_STATE, parm);
493 }
494
495 /* PW 3/4/7 (1ch/1dh/23h) */
496 parm = AC_PWRST_D3;
497 /* force to D0 for internal Speaker */
498 set_pin_power_state(codec, 0x1c, &parm);
499 set_pin_power_state(codec, 0x1d, &parm);
500 if (is_8ch)
501 set_pin_power_state(codec, 0x23, &parm);
502 /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
503 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
504 imux_is_smixer ? AC_PWRST_D0 : parm);
505 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
506 parm);
507 if (is_8ch) {
508 snd_hda_codec_write(codec, 0x25, 0,
509 AC_VERB_SET_POWER_STATE, parm);
510 snd_hda_codec_write(codec, 0x27, 0,
511 AC_VERB_SET_POWER_STATE, parm);
512 }
513 }
514}
515
Joseph Chanc577b8a2006-11-29 15:29:40 +0100516/*
517 * input MUX handling
518 */
519static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
520 struct snd_ctl_elem_info *uinfo)
521{
522 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
523 struct via_spec *spec = codec->spec;
524 return snd_hda_input_mux_info(spec->input_mux, uinfo);
525}
526
527static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
528 struct snd_ctl_elem_value *ucontrol)
529{
530 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
531 struct via_spec *spec = codec->spec;
532 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
533
534 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
535 return 0;
536}
537
538static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
539 struct snd_ctl_elem_value *ucontrol)
540{
541 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
542 struct via_spec *spec = codec->spec;
543 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100544
Takashi Iwai337b9d02009-07-07 18:18:59 +0200545 if (!spec->mux_nids[adc_idx])
546 return -EINVAL;
547 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
548 spec->mux_nids[adc_idx],
549 &spec->cur_mux[adc_idx]);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100550}
551
Harald Welte0aa62ae2008-09-09 15:58:27 +0800552static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
553 struct snd_ctl_elem_info *uinfo)
554{
555 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
556 struct via_spec *spec = codec->spec;
557 return snd_hda_input_mux_info(spec->hp_mux, uinfo);
558}
559
560static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
561 struct snd_ctl_elem_value *ucontrol)
562{
563 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
564 struct via_spec *spec = codec->spec;
565 hda_nid_t nid = spec->autocfg.hp_pins[0];
566 unsigned int pinsel = snd_hda_codec_read(codec, nid, 0,
567 AC_VERB_GET_CONNECT_SEL,
568 0x00);
569
570 ucontrol->value.enumerated.item[0] = pinsel;
571
572 return 0;
573}
574
575static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
576 struct snd_ctl_elem_value *ucontrol)
577{
578 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
579 struct via_spec *spec = codec->spec;
580 hda_nid_t nid = spec->autocfg.hp_pins[0];
581 unsigned int pinsel = ucontrol->value.enumerated.item[0];
582 unsigned int con_nid = snd_hda_codec_read(codec, nid, 0,
583 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
584
585 if (con_nid == spec->multiout.hp_nid) {
586 if (pinsel == 0) {
587 if (!spec->hp_independent_mode) {
588 if (spec->multiout.num_dacs > 1)
589 spec->multiout.num_dacs -= 1;
590 spec->hp_independent_mode = 1;
591 }
592 } else if (pinsel == 1) {
593 if (spec->hp_independent_mode) {
594 if (spec->multiout.num_dacs > 1)
595 spec->multiout.num_dacs += 1;
596 spec->hp_independent_mode = 0;
597 }
598 }
599 } else {
600 if (pinsel == 0) {
601 if (spec->hp_independent_mode) {
602 if (spec->multiout.num_dacs > 1)
603 spec->multiout.num_dacs += 1;
604 spec->hp_independent_mode = 0;
605 }
606 } else if (pinsel == 1) {
607 if (!spec->hp_independent_mode) {
608 if (spec->multiout.num_dacs > 1)
609 spec->multiout.num_dacs -= 1;
610 spec->hp_independent_mode = 1;
611 }
612 }
613 }
614 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL,
615 pinsel);
616
617 if (spec->multiout.hp_nid &&
618 spec->multiout.hp_nid != spec->multiout.dac_nids[HDA_FRONT])
619 snd_hda_codec_setup_stream(codec,
620 spec->multiout.hp_nid,
621 0, 0, 0);
622
623 return 0;
624}
625
626static struct snd_kcontrol_new via_hp_mixer[] = {
627 {
628 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
629 .name = "Independent HP",
630 .count = 1,
631 .info = via_independent_hp_info,
632 .get = via_independent_hp_get,
633 .put = via_independent_hp_put,
634 },
635 { } /* end */
636};
637
Joseph Chanc577b8a2006-11-29 15:29:40 +0100638/* capture mixer elements */
639static struct snd_kcontrol_new vt1708_capture_mixer[] = {
640 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
641 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
642 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
643 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
644 {
645 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
646 /* The multiple "Capture Source" controls confuse alsamixer
647 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +0100648 */
649 /* .name = "Capture Source", */
650 .name = "Input Source",
651 .count = 1,
652 .info = via_mux_enum_info,
653 .get = via_mux_enum_get,
654 .put = via_mux_enum_put,
655 },
656 { } /* end */
657};
Lydia Wangf5271102009-10-10 19:07:35 +0800658
659/* check AA path's mute statue */
660static int is_aa_path_mute(struct hda_codec *codec)
661{
662 int mute = 1;
663 hda_nid_t nid_mixer;
664 int start_idx;
665 int end_idx;
666 int i;
667 struct via_spec *spec = codec->spec;
668 /* get nid of MW0 and start & end index */
669 switch (spec->codec_type) {
670 case VT1708B_8CH:
671 case VT1708B_4CH:
672 case VT1708S:
673 nid_mixer = 0x16;
674 start_idx = 2;
675 end_idx = 4;
676 break;
677 case VT1702:
678 nid_mixer = 0x1a;
679 start_idx = 1;
680 end_idx = 3;
681 break;
682 default:
683 return 0;
684 }
685 /* check AA path's mute status */
686 for (i = start_idx; i <= end_idx; i++) {
687 unsigned int con_list = snd_hda_codec_read(
688 codec, nid_mixer, 0, AC_VERB_GET_CONNECT_LIST, i/4*4);
689 int shift = 8 * (i % 4);
690 hda_nid_t nid_pin = (con_list & (0xff << shift)) >> shift;
691 unsigned int defconf = snd_hda_codec_get_pincfg(codec, nid_pin);
692 if (get_defcfg_connect(defconf) == AC_JACK_PORT_COMPLEX) {
693 /* check mute status while the pin is connected */
694 int mute_l = snd_hda_codec_amp_read(codec, nid_mixer, 0,
695 HDA_INPUT, i) >> 7;
696 int mute_r = snd_hda_codec_amp_read(codec, nid_mixer, 1,
697 HDA_INPUT, i) >> 7;
698 if (!mute_l || !mute_r) {
699 mute = 0;
700 break;
701 }
702 }
703 }
704 return mute;
705}
706
707/* enter/exit analog low-current mode */
708static void analog_low_current_mode(struct hda_codec *codec, int stream_idle)
709{
710 struct via_spec *spec = codec->spec;
711 static int saved_stream_idle = 1; /* saved stream idle status */
712 int enable = is_aa_path_mute(codec);
713 unsigned int verb = 0;
714 unsigned int parm = 0;
715
716 if (stream_idle == -1) /* stream status did not change */
717 enable = enable && saved_stream_idle;
718 else {
719 enable = enable && stream_idle;
720 saved_stream_idle = stream_idle;
721 }
722
723 /* decide low current mode's verb & parameter */
724 switch (spec->codec_type) {
725 case VT1708B_8CH:
726 case VT1708B_4CH:
727 verb = 0xf70;
728 parm = enable ? 0x02 : 0x00; /* 0x02: 2/3x, 0x00: 1x */
729 break;
730 case VT1708S:
731 verb = 0xf73;
732 parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */
733 break;
734 case VT1702:
735 verb = 0xf73;
736 parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */
737 break;
738 default:
739 return; /* other codecs are not supported */
740 }
741 /* send verb */
742 snd_hda_codec_write(codec, codec->afg, 0, verb, parm);
743}
744
Joseph Chanc577b8a2006-11-29 15:29:40 +0100745/*
746 * generic initialization of ADC, input mixers and output mixers
747 */
748static struct hda_verb vt1708_volume_init_verbs[] = {
749 /*
750 * Unmute ADC0-1 and set the default input to mic-in
751 */
752 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
753 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
754
755
Josepch Chanf7278fd2007-12-13 16:40:40 +0100756 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +0100757 * mixer widget
758 */
759 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +0100760 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
761 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
762 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
763 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
764 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100765
766 /*
767 * Set up output mixers (0x19 - 0x1b)
768 */
769 /* set vol=0 to output mixers */
770 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
771 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
772 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
773
774 /* Setup default input to PW4 */
775 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +0100776 /* PW9 Output enable */
777 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Josepch Chanf7278fd2007-12-13 16:40:40 +0100778 { }
Joseph Chanc577b8a2006-11-29 15:29:40 +0100779};
780
781static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
782 struct hda_codec *codec,
783 struct snd_pcm_substream *substream)
784{
785 struct via_spec *spec = codec->spec;
Lydia Wang17314372009-10-10 19:07:37 +0800786 int idle = substream->pstr->substream_opened == 1
787 && substream->ref_count == 0;
788
789 analog_low_current_mode(codec, idle);
Takashi Iwai9a081602008-02-12 18:37:26 +0100790 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
791 hinfo);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100792}
793
794static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
795 struct hda_codec *codec,
796 unsigned int stream_tag,
797 unsigned int format,
798 struct snd_pcm_substream *substream)
799{
800 struct via_spec *spec = codec->spec;
801 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
802 stream_tag, format, substream);
803}
804
805static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
806 struct hda_codec *codec,
807 struct snd_pcm_substream *substream)
808{
809 struct via_spec *spec = codec->spec;
810 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
811}
812
Harald Welte0aa62ae2008-09-09 15:58:27 +0800813
814static void playback_multi_pcm_prep_0(struct hda_codec *codec,
815 unsigned int stream_tag,
816 unsigned int format,
817 struct snd_pcm_substream *substream)
818{
819 struct via_spec *spec = codec->spec;
820 struct hda_multi_out *mout = &spec->multiout;
821 hda_nid_t *nids = mout->dac_nids;
822 int chs = substream->runtime->channels;
823 int i;
824
825 mutex_lock(&codec->spdif_mutex);
826 if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
827 if (chs == 2 &&
828 snd_hda_is_supported_format(codec, mout->dig_out_nid,
829 format) &&
830 !(codec->spdif_status & IEC958_AES0_NONAUDIO)) {
831 mout->dig_out_used = HDA_DIG_ANALOG_DUP;
832 /* turn off SPDIF once; otherwise the IEC958 bits won't
833 * be updated */
834 if (codec->spdif_ctls & AC_DIG1_ENABLE)
835 snd_hda_codec_write(codec, mout->dig_out_nid, 0,
836 AC_VERB_SET_DIGI_CONVERT_1,
837 codec->spdif_ctls &
838 ~AC_DIG1_ENABLE & 0xff);
839 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
840 stream_tag, 0, format);
841 /* turn on again (if needed) */
842 if (codec->spdif_ctls & AC_DIG1_ENABLE)
843 snd_hda_codec_write(codec, mout->dig_out_nid, 0,
844 AC_VERB_SET_DIGI_CONVERT_1,
845 codec->spdif_ctls & 0xff);
846 } else {
847 mout->dig_out_used = 0;
848 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
849 0, 0, 0);
850 }
851 }
852 mutex_unlock(&codec->spdif_mutex);
853
854 /* front */
855 snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag,
856 0, format);
857
858 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
859 !spec->hp_independent_mode)
860 /* headphone out will just decode front left/right (stereo) */
861 snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag,
862 0, format);
863
864 /* extra outputs copied from front */
865 for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
866 if (mout->extra_out_nid[i])
867 snd_hda_codec_setup_stream(codec,
868 mout->extra_out_nid[i],
869 stream_tag, 0, format);
870
871 /* surrounds */
872 for (i = 1; i < mout->num_dacs; i++) {
873 if (chs >= (i + 1) * 2) /* independent out */
874 snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
875 i * 2, format);
876 else /* copy front */
877 snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
878 0, format);
879 }
880}
881
882static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
883 struct hda_codec *codec,
884 unsigned int stream_tag,
885 unsigned int format,
886 struct snd_pcm_substream *substream)
887{
888 struct via_spec *spec = codec->spec;
889 struct hda_multi_out *mout = &spec->multiout;
890 hda_nid_t *nids = mout->dac_nids;
891
892 if (substream->number == 0)
893 playback_multi_pcm_prep_0(codec, stream_tag, format,
894 substream);
895 else {
896 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
897 spec->hp_independent_mode)
898 snd_hda_codec_setup_stream(codec, mout->hp_nid,
899 stream_tag, 0, format);
900 }
901
902 return 0;
903}
904
905static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
906 struct hda_codec *codec,
907 struct snd_pcm_substream *substream)
908{
909 struct via_spec *spec = codec->spec;
910 struct hda_multi_out *mout = &spec->multiout;
911 hda_nid_t *nids = mout->dac_nids;
912 int i;
913
914 if (substream->number == 0) {
915 for (i = 0; i < mout->num_dacs; i++)
916 snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
917
918 if (mout->hp_nid && !spec->hp_independent_mode)
919 snd_hda_codec_setup_stream(codec, mout->hp_nid,
920 0, 0, 0);
921
922 for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
923 if (mout->extra_out_nid[i])
924 snd_hda_codec_setup_stream(codec,
925 mout->extra_out_nid[i],
926 0, 0, 0);
927 mutex_lock(&codec->spdif_mutex);
928 if (mout->dig_out_nid &&
929 mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
930 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
931 0, 0, 0);
932 mout->dig_out_used = 0;
933 }
934 mutex_unlock(&codec->spdif_mutex);
935 } else {
936 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
937 spec->hp_independent_mode)
938 snd_hda_codec_setup_stream(codec, mout->hp_nid,
939 0, 0, 0);
940 }
941
942 return 0;
943}
944
Joseph Chanc577b8a2006-11-29 15:29:40 +0100945/*
946 * Digital out
947 */
948static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
949 struct hda_codec *codec,
950 struct snd_pcm_substream *substream)
951{
952 struct via_spec *spec = codec->spec;
953 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
954}
955
956static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
957 struct hda_codec *codec,
958 struct snd_pcm_substream *substream)
959{
960 struct via_spec *spec = codec->spec;
961 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
962}
963
Harald Welte5691ec72008-09-15 22:42:26 +0800964static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
Harald Welte98aa34c2008-09-09 16:02:09 +0800965 struct hda_codec *codec,
966 unsigned int stream_tag,
967 unsigned int format,
968 struct snd_pcm_substream *substream)
969{
970 struct via_spec *spec = codec->spec;
Takashi Iwai9da29272009-05-07 16:31:14 +0200971 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
972 stream_tag, format, substream);
973}
Harald Welte5691ec72008-09-15 22:42:26 +0800974
Takashi Iwai9da29272009-05-07 16:31:14 +0200975static int via_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
976 struct hda_codec *codec,
977 struct snd_pcm_substream *substream)
978{
979 struct via_spec *spec = codec->spec;
980 snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
Harald Welte98aa34c2008-09-09 16:02:09 +0800981 return 0;
982}
983
Joseph Chanc577b8a2006-11-29 15:29:40 +0100984/*
985 * Analog capture
986 */
987static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
988 struct hda_codec *codec,
989 unsigned int stream_tag,
990 unsigned int format,
991 struct snd_pcm_substream *substream)
992{
993 struct via_spec *spec = codec->spec;
994
995 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
996 stream_tag, 0, format);
997 return 0;
998}
999
1000static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1001 struct hda_codec *codec,
1002 struct snd_pcm_substream *substream)
1003{
1004 struct via_spec *spec = codec->spec;
Takashi Iwai888afa12008-03-18 09:57:50 +01001005 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001006 return 0;
1007}
1008
1009static struct hda_pcm_stream vt1708_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08001010 .substreams = 2,
Joseph Chanc577b8a2006-11-29 15:29:40 +01001011 .channels_min = 2,
1012 .channels_max = 8,
1013 .nid = 0x10, /* NID to query formats and rates */
1014 .ops = {
1015 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08001016 .prepare = via_playback_multi_pcm_prepare,
1017 .cleanup = via_playback_multi_pcm_cleanup
Joseph Chanc577b8a2006-11-29 15:29:40 +01001018 },
1019};
1020
Takashi Iwaibc9b5622008-05-23 17:50:27 +02001021static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
1022 .substreams = 1,
1023 .channels_min = 2,
1024 .channels_max = 8,
1025 .nid = 0x10, /* NID to query formats and rates */
1026 /* We got noisy outputs on the right channel on VT1708 when
1027 * 24bit samples are used. Until any workaround is found,
1028 * disable the 24bit format, so far.
1029 */
1030 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1031 .ops = {
1032 .open = via_playback_pcm_open,
1033 .prepare = via_playback_pcm_prepare,
1034 .cleanup = via_playback_pcm_cleanup
1035 },
1036};
1037
Joseph Chanc577b8a2006-11-29 15:29:40 +01001038static struct hda_pcm_stream vt1708_pcm_analog_capture = {
1039 .substreams = 2,
1040 .channels_min = 2,
1041 .channels_max = 2,
1042 .nid = 0x15, /* NID to query formats and rates */
1043 .ops = {
1044 .prepare = via_capture_pcm_prepare,
1045 .cleanup = via_capture_pcm_cleanup
1046 },
1047};
1048
1049static struct hda_pcm_stream vt1708_pcm_digital_playback = {
1050 .substreams = 1,
1051 .channels_min = 2,
1052 .channels_max = 2,
1053 /* NID is set in via_build_pcms */
1054 .ops = {
1055 .open = via_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001056 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02001057 .prepare = via_dig_playback_pcm_prepare,
1058 .cleanup = via_dig_playback_pcm_cleanup
Joseph Chanc577b8a2006-11-29 15:29:40 +01001059 },
1060};
1061
1062static struct hda_pcm_stream vt1708_pcm_digital_capture = {
1063 .substreams = 1,
1064 .channels_min = 2,
1065 .channels_max = 2,
1066};
1067
1068static int via_build_controls(struct hda_codec *codec)
1069{
1070 struct via_spec *spec = codec->spec;
1071 int err;
1072 int i;
1073
1074 for (i = 0; i < spec->num_mixers; i++) {
1075 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1076 if (err < 0)
1077 return err;
1078 }
1079
1080 if (spec->multiout.dig_out_nid) {
1081 err = snd_hda_create_spdif_out_ctls(codec,
1082 spec->multiout.dig_out_nid);
1083 if (err < 0)
1084 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001085 err = snd_hda_create_spdif_share_sw(codec,
1086 &spec->multiout);
1087 if (err < 0)
1088 return err;
1089 spec->multiout.share_spdif = 1;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001090 }
1091 if (spec->dig_in_nid) {
1092 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1093 if (err < 0)
1094 return err;
1095 }
Lydia Wang17314372009-10-10 19:07:37 +08001096
1097 /* init power states */
1098 set_jack_power_state(codec);
1099 analog_low_current_mode(codec, 1);
1100
Takashi Iwai603c4012008-07-30 15:01:44 +02001101 via_free_kctls(codec); /* no longer needed */
Joseph Chanc577b8a2006-11-29 15:29:40 +01001102 return 0;
1103}
1104
1105static int via_build_pcms(struct hda_codec *codec)
1106{
1107 struct via_spec *spec = codec->spec;
1108 struct hda_pcm *info = spec->pcm_rec;
1109
1110 codec->num_pcms = 1;
1111 codec->pcm_info = info;
1112
1113 info->name = spec->stream_name_analog;
1114 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
1115 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
1116 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
1117 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
1118
1119 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
1120 spec->multiout.max_channels;
1121
1122 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1123 codec->num_pcms++;
1124 info++;
1125 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01001126 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001127 if (spec->multiout.dig_out_nid) {
1128 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
1129 *(spec->stream_digital_playback);
1130 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
1131 spec->multiout.dig_out_nid;
1132 }
1133 if (spec->dig_in_nid) {
1134 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
1135 *(spec->stream_digital_capture);
1136 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
1137 spec->dig_in_nid;
1138 }
1139 }
1140
1141 return 0;
1142}
1143
1144static void via_free(struct hda_codec *codec)
1145{
1146 struct via_spec *spec = codec->spec;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001147
1148 if (!spec)
1149 return;
1150
Takashi Iwai603c4012008-07-30 15:01:44 +02001151 via_free_kctls(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001152 kfree(codec->spec);
1153}
1154
Harald Welte69e52a82008-09-09 15:57:32 +08001155/* mute internal speaker if HP is plugged */
1156static void via_hp_automute(struct hda_codec *codec)
1157{
1158 unsigned int present;
1159 struct via_spec *spec = codec->spec;
1160
1161 present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
1162 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1163 snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
1164 HDA_OUTPUT, 0, HDA_AMP_MUTE,
1165 present ? HDA_AMP_MUTE : 0);
1166}
1167
1168static void via_gpio_control(struct hda_codec *codec)
1169{
1170 unsigned int gpio_data;
1171 unsigned int vol_counter;
1172 unsigned int vol;
1173 unsigned int master_vol;
1174
1175 struct via_spec *spec = codec->spec;
1176
1177 gpio_data = snd_hda_codec_read(codec, codec->afg, 0,
1178 AC_VERB_GET_GPIO_DATA, 0) & 0x03;
1179
1180 vol_counter = (snd_hda_codec_read(codec, codec->afg, 0,
1181 0xF84, 0) & 0x3F0000) >> 16;
1182
1183 vol = vol_counter & 0x1F;
1184 master_vol = snd_hda_codec_read(codec, 0x1A, 0,
1185 AC_VERB_GET_AMP_GAIN_MUTE,
1186 AC_AMP_GET_INPUT);
1187
1188 if (gpio_data == 0x02) {
1189 /* unmute line out */
1190 snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
1191 HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
1192
1193 if (vol_counter & 0x20) {
1194 /* decrease volume */
1195 if (vol > master_vol)
1196 vol = master_vol;
1197 snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT,
1198 0, HDA_AMP_VOLMASK,
1199 master_vol-vol);
1200 } else {
1201 /* increase volume */
1202 snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, 0,
1203 HDA_AMP_VOLMASK,
1204 ((master_vol+vol) > 0x2A) ? 0x2A :
1205 (master_vol+vol));
1206 }
1207 } else if (!(gpio_data & 0x02)) {
1208 /* mute line out */
1209 snd_hda_codec_amp_stereo(codec,
1210 spec->autocfg.line_out_pins[0],
1211 HDA_OUTPUT, 0, HDA_AMP_MUTE,
1212 HDA_AMP_MUTE);
1213 }
1214}
1215
1216/* unsolicited event for jack sensing */
1217static void via_unsol_event(struct hda_codec *codec,
1218 unsigned int res)
1219{
1220 res >>= 26;
1221 if (res == VIA_HP_EVENT)
1222 via_hp_automute(codec);
1223 else if (res == VIA_GPIO_EVENT)
1224 via_gpio_control(codec);
1225}
1226
Joseph Chanc577b8a2006-11-29 15:29:40 +01001227static int via_init(struct hda_codec *codec)
1228{
1229 struct via_spec *spec = codec->spec;
Harald Welte69e52a82008-09-09 15:57:32 +08001230 int i;
1231 for (i = 0; i < spec->num_iverbs; i++)
1232 snd_hda_sequence_write(codec, spec->init_verbs[i]);
1233
Lydia Wang518bf3b2009-10-10 19:07:29 +08001234 spec->codec_type = get_codec_type(codec);
1235 if (spec->codec_type == VT1708BCE)
1236 spec->codec_type = VT1708S; /* VT1708BCE & VT1708S are almost
1237 same */
Josepch Chanf7278fd2007-12-13 16:40:40 +01001238 /* Lydia Add for EAPD enable */
1239 if (!spec->dig_in_nid) { /* No Digital In connection */
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02001240 if (spec->dig_in_pin) {
1241 snd_hda_codec_write(codec, spec->dig_in_pin, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001242 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +01001243 PIN_OUT);
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02001244 snd_hda_codec_write(codec, spec->dig_in_pin, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001245 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
1246 }
Takashi Iwai12b74c82008-01-15 12:39:38 +01001247 } else /* enable SPDIF-input pin */
1248 snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
1249 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
Josepch Chanf7278fd2007-12-13 16:40:40 +01001250
Takashi Iwai9da29272009-05-07 16:31:14 +02001251 /* assign slave outs */
1252 if (spec->slave_dig_outs[0])
1253 codec->slave_dig_outs = spec->slave_dig_outs;
Harald Welte5691ec72008-09-15 22:42:26 +08001254
Joseph Chanc577b8a2006-11-29 15:29:40 +01001255 return 0;
1256}
1257
Takashi Iwaicb53c622007-08-10 17:21:45 +02001258#ifdef CONFIG_SND_HDA_POWER_SAVE
1259static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
1260{
1261 struct via_spec *spec = codec->spec;
1262 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
1263}
1264#endif
1265
Joseph Chanc577b8a2006-11-29 15:29:40 +01001266/*
1267 */
1268static struct hda_codec_ops via_patch_ops = {
1269 .build_controls = via_build_controls,
1270 .build_pcms = via_build_pcms,
1271 .init = via_init,
1272 .free = via_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02001273#ifdef CONFIG_SND_HDA_POWER_SAVE
1274 .check_power_status = via_check_power_status,
1275#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001276};
1277
1278/* fill in the dac_nids table from the parsed pin configuration */
1279static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
1280 const struct auto_pin_cfg *cfg)
1281{
1282 int i;
1283 hda_nid_t nid;
1284
1285 spec->multiout.num_dacs = cfg->line_outs;
1286
1287 spec->multiout.dac_nids = spec->private_dac_nids;
1288
1289 for(i = 0; i < 4; i++) {
1290 nid = cfg->line_out_pins[i];
1291 if (nid) {
1292 /* config dac list */
1293 switch (i) {
1294 case AUTO_SEQ_FRONT:
1295 spec->multiout.dac_nids[i] = 0x10;
1296 break;
1297 case AUTO_SEQ_CENLFE:
1298 spec->multiout.dac_nids[i] = 0x12;
1299 break;
1300 case AUTO_SEQ_SURROUND:
Harald Weltefb4cb772008-09-09 15:53:36 +08001301 spec->multiout.dac_nids[i] = 0x11;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001302 break;
1303 case AUTO_SEQ_SIDE:
Harald Weltefb4cb772008-09-09 15:53:36 +08001304 spec->multiout.dac_nids[i] = 0x13;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001305 break;
1306 }
1307 }
1308 }
1309
1310 return 0;
1311}
1312
1313/* add playback controls from the parsed DAC table */
1314static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
1315 const struct auto_pin_cfg *cfg)
1316{
1317 char name[32];
1318 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1319 hda_nid_t nid, nid_vol = 0;
1320 int i, err;
1321
1322 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1323 nid = cfg->line_out_pins[i];
1324
1325 if (!nid)
1326 continue;
1327
1328 if (i != AUTO_SEQ_FRONT)
Harald Weltefb4cb772008-09-09 15:53:36 +08001329 nid_vol = 0x18 + i;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001330
1331 if (i == AUTO_SEQ_CENLFE) {
1332 /* Center/LFE */
1333 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001334 "Center Playback Volume",
1335 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1336 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001337 if (err < 0)
1338 return err;
1339 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1340 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001341 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1342 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001343 if (err < 0)
1344 return err;
1345 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1346 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001347 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1348 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001349 if (err < 0)
1350 return err;
1351 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1352 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001353 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1354 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001355 if (err < 0)
1356 return err;
1357 } else if (i == AUTO_SEQ_FRONT){
1358 /* add control to mixer index 0 */
1359 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1360 "Master Front Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001361 HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
1362 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001363 if (err < 0)
1364 return err;
1365 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1366 "Master Front Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001367 HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
1368 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001369 if (err < 0)
1370 return err;
1371
1372 /* add control to PW3 */
1373 sprintf(name, "%s Playback Volume", chname[i]);
1374 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001375 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1376 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001377 if (err < 0)
1378 return err;
1379 sprintf(name, "%s Playback Switch", chname[i]);
1380 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001381 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1382 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001383 if (err < 0)
1384 return err;
1385 } else {
1386 sprintf(name, "%s Playback Volume", chname[i]);
1387 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001388 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1389 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001390 if (err < 0)
1391 return err;
1392 sprintf(name, "%s Playback Switch", chname[i]);
1393 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001394 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1395 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001396 if (err < 0)
1397 return err;
1398 }
1399 }
1400
1401 return 0;
1402}
1403
Harald Welte0aa62ae2008-09-09 15:58:27 +08001404static void create_hp_imux(struct via_spec *spec)
1405{
1406 int i;
1407 struct hda_input_mux *imux = &spec->private_imux[1];
1408 static const char *texts[] = { "OFF", "ON", NULL};
1409
1410 /* for hp mode select */
1411 i = 0;
1412 while (texts[i] != NULL) {
1413 imux->items[imux->num_items].label = texts[i];
1414 imux->items[imux->num_items].index = i;
1415 imux->num_items++;
1416 i++;
1417 }
1418
1419 spec->hp_mux = &spec->private_imux[1];
1420}
1421
Joseph Chanc577b8a2006-11-29 15:29:40 +01001422static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1423{
1424 int err;
1425
1426 if (!pin)
1427 return 0;
1428
1429 spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
1430
1431 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1432 "Headphone Playback Volume",
1433 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1434 if (err < 0)
1435 return err;
1436 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1437 "Headphone Playback Switch",
1438 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1439 if (err < 0)
1440 return err;
1441
Harald Welte0aa62ae2008-09-09 15:58:27 +08001442 create_hp_imux(spec);
1443
Joseph Chanc577b8a2006-11-29 15:29:40 +01001444 return 0;
1445}
1446
1447/* create playback/capture controls for input pins */
1448static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
1449 const struct auto_pin_cfg *cfg)
1450{
1451 static char *labels[] = {
1452 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1453 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08001454 struct hda_input_mux *imux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01001455 int i, err, idx = 0;
1456
1457 /* for internal loopback recording select */
1458 imux->items[imux->num_items].label = "Stereo Mixer";
1459 imux->items[imux->num_items].index = idx;
1460 imux->num_items++;
1461
1462 for (i = 0; i < AUTO_PIN_LAST; i++) {
1463 if (!cfg->input_pins[i])
1464 continue;
1465
1466 switch (cfg->input_pins[i]) {
1467 case 0x1d: /* Mic */
1468 idx = 2;
1469 break;
1470
1471 case 0x1e: /* Line In */
1472 idx = 3;
1473 break;
1474
1475 case 0x21: /* Front Mic */
1476 idx = 4;
1477 break;
1478
1479 case 0x24: /* CD */
1480 idx = 1;
1481 break;
1482 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08001483 err = via_new_analog_input(spec, labels[i], idx, 0x17);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001484 if (err < 0)
1485 return err;
1486 imux->items[imux->num_items].label = labels[i];
1487 imux->items[imux->num_items].index = idx;
1488 imux->num_items++;
1489 }
1490 return 0;
1491}
1492
Takashi Iwaicb53c622007-08-10 17:21:45 +02001493#ifdef CONFIG_SND_HDA_POWER_SAVE
1494static struct hda_amp_list vt1708_loopbacks[] = {
1495 { 0x17, HDA_INPUT, 1 },
1496 { 0x17, HDA_INPUT, 2 },
1497 { 0x17, HDA_INPUT, 3 },
1498 { 0x17, HDA_INPUT, 4 },
1499 { } /* end */
1500};
1501#endif
1502
Harald Welte76d9b0d2008-09-09 15:50:37 +08001503static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
1504{
1505 unsigned int def_conf;
1506 unsigned char seqassoc;
1507
Takashi Iwai2f334f92009-02-20 14:37:42 +01001508 def_conf = snd_hda_codec_get_pincfg(codec, nid);
Harald Welte76d9b0d2008-09-09 15:50:37 +08001509 seqassoc = (unsigned char) get_defcfg_association(def_conf);
1510 seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
1511 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) {
1512 if (seqassoc == 0xff) {
1513 def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
Takashi Iwai2f334f92009-02-20 14:37:42 +01001514 snd_hda_codec_set_pincfg(codec, nid, def_conf);
Harald Welte76d9b0d2008-09-09 15:50:37 +08001515 }
1516 }
1517
1518 return;
1519}
1520
Joseph Chanc577b8a2006-11-29 15:29:40 +01001521static int vt1708_parse_auto_config(struct hda_codec *codec)
1522{
1523 struct via_spec *spec = codec->spec;
1524 int err;
1525
Harald Welte76d9b0d2008-09-09 15:50:37 +08001526 /* Add HP and CD pin config connect bit re-config action */
1527 vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
1528 vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
1529
Joseph Chanc577b8a2006-11-29 15:29:40 +01001530 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
1531 if (err < 0)
1532 return err;
1533 err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
1534 if (err < 0)
1535 return err;
1536 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
1537 return 0; /* can't find valid BIOS pin config */
1538
1539 err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
1540 if (err < 0)
1541 return err;
1542 err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
1543 if (err < 0)
1544 return err;
1545 err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
1546 if (err < 0)
1547 return err;
1548
1549 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1550
Takashi Iwai0852d7a2009-02-11 11:35:15 +01001551 if (spec->autocfg.dig_outs)
Joseph Chanc577b8a2006-11-29 15:29:40 +01001552 spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02001553 spec->dig_in_pin = VT1708_DIGIN_PIN;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001554 if (spec->autocfg.dig_in_pin)
1555 spec->dig_in_nid = VT1708_DIGIN_NID;
1556
Takashi Iwai603c4012008-07-30 15:01:44 +02001557 if (spec->kctls.list)
1558 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001559
Harald Welte69e52a82008-09-09 15:57:32 +08001560 spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001561
Harald Welte0aa62ae2008-09-09 15:58:27 +08001562 spec->input_mux = &spec->private_imux[0];
1563
Harald Weltef8fdd492008-09-15 22:41:31 +08001564 if (spec->hp_mux)
1565 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001566
1567 return 1;
1568}
1569
1570/* init callback for auto-configuration model -- overriding the default init */
1571static int via_auto_init(struct hda_codec *codec)
1572{
1573 via_init(codec);
1574 via_auto_init_multi_out(codec);
1575 via_auto_init_hp_out(codec);
1576 via_auto_init_analog_input(codec);
1577 return 0;
1578}
1579
Takashi Iwai337b9d02009-07-07 18:18:59 +02001580static int get_mux_nids(struct hda_codec *codec)
1581{
1582 struct via_spec *spec = codec->spec;
1583 hda_nid_t nid, conn[8];
1584 unsigned int type;
1585 int i, n;
1586
1587 for (i = 0; i < spec->num_adc_nids; i++) {
1588 nid = spec->adc_nids[i];
1589 while (nid) {
Takashi Iwaia22d5432009-07-27 12:54:26 +02001590 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai1c55d522009-07-08 07:45:46 +02001591 if (type == AC_WID_PIN)
1592 break;
Takashi Iwai337b9d02009-07-07 18:18:59 +02001593 n = snd_hda_get_connections(codec, nid, conn,
1594 ARRAY_SIZE(conn));
1595 if (n <= 0)
1596 break;
1597 if (n > 1) {
1598 spec->mux_nids[i] = nid;
1599 break;
1600 }
1601 nid = conn[0];
1602 }
1603 }
Takashi Iwai1c55d522009-07-08 07:45:46 +02001604 return 0;
Takashi Iwai337b9d02009-07-07 18:18:59 +02001605}
1606
Joseph Chanc577b8a2006-11-29 15:29:40 +01001607static int patch_vt1708(struct hda_codec *codec)
1608{
1609 struct via_spec *spec;
1610 int err;
1611
1612 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08001613 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001614 if (spec == NULL)
1615 return -ENOMEM;
1616
1617 codec->spec = spec;
1618
1619 /* automatic parse from the BIOS config */
1620 err = vt1708_parse_auto_config(codec);
1621 if (err < 0) {
1622 via_free(codec);
1623 return err;
1624 } else if (!err) {
1625 printk(KERN_INFO "hda_codec: Cannot set up configuration "
1626 "from BIOS. Using genenic mode...\n");
1627 }
1628
1629
1630 spec->stream_name_analog = "VT1708 Analog";
1631 spec->stream_analog_playback = &vt1708_pcm_analog_playback;
Takashi Iwaibc9b5622008-05-23 17:50:27 +02001632 /* disable 32bit format on VT1708 */
1633 if (codec->vendor_id == 0x11061708)
1634 spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001635 spec->stream_analog_capture = &vt1708_pcm_analog_capture;
1636
1637 spec->stream_name_digital = "VT1708 Digital";
1638 spec->stream_digital_playback = &vt1708_pcm_digital_playback;
1639 spec->stream_digital_capture = &vt1708_pcm_digital_capture;
1640
1641
1642 if (!spec->adc_nids && spec->input_mux) {
1643 spec->adc_nids = vt1708_adc_nids;
1644 spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
Takashi Iwai0f67a612009-08-31 08:12:29 +02001645 get_mux_nids(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001646 spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
1647 spec->num_mixers++;
1648 }
1649
1650 codec->patch_ops = via_patch_ops;
1651
1652 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001653#ifdef CONFIG_SND_HDA_POWER_SAVE
1654 spec->loopback.amplist = vt1708_loopbacks;
1655#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001656
1657 return 0;
1658}
1659
1660/* capture mixer elements */
1661static struct snd_kcontrol_new vt1709_capture_mixer[] = {
1662 HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
1663 HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
1664 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
1665 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
1666 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
1667 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
1668 {
1669 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1670 /* The multiple "Capture Source" controls confuse alsamixer
1671 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +01001672 */
1673 /* .name = "Capture Source", */
1674 .name = "Input Source",
1675 .count = 1,
1676 .info = via_mux_enum_info,
1677 .get = via_mux_enum_get,
1678 .put = via_mux_enum_put,
1679 },
1680 { } /* end */
1681};
1682
Harald Welte69e52a82008-09-09 15:57:32 +08001683static struct hda_verb vt1709_uniwill_init_verbs[] = {
1684 {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
1685 { }
1686};
1687
Joseph Chanc577b8a2006-11-29 15:29:40 +01001688/*
1689 * generic initialization of ADC, input mixers and output mixers
1690 */
1691static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
1692 /*
1693 * Unmute ADC0-2 and set the default input to mic-in
1694 */
1695 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1696 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1697 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1698
1699
Josepch Chanf7278fd2007-12-13 16:40:40 +01001700 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +01001701 * mixer widget
1702 */
1703 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +01001704 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1705 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1706 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1707 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1708 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001709
1710 /*
1711 * Set up output selector (0x1a, 0x1b, 0x29)
1712 */
1713 /* set vol=0 to output mixers */
1714 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1715 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1716 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1717
1718 /*
1719 * Unmute PW3 and PW4
1720 */
1721 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1722 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1723
1724 /* Set input of PW4 as AOW4 */
1725 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001726 /* PW9 Output enable */
1727 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
1728 { }
1729};
1730
1731static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
1732 .substreams = 1,
1733 .channels_min = 2,
1734 .channels_max = 10,
1735 .nid = 0x10, /* NID to query formats and rates */
1736 .ops = {
1737 .open = via_playback_pcm_open,
1738 .prepare = via_playback_pcm_prepare,
1739 .cleanup = via_playback_pcm_cleanup
1740 },
1741};
1742
1743static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
1744 .substreams = 1,
1745 .channels_min = 2,
1746 .channels_max = 6,
1747 .nid = 0x10, /* NID to query formats and rates */
1748 .ops = {
1749 .open = via_playback_pcm_open,
1750 .prepare = via_playback_pcm_prepare,
1751 .cleanup = via_playback_pcm_cleanup
1752 },
1753};
1754
1755static struct hda_pcm_stream vt1709_pcm_analog_capture = {
1756 .substreams = 2,
1757 .channels_min = 2,
1758 .channels_max = 2,
1759 .nid = 0x14, /* NID to query formats and rates */
1760 .ops = {
1761 .prepare = via_capture_pcm_prepare,
1762 .cleanup = via_capture_pcm_cleanup
1763 },
1764};
1765
1766static struct hda_pcm_stream vt1709_pcm_digital_playback = {
1767 .substreams = 1,
1768 .channels_min = 2,
1769 .channels_max = 2,
1770 /* NID is set in via_build_pcms */
1771 .ops = {
1772 .open = via_dig_playback_pcm_open,
1773 .close = via_dig_playback_pcm_close
1774 },
1775};
1776
1777static struct hda_pcm_stream vt1709_pcm_digital_capture = {
1778 .substreams = 1,
1779 .channels_min = 2,
1780 .channels_max = 2,
1781};
1782
1783static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
1784 const struct auto_pin_cfg *cfg)
1785{
1786 int i;
1787 hda_nid_t nid;
1788
1789 if (cfg->line_outs == 4) /* 10 channels */
1790 spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
1791 else if (cfg->line_outs == 3) /* 6 channels */
1792 spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
1793
1794 spec->multiout.dac_nids = spec->private_dac_nids;
1795
1796 if (cfg->line_outs == 4) { /* 10 channels */
1797 for (i = 0; i < cfg->line_outs; i++) {
1798 nid = cfg->line_out_pins[i];
1799 if (nid) {
1800 /* config dac list */
1801 switch (i) {
1802 case AUTO_SEQ_FRONT:
1803 /* AOW0 */
1804 spec->multiout.dac_nids[i] = 0x10;
1805 break;
1806 case AUTO_SEQ_CENLFE:
1807 /* AOW2 */
1808 spec->multiout.dac_nids[i] = 0x12;
1809 break;
1810 case AUTO_SEQ_SURROUND:
1811 /* AOW3 */
Harald Weltefb4cb772008-09-09 15:53:36 +08001812 spec->multiout.dac_nids[i] = 0x11;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001813 break;
1814 case AUTO_SEQ_SIDE:
1815 /* AOW1 */
Harald Weltefb4cb772008-09-09 15:53:36 +08001816 spec->multiout.dac_nids[i] = 0x27;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001817 break;
1818 default:
1819 break;
1820 }
1821 }
1822 }
1823 spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
1824
1825 } else if (cfg->line_outs == 3) { /* 6 channels */
1826 for(i = 0; i < cfg->line_outs; i++) {
1827 nid = cfg->line_out_pins[i];
1828 if (nid) {
1829 /* config dac list */
1830 switch(i) {
1831 case AUTO_SEQ_FRONT:
1832 /* AOW0 */
1833 spec->multiout.dac_nids[i] = 0x10;
1834 break;
1835 case AUTO_SEQ_CENLFE:
1836 /* AOW2 */
1837 spec->multiout.dac_nids[i] = 0x12;
1838 break;
1839 case AUTO_SEQ_SURROUND:
1840 /* AOW1 */
1841 spec->multiout.dac_nids[i] = 0x11;
1842 break;
1843 default:
1844 break;
1845 }
1846 }
1847 }
1848 }
1849
1850 return 0;
1851}
1852
1853/* add playback controls from the parsed DAC table */
1854static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
1855 const struct auto_pin_cfg *cfg)
1856{
1857 char name[32];
1858 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
1859 hda_nid_t nid = 0;
1860 int i, err;
1861
1862 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1863 nid = cfg->line_out_pins[i];
1864
1865 if (!nid)
1866 continue;
1867
1868 if (i == AUTO_SEQ_CENLFE) {
1869 /* Center/LFE */
1870 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1871 "Center Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001872 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
1873 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001874 if (err < 0)
1875 return err;
1876 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1877 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001878 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
1879 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001880 if (err < 0)
1881 return err;
1882 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1883 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001884 HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
1885 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001886 if (err < 0)
1887 return err;
1888 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1889 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001890 HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
1891 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001892 if (err < 0)
1893 return err;
1894 } else if (i == AUTO_SEQ_FRONT){
1895 /* add control to mixer index 0 */
1896 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1897 "Master Front Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001898 HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
1899 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001900 if (err < 0)
1901 return err;
1902 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1903 "Master Front Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001904 HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
1905 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001906 if (err < 0)
1907 return err;
1908
1909 /* add control to PW3 */
1910 sprintf(name, "%s Playback Volume", chname[i]);
1911 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001912 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1913 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001914 if (err < 0)
1915 return err;
1916 sprintf(name, "%s Playback Switch", chname[i]);
1917 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001918 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1919 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001920 if (err < 0)
1921 return err;
1922 } else if (i == AUTO_SEQ_SURROUND) {
1923 sprintf(name, "%s Playback Volume", chname[i]);
1924 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001925 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001926 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001927 if (err < 0)
1928 return err;
1929 sprintf(name, "%s Playback Switch", chname[i]);
1930 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001931 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001932 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001933 if (err < 0)
1934 return err;
1935 } else if (i == AUTO_SEQ_SIDE) {
1936 sprintf(name, "%s Playback Volume", chname[i]);
1937 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001938 HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001939 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001940 if (err < 0)
1941 return err;
1942 sprintf(name, "%s Playback Switch", chname[i]);
1943 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Harald Weltefb4cb772008-09-09 15:53:36 +08001944 HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001945 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001946 if (err < 0)
1947 return err;
1948 }
1949 }
1950
1951 return 0;
1952}
1953
1954static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1955{
1956 int err;
1957
1958 if (!pin)
1959 return 0;
1960
1961 if (spec->multiout.num_dacs == 5) /* 10 channels */
1962 spec->multiout.hp_nid = VT1709_HP_DAC_NID;
1963 else if (spec->multiout.num_dacs == 3) /* 6 channels */
1964 spec->multiout.hp_nid = 0;
1965
1966 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1967 "Headphone Playback Volume",
1968 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1969 if (err < 0)
1970 return err;
1971 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1972 "Headphone Playback Switch",
1973 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1974 if (err < 0)
1975 return err;
1976
1977 return 0;
1978}
1979
1980/* create playback/capture controls for input pins */
1981static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
1982 const struct auto_pin_cfg *cfg)
1983{
1984 static char *labels[] = {
1985 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1986 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08001987 struct hda_input_mux *imux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01001988 int i, err, idx = 0;
1989
1990 /* for internal loopback recording select */
1991 imux->items[imux->num_items].label = "Stereo Mixer";
1992 imux->items[imux->num_items].index = idx;
1993 imux->num_items++;
1994
1995 for (i = 0; i < AUTO_PIN_LAST; i++) {
1996 if (!cfg->input_pins[i])
1997 continue;
1998
1999 switch (cfg->input_pins[i]) {
2000 case 0x1d: /* Mic */
2001 idx = 2;
2002 break;
2003
2004 case 0x1e: /* Line In */
2005 idx = 3;
2006 break;
2007
2008 case 0x21: /* Front Mic */
2009 idx = 4;
2010 break;
2011
2012 case 0x23: /* CD */
2013 idx = 1;
2014 break;
2015 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08002016 err = via_new_analog_input(spec, labels[i], idx, 0x18);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002017 if (err < 0)
2018 return err;
2019 imux->items[imux->num_items].label = labels[i];
2020 imux->items[imux->num_items].index = idx;
2021 imux->num_items++;
2022 }
2023 return 0;
2024}
2025
2026static int vt1709_parse_auto_config(struct hda_codec *codec)
2027{
2028 struct via_spec *spec = codec->spec;
2029 int err;
2030
2031 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
2032 if (err < 0)
2033 return err;
2034 err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
2035 if (err < 0)
2036 return err;
2037 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2038 return 0; /* can't find valid BIOS pin config */
2039
2040 err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
2041 if (err < 0)
2042 return err;
2043 err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2044 if (err < 0)
2045 return err;
2046 err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
2047 if (err < 0)
2048 return err;
2049
2050 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2051
Takashi Iwai0852d7a2009-02-11 11:35:15 +01002052 if (spec->autocfg.dig_outs)
Joseph Chanc577b8a2006-11-29 15:29:40 +01002053 spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02002054 spec->dig_in_pin = VT1709_DIGIN_PIN;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002055 if (spec->autocfg.dig_in_pin)
2056 spec->dig_in_nid = VT1709_DIGIN_NID;
2057
Takashi Iwai603c4012008-07-30 15:01:44 +02002058 if (spec->kctls.list)
2059 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002060
Harald Welte0aa62ae2008-09-09 15:58:27 +08002061 spec->input_mux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01002062
Harald Weltef8fdd492008-09-15 22:41:31 +08002063 if (spec->hp_mux)
2064 spec->mixers[spec->num_mixers++] = via_hp_mixer;
2065
Joseph Chanc577b8a2006-11-29 15:29:40 +01002066 return 1;
2067}
2068
Takashi Iwaicb53c622007-08-10 17:21:45 +02002069#ifdef CONFIG_SND_HDA_POWER_SAVE
2070static struct hda_amp_list vt1709_loopbacks[] = {
2071 { 0x18, HDA_INPUT, 1 },
2072 { 0x18, HDA_INPUT, 2 },
2073 { 0x18, HDA_INPUT, 3 },
2074 { 0x18, HDA_INPUT, 4 },
2075 { } /* end */
2076};
2077#endif
2078
Joseph Chanc577b8a2006-11-29 15:29:40 +01002079static int patch_vt1709_10ch(struct hda_codec *codec)
2080{
2081 struct via_spec *spec;
2082 int err;
2083
2084 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08002085 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002086 if (spec == NULL)
2087 return -ENOMEM;
2088
2089 codec->spec = spec;
2090
2091 err = vt1709_parse_auto_config(codec);
2092 if (err < 0) {
2093 via_free(codec);
2094 return err;
2095 } else if (!err) {
2096 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
2097 "Using genenic mode...\n");
2098 }
2099
Harald Welte69e52a82008-09-09 15:57:32 +08002100 spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs;
2101 spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002102
2103 spec->stream_name_analog = "VT1709 Analog";
2104 spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
2105 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
2106
2107 spec->stream_name_digital = "VT1709 Digital";
2108 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
2109 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
2110
2111
2112 if (!spec->adc_nids && spec->input_mux) {
2113 spec->adc_nids = vt1709_adc_nids;
2114 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02002115 get_mux_nids(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002116 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
2117 spec->num_mixers++;
2118 }
2119
2120 codec->patch_ops = via_patch_ops;
2121
2122 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08002123 codec->patch_ops.unsol_event = via_unsol_event;
Takashi Iwaicb53c622007-08-10 17:21:45 +02002124#ifdef CONFIG_SND_HDA_POWER_SAVE
2125 spec->loopback.amplist = vt1709_loopbacks;
2126#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01002127
2128 return 0;
2129}
2130/*
2131 * generic initialization of ADC, input mixers and output mixers
2132 */
2133static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
2134 /*
2135 * Unmute ADC0-2 and set the default input to mic-in
2136 */
2137 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2138 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2139 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2140
2141
2142 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2143 * mixer widget
2144 */
2145 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2146 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2147 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2148 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2149 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2150 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2151
2152 /*
2153 * Set up output selector (0x1a, 0x1b, 0x29)
2154 */
2155 /* set vol=0 to output mixers */
2156 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2157 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2158 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2159
2160 /*
2161 * Unmute PW3 and PW4
2162 */
2163 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2164 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2165
2166 /* Set input of PW4 as MW0 */
2167 {0x20, AC_VERB_SET_CONNECT_SEL, 0},
Joseph Chanc577b8a2006-11-29 15:29:40 +01002168 /* PW9 Output enable */
2169 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2170 { }
2171};
2172
2173static int patch_vt1709_6ch(struct hda_codec *codec)
2174{
2175 struct via_spec *spec;
2176 int err;
2177
2178 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08002179 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002180 if (spec == NULL)
2181 return -ENOMEM;
2182
2183 codec->spec = spec;
2184
2185 err = vt1709_parse_auto_config(codec);
2186 if (err < 0) {
2187 via_free(codec);
2188 return err;
2189 } else if (!err) {
2190 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
2191 "Using genenic mode...\n");
2192 }
2193
Harald Welte69e52a82008-09-09 15:57:32 +08002194 spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs;
2195 spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002196
2197 spec->stream_name_analog = "VT1709 Analog";
2198 spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
2199 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
2200
2201 spec->stream_name_digital = "VT1709 Digital";
2202 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
2203 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
2204
2205
2206 if (!spec->adc_nids && spec->input_mux) {
2207 spec->adc_nids = vt1709_adc_nids;
2208 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02002209 get_mux_nids(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002210 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
2211 spec->num_mixers++;
2212 }
2213
2214 codec->patch_ops = via_patch_ops;
2215
2216 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08002217 codec->patch_ops.unsol_event = via_unsol_event;
Takashi Iwaicb53c622007-08-10 17:21:45 +02002218#ifdef CONFIG_SND_HDA_POWER_SAVE
2219 spec->loopback.amplist = vt1709_loopbacks;
2220#endif
Josepch Chanf7278fd2007-12-13 16:40:40 +01002221 return 0;
2222}
2223
2224/* capture mixer elements */
2225static struct snd_kcontrol_new vt1708B_capture_mixer[] = {
2226 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
2227 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
2228 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
2229 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
2230 {
2231 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2232 /* The multiple "Capture Source" controls confuse alsamixer
2233 * So call somewhat different..
Josepch Chanf7278fd2007-12-13 16:40:40 +01002234 */
2235 /* .name = "Capture Source", */
2236 .name = "Input Source",
2237 .count = 1,
2238 .info = via_mux_enum_info,
2239 .get = via_mux_enum_get,
2240 .put = via_mux_enum_put,
2241 },
2242 { } /* end */
2243};
2244/*
2245 * generic initialization of ADC, input mixers and output mixers
2246 */
2247static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
2248 /*
2249 * Unmute ADC0-1 and set the default input to mic-in
2250 */
2251 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2252 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2253
2254
2255 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2256 * mixer widget
2257 */
2258 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2259 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2260 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2261 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2262 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2263 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2264
2265 /*
2266 * Set up output mixers
2267 */
2268 /* set vol=0 to output mixers */
2269 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2270 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2271 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2272
2273 /* Setup default input to PW4 */
2274 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1},
2275 /* PW9 Output enable */
2276 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2277 /* PW10 Input enable */
2278 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
2279 { }
2280};
2281
2282static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
2283 /*
2284 * Unmute ADC0-1 and set the default input to mic-in
2285 */
2286 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2287 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2288
2289
2290 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2291 * mixer widget
2292 */
2293 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2294 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2295 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2296 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2297 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2298 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2299
2300 /*
2301 * Set up output mixers
2302 */
2303 /* set vol=0 to output mixers */
2304 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2305 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2306 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2307
2308 /* Setup default input of PW4 to MW0 */
2309 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
2310 /* PW9 Output enable */
2311 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2312 /* PW10 Input enable */
2313 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
2314 { }
2315};
2316
Harald Welte69e52a82008-09-09 15:57:32 +08002317static struct hda_verb vt1708B_uniwill_init_verbs[] = {
2318 {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
2319 { }
2320};
2321
Lydia Wang17314372009-10-10 19:07:37 +08002322static int via_pcm_open_close(struct hda_pcm_stream *hinfo,
2323 struct hda_codec *codec,
2324 struct snd_pcm_substream *substream)
2325{
2326 int idle = substream->pstr->substream_opened == 1
2327 && substream->ref_count == 0;
2328
2329 analog_low_current_mode(codec, idle);
2330 return 0;
2331}
2332
Josepch Chanf7278fd2007-12-13 16:40:40 +01002333static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08002334 .substreams = 2,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002335 .channels_min = 2,
2336 .channels_max = 8,
2337 .nid = 0x10, /* NID to query formats and rates */
2338 .ops = {
2339 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08002340 .prepare = via_playback_multi_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08002341 .cleanup = via_playback_multi_pcm_cleanup,
2342 .close = via_pcm_open_close
Josepch Chanf7278fd2007-12-13 16:40:40 +01002343 },
2344};
2345
2346static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08002347 .substreams = 2,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002348 .channels_min = 2,
2349 .channels_max = 4,
2350 .nid = 0x10, /* NID to query formats and rates */
2351 .ops = {
2352 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08002353 .prepare = via_playback_multi_pcm_prepare,
2354 .cleanup = via_playback_multi_pcm_cleanup
Josepch Chanf7278fd2007-12-13 16:40:40 +01002355 },
2356};
2357
2358static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
2359 .substreams = 2,
2360 .channels_min = 2,
2361 .channels_max = 2,
2362 .nid = 0x13, /* NID to query formats and rates */
2363 .ops = {
Lydia Wang17314372009-10-10 19:07:37 +08002364 .open = via_pcm_open_close,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002365 .prepare = via_capture_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08002366 .cleanup = via_capture_pcm_cleanup,
2367 .close = via_pcm_open_close
Josepch Chanf7278fd2007-12-13 16:40:40 +01002368 },
2369};
2370
2371static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
2372 .substreams = 1,
2373 .channels_min = 2,
2374 .channels_max = 2,
2375 /* NID is set in via_build_pcms */
2376 .ops = {
2377 .open = via_dig_playback_pcm_open,
2378 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02002379 .prepare = via_dig_playback_pcm_prepare,
2380 .cleanup = via_dig_playback_pcm_cleanup
Josepch Chanf7278fd2007-12-13 16:40:40 +01002381 },
2382};
2383
2384static struct hda_pcm_stream vt1708B_pcm_digital_capture = {
2385 .substreams = 1,
2386 .channels_min = 2,
2387 .channels_max = 2,
2388};
2389
2390/* fill in the dac_nids table from the parsed pin configuration */
2391static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
2392 const struct auto_pin_cfg *cfg)
2393{
2394 int i;
2395 hda_nid_t nid;
2396
2397 spec->multiout.num_dacs = cfg->line_outs;
2398
2399 spec->multiout.dac_nids = spec->private_dac_nids;
2400
2401 for (i = 0; i < 4; i++) {
2402 nid = cfg->line_out_pins[i];
2403 if (nid) {
2404 /* config dac list */
2405 switch (i) {
2406 case AUTO_SEQ_FRONT:
2407 spec->multiout.dac_nids[i] = 0x10;
2408 break;
2409 case AUTO_SEQ_CENLFE:
2410 spec->multiout.dac_nids[i] = 0x24;
2411 break;
2412 case AUTO_SEQ_SURROUND:
Harald Weltefb4cb772008-09-09 15:53:36 +08002413 spec->multiout.dac_nids[i] = 0x11;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002414 break;
2415 case AUTO_SEQ_SIDE:
Harald Weltefb4cb772008-09-09 15:53:36 +08002416 spec->multiout.dac_nids[i] = 0x25;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002417 break;
2418 }
2419 }
2420 }
2421
2422 return 0;
2423}
2424
2425/* add playback controls from the parsed DAC table */
2426static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
2427 const struct auto_pin_cfg *cfg)
2428{
2429 char name[32];
2430 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
Harald Weltefb4cb772008-09-09 15:53:36 +08002431 hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27};
Josepch Chanf7278fd2007-12-13 16:40:40 +01002432 hda_nid_t nid, nid_vol = 0;
2433 int i, err;
2434
2435 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2436 nid = cfg->line_out_pins[i];
2437
2438 if (!nid)
2439 continue;
2440
2441 nid_vol = nid_vols[i];
2442
2443 if (i == AUTO_SEQ_CENLFE) {
2444 /* Center/LFE */
2445 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2446 "Center Playback Volume",
2447 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2448 HDA_OUTPUT));
2449 if (err < 0)
2450 return err;
2451 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2452 "LFE Playback Volume",
2453 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2454 HDA_OUTPUT));
2455 if (err < 0)
2456 return err;
2457 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2458 "Center Playback Switch",
2459 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2460 HDA_OUTPUT));
2461 if (err < 0)
2462 return err;
2463 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2464 "LFE Playback Switch",
2465 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2466 HDA_OUTPUT));
2467 if (err < 0)
2468 return err;
2469 } else if (i == AUTO_SEQ_FRONT) {
2470 /* add control to mixer index 0 */
2471 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2472 "Master Front Playback Volume",
2473 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2474 HDA_INPUT));
2475 if (err < 0)
2476 return err;
2477 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2478 "Master Front Playback Switch",
2479 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2480 HDA_INPUT));
2481 if (err < 0)
2482 return err;
2483
2484 /* add control to PW3 */
2485 sprintf(name, "%s Playback Volume", chname[i]);
2486 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2487 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2488 HDA_OUTPUT));
2489 if (err < 0)
2490 return err;
2491 sprintf(name, "%s Playback Switch", chname[i]);
2492 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2493 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2494 HDA_OUTPUT));
2495 if (err < 0)
2496 return err;
2497 } else {
2498 sprintf(name, "%s Playback Volume", chname[i]);
2499 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2500 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2501 HDA_OUTPUT));
2502 if (err < 0)
2503 return err;
2504 sprintf(name, "%s Playback Switch", chname[i]);
2505 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2506 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2507 HDA_OUTPUT));
2508 if (err < 0)
2509 return err;
2510 }
2511 }
2512
2513 return 0;
2514}
2515
2516static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2517{
2518 int err;
2519
2520 if (!pin)
2521 return 0;
2522
2523 spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
2524
2525 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2526 "Headphone Playback Volume",
2527 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2528 if (err < 0)
2529 return err;
2530 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2531 "Headphone Playback Switch",
2532 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2533 if (err < 0)
2534 return err;
2535
Harald Welte0aa62ae2008-09-09 15:58:27 +08002536 create_hp_imux(spec);
2537
Josepch Chanf7278fd2007-12-13 16:40:40 +01002538 return 0;
2539}
2540
2541/* create playback/capture controls for input pins */
2542static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
2543 const struct auto_pin_cfg *cfg)
2544{
2545 static char *labels[] = {
2546 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2547 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08002548 struct hda_input_mux *imux = &spec->private_imux[0];
Josepch Chanf7278fd2007-12-13 16:40:40 +01002549 int i, err, idx = 0;
2550
2551 /* for internal loopback recording select */
2552 imux->items[imux->num_items].label = "Stereo Mixer";
2553 imux->items[imux->num_items].index = idx;
2554 imux->num_items++;
2555
2556 for (i = 0; i < AUTO_PIN_LAST; i++) {
2557 if (!cfg->input_pins[i])
2558 continue;
2559
2560 switch (cfg->input_pins[i]) {
2561 case 0x1a: /* Mic */
2562 idx = 2;
2563 break;
2564
2565 case 0x1b: /* Line In */
2566 idx = 3;
2567 break;
2568
2569 case 0x1e: /* Front Mic */
2570 idx = 4;
2571 break;
2572
2573 case 0x1f: /* CD */
2574 idx = 1;
2575 break;
2576 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08002577 err = via_new_analog_input(spec, labels[i], idx, 0x16);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002578 if (err < 0)
2579 return err;
2580 imux->items[imux->num_items].label = labels[i];
2581 imux->items[imux->num_items].index = idx;
2582 imux->num_items++;
2583 }
2584 return 0;
2585}
2586
2587static int vt1708B_parse_auto_config(struct hda_codec *codec)
2588{
2589 struct via_spec *spec = codec->spec;
2590 int err;
2591
2592 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
2593 if (err < 0)
2594 return err;
2595 err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg);
2596 if (err < 0)
2597 return err;
2598 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2599 return 0; /* can't find valid BIOS pin config */
2600
2601 err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg);
2602 if (err < 0)
2603 return err;
2604 err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2605 if (err < 0)
2606 return err;
2607 err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
2608 if (err < 0)
2609 return err;
2610
2611 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2612
Takashi Iwai0852d7a2009-02-11 11:35:15 +01002613 if (spec->autocfg.dig_outs)
Josepch Chanf7278fd2007-12-13 16:40:40 +01002614 spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02002615 spec->dig_in_pin = VT1708B_DIGIN_PIN;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002616 if (spec->autocfg.dig_in_pin)
2617 spec->dig_in_nid = VT1708B_DIGIN_NID;
2618
Takashi Iwai603c4012008-07-30 15:01:44 +02002619 if (spec->kctls.list)
2620 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002621
Harald Welte0aa62ae2008-09-09 15:58:27 +08002622 spec->input_mux = &spec->private_imux[0];
2623
Harald Weltef8fdd492008-09-15 22:41:31 +08002624 if (spec->hp_mux)
2625 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002626
2627 return 1;
2628}
2629
2630#ifdef CONFIG_SND_HDA_POWER_SAVE
2631static struct hda_amp_list vt1708B_loopbacks[] = {
2632 { 0x16, HDA_INPUT, 1 },
2633 { 0x16, HDA_INPUT, 2 },
2634 { 0x16, HDA_INPUT, 3 },
2635 { 0x16, HDA_INPUT, 4 },
2636 { } /* end */
2637};
2638#endif
Lydia Wang518bf3b2009-10-10 19:07:29 +08002639static int patch_vt1708S(struct hda_codec *codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002640static int patch_vt1708B_8ch(struct hda_codec *codec)
2641{
2642 struct via_spec *spec;
2643 int err;
2644
Lydia Wang518bf3b2009-10-10 19:07:29 +08002645 if (get_codec_type(codec) == VT1708BCE)
2646 return patch_vt1708S(codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002647 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08002648 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002649 if (spec == NULL)
2650 return -ENOMEM;
2651
2652 codec->spec = spec;
2653
2654 /* automatic parse from the BIOS config */
2655 err = vt1708B_parse_auto_config(codec);
2656 if (err < 0) {
2657 via_free(codec);
2658 return err;
2659 } else if (!err) {
2660 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2661 "from BIOS. Using genenic mode...\n");
2662 }
2663
Harald Welte69e52a82008-09-09 15:57:32 +08002664 spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs;
2665 spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002666
2667 spec->stream_name_analog = "VT1708B Analog";
2668 spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
2669 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
2670
2671 spec->stream_name_digital = "VT1708B Digital";
2672 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
2673 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
2674
2675 if (!spec->adc_nids && spec->input_mux) {
2676 spec->adc_nids = vt1708B_adc_nids;
2677 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02002678 get_mux_nids(codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002679 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
2680 spec->num_mixers++;
2681 }
2682
2683 codec->patch_ops = via_patch_ops;
2684
2685 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08002686 codec->patch_ops.unsol_event = via_unsol_event;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002687#ifdef CONFIG_SND_HDA_POWER_SAVE
2688 spec->loopback.amplist = vt1708B_loopbacks;
2689#endif
2690
2691 return 0;
2692}
2693
2694static int patch_vt1708B_4ch(struct hda_codec *codec)
2695{
2696 struct via_spec *spec;
2697 int err;
2698
2699 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08002700 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002701 if (spec == NULL)
2702 return -ENOMEM;
2703
2704 codec->spec = spec;
2705
2706 /* automatic parse from the BIOS config */
2707 err = vt1708B_parse_auto_config(codec);
2708 if (err < 0) {
2709 via_free(codec);
2710 return err;
2711 } else if (!err) {
2712 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2713 "from BIOS. Using genenic mode...\n");
2714 }
2715
Harald Welte69e52a82008-09-09 15:57:32 +08002716 spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs;
2717 spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002718
2719 spec->stream_name_analog = "VT1708B Analog";
2720 spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
2721 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
2722
2723 spec->stream_name_digital = "VT1708B Digital";
2724 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
2725 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
2726
2727 if (!spec->adc_nids && spec->input_mux) {
2728 spec->adc_nids = vt1708B_adc_nids;
2729 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02002730 get_mux_nids(codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002731 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
2732 spec->num_mixers++;
2733 }
2734
2735 codec->patch_ops = via_patch_ops;
2736
2737 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08002738 codec->patch_ops.unsol_event = via_unsol_event;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002739#ifdef CONFIG_SND_HDA_POWER_SAVE
2740 spec->loopback.amplist = vt1708B_loopbacks;
2741#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01002742
2743 return 0;
2744}
2745
Harald Welted949cac2008-09-09 15:56:01 +08002746/* Patch for VT1708S */
2747
Harald Welted7426322008-09-15 22:43:23 +08002748/* VT1708S software backdoor based override for buggy hardware micboost
2749 * setting */
2750#define MIC_BOOST_VOLUME(xname, nid) { \
2751 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2752 .name = xname, \
2753 .index = 0, \
2754 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
2755 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
2756 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
2757 .info = mic_boost_volume_info, \
2758 .get = snd_hda_mixer_amp_volume_get, \
2759 .put = snd_hda_mixer_amp_volume_put, \
2760 .tlv = { .c = mic_boost_tlv }, \
2761 .private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT) }
2762
Harald Welted949cac2008-09-09 15:56:01 +08002763/* capture mixer elements */
2764static struct snd_kcontrol_new vt1708S_capture_mixer[] = {
2765 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
2766 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
2767 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
2768 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
Harald Welted7426322008-09-15 22:43:23 +08002769 MIC_BOOST_VOLUME("Mic Boost Capture Volume", 0x1A),
2770 MIC_BOOST_VOLUME("Front Mic Boost Capture Volume", 0x1E),
Harald Welted949cac2008-09-09 15:56:01 +08002771 {
2772 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2773 /* The multiple "Capture Source" controls confuse alsamixer
2774 * So call somewhat different..
2775 */
2776 /* .name = "Capture Source", */
2777 .name = "Input Source",
2778 .count = 1,
2779 .info = via_mux_enum_info,
2780 .get = via_mux_enum_get,
2781 .put = via_mux_enum_put,
2782 },
2783 { } /* end */
2784};
2785
2786static struct hda_verb vt1708S_volume_init_verbs[] = {
2787 /* Unmute ADC0-1 and set the default input to mic-in */
2788 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2789 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2790
2791 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the
2792 * analog-loopback mixer widget */
2793 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2794 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2795 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2796 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2797 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2798 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2799
2800 /* Setup default input of PW4 to MW0 */
2801 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
Harald Welte5691ec72008-09-15 22:42:26 +08002802 /* PW9, PW10 Output enable */
Harald Welted949cac2008-09-09 15:56:01 +08002803 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Harald Welte5691ec72008-09-15 22:42:26 +08002804 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Harald Welted7426322008-09-15 22:43:23 +08002805 /* Enable Mic Boost Volume backdoor */
2806 {0x1, 0xf98, 0x1},
Harald Welted949cac2008-09-09 15:56:01 +08002807 { }
2808};
2809
Harald Welte69e52a82008-09-09 15:57:32 +08002810static struct hda_verb vt1708S_uniwill_init_verbs[] = {
2811 {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
2812 { }
2813};
2814
Harald Welted949cac2008-09-09 15:56:01 +08002815static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
2816 .substreams = 2,
2817 .channels_min = 2,
2818 .channels_max = 8,
2819 .nid = 0x10, /* NID to query formats and rates */
2820 .ops = {
2821 .open = via_playback_pcm_open,
2822 .prepare = via_playback_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08002823 .cleanup = via_playback_pcm_cleanup,
2824 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08002825 },
2826};
2827
2828static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
2829 .substreams = 2,
2830 .channels_min = 2,
2831 .channels_max = 2,
2832 .nid = 0x13, /* NID to query formats and rates */
2833 .ops = {
Lydia Wang17314372009-10-10 19:07:37 +08002834 .open = via_pcm_open_close,
Harald Welted949cac2008-09-09 15:56:01 +08002835 .prepare = via_capture_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08002836 .cleanup = via_capture_pcm_cleanup,
2837 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08002838 },
2839};
2840
2841static struct hda_pcm_stream vt1708S_pcm_digital_playback = {
Takashi Iwai9da29272009-05-07 16:31:14 +02002842 .substreams = 1,
Harald Welted949cac2008-09-09 15:56:01 +08002843 .channels_min = 2,
2844 .channels_max = 2,
2845 /* NID is set in via_build_pcms */
2846 .ops = {
2847 .open = via_dig_playback_pcm_open,
2848 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02002849 .prepare = via_dig_playback_pcm_prepare,
2850 .cleanup = via_dig_playback_pcm_cleanup
Harald Welted949cac2008-09-09 15:56:01 +08002851 },
2852};
2853
2854/* fill in the dac_nids table from the parsed pin configuration */
2855static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
2856 const struct auto_pin_cfg *cfg)
2857{
2858 int i;
2859 hda_nid_t nid;
2860
2861 spec->multiout.num_dacs = cfg->line_outs;
2862
2863 spec->multiout.dac_nids = spec->private_dac_nids;
2864
2865 for (i = 0; i < 4; i++) {
2866 nid = cfg->line_out_pins[i];
2867 if (nid) {
2868 /* config dac list */
2869 switch (i) {
2870 case AUTO_SEQ_FRONT:
2871 spec->multiout.dac_nids[i] = 0x10;
2872 break;
2873 case AUTO_SEQ_CENLFE:
2874 spec->multiout.dac_nids[i] = 0x24;
2875 break;
2876 case AUTO_SEQ_SURROUND:
2877 spec->multiout.dac_nids[i] = 0x11;
2878 break;
2879 case AUTO_SEQ_SIDE:
2880 spec->multiout.dac_nids[i] = 0x25;
2881 break;
2882 }
2883 }
2884 }
2885
2886 return 0;
2887}
2888
2889/* add playback controls from the parsed DAC table */
2890static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
2891 const struct auto_pin_cfg *cfg)
2892{
2893 char name[32];
2894 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
2895 hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25};
2896 hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27};
2897 hda_nid_t nid, nid_vol, nid_mute;
2898 int i, err;
2899
2900 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2901 nid = cfg->line_out_pins[i];
2902
2903 if (!nid)
2904 continue;
2905
2906 nid_vol = nid_vols[i];
2907 nid_mute = nid_mutes[i];
2908
2909 if (i == AUTO_SEQ_CENLFE) {
2910 /* Center/LFE */
2911 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2912 "Center Playback Volume",
2913 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2914 HDA_OUTPUT));
2915 if (err < 0)
2916 return err;
2917 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2918 "LFE Playback Volume",
2919 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2920 HDA_OUTPUT));
2921 if (err < 0)
2922 return err;
2923 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2924 "Center Playback Switch",
2925 HDA_COMPOSE_AMP_VAL(nid_mute,
2926 1, 0,
2927 HDA_OUTPUT));
2928 if (err < 0)
2929 return err;
2930 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2931 "LFE Playback Switch",
2932 HDA_COMPOSE_AMP_VAL(nid_mute,
2933 2, 0,
2934 HDA_OUTPUT));
2935 if (err < 0)
2936 return err;
2937 } else if (i == AUTO_SEQ_FRONT) {
2938 /* add control to mixer index 0 */
2939 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2940 "Master Front Playback Volume",
2941 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
2942 HDA_INPUT));
2943 if (err < 0)
2944 return err;
2945 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2946 "Master Front Playback Switch",
2947 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
2948 HDA_INPUT));
2949 if (err < 0)
2950 return err;
2951
2952 /* Front */
2953 sprintf(name, "%s Playback Volume", chname[i]);
2954 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2955 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2956 HDA_OUTPUT));
2957 if (err < 0)
2958 return err;
2959 sprintf(name, "%s Playback Switch", chname[i]);
2960 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2961 HDA_COMPOSE_AMP_VAL(nid_mute,
2962 3, 0,
2963 HDA_OUTPUT));
2964 if (err < 0)
2965 return err;
2966 } else {
2967 sprintf(name, "%s Playback Volume", chname[i]);
2968 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2969 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2970 HDA_OUTPUT));
2971 if (err < 0)
2972 return err;
2973 sprintf(name, "%s Playback Switch", chname[i]);
2974 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2975 HDA_COMPOSE_AMP_VAL(nid_mute,
2976 3, 0,
2977 HDA_OUTPUT));
2978 if (err < 0)
2979 return err;
2980 }
2981 }
2982
2983 return 0;
2984}
2985
2986static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2987{
2988 int err;
2989
2990 if (!pin)
2991 return 0;
2992
2993 spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */
2994
2995 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2996 "Headphone Playback Volume",
2997 HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
2998 if (err < 0)
2999 return err;
3000
3001 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3002 "Headphone Playback Switch",
3003 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3004 if (err < 0)
3005 return err;
3006
Harald Welte0aa62ae2008-09-09 15:58:27 +08003007 create_hp_imux(spec);
3008
Harald Welted949cac2008-09-09 15:56:01 +08003009 return 0;
3010}
3011
3012/* create playback/capture controls for input pins */
3013static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
3014 const struct auto_pin_cfg *cfg)
3015{
3016 static char *labels[] = {
3017 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
3018 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08003019 struct hda_input_mux *imux = &spec->private_imux[0];
Harald Welted949cac2008-09-09 15:56:01 +08003020 int i, err, idx = 0;
3021
3022 /* for internal loopback recording select */
3023 imux->items[imux->num_items].label = "Stereo Mixer";
3024 imux->items[imux->num_items].index = 5;
3025 imux->num_items++;
3026
3027 for (i = 0; i < AUTO_PIN_LAST; i++) {
3028 if (!cfg->input_pins[i])
3029 continue;
3030
3031 switch (cfg->input_pins[i]) {
3032 case 0x1a: /* Mic */
3033 idx = 2;
3034 break;
3035
3036 case 0x1b: /* Line In */
3037 idx = 3;
3038 break;
3039
3040 case 0x1e: /* Front Mic */
3041 idx = 4;
3042 break;
3043
3044 case 0x1f: /* CD */
3045 idx = 1;
3046 break;
3047 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08003048 err = via_new_analog_input(spec, labels[i], idx, 0x16);
Harald Welted949cac2008-09-09 15:56:01 +08003049 if (err < 0)
3050 return err;
3051 imux->items[imux->num_items].label = labels[i];
3052 imux->items[imux->num_items].index = idx-1;
3053 imux->num_items++;
3054 }
3055 return 0;
3056}
3057
Takashi Iwai9da29272009-05-07 16:31:14 +02003058/* fill out digital output widgets; one for master and one for slave outputs */
3059static void fill_dig_outs(struct hda_codec *codec)
3060{
3061 struct via_spec *spec = codec->spec;
3062 int i;
3063
3064 for (i = 0; i < spec->autocfg.dig_outs; i++) {
3065 hda_nid_t nid;
3066 int conn;
3067
3068 nid = spec->autocfg.dig_out_pins[i];
3069 if (!nid)
3070 continue;
3071 conn = snd_hda_get_connections(codec, nid, &nid, 1);
3072 if (conn < 1)
3073 continue;
3074 if (!spec->multiout.dig_out_nid)
3075 spec->multiout.dig_out_nid = nid;
3076 else {
3077 spec->slave_dig_outs[0] = nid;
3078 break; /* at most two dig outs */
3079 }
3080 }
3081}
3082
Harald Welted949cac2008-09-09 15:56:01 +08003083static int vt1708S_parse_auto_config(struct hda_codec *codec)
3084{
3085 struct via_spec *spec = codec->spec;
3086 int err;
Harald Welted949cac2008-09-09 15:56:01 +08003087
Takashi Iwai9da29272009-05-07 16:31:14 +02003088 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
Harald Welted949cac2008-09-09 15:56:01 +08003089 if (err < 0)
3090 return err;
3091 err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg);
3092 if (err < 0)
3093 return err;
3094 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
3095 return 0; /* can't find valid BIOS pin config */
3096
3097 err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg);
3098 if (err < 0)
3099 return err;
3100 err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
3101 if (err < 0)
3102 return err;
3103 err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
3104 if (err < 0)
3105 return err;
3106
3107 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3108
Takashi Iwai9da29272009-05-07 16:31:14 +02003109 fill_dig_outs(codec);
Harald Welte98aa34c2008-09-09 16:02:09 +08003110
Takashi Iwai603c4012008-07-30 15:01:44 +02003111 if (spec->kctls.list)
3112 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Harald Welted949cac2008-09-09 15:56:01 +08003113
Harald Welte0aa62ae2008-09-09 15:58:27 +08003114 spec->input_mux = &spec->private_imux[0];
3115
Harald Weltef8fdd492008-09-15 22:41:31 +08003116 if (spec->hp_mux)
3117 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08003118
3119 return 1;
3120}
3121
3122#ifdef CONFIG_SND_HDA_POWER_SAVE
3123static struct hda_amp_list vt1708S_loopbacks[] = {
3124 { 0x16, HDA_INPUT, 1 },
3125 { 0x16, HDA_INPUT, 2 },
3126 { 0x16, HDA_INPUT, 3 },
3127 { 0x16, HDA_INPUT, 4 },
3128 { } /* end */
3129};
3130#endif
3131
3132static int patch_vt1708S(struct hda_codec *codec)
3133{
3134 struct via_spec *spec;
3135 int err;
3136
3137 /* create a codec specific record */
3138 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3139 if (spec == NULL)
3140 return -ENOMEM;
3141
3142 codec->spec = spec;
3143
3144 /* automatic parse from the BIOS config */
3145 err = vt1708S_parse_auto_config(codec);
3146 if (err < 0) {
3147 via_free(codec);
3148 return err;
3149 } else if (!err) {
3150 printk(KERN_INFO "hda_codec: Cannot set up configuration "
3151 "from BIOS. Using genenic mode...\n");
3152 }
3153
Harald Welte69e52a82008-09-09 15:57:32 +08003154 spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
3155 spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs;
Harald Welted949cac2008-09-09 15:56:01 +08003156
3157 spec->stream_name_analog = "VT1708S Analog";
3158 spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
3159 spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
3160
3161 spec->stream_name_digital = "VT1708S Digital";
3162 spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
3163
3164 if (!spec->adc_nids && spec->input_mux) {
3165 spec->adc_nids = vt1708S_adc_nids;
3166 spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02003167 get_mux_nids(codec);
Harald Welted949cac2008-09-09 15:56:01 +08003168 spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
3169 spec->num_mixers++;
3170 }
3171
3172 codec->patch_ops = via_patch_ops;
3173
3174 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003175 codec->patch_ops.unsol_event = via_unsol_event;
Harald Welted949cac2008-09-09 15:56:01 +08003176#ifdef CONFIG_SND_HDA_POWER_SAVE
3177 spec->loopback.amplist = vt1708S_loopbacks;
3178#endif
3179
Lydia Wang518bf3b2009-10-10 19:07:29 +08003180 /* correct names for VT1708BCE */
3181 if (get_codec_type(codec) == VT1708BCE) {
3182 kfree(codec->chip_name);
3183 codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
3184 snprintf(codec->bus->card->mixername,
3185 sizeof(codec->bus->card->mixername),
3186 "%s %s", codec->vendor_name, codec->chip_name);
3187 spec->stream_name_analog = "VT1708BCE Analog";
3188 spec->stream_name_digital = "VT1708BCE Digital";
3189 }
Harald Welted949cac2008-09-09 15:56:01 +08003190 return 0;
3191}
3192
3193/* Patch for VT1702 */
3194
3195/* capture mixer elements */
3196static struct snd_kcontrol_new vt1702_capture_mixer[] = {
3197 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
3198 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
3199 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
3200 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT),
3201 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT),
3202 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT),
3203 HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0,
3204 HDA_INPUT),
3205 {
3206 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3207 /* The multiple "Capture Source" controls confuse alsamixer
3208 * So call somewhat different..
3209 */
3210 /* .name = "Capture Source", */
3211 .name = "Input Source",
3212 .count = 1,
3213 .info = via_mux_enum_info,
3214 .get = via_mux_enum_get,
3215 .put = via_mux_enum_put,
3216 },
3217 { } /* end */
3218};
3219
3220static struct hda_verb vt1702_volume_init_verbs[] = {
3221 /*
3222 * Unmute ADC0-1 and set the default input to mic-in
3223 */
3224 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3225 {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3226 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3227
3228
3229 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3230 * mixer widget
3231 */
3232 /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */
3233 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3234 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3235 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3236 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3237 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3238
3239 /* Setup default input of PW4 to MW0 */
3240 {0x17, AC_VERB_SET_CONNECT_SEL, 0x1},
3241 /* PW6 PW7 Output enable */
3242 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
3243 {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
3244 { }
3245};
3246
Harald Welte69e52a82008-09-09 15:57:32 +08003247static struct hda_verb vt1702_uniwill_init_verbs[] = {
3248 {0x01, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_GPIO_EVENT},
3249 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
3250 { }
3251};
3252
Harald Welted949cac2008-09-09 15:56:01 +08003253static struct hda_pcm_stream vt1702_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08003254 .substreams = 2,
Harald Welted949cac2008-09-09 15:56:01 +08003255 .channels_min = 2,
3256 .channels_max = 2,
3257 .nid = 0x10, /* NID to query formats and rates */
3258 .ops = {
3259 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08003260 .prepare = via_playback_multi_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08003261 .cleanup = via_playback_multi_pcm_cleanup,
3262 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08003263 },
3264};
3265
3266static struct hda_pcm_stream vt1702_pcm_analog_capture = {
3267 .substreams = 3,
3268 .channels_min = 2,
3269 .channels_max = 2,
3270 .nid = 0x12, /* NID to query formats and rates */
3271 .ops = {
Lydia Wang17314372009-10-10 19:07:37 +08003272 .open = via_pcm_open_close,
Harald Welted949cac2008-09-09 15:56:01 +08003273 .prepare = via_capture_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08003274 .cleanup = via_capture_pcm_cleanup,
3275 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08003276 },
3277};
3278
3279static struct hda_pcm_stream vt1702_pcm_digital_playback = {
Harald Welte5691ec72008-09-15 22:42:26 +08003280 .substreams = 2,
Harald Welted949cac2008-09-09 15:56:01 +08003281 .channels_min = 2,
3282 .channels_max = 2,
3283 /* NID is set in via_build_pcms */
3284 .ops = {
3285 .open = via_dig_playback_pcm_open,
3286 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02003287 .prepare = via_dig_playback_pcm_prepare,
3288 .cleanup = via_dig_playback_pcm_cleanup
Harald Welted949cac2008-09-09 15:56:01 +08003289 },
3290};
3291
3292/* fill in the dac_nids table from the parsed pin configuration */
3293static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
3294 const struct auto_pin_cfg *cfg)
3295{
3296 spec->multiout.num_dacs = 1;
3297 spec->multiout.dac_nids = spec->private_dac_nids;
3298
3299 if (cfg->line_out_pins[0]) {
3300 /* config dac list */
3301 spec->multiout.dac_nids[0] = 0x10;
3302 }
3303
3304 return 0;
3305}
3306
3307/* add playback controls from the parsed DAC table */
3308static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
3309 const struct auto_pin_cfg *cfg)
3310{
3311 int err;
3312
3313 if (!cfg->line_out_pins[0])
3314 return -1;
3315
3316 /* add control to mixer index 0 */
3317 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3318 "Master Front Playback Volume",
3319 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
3320 if (err < 0)
3321 return err;
3322 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3323 "Master Front Playback Switch",
3324 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
3325 if (err < 0)
3326 return err;
3327
3328 /* Front */
3329 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3330 "Front Playback Volume",
3331 HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT));
3332 if (err < 0)
3333 return err;
3334 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3335 "Front Playback Switch",
3336 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT));
3337 if (err < 0)
3338 return err;
3339
3340 return 0;
3341}
3342
3343static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
3344{
3345 int err;
3346
3347 if (!pin)
3348 return 0;
3349
3350 spec->multiout.hp_nid = 0x1D;
3351
3352 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3353 "Headphone Playback Volume",
3354 HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT));
3355 if (err < 0)
3356 return err;
3357
3358 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3359 "Headphone Playback Switch",
3360 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3361 if (err < 0)
3362 return err;
3363
Harald Welte0aa62ae2008-09-09 15:58:27 +08003364 create_hp_imux(spec);
3365
Harald Welted949cac2008-09-09 15:56:01 +08003366 return 0;
3367}
3368
3369/* create playback/capture controls for input pins */
3370static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
3371 const struct auto_pin_cfg *cfg)
3372{
3373 static char *labels[] = {
3374 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
3375 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08003376 struct hda_input_mux *imux = &spec->private_imux[0];
Harald Welted949cac2008-09-09 15:56:01 +08003377 int i, err, idx = 0;
3378
3379 /* for internal loopback recording select */
3380 imux->items[imux->num_items].label = "Stereo Mixer";
3381 imux->items[imux->num_items].index = 3;
3382 imux->num_items++;
3383
3384 for (i = 0; i < AUTO_PIN_LAST; i++) {
3385 if (!cfg->input_pins[i])
3386 continue;
3387
3388 switch (cfg->input_pins[i]) {
3389 case 0x14: /* Mic */
3390 idx = 1;
3391 break;
3392
3393 case 0x15: /* Line In */
3394 idx = 2;
3395 break;
3396
3397 case 0x18: /* Front Mic */
3398 idx = 3;
3399 break;
3400 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08003401 err = via_new_analog_input(spec, labels[i], idx, 0x1A);
Harald Welted949cac2008-09-09 15:56:01 +08003402 if (err < 0)
3403 return err;
3404 imux->items[imux->num_items].label = labels[i];
3405 imux->items[imux->num_items].index = idx-1;
3406 imux->num_items++;
3407 }
3408 return 0;
3409}
3410
3411static int vt1702_parse_auto_config(struct hda_codec *codec)
3412{
3413 struct via_spec *spec = codec->spec;
3414 int err;
Harald Welted949cac2008-09-09 15:56:01 +08003415
Takashi Iwai9da29272009-05-07 16:31:14 +02003416 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
Harald Welted949cac2008-09-09 15:56:01 +08003417 if (err < 0)
3418 return err;
3419 err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg);
3420 if (err < 0)
3421 return err;
3422 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
3423 return 0; /* can't find valid BIOS pin config */
3424
3425 err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg);
3426 if (err < 0)
3427 return err;
3428 err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
3429 if (err < 0)
3430 return err;
Lydia Wangc2c02ea2009-10-10 19:07:32 +08003431 /* limit AA path volume to 0 dB */
3432 snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT,
3433 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
3434 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3435 (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3436 (1 << AC_AMPCAP_MUTE_SHIFT));
Harald Welted949cac2008-09-09 15:56:01 +08003437 err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
3438 if (err < 0)
3439 return err;
3440
3441 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3442
Takashi Iwai9da29272009-05-07 16:31:14 +02003443 fill_dig_outs(codec);
Harald Welte98aa34c2008-09-09 16:02:09 +08003444
Takashi Iwai603c4012008-07-30 15:01:44 +02003445 if (spec->kctls.list)
3446 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Harald Welted949cac2008-09-09 15:56:01 +08003447
Harald Welte0aa62ae2008-09-09 15:58:27 +08003448 spec->input_mux = &spec->private_imux[0];
3449
Harald Weltef8fdd492008-09-15 22:41:31 +08003450 if (spec->hp_mux)
3451 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08003452
3453 return 1;
3454}
3455
3456#ifdef CONFIG_SND_HDA_POWER_SAVE
3457static struct hda_amp_list vt1702_loopbacks[] = {
3458 { 0x1A, HDA_INPUT, 1 },
3459 { 0x1A, HDA_INPUT, 2 },
3460 { 0x1A, HDA_INPUT, 3 },
3461 { 0x1A, HDA_INPUT, 4 },
3462 { } /* end */
3463};
3464#endif
3465
3466static int patch_vt1702(struct hda_codec *codec)
3467{
3468 struct via_spec *spec;
3469 int err;
3470 unsigned int response;
3471 unsigned char control;
3472
3473 /* create a codec specific record */
3474 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3475 if (spec == NULL)
3476 return -ENOMEM;
3477
3478 codec->spec = spec;
3479
3480 /* automatic parse from the BIOS config */
3481 err = vt1702_parse_auto_config(codec);
3482 if (err < 0) {
3483 via_free(codec);
3484 return err;
3485 } else if (!err) {
3486 printk(KERN_INFO "hda_codec: Cannot set up configuration "
3487 "from BIOS. Using genenic mode...\n");
3488 }
3489
Harald Welte69e52a82008-09-09 15:57:32 +08003490 spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs;
3491 spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs;
Harald Welted949cac2008-09-09 15:56:01 +08003492
3493 spec->stream_name_analog = "VT1702 Analog";
3494 spec->stream_analog_playback = &vt1702_pcm_analog_playback;
3495 spec->stream_analog_capture = &vt1702_pcm_analog_capture;
3496
3497 spec->stream_name_digital = "VT1702 Digital";
3498 spec->stream_digital_playback = &vt1702_pcm_digital_playback;
3499
3500 if (!spec->adc_nids && spec->input_mux) {
3501 spec->adc_nids = vt1702_adc_nids;
3502 spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02003503 get_mux_nids(codec);
Harald Welted949cac2008-09-09 15:56:01 +08003504 spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
3505 spec->num_mixers++;
3506 }
3507
3508 codec->patch_ops = via_patch_ops;
3509
3510 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003511 codec->patch_ops.unsol_event = via_unsol_event;
Harald Welted949cac2008-09-09 15:56:01 +08003512#ifdef CONFIG_SND_HDA_POWER_SAVE
3513 spec->loopback.amplist = vt1702_loopbacks;
3514#endif
3515
3516 /* Open backdoor */
3517 response = snd_hda_codec_read(codec, codec->afg, 0, 0xF8C, 0);
3518 control = (unsigned char)(response & 0xff);
3519 control |= 0x3;
3520 snd_hda_codec_write(codec, codec->afg, 0, 0xF88, control);
3521
3522 /* Enable GPIO 0&1 for volume&mute control */
3523 /* Enable GPIO 2 for DMIC-DATA */
3524 response = snd_hda_codec_read(codec, codec->afg, 0, 0xF84, 0);
3525 control = (unsigned char)((response >> 16) & 0x3f);
3526 snd_hda_codec_write(codec, codec->afg, 0, 0xF82, control);
3527
3528 return 0;
3529}
3530
Joseph Chanc577b8a2006-11-29 15:29:40 +01003531/*
3532 * patch entries
3533 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +01003534static struct hda_codec_preset snd_hda_preset_via[] = {
Takashi Iwai3218c172008-12-18 09:17:56 +01003535 { .id = 0x11061708, .name = "VT1708", .patch = patch_vt1708},
3536 { .id = 0x11061709, .name = "VT1708", .patch = patch_vt1708},
3537 { .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708},
3538 { .id = 0x1106170b, .name = "VT1708", .patch = patch_vt1708},
3539 { .id = 0x1106e710, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003540 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003541 { .id = 0x1106e711, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003542 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003543 { .id = 0x1106e712, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003544 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003545 { .id = 0x1106e713, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003546 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003547 { .id = 0x1106e714, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003548 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003549 { .id = 0x1106e715, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003550 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003551 { .id = 0x1106e716, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003552 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003553 { .id = 0x1106e717, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003554 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003555 { .id = 0x1106e720, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003556 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003557 { .id = 0x1106e721, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003558 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003559 { .id = 0x1106e722, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003560 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003561 { .id = 0x1106e723, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003562 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003563 { .id = 0x1106e724, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003564 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003565 { .id = 0x1106e725, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003566 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003567 { .id = 0x1106e726, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003568 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003569 { .id = 0x1106e727, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01003570 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01003571 { .id = 0x11060397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08003572 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01003573 { .id = 0x11061397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08003574 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01003575 { .id = 0x11062397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08003576 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01003577 { .id = 0x11063397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08003578 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01003579 { .id = 0x11064397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08003580 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01003581 { .id = 0x11065397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08003582 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01003583 { .id = 0x11066397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08003584 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01003585 { .id = 0x11067397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08003586 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01003587 { .id = 0x11060398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08003588 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01003589 { .id = 0x11061398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08003590 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01003591 { .id = 0x11062398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08003592 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01003593 { .id = 0x11063398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08003594 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01003595 { .id = 0x11064398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08003596 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01003597 { .id = 0x11065398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08003598 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01003599 { .id = 0x11066398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08003600 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01003601 { .id = 0x11067398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08003602 .patch = patch_vt1702},
Joseph Chanc577b8a2006-11-29 15:29:40 +01003603 {} /* terminator */
3604};
Takashi Iwai1289e9e2008-11-27 15:47:11 +01003605
3606MODULE_ALIAS("snd-hda-codec-id:1106*");
3607
3608static struct hda_codec_preset_list via_list = {
3609 .preset = snd_hda_preset_via,
3610 .owner = THIS_MODULE,
3611};
3612
3613MODULE_LICENSE("GPL");
3614MODULE_DESCRIPTION("VIA HD-audio codec");
3615
3616static int __init patch_via_init(void)
3617{
3618 return snd_hda_add_codec_preset(&via_list);
3619}
3620
3621static void __exit patch_via_exit(void)
3622{
3623 snd_hda_delete_codec_preset(&via_list);
3624}
3625
3626module_init(patch_via_init)
3627module_exit(patch_via_exit)