blob: 2977004677ec9a11d75bbee5cbadc4c9c3844291 [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,
Lydia Wangeb7188c2009-10-10 19:08:34 +080089 VT1718S,
Lydia Wangf3db4232009-10-10 19:08:41 +080090 VT1716S,
Harald Welted7426322008-09-15 22:43:23 +080091 CODEC_TYPES,
92};
93
Lydia Wang1f2e99f2009-10-10 19:08:17 +080094struct via_spec {
95 /* codec parameterization */
Lydia Wangf3db4232009-10-10 19:08:41 +080096 struct snd_kcontrol_new *mixers[6];
Lydia Wang1f2e99f2009-10-10 19:08:17 +080097 unsigned int num_mixers;
98
99 struct hda_verb *init_verbs[5];
100 unsigned int num_iverbs;
101
102 char *stream_name_analog;
103 struct hda_pcm_stream *stream_analog_playback;
104 struct hda_pcm_stream *stream_analog_capture;
105
106 char *stream_name_digital;
107 struct hda_pcm_stream *stream_digital_playback;
108 struct hda_pcm_stream *stream_digital_capture;
109
110 /* playback */
111 struct hda_multi_out multiout;
112 hda_nid_t slave_dig_outs[2];
113
114 /* capture */
115 unsigned int num_adc_nids;
116 hda_nid_t *adc_nids;
117 hda_nid_t mux_nids[3];
118 hda_nid_t dig_in_nid;
119 hda_nid_t dig_in_pin;
120
121 /* capture source */
122 const struct hda_input_mux *input_mux;
123 unsigned int cur_mux[3];
124
125 /* PCM information */
126 struct hda_pcm pcm_rec[3];
127
128 /* dynamic controls, init_verbs and input_mux */
129 struct auto_pin_cfg autocfg;
130 struct snd_array kctls;
131 struct hda_input_mux private_imux[2];
132 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
133
134 /* HP mode source */
135 const struct hda_input_mux *hp_mux;
136 unsigned int hp_independent_mode;
137 unsigned int hp_independent_mode_index;
138 unsigned int smart51_enabled;
Lydia Wangf3db4232009-10-10 19:08:41 +0800139 unsigned int dmic_enabled;
Lydia Wang1f2e99f2009-10-10 19:08:17 +0800140 enum VIA_HDA_CODEC codec_type;
141
142 /* work to check hp jack state */
143 struct hda_codec *codec;
144 struct delayed_work vt1708_hp_work;
145 int vt1708_jack_detectect;
146 int vt1708_hp_present;
147#ifdef CONFIG_SND_HDA_POWER_SAVE
148 struct hda_loopback_check loopback;
149#endif
150};
151
Lydia Wang744ff5f2009-10-10 19:07:26 +0800152static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
Harald Welted7426322008-09-15 22:43:23 +0800153{
Lydia Wang744ff5f2009-10-10 19:07:26 +0800154 u32 vendor_id = codec->vendor_id;
Harald Welted7426322008-09-15 22:43:23 +0800155 u16 ven_id = vendor_id >> 16;
156 u16 dev_id = vendor_id & 0xffff;
157 enum VIA_HDA_CODEC codec_type;
158
159 /* get codec type */
160 if (ven_id != 0x1106)
161 codec_type = UNKNOWN;
162 else if (dev_id >= 0x1708 && dev_id <= 0x170b)
163 codec_type = VT1708;
164 else if (dev_id >= 0xe710 && dev_id <= 0xe713)
165 codec_type = VT1709_10CH;
166 else if (dev_id >= 0xe714 && dev_id <= 0xe717)
167 codec_type = VT1709_6CH;
Lydia Wang518bf3b2009-10-10 19:07:29 +0800168 else if (dev_id >= 0xe720 && dev_id <= 0xe723) {
Harald Welted7426322008-09-15 22:43:23 +0800169 codec_type = VT1708B_8CH;
Lydia Wang518bf3b2009-10-10 19:07:29 +0800170 if (snd_hda_param_read(codec, 0x16, AC_PAR_CONNLIST_LEN) == 0x7)
171 codec_type = VT1708BCE;
172 } else if (dev_id >= 0xe724 && dev_id <= 0xe727)
Harald Welted7426322008-09-15 22:43:23 +0800173 codec_type = VT1708B_4CH;
174 else if ((dev_id & 0xfff) == 0x397
175 && (dev_id >> 12) < 8)
176 codec_type = VT1708S;
177 else if ((dev_id & 0xfff) == 0x398
178 && (dev_id >> 12) < 8)
179 codec_type = VT1702;
Lydia Wangeb7188c2009-10-10 19:08:34 +0800180 else if ((dev_id & 0xfff) == 0x428
181 && (dev_id >> 12) < 8)
182 codec_type = VT1718S;
Lydia Wangf3db4232009-10-10 19:08:41 +0800183 else if (dev_id == 0x0433 || dev_id == 0xa721)
184 codec_type = VT1716S;
Lydia Wangbb3c6bf2009-10-10 19:08:39 +0800185 else if (dev_id == 0x0441 || dev_id == 0x4441)
186 codec_type = VT1718S;
Harald Welted7426322008-09-15 22:43:23 +0800187 else
188 codec_type = UNKNOWN;
189 return codec_type;
190};
191
Harald Welte69e52a82008-09-09 15:57:32 +0800192#define VIA_HP_EVENT 0x01
193#define VIA_GPIO_EVENT 0x02
Lydia Wanga34df192009-10-10 19:08:01 +0800194#define VIA_JACK_EVENT 0x04
Lydia Wangf3db4232009-10-10 19:08:41 +0800195#define VIA_MONO_EVENT 0x08
Harald Welte69e52a82008-09-09 15:57:32 +0800196
Joseph Chanc577b8a2006-11-29 15:29:40 +0100197enum {
198 VIA_CTL_WIDGET_VOL,
199 VIA_CTL_WIDGET_MUTE,
Lydia Wangf5271102009-10-10 19:07:35 +0800200 VIA_CTL_WIDGET_ANALOG_MUTE,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100201};
202
203enum {
Harald Welteeb14a462008-09-09 15:40:38 +0800204 AUTO_SEQ_FRONT = 0,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100205 AUTO_SEQ_SURROUND,
206 AUTO_SEQ_CENLFE,
207 AUTO_SEQ_SIDE
208};
209
Lydia Wangf5271102009-10-10 19:07:35 +0800210static void analog_low_current_mode(struct hda_codec *codec, int stream_idle);
211static void set_jack_power_state(struct hda_codec *codec);
Lydia Wang1f2e99f2009-10-10 19:08:17 +0800212static int is_aa_path_mute(struct hda_codec *codec);
213
214static void vt1708_start_hp_work(struct via_spec *spec)
215{
216 if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
217 return;
218 snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
219 !spec->vt1708_jack_detectect);
220 if (!delayed_work_pending(&spec->vt1708_hp_work))
221 schedule_delayed_work(&spec->vt1708_hp_work,
222 msecs_to_jiffies(100));
223}
224
225static void vt1708_stop_hp_work(struct via_spec *spec)
226{
227 if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
228 return;
229 if (snd_hda_get_bool_hint(spec->codec, "analog_loopback_hp_detect") == 1
230 && !is_aa_path_mute(spec->codec))
231 return;
232 snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
233 !spec->vt1708_jack_detectect);
234 cancel_delayed_work(&spec->vt1708_hp_work);
235 flush_scheduled_work();
236}
Lydia Wangf5271102009-10-10 19:07:35 +0800237
238static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
239 struct snd_ctl_elem_value *ucontrol)
240{
241 int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
242 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
243
244 set_jack_power_state(codec);
245 analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1);
Lydia Wang1f2e99f2009-10-10 19:08:17 +0800246 if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) {
247 if (is_aa_path_mute(codec))
248 vt1708_start_hp_work(codec->spec);
249 else
250 vt1708_stop_hp_work(codec->spec);
251 }
Lydia Wangf5271102009-10-10 19:07:35 +0800252 return change;
253}
254
255/* modify .put = snd_hda_mixer_amp_switch_put */
256#define ANALOG_INPUT_MUTE \
257 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
258 .name = NULL, \
259 .index = 0, \
260 .info = snd_hda_mixer_amp_switch_info, \
261 .get = snd_hda_mixer_amp_switch_get, \
262 .put = analog_input_switch_put, \
263 .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
264
Joseph Chanc577b8a2006-11-29 15:29:40 +0100265static struct snd_kcontrol_new vt1708_control_templates[] = {
266 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
267 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Lydia Wangf5271102009-10-10 19:07:35 +0800268 ANALOG_INPUT_MUTE,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100269};
270
271
Joseph Chanc577b8a2006-11-29 15:29:40 +0100272static hda_nid_t vt1708_adc_nids[2] = {
273 /* ADC1-2 */
274 0x15, 0x27
275};
276
277static hda_nid_t vt1709_adc_nids[3] = {
278 /* ADC1-2 */
279 0x14, 0x15, 0x16
280};
281
Josepch Chanf7278fd2007-12-13 16:40:40 +0100282static hda_nid_t vt1708B_adc_nids[2] = {
283 /* ADC1-2 */
284 0x13, 0x14
285};
286
Harald Welted949cac2008-09-09 15:56:01 +0800287static hda_nid_t vt1708S_adc_nids[2] = {
288 /* ADC1-2 */
289 0x13, 0x14
290};
291
292static hda_nid_t vt1702_adc_nids[3] = {
293 /* ADC1-2 */
294 0x12, 0x20, 0x1F
295};
296
Lydia Wangeb7188c2009-10-10 19:08:34 +0800297static hda_nid_t vt1718S_adc_nids[2] = {
298 /* ADC1-2 */
299 0x10, 0x11
300};
301
Lydia Wangf3db4232009-10-10 19:08:41 +0800302static hda_nid_t vt1716S_adc_nids[2] = {
303 /* ADC1-2 */
304 0x13, 0x14
305};
306
Joseph Chanc577b8a2006-11-29 15:29:40 +0100307/* add dynamic controls */
308static int via_add_control(struct via_spec *spec, int type, const char *name,
309 unsigned long val)
310{
311 struct snd_kcontrol_new *knew;
312
Takashi Iwai603c4012008-07-30 15:01:44 +0200313 snd_array_init(&spec->kctls, sizeof(*knew), 32);
314 knew = snd_array_new(&spec->kctls);
315 if (!knew)
316 return -ENOMEM;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100317 *knew = vt1708_control_templates[type];
318 knew->name = kstrdup(name, GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100319 if (!knew->name)
320 return -ENOMEM;
321 knew->private_value = val;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100322 return 0;
323}
324
Takashi Iwai603c4012008-07-30 15:01:44 +0200325static void via_free_kctls(struct hda_codec *codec)
326{
327 struct via_spec *spec = codec->spec;
328
329 if (spec->kctls.list) {
330 struct snd_kcontrol_new *kctl = spec->kctls.list;
331 int i;
332 for (i = 0; i < spec->kctls.used; i++)
333 kfree(kctl[i].name);
334 }
335 snd_array_free(&spec->kctls);
336}
337
Joseph Chanc577b8a2006-11-29 15:29:40 +0100338/* create input playback/capture controls for the given pin */
Lydia Wang9510e8d2009-10-10 19:07:39 +0800339static int via_new_analog_input(struct via_spec *spec, const char *ctlname,
340 int idx, int mix_nid)
Joseph Chanc577b8a2006-11-29 15:29:40 +0100341{
342 char name[32];
343 int err;
344
345 sprintf(name, "%s Playback Volume", ctlname);
346 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
347 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
348 if (err < 0)
349 return err;
350 sprintf(name, "%s Playback Switch", ctlname);
Lydia Wangf5271102009-10-10 19:07:35 +0800351 err = via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100352 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
353 if (err < 0)
354 return err;
355 return 0;
356}
357
358static void via_auto_set_output_and_unmute(struct hda_codec *codec,
359 hda_nid_t nid, int pin_type,
360 int dac_idx)
361{
362 /* set as output */
363 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
364 pin_type);
365 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
366 AMP_OUT_UNMUTE);
Takashi Iwaid3a11e62009-07-07 13:43:35 +0200367 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
368 snd_hda_codec_write(codec, nid, 0,
369 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100370}
371
372
373static void via_auto_init_multi_out(struct hda_codec *codec)
374{
375 struct via_spec *spec = codec->spec;
376 int i;
377
378 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
379 hda_nid_t nid = spec->autocfg.line_out_pins[i];
380 if (nid)
381 via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
382 }
383}
384
385static void via_auto_init_hp_out(struct hda_codec *codec)
386{
387 struct via_spec *spec = codec->spec;
388 hda_nid_t pin;
389
390 pin = spec->autocfg.hp_pins[0];
391 if (pin) /* connect to front */
392 via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
393}
394
395static void via_auto_init_analog_input(struct hda_codec *codec)
396{
397 struct via_spec *spec = codec->spec;
398 int i;
399
400 for (i = 0; i < AUTO_PIN_LAST; i++) {
401 hda_nid_t nid = spec->autocfg.input_pins[i];
402
403 snd_hda_codec_write(codec, nid, 0,
404 AC_VERB_SET_PIN_WIDGET_CONTROL,
405 (i <= AUTO_PIN_FRONT_MIC ?
406 PIN_VREF50 : PIN_IN));
407
408 }
409}
Lydia Wangf5271102009-10-10 19:07:35 +0800410
Lydia Wang1564b282009-10-10 19:07:52 +0800411static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
412
Lydia Wangf5271102009-10-10 19:07:35 +0800413static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
414 unsigned int *affected_parm)
415{
416 unsigned parm;
417 unsigned def_conf = snd_hda_codec_get_pincfg(codec, nid);
418 unsigned no_presence = (def_conf & AC_DEFCFG_MISC)
419 >> AC_DEFCFG_MISC_SHIFT
420 & AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */
421 unsigned present = snd_hda_codec_read(codec, nid, 0,
422 AC_VERB_GET_PIN_SENSE, 0) >> 31;
Lydia Wang1564b282009-10-10 19:07:52 +0800423 struct via_spec *spec = codec->spec;
424 if ((spec->smart51_enabled && is_smart51_pins(spec, nid))
425 || ((no_presence || present)
426 && get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) {
Lydia Wangf5271102009-10-10 19:07:35 +0800427 *affected_parm = AC_PWRST_D0; /* if it's connected */
428 parm = AC_PWRST_D0;
429 } else
430 parm = AC_PWRST_D3;
431
432 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
433}
434
435static void set_jack_power_state(struct hda_codec *codec)
436{
437 struct via_spec *spec = codec->spec;
438 int imux_is_smixer;
439 unsigned int parm;
440
441 if (spec->codec_type == VT1702) {
442 imux_is_smixer = snd_hda_codec_read(
443 codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
444 /* inputs */
445 /* PW 1/2/5 (14h/15h/18h) */
446 parm = AC_PWRST_D3;
447 set_pin_power_state(codec, 0x14, &parm);
448 set_pin_power_state(codec, 0x15, &parm);
449 set_pin_power_state(codec, 0x18, &parm);
450 if (imux_is_smixer)
451 parm = AC_PWRST_D0; /* SW0 = stereo mixer (idx 3) */
452 /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
453 snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
454 parm);
455 snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE,
456 parm);
457 snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
458 parm);
459 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE,
460 parm);
461
462 /* outputs */
463 /* PW 3/4 (16h/17h) */
464 parm = AC_PWRST_D3;
465 set_pin_power_state(codec, 0x16, &parm);
466 set_pin_power_state(codec, 0x17, &parm);
467 /* MW0 (1ah), AOW 0/1 (10h/1dh) */
468 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
469 imux_is_smixer ? AC_PWRST_D0 : parm);
470 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
471 parm);
472 snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE,
473 parm);
474 } else if (spec->codec_type == VT1708B_8CH
475 || spec->codec_type == VT1708B_4CH
476 || spec->codec_type == VT1708S) {
477 /* SW0 (17h) = stereo mixer */
478 int is_8ch = spec->codec_type != VT1708B_4CH;
479 imux_is_smixer = snd_hda_codec_read(
480 codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
481 == ((spec->codec_type == VT1708S) ? 5 : 0);
482 /* inputs */
483 /* PW 1/2/5 (1ah/1bh/1eh) */
484 parm = AC_PWRST_D3;
485 set_pin_power_state(codec, 0x1a, &parm);
486 set_pin_power_state(codec, 0x1b, &parm);
487 set_pin_power_state(codec, 0x1e, &parm);
488 if (imux_is_smixer)
489 parm = AC_PWRST_D0;
490 /* SW0 (17h), AIW 0/1 (13h/14h) */
491 snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
492 parm);
493 snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
494 parm);
495 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
496 parm);
497
498 /* outputs */
499 /* PW0 (19h), SW1 (18h), AOW1 (11h) */
500 parm = AC_PWRST_D3;
501 set_pin_power_state(codec, 0x19, &parm);
502 snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
503 parm);
504 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
505 parm);
506
507 /* PW6 (22h), SW2 (26h), AOW2 (24h) */
508 if (is_8ch) {
509 parm = AC_PWRST_D3;
510 set_pin_power_state(codec, 0x22, &parm);
511 snd_hda_codec_write(codec, 0x26, 0,
512 AC_VERB_SET_POWER_STATE, parm);
513 snd_hda_codec_write(codec, 0x24, 0,
514 AC_VERB_SET_POWER_STATE, parm);
515 }
516
517 /* PW 3/4/7 (1ch/1dh/23h) */
518 parm = AC_PWRST_D3;
519 /* force to D0 for internal Speaker */
520 set_pin_power_state(codec, 0x1c, &parm);
521 set_pin_power_state(codec, 0x1d, &parm);
522 if (is_8ch)
523 set_pin_power_state(codec, 0x23, &parm);
524 /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
525 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
526 imux_is_smixer ? AC_PWRST_D0 : parm);
527 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
528 parm);
529 if (is_8ch) {
530 snd_hda_codec_write(codec, 0x25, 0,
531 AC_VERB_SET_POWER_STATE, parm);
532 snd_hda_codec_write(codec, 0x27, 0,
533 AC_VERB_SET_POWER_STATE, parm);
534 }
Lydia Wangeb7188c2009-10-10 19:08:34 +0800535 } else if (spec->codec_type == VT1718S) {
536 /* MUX6 (1eh) = stereo mixer */
537 imux_is_smixer = snd_hda_codec_read(
538 codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
539 /* inputs */
540 /* PW 5/6/7 (29h/2ah/2bh) */
541 parm = AC_PWRST_D3;
542 set_pin_power_state(codec, 0x29, &parm);
543 set_pin_power_state(codec, 0x2a, &parm);
544 set_pin_power_state(codec, 0x2b, &parm);
545 if (imux_is_smixer)
546 parm = AC_PWRST_D0;
547 /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */
548 snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE,
549 parm);
550 snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
551 parm);
552 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
553 parm);
554 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
555 parm);
556
557 /* outputs */
558 /* PW3 (27h), MW2 (1ah), AOW3 (bh) */
559 parm = AC_PWRST_D3;
560 set_pin_power_state(codec, 0x27, &parm);
561 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
562 parm);
563 snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE,
564 parm);
565
566 /* PW2 (26h), AOW2 (ah) */
567 parm = AC_PWRST_D3;
568 set_pin_power_state(codec, 0x26, &parm);
569 snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE,
570 parm);
571
572 /* PW0/1 (24h/25h) */
573 parm = AC_PWRST_D3;
574 set_pin_power_state(codec, 0x24, &parm);
575 set_pin_power_state(codec, 0x25, &parm);
576 if (!spec->hp_independent_mode) /* check for redirected HP */
577 set_pin_power_state(codec, 0x28, &parm);
578 snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE,
579 parm);
580 snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE,
581 parm);
582 /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
583 snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE,
584 imux_is_smixer ? AC_PWRST_D0 : parm);
585 if (spec->hp_independent_mode) {
586 /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */
587 parm = AC_PWRST_D3;
588 set_pin_power_state(codec, 0x28, &parm);
589 snd_hda_codec_write(codec, 0x1b, 0,
590 AC_VERB_SET_POWER_STATE, parm);
591 snd_hda_codec_write(codec, 0x34, 0,
592 AC_VERB_SET_POWER_STATE, parm);
593 snd_hda_codec_write(codec, 0xc, 0,
594 AC_VERB_SET_POWER_STATE, parm);
595 }
Lydia Wangf3db4232009-10-10 19:08:41 +0800596 } else if (spec->codec_type == VT1716S) {
597 unsigned int mono_out, present;
598 /* SW0 (17h) = stereo mixer */
599 imux_is_smixer = snd_hda_codec_read(
600 codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
601 /* inputs */
602 /* PW 1/2/5 (1ah/1bh/1eh) */
603 parm = AC_PWRST_D3;
604 set_pin_power_state(codec, 0x1a, &parm);
605 set_pin_power_state(codec, 0x1b, &parm);
606 set_pin_power_state(codec, 0x1e, &parm);
607 if (imux_is_smixer)
608 parm = AC_PWRST_D0;
609 /* SW0 (17h), AIW0(13h) */
610 snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
611 parm);
612 snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
613 parm);
614
615 parm = AC_PWRST_D3;
616 set_pin_power_state(codec, 0x1e, &parm);
617 /* PW11 (22h) */
618 if (spec->dmic_enabled)
619 set_pin_power_state(codec, 0x22, &parm);
620 else
621 snd_hda_codec_write(
622 codec, 0x22, 0,
623 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
624
625 /* SW2(26h), AIW1(14h) */
626 snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE,
627 parm);
628 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
629 parm);
630
631 /* outputs */
632 /* PW0 (19h), SW1 (18h), AOW1 (11h) */
633 parm = AC_PWRST_D3;
634 set_pin_power_state(codec, 0x19, &parm);
635 /* Smart 5.1 PW2(1bh) */
636 if (spec->smart51_enabled)
637 set_pin_power_state(codec, 0x1b, &parm);
638 snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
639 parm);
640 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
641 parm);
642
643 /* PW7 (23h), SW3 (27h), AOW3 (25h) */
644 parm = AC_PWRST_D3;
645 set_pin_power_state(codec, 0x23, &parm);
646 /* Smart 5.1 PW1(1ah) */
647 if (spec->smart51_enabled)
648 set_pin_power_state(codec, 0x1a, &parm);
649 snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE,
650 parm);
651
652 /* Smart 5.1 PW5(1eh) */
653 if (spec->smart51_enabled)
654 set_pin_power_state(codec, 0x1e, &parm);
655 snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE,
656 parm);
657
658 /* Mono out */
659 /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/
660 present = snd_hda_codec_read(
661 codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
662 if (present)
663 mono_out = 0;
664 else {
665 present = snd_hda_codec_read(
666 codec, 0x1d, 0, AC_VERB_GET_PIN_SENSE, 0)
667 & 0x80000000;
668 if (!spec->hp_independent_mode && present)
669 mono_out = 0;
670 else
671 mono_out = 1;
672 }
673 parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3;
674 snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE,
675 parm);
676 snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE,
677 parm);
678 snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE,
679 parm);
680
681 /* PW 3/4 (1ch/1dh) */
682 parm = AC_PWRST_D3;
683 set_pin_power_state(codec, 0x1c, &parm);
684 set_pin_power_state(codec, 0x1d, &parm);
685 /* HP Independent Mode, power on AOW3 */
686 if (spec->hp_independent_mode)
687 snd_hda_codec_write(codec, 0x25, 0,
688 AC_VERB_SET_POWER_STATE, parm);
689
690 /* force to D0 for internal Speaker */
691 /* MW0 (16h), AOW0 (10h) */
692 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
693 imux_is_smixer ? AC_PWRST_D0 : parm);
694 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
695 mono_out ? AC_PWRST_D0 : parm);
Lydia Wangf5271102009-10-10 19:07:35 +0800696 }
697}
698
Joseph Chanc577b8a2006-11-29 15:29:40 +0100699/*
700 * input MUX handling
701 */
702static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
703 struct snd_ctl_elem_info *uinfo)
704{
705 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
706 struct via_spec *spec = codec->spec;
707 return snd_hda_input_mux_info(spec->input_mux, uinfo);
708}
709
710static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
711 struct snd_ctl_elem_value *ucontrol)
712{
713 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
714 struct via_spec *spec = codec->spec;
715 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
716
717 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
718 return 0;
719}
720
721static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
722 struct snd_ctl_elem_value *ucontrol)
723{
724 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
725 struct via_spec *spec = codec->spec;
726 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100727
Takashi Iwai337b9d02009-07-07 18:18:59 +0200728 if (!spec->mux_nids[adc_idx])
729 return -EINVAL;
Lydia Wanga80e6e32009-10-10 19:07:55 +0800730 /* switch to D0 beofre change index */
731 if (snd_hda_codec_read(codec, spec->mux_nids[adc_idx], 0,
732 AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0)
733 snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0,
734 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
735 /* update jack power state */
736 set_jack_power_state(codec);
737
Takashi Iwai337b9d02009-07-07 18:18:59 +0200738 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
739 spec->mux_nids[adc_idx],
740 &spec->cur_mux[adc_idx]);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100741}
742
Harald Welte0aa62ae2008-09-09 15:58:27 +0800743static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
744 struct snd_ctl_elem_info *uinfo)
745{
746 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
747 struct via_spec *spec = codec->spec;
748 return snd_hda_input_mux_info(spec->hp_mux, uinfo);
749}
750
751static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
752 struct snd_ctl_elem_value *ucontrol)
753{
754 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
755 struct via_spec *spec = codec->spec;
Lydia Wangeb7188c2009-10-10 19:08:34 +0800756 hda_nid_t nid;
757 unsigned int pinsel;
Harald Welte0aa62ae2008-09-09 15:58:27 +0800758
Lydia Wangeb7188c2009-10-10 19:08:34 +0800759 switch (spec->codec_type) {
760 case VT1718S:
761 nid = 0x34;
762 break;
763 default:
764 nid = spec->autocfg.hp_pins[0];
765 break;
766 }
767 /* use !! to translate conn sel 2 for VT1718S */
768 pinsel = !!snd_hda_codec_read(codec, nid, 0,
769 AC_VERB_GET_CONNECT_SEL,
770 0x00);
Harald Welte0aa62ae2008-09-09 15:58:27 +0800771 ucontrol->value.enumerated.item[0] = pinsel;
772
773 return 0;
774}
775
Lydia Wang0713efe2009-10-10 19:07:43 +0800776static void activate_ctl(struct hda_codec *codec, const char *name, int active)
777{
778 struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name);
779 if (ctl) {
780 ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
781 ctl->vd[0].access |= active
782 ? 0 : SNDRV_CTL_ELEM_ACCESS_INACTIVE;
783 snd_ctl_notify(codec->bus->card,
784 SNDRV_CTL_EVENT_MASK_VALUE, &ctl->id);
785 }
786}
787
Lydia Wangcdc17842009-10-10 19:07:47 +0800788static int update_side_mute_status(struct hda_codec *codec)
789{
790 /* mute side channel */
791 struct via_spec *spec = codec->spec;
792 unsigned int parm = spec->hp_independent_mode
793 ? AMP_OUT_MUTE : AMP_OUT_UNMUTE;
794 hda_nid_t sw3;
795
796 switch (spec->codec_type) {
797 case VT1708:
798 sw3 = 0x1b;
799 break;
800 case VT1709_10CH:
801 sw3 = 0x29;
802 break;
803 case VT1708B_8CH:
804 case VT1708S:
805 sw3 = 0x27;
806 break;
807 default:
808 sw3 = 0;
809 break;
810 }
811
812 if (sw3)
813 snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE,
814 parm);
815 return 0;
816}
817
Harald Welte0aa62ae2008-09-09 15:58:27 +0800818static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
819 struct snd_ctl_elem_value *ucontrol)
820{
821 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
822 struct via_spec *spec = codec->spec;
823 hda_nid_t nid = spec->autocfg.hp_pins[0];
824 unsigned int pinsel = ucontrol->value.enumerated.item[0];
Lydia Wangcdc17842009-10-10 19:07:47 +0800825 /* Get Independent Mode index of headphone pin widget */
826 spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel
827 ? 1 : 0;
Harald Welte0aa62ae2008-09-09 15:58:27 +0800828
Lydia Wangeb7188c2009-10-10 19:08:34 +0800829 switch (spec->codec_type) {
830 case VT1718S:
831 nid = 0x34;
832 pinsel = pinsel ? 2 : 0; /* indep HP use AOW4 (index 2) */
833 spec->multiout.num_dacs = 4;
834 break;
835 default:
836 nid = spec->autocfg.hp_pins[0];
837 break;
838 }
Lydia Wangcdc17842009-10-10 19:07:47 +0800839 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel);
Harald Welte0aa62ae2008-09-09 15:58:27 +0800840
Lydia Wangcdc17842009-10-10 19:07:47 +0800841 if (spec->multiout.hp_nid && spec->multiout.hp_nid
842 != spec->multiout.dac_nids[HDA_FRONT])
843 snd_hda_codec_setup_stream(codec, spec->multiout.hp_nid,
844 0, 0, 0);
Harald Welte0aa62ae2008-09-09 15:58:27 +0800845
Lydia Wangcdc17842009-10-10 19:07:47 +0800846 update_side_mute_status(codec);
Lydia Wang0713efe2009-10-10 19:07:43 +0800847 /* update HP volume/swtich active state */
848 if (spec->codec_type == VT1708S
Lydia Wangeb7188c2009-10-10 19:08:34 +0800849 || spec->codec_type == VT1702
Lydia Wangf3db4232009-10-10 19:08:41 +0800850 || spec->codec_type == VT1718S
851 || spec->codec_type == VT1716S) {
Lydia Wang0713efe2009-10-10 19:07:43 +0800852 activate_ctl(codec, "Headphone Playback Volume",
853 spec->hp_independent_mode);
854 activate_ctl(codec, "Headphone Playback Switch",
855 spec->hp_independent_mode);
856 }
Harald Welte0aa62ae2008-09-09 15:58:27 +0800857 return 0;
858}
859
860static struct snd_kcontrol_new via_hp_mixer[] = {
861 {
862 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
863 .name = "Independent HP",
864 .count = 1,
865 .info = via_independent_hp_info,
866 .get = via_independent_hp_get,
867 .put = via_independent_hp_put,
868 },
869 { } /* end */
870};
871
Lydia Wang1564b282009-10-10 19:07:52 +0800872static void notify_aa_path_ctls(struct hda_codec *codec)
873{
874 int i;
875 struct snd_ctl_elem_id id;
876 const char *labels[] = {"Mic", "Front Mic", "Line"};
877
878 memset(&id, 0, sizeof(id));
879 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
880 for (i = 0; i < ARRAY_SIZE(labels); i++) {
881 sprintf(id.name, "%s Playback Volume", labels[i]);
882 snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
883 &id);
884 }
885}
886
887static void mute_aa_path(struct hda_codec *codec, int mute)
888{
889 struct via_spec *spec = codec->spec;
890 hda_nid_t nid_mixer;
891 int start_idx;
892 int end_idx;
893 int i;
894 /* get nid of MW0 and start & end index */
895 switch (spec->codec_type) {
896 case VT1708:
897 nid_mixer = 0x17;
898 start_idx = 2;
899 end_idx = 4;
900 break;
901 case VT1709_10CH:
902 case VT1709_6CH:
903 nid_mixer = 0x18;
904 start_idx = 2;
905 end_idx = 4;
906 break;
907 case VT1708B_8CH:
908 case VT1708B_4CH:
909 case VT1708S:
Lydia Wangf3db4232009-10-10 19:08:41 +0800910 case VT1716S:
Lydia Wang1564b282009-10-10 19:07:52 +0800911 nid_mixer = 0x16;
912 start_idx = 2;
913 end_idx = 4;
914 break;
915 default:
916 return;
917 }
918 /* check AA path's mute status */
919 for (i = start_idx; i <= end_idx; i++) {
920 int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE;
921 snd_hda_codec_amp_stereo(codec, nid_mixer, HDA_INPUT, i,
922 HDA_AMP_MUTE, val);
923 }
924}
925static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin)
926{
927 int res = 0;
928 int index;
929 for (index = AUTO_PIN_MIC; index < AUTO_PIN_FRONT_LINE; index++) {
930 if (pin == spec->autocfg.input_pins[index]) {
931 res = 1;
932 break;
933 }
934 }
935 return res;
936}
937
938static int via_smart51_info(struct snd_kcontrol *kcontrol,
939 struct snd_ctl_elem_info *uinfo)
940{
941 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
942 uinfo->count = 1;
943 uinfo->value.integer.min = 0;
944 uinfo->value.integer.max = 1;
945 return 0;
946}
947
948static int via_smart51_get(struct snd_kcontrol *kcontrol,
949 struct snd_ctl_elem_value *ucontrol)
950{
951 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
952 struct via_spec *spec = codec->spec;
953 int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
954 int on = 1;
955 int i;
956
957 for (i = 0; i < ARRAY_SIZE(index); i++) {
958 hda_nid_t nid = spec->autocfg.input_pins[index[i]];
959 if (nid) {
960 int ctl =
961 snd_hda_codec_read(codec, nid, 0,
962 AC_VERB_GET_PIN_WIDGET_CONTROL,
963 0);
964 if (i == AUTO_PIN_FRONT_MIC
Lydia Wangeb7188c2009-10-10 19:08:34 +0800965 && spec->hp_independent_mode
966 && spec->codec_type != VT1718S)
Lydia Wang1564b282009-10-10 19:07:52 +0800967 continue; /* ignore FMic for independent HP */
968 if (ctl & AC_PINCTL_IN_EN
969 && !(ctl & AC_PINCTL_OUT_EN))
970 on = 0;
971 }
972 }
973 *ucontrol->value.integer.value = on;
974 return 0;
975}
976
977static int via_smart51_put(struct snd_kcontrol *kcontrol,
978 struct snd_ctl_elem_value *ucontrol)
979{
980 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
981 struct via_spec *spec = codec->spec;
982 int out_in = *ucontrol->value.integer.value
983 ? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN;
984 int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
985 int i;
986
987 for (i = 0; i < ARRAY_SIZE(index); i++) {
988 hda_nid_t nid = spec->autocfg.input_pins[index[i]];
989 if (i == AUTO_PIN_FRONT_MIC
Lydia Wangeb7188c2009-10-10 19:08:34 +0800990 && spec->hp_independent_mode
991 && spec->codec_type != VT1718S)
Lydia Wang1564b282009-10-10 19:07:52 +0800992 continue; /* don't retask FMic for independent HP */
993 if (nid) {
994 unsigned int parm = snd_hda_codec_read(
995 codec, nid, 0,
996 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
997 parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
998 parm |= out_in;
999 snd_hda_codec_write(codec, nid, 0,
1000 AC_VERB_SET_PIN_WIDGET_CONTROL,
1001 parm);
1002 if (out_in == AC_PINCTL_OUT_EN) {
1003 mute_aa_path(codec, 1);
1004 notify_aa_path_ctls(codec);
1005 }
Lydia Wangeb7188c2009-10-10 19:08:34 +08001006 if (spec->codec_type == VT1718S)
1007 snd_hda_codec_amp_stereo(
1008 codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE,
1009 HDA_AMP_UNMUTE);
Lydia Wang1564b282009-10-10 19:07:52 +08001010 }
1011 if (i == AUTO_PIN_FRONT_MIC) {
Lydia Wangf3db4232009-10-10 19:08:41 +08001012 if (spec->codec_type == VT1708S
1013 || spec->codec_type == VT1716S) {
Lydia Wang1564b282009-10-10 19:07:52 +08001014 /* input = index 1 (AOW3) */
1015 snd_hda_codec_write(
1016 codec, nid, 0,
1017 AC_VERB_SET_CONNECT_SEL, 1);
1018 snd_hda_codec_amp_stereo(
1019 codec, nid, HDA_OUTPUT,
1020 0, HDA_AMP_MUTE, HDA_AMP_UNMUTE);
1021 }
1022 }
1023 }
1024 spec->smart51_enabled = *ucontrol->value.integer.value;
1025 set_jack_power_state(codec);
1026 return 1;
1027}
1028
1029static struct snd_kcontrol_new via_smart51_mixer[] = {
1030 {
1031 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1032 .name = "Smart 5.1",
1033 .count = 1,
1034 .info = via_smart51_info,
1035 .get = via_smart51_get,
1036 .put = via_smart51_put,
1037 },
1038 {} /* end */
1039};
1040
Joseph Chanc577b8a2006-11-29 15:29:40 +01001041/* capture mixer elements */
1042static struct snd_kcontrol_new vt1708_capture_mixer[] = {
1043 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
1044 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
1045 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
1046 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
1047 {
1048 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1049 /* The multiple "Capture Source" controls confuse alsamixer
1050 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +01001051 */
1052 /* .name = "Capture Source", */
1053 .name = "Input Source",
1054 .count = 1,
1055 .info = via_mux_enum_info,
1056 .get = via_mux_enum_get,
1057 .put = via_mux_enum_put,
1058 },
1059 { } /* end */
1060};
Lydia Wangf5271102009-10-10 19:07:35 +08001061
1062/* check AA path's mute statue */
1063static int is_aa_path_mute(struct hda_codec *codec)
1064{
1065 int mute = 1;
1066 hda_nid_t nid_mixer;
1067 int start_idx;
1068 int end_idx;
1069 int i;
1070 struct via_spec *spec = codec->spec;
1071 /* get nid of MW0 and start & end index */
1072 switch (spec->codec_type) {
1073 case VT1708B_8CH:
1074 case VT1708B_4CH:
1075 case VT1708S:
Lydia Wangf3db4232009-10-10 19:08:41 +08001076 case VT1716S:
Lydia Wangf5271102009-10-10 19:07:35 +08001077 nid_mixer = 0x16;
1078 start_idx = 2;
1079 end_idx = 4;
1080 break;
1081 case VT1702:
1082 nid_mixer = 0x1a;
1083 start_idx = 1;
1084 end_idx = 3;
1085 break;
Lydia Wangeb7188c2009-10-10 19:08:34 +08001086 case VT1718S:
1087 nid_mixer = 0x21;
1088 start_idx = 1;
1089 end_idx = 3;
1090 break;
Lydia Wangf5271102009-10-10 19:07:35 +08001091 default:
1092 return 0;
1093 }
1094 /* check AA path's mute status */
1095 for (i = start_idx; i <= end_idx; i++) {
1096 unsigned int con_list = snd_hda_codec_read(
1097 codec, nid_mixer, 0, AC_VERB_GET_CONNECT_LIST, i/4*4);
1098 int shift = 8 * (i % 4);
1099 hda_nid_t nid_pin = (con_list & (0xff << shift)) >> shift;
1100 unsigned int defconf = snd_hda_codec_get_pincfg(codec, nid_pin);
1101 if (get_defcfg_connect(defconf) == AC_JACK_PORT_COMPLEX) {
1102 /* check mute status while the pin is connected */
1103 int mute_l = snd_hda_codec_amp_read(codec, nid_mixer, 0,
1104 HDA_INPUT, i) >> 7;
1105 int mute_r = snd_hda_codec_amp_read(codec, nid_mixer, 1,
1106 HDA_INPUT, i) >> 7;
1107 if (!mute_l || !mute_r) {
1108 mute = 0;
1109 break;
1110 }
1111 }
1112 }
1113 return mute;
1114}
1115
1116/* enter/exit analog low-current mode */
1117static void analog_low_current_mode(struct hda_codec *codec, int stream_idle)
1118{
1119 struct via_spec *spec = codec->spec;
1120 static int saved_stream_idle = 1; /* saved stream idle status */
1121 int enable = is_aa_path_mute(codec);
1122 unsigned int verb = 0;
1123 unsigned int parm = 0;
1124
1125 if (stream_idle == -1) /* stream status did not change */
1126 enable = enable && saved_stream_idle;
1127 else {
1128 enable = enable && stream_idle;
1129 saved_stream_idle = stream_idle;
1130 }
1131
1132 /* decide low current mode's verb & parameter */
1133 switch (spec->codec_type) {
1134 case VT1708B_8CH:
1135 case VT1708B_4CH:
1136 verb = 0xf70;
1137 parm = enable ? 0x02 : 0x00; /* 0x02: 2/3x, 0x00: 1x */
1138 break;
1139 case VT1708S:
Lydia Wangeb7188c2009-10-10 19:08:34 +08001140 case VT1718S:
Lydia Wangf3db4232009-10-10 19:08:41 +08001141 case VT1716S:
Lydia Wangf5271102009-10-10 19:07:35 +08001142 verb = 0xf73;
1143 parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */
1144 break;
1145 case VT1702:
1146 verb = 0xf73;
1147 parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */
1148 break;
1149 default:
1150 return; /* other codecs are not supported */
1151 }
1152 /* send verb */
1153 snd_hda_codec_write(codec, codec->afg, 0, verb, parm);
1154}
1155
Joseph Chanc577b8a2006-11-29 15:29:40 +01001156/*
1157 * generic initialization of ADC, input mixers and output mixers
1158 */
1159static struct hda_verb vt1708_volume_init_verbs[] = {
1160 /*
1161 * Unmute ADC0-1 and set the default input to mic-in
1162 */
1163 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1164 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1165
1166
Josepch Chanf7278fd2007-12-13 16:40:40 +01001167 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +01001168 * mixer widget
1169 */
1170 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +01001171 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1172 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1173 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1174 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1175 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001176
1177 /*
1178 * Set up output mixers (0x19 - 0x1b)
1179 */
1180 /* set vol=0 to output mixers */
1181 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1182 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1183 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1184
1185 /* Setup default input to PW4 */
1186 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001187 /* PW9 Output enable */
1188 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Josepch Chanf7278fd2007-12-13 16:40:40 +01001189 { }
Joseph Chanc577b8a2006-11-29 15:29:40 +01001190};
1191
1192static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
1193 struct hda_codec *codec,
1194 struct snd_pcm_substream *substream)
1195{
1196 struct via_spec *spec = codec->spec;
Lydia Wang17314372009-10-10 19:07:37 +08001197 int idle = substream->pstr->substream_opened == 1
1198 && substream->ref_count == 0;
Lydia Wang17314372009-10-10 19:07:37 +08001199 analog_low_current_mode(codec, idle);
Takashi Iwai9a081602008-02-12 18:37:26 +01001200 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
1201 hinfo);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001202}
1203
Harald Welte0aa62ae2008-09-09 15:58:27 +08001204static void playback_multi_pcm_prep_0(struct hda_codec *codec,
1205 unsigned int stream_tag,
1206 unsigned int format,
1207 struct snd_pcm_substream *substream)
1208{
1209 struct via_spec *spec = codec->spec;
1210 struct hda_multi_out *mout = &spec->multiout;
1211 hda_nid_t *nids = mout->dac_nids;
1212 int chs = substream->runtime->channels;
1213 int i;
1214
1215 mutex_lock(&codec->spdif_mutex);
1216 if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
1217 if (chs == 2 &&
1218 snd_hda_is_supported_format(codec, mout->dig_out_nid,
1219 format) &&
1220 !(codec->spdif_status & IEC958_AES0_NONAUDIO)) {
1221 mout->dig_out_used = HDA_DIG_ANALOG_DUP;
1222 /* turn off SPDIF once; otherwise the IEC958 bits won't
1223 * be updated */
1224 if (codec->spdif_ctls & AC_DIG1_ENABLE)
1225 snd_hda_codec_write(codec, mout->dig_out_nid, 0,
1226 AC_VERB_SET_DIGI_CONVERT_1,
1227 codec->spdif_ctls &
1228 ~AC_DIG1_ENABLE & 0xff);
1229 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
1230 stream_tag, 0, format);
1231 /* turn on again (if needed) */
1232 if (codec->spdif_ctls & AC_DIG1_ENABLE)
1233 snd_hda_codec_write(codec, mout->dig_out_nid, 0,
1234 AC_VERB_SET_DIGI_CONVERT_1,
1235 codec->spdif_ctls & 0xff);
1236 } else {
1237 mout->dig_out_used = 0;
1238 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
1239 0, 0, 0);
1240 }
1241 }
1242 mutex_unlock(&codec->spdif_mutex);
1243
1244 /* front */
1245 snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag,
1246 0, format);
1247
Lydia Wangeb7188c2009-10-10 19:08:34 +08001248 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT]
1249 && !spec->hp_independent_mode)
Harald Welte0aa62ae2008-09-09 15:58:27 +08001250 /* headphone out will just decode front left/right (stereo) */
1251 snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag,
1252 0, format);
1253
1254 /* extra outputs copied from front */
1255 for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
1256 if (mout->extra_out_nid[i])
1257 snd_hda_codec_setup_stream(codec,
1258 mout->extra_out_nid[i],
1259 stream_tag, 0, format);
1260
1261 /* surrounds */
1262 for (i = 1; i < mout->num_dacs; i++) {
1263 if (chs >= (i + 1) * 2) /* independent out */
1264 snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
1265 i * 2, format);
1266 else /* copy front */
1267 snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
1268 0, format);
1269 }
1270}
1271
1272static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
1273 struct hda_codec *codec,
1274 unsigned int stream_tag,
1275 unsigned int format,
1276 struct snd_pcm_substream *substream)
1277{
1278 struct via_spec *spec = codec->spec;
1279 struct hda_multi_out *mout = &spec->multiout;
1280 hda_nid_t *nids = mout->dac_nids;
1281
1282 if (substream->number == 0)
1283 playback_multi_pcm_prep_0(codec, stream_tag, format,
1284 substream);
1285 else {
1286 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
1287 spec->hp_independent_mode)
1288 snd_hda_codec_setup_stream(codec, mout->hp_nid,
1289 stream_tag, 0, format);
1290 }
Lydia Wang1f2e99f2009-10-10 19:08:17 +08001291 vt1708_start_hp_work(spec);
Harald Welte0aa62ae2008-09-09 15:58:27 +08001292 return 0;
1293}
1294
1295static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
1296 struct hda_codec *codec,
1297 struct snd_pcm_substream *substream)
1298{
1299 struct via_spec *spec = codec->spec;
1300 struct hda_multi_out *mout = &spec->multiout;
1301 hda_nid_t *nids = mout->dac_nids;
1302 int i;
1303
1304 if (substream->number == 0) {
1305 for (i = 0; i < mout->num_dacs; i++)
1306 snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
1307
1308 if (mout->hp_nid && !spec->hp_independent_mode)
1309 snd_hda_codec_setup_stream(codec, mout->hp_nid,
1310 0, 0, 0);
1311
1312 for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
1313 if (mout->extra_out_nid[i])
1314 snd_hda_codec_setup_stream(codec,
1315 mout->extra_out_nid[i],
1316 0, 0, 0);
1317 mutex_lock(&codec->spdif_mutex);
1318 if (mout->dig_out_nid &&
1319 mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
1320 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
1321 0, 0, 0);
1322 mout->dig_out_used = 0;
1323 }
1324 mutex_unlock(&codec->spdif_mutex);
1325 } else {
1326 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
1327 spec->hp_independent_mode)
1328 snd_hda_codec_setup_stream(codec, mout->hp_nid,
1329 0, 0, 0);
1330 }
Lydia Wang1f2e99f2009-10-10 19:08:17 +08001331 vt1708_stop_hp_work(spec);
Harald Welte0aa62ae2008-09-09 15:58:27 +08001332 return 0;
1333}
1334
Joseph Chanc577b8a2006-11-29 15:29:40 +01001335/*
1336 * Digital out
1337 */
1338static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1339 struct hda_codec *codec,
1340 struct snd_pcm_substream *substream)
1341{
1342 struct via_spec *spec = codec->spec;
1343 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1344}
1345
1346static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1347 struct hda_codec *codec,
1348 struct snd_pcm_substream *substream)
1349{
1350 struct via_spec *spec = codec->spec;
1351 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1352}
1353
Harald Welte5691ec72008-09-15 22:42:26 +08001354static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
Harald Welte98aa34c2008-09-09 16:02:09 +08001355 struct hda_codec *codec,
1356 unsigned int stream_tag,
1357 unsigned int format,
1358 struct snd_pcm_substream *substream)
1359{
1360 struct via_spec *spec = codec->spec;
Takashi Iwai9da29272009-05-07 16:31:14 +02001361 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1362 stream_tag, format, substream);
1363}
Harald Welte5691ec72008-09-15 22:42:26 +08001364
Takashi Iwai9da29272009-05-07 16:31:14 +02001365static int via_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1366 struct hda_codec *codec,
1367 struct snd_pcm_substream *substream)
1368{
1369 struct via_spec *spec = codec->spec;
1370 snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
Harald Welte98aa34c2008-09-09 16:02:09 +08001371 return 0;
1372}
1373
Joseph Chanc577b8a2006-11-29 15:29:40 +01001374/*
1375 * Analog capture
1376 */
1377static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1378 struct hda_codec *codec,
1379 unsigned int stream_tag,
1380 unsigned int format,
1381 struct snd_pcm_substream *substream)
1382{
1383 struct via_spec *spec = codec->spec;
1384
1385 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1386 stream_tag, 0, format);
1387 return 0;
1388}
1389
1390static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1391 struct hda_codec *codec,
1392 struct snd_pcm_substream *substream)
1393{
1394 struct via_spec *spec = codec->spec;
Takashi Iwai888afa12008-03-18 09:57:50 +01001395 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001396 return 0;
1397}
1398
1399static struct hda_pcm_stream vt1708_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08001400 .substreams = 2,
Joseph Chanc577b8a2006-11-29 15:29:40 +01001401 .channels_min = 2,
1402 .channels_max = 8,
1403 .nid = 0x10, /* NID to query formats and rates */
1404 .ops = {
1405 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08001406 .prepare = via_playback_multi_pcm_prepare,
1407 .cleanup = via_playback_multi_pcm_cleanup
Joseph Chanc577b8a2006-11-29 15:29:40 +01001408 },
1409};
1410
Takashi Iwaibc9b5622008-05-23 17:50:27 +02001411static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
Lydia Wangc873cc22009-10-10 19:08:21 +08001412 .substreams = 2,
Takashi Iwaibc9b5622008-05-23 17:50:27 +02001413 .channels_min = 2,
1414 .channels_max = 8,
1415 .nid = 0x10, /* NID to query formats and rates */
1416 /* We got noisy outputs on the right channel on VT1708 when
1417 * 24bit samples are used. Until any workaround is found,
1418 * disable the 24bit format, so far.
1419 */
1420 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1421 .ops = {
1422 .open = via_playback_pcm_open,
Lydia Wangc873cc22009-10-10 19:08:21 +08001423 .prepare = via_playback_multi_pcm_prepare,
1424 .cleanup = via_playback_multi_pcm_cleanup
Takashi Iwaibc9b5622008-05-23 17:50:27 +02001425 },
1426};
1427
Joseph Chanc577b8a2006-11-29 15:29:40 +01001428static struct hda_pcm_stream vt1708_pcm_analog_capture = {
1429 .substreams = 2,
1430 .channels_min = 2,
1431 .channels_max = 2,
1432 .nid = 0x15, /* NID to query formats and rates */
1433 .ops = {
1434 .prepare = via_capture_pcm_prepare,
1435 .cleanup = via_capture_pcm_cleanup
1436 },
1437};
1438
1439static struct hda_pcm_stream vt1708_pcm_digital_playback = {
1440 .substreams = 1,
1441 .channels_min = 2,
1442 .channels_max = 2,
1443 /* NID is set in via_build_pcms */
1444 .ops = {
1445 .open = via_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001446 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02001447 .prepare = via_dig_playback_pcm_prepare,
1448 .cleanup = via_dig_playback_pcm_cleanup
Joseph Chanc577b8a2006-11-29 15:29:40 +01001449 },
1450};
1451
1452static struct hda_pcm_stream vt1708_pcm_digital_capture = {
1453 .substreams = 1,
1454 .channels_min = 2,
1455 .channels_max = 2,
1456};
1457
1458static int via_build_controls(struct hda_codec *codec)
1459{
1460 struct via_spec *spec = codec->spec;
1461 int err;
1462 int i;
1463
1464 for (i = 0; i < spec->num_mixers; i++) {
1465 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1466 if (err < 0)
1467 return err;
1468 }
1469
1470 if (spec->multiout.dig_out_nid) {
1471 err = snd_hda_create_spdif_out_ctls(codec,
1472 spec->multiout.dig_out_nid);
1473 if (err < 0)
1474 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001475 err = snd_hda_create_spdif_share_sw(codec,
1476 &spec->multiout);
1477 if (err < 0)
1478 return err;
1479 spec->multiout.share_spdif = 1;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001480 }
1481 if (spec->dig_in_nid) {
1482 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1483 if (err < 0)
1484 return err;
1485 }
Lydia Wang17314372009-10-10 19:07:37 +08001486
1487 /* init power states */
1488 set_jack_power_state(codec);
1489 analog_low_current_mode(codec, 1);
1490
Takashi Iwai603c4012008-07-30 15:01:44 +02001491 via_free_kctls(codec); /* no longer needed */
Joseph Chanc577b8a2006-11-29 15:29:40 +01001492 return 0;
1493}
1494
1495static int via_build_pcms(struct hda_codec *codec)
1496{
1497 struct via_spec *spec = codec->spec;
1498 struct hda_pcm *info = spec->pcm_rec;
1499
1500 codec->num_pcms = 1;
1501 codec->pcm_info = info;
1502
1503 info->name = spec->stream_name_analog;
1504 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
1505 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
1506 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
1507 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
1508
1509 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
1510 spec->multiout.max_channels;
1511
1512 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1513 codec->num_pcms++;
1514 info++;
1515 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01001516 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001517 if (spec->multiout.dig_out_nid) {
1518 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
1519 *(spec->stream_digital_playback);
1520 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
1521 spec->multiout.dig_out_nid;
1522 }
1523 if (spec->dig_in_nid) {
1524 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
1525 *(spec->stream_digital_capture);
1526 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
1527 spec->dig_in_nid;
1528 }
1529 }
1530
1531 return 0;
1532}
1533
1534static void via_free(struct hda_codec *codec)
1535{
1536 struct via_spec *spec = codec->spec;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001537
1538 if (!spec)
1539 return;
1540
Takashi Iwai603c4012008-07-30 15:01:44 +02001541 via_free_kctls(codec);
Lydia Wang1f2e99f2009-10-10 19:08:17 +08001542 vt1708_stop_hp_work(spec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001543 kfree(codec->spec);
1544}
1545
Harald Welte69e52a82008-09-09 15:57:32 +08001546/* mute internal speaker if HP is plugged */
1547static void via_hp_automute(struct hda_codec *codec)
1548{
Lydia Wangdcf34c82009-10-10 19:08:15 +08001549 unsigned int present = 0;
Harald Welte69e52a82008-09-09 15:57:32 +08001550 struct via_spec *spec = codec->spec;
1551
1552 present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
1553 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Lydia Wangdcf34c82009-10-10 19:08:15 +08001554
1555 if (!spec->hp_independent_mode) {
1556 struct snd_ctl_elem_id id;
1557 /* auto mute */
1558 snd_hda_codec_amp_stereo(
1559 codec, spec->autocfg.line_out_pins[0], HDA_OUTPUT, 0,
1560 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
1561 /* notify change */
1562 memset(&id, 0, sizeof(id));
1563 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1564 strcpy(id.name, "Front Playback Switch");
1565 snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
1566 &id);
1567 }
Harald Welte69e52a82008-09-09 15:57:32 +08001568}
1569
Lydia Wangf3db4232009-10-10 19:08:41 +08001570/* mute mono out if HP or Line out is plugged */
1571static void via_mono_automute(struct hda_codec *codec)
1572{
1573 unsigned int hp_present, lineout_present;
1574 struct via_spec *spec = codec->spec;
1575
1576 if (spec->codec_type != VT1716S)
1577 return;
1578
1579 lineout_present = snd_hda_codec_read(
1580 codec, spec->autocfg.line_out_pins[0], 0,
1581 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1582
1583 /* Mute Mono Out if Line Out is plugged */
1584 if (lineout_present) {
1585 snd_hda_codec_amp_stereo(
1586 codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE, HDA_AMP_MUTE);
1587 return;
1588 }
1589
1590 hp_present = snd_hda_codec_read(
1591 codec, spec->autocfg.hp_pins[0], 0,
1592 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1593
1594 if (!spec->hp_independent_mode)
1595 snd_hda_codec_amp_stereo(
1596 codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE,
1597 hp_present ? HDA_AMP_MUTE : 0);
1598}
1599
Harald Welte69e52a82008-09-09 15:57:32 +08001600static void via_gpio_control(struct hda_codec *codec)
1601{
1602 unsigned int gpio_data;
1603 unsigned int vol_counter;
1604 unsigned int vol;
1605 unsigned int master_vol;
1606
1607 struct via_spec *spec = codec->spec;
1608
1609 gpio_data = snd_hda_codec_read(codec, codec->afg, 0,
1610 AC_VERB_GET_GPIO_DATA, 0) & 0x03;
1611
1612 vol_counter = (snd_hda_codec_read(codec, codec->afg, 0,
1613 0xF84, 0) & 0x3F0000) >> 16;
1614
1615 vol = vol_counter & 0x1F;
1616 master_vol = snd_hda_codec_read(codec, 0x1A, 0,
1617 AC_VERB_GET_AMP_GAIN_MUTE,
1618 AC_AMP_GET_INPUT);
1619
1620 if (gpio_data == 0x02) {
1621 /* unmute line out */
1622 snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
1623 HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
1624
1625 if (vol_counter & 0x20) {
1626 /* decrease volume */
1627 if (vol > master_vol)
1628 vol = master_vol;
1629 snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT,
1630 0, HDA_AMP_VOLMASK,
1631 master_vol-vol);
1632 } else {
1633 /* increase volume */
1634 snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, 0,
1635 HDA_AMP_VOLMASK,
1636 ((master_vol+vol) > 0x2A) ? 0x2A :
1637 (master_vol+vol));
1638 }
1639 } else if (!(gpio_data & 0x02)) {
1640 /* mute line out */
1641 snd_hda_codec_amp_stereo(codec,
1642 spec->autocfg.line_out_pins[0],
1643 HDA_OUTPUT, 0, HDA_AMP_MUTE,
1644 HDA_AMP_MUTE);
1645 }
1646}
1647
1648/* unsolicited event for jack sensing */
1649static void via_unsol_event(struct hda_codec *codec,
1650 unsigned int res)
1651{
1652 res >>= 26;
Lydia Wanga34df192009-10-10 19:08:01 +08001653 if (res & VIA_HP_EVENT)
Harald Welte69e52a82008-09-09 15:57:32 +08001654 via_hp_automute(codec);
Lydia Wanga34df192009-10-10 19:08:01 +08001655 if (res & VIA_GPIO_EVENT)
Harald Welte69e52a82008-09-09 15:57:32 +08001656 via_gpio_control(codec);
Lydia Wanga34df192009-10-10 19:08:01 +08001657 if (res & VIA_JACK_EVENT)
1658 set_jack_power_state(codec);
Lydia Wangf3db4232009-10-10 19:08:41 +08001659 if (res & VIA_MONO_EVENT)
1660 via_mono_automute(codec);
Harald Welte69e52a82008-09-09 15:57:32 +08001661}
1662
Joseph Chanc577b8a2006-11-29 15:29:40 +01001663static int via_init(struct hda_codec *codec)
1664{
1665 struct via_spec *spec = codec->spec;
Harald Welte69e52a82008-09-09 15:57:32 +08001666 int i;
1667 for (i = 0; i < spec->num_iverbs; i++)
1668 snd_hda_sequence_write(codec, spec->init_verbs[i]);
1669
Lydia Wang518bf3b2009-10-10 19:07:29 +08001670 spec->codec_type = get_codec_type(codec);
1671 if (spec->codec_type == VT1708BCE)
1672 spec->codec_type = VT1708S; /* VT1708BCE & VT1708S are almost
1673 same */
Josepch Chanf7278fd2007-12-13 16:40:40 +01001674 /* Lydia Add for EAPD enable */
1675 if (!spec->dig_in_nid) { /* No Digital In connection */
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02001676 if (spec->dig_in_pin) {
1677 snd_hda_codec_write(codec, spec->dig_in_pin, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001678 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +01001679 PIN_OUT);
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02001680 snd_hda_codec_write(codec, spec->dig_in_pin, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001681 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
1682 }
Takashi Iwai12b74c82008-01-15 12:39:38 +01001683 } else /* enable SPDIF-input pin */
1684 snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
1685 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
Josepch Chanf7278fd2007-12-13 16:40:40 +01001686
Takashi Iwai9da29272009-05-07 16:31:14 +02001687 /* assign slave outs */
1688 if (spec->slave_dig_outs[0])
1689 codec->slave_dig_outs = spec->slave_dig_outs;
Harald Welte5691ec72008-09-15 22:42:26 +08001690
Joseph Chanc577b8a2006-11-29 15:29:40 +01001691 return 0;
1692}
1693
Lydia Wang1f2e99f2009-10-10 19:08:17 +08001694#ifdef SND_HDA_NEEDS_RESUME
1695static int via_suspend(struct hda_codec *codec, pm_message_t state)
1696{
1697 struct via_spec *spec = codec->spec;
1698 vt1708_stop_hp_work(spec);
1699 return 0;
1700}
1701#endif
1702
Takashi Iwaicb53c622007-08-10 17:21:45 +02001703#ifdef CONFIG_SND_HDA_POWER_SAVE
1704static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
1705{
1706 struct via_spec *spec = codec->spec;
1707 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
1708}
1709#endif
1710
Joseph Chanc577b8a2006-11-29 15:29:40 +01001711/*
1712 */
1713static struct hda_codec_ops via_patch_ops = {
1714 .build_controls = via_build_controls,
1715 .build_pcms = via_build_pcms,
1716 .init = via_init,
1717 .free = via_free,
Lydia Wang1f2e99f2009-10-10 19:08:17 +08001718#ifdef SND_HDA_NEEDS_RESUME
1719 .suspend = via_suspend,
1720#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02001721#ifdef CONFIG_SND_HDA_POWER_SAVE
1722 .check_power_status = via_check_power_status,
1723#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01001724};
1725
1726/* fill in the dac_nids table from the parsed pin configuration */
1727static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
1728 const struct auto_pin_cfg *cfg)
1729{
1730 int i;
1731 hda_nid_t nid;
1732
1733 spec->multiout.num_dacs = cfg->line_outs;
1734
1735 spec->multiout.dac_nids = spec->private_dac_nids;
1736
1737 for(i = 0; i < 4; i++) {
1738 nid = cfg->line_out_pins[i];
1739 if (nid) {
1740 /* config dac list */
1741 switch (i) {
1742 case AUTO_SEQ_FRONT:
1743 spec->multiout.dac_nids[i] = 0x10;
1744 break;
1745 case AUTO_SEQ_CENLFE:
1746 spec->multiout.dac_nids[i] = 0x12;
1747 break;
1748 case AUTO_SEQ_SURROUND:
Harald Weltefb4cb772008-09-09 15:53:36 +08001749 spec->multiout.dac_nids[i] = 0x11;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001750 break;
1751 case AUTO_SEQ_SIDE:
Harald Weltefb4cb772008-09-09 15:53:36 +08001752 spec->multiout.dac_nids[i] = 0x13;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001753 break;
1754 }
1755 }
1756 }
1757
1758 return 0;
1759}
1760
1761/* add playback controls from the parsed DAC table */
1762static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
1763 const struct auto_pin_cfg *cfg)
1764{
1765 char name[32];
1766 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
Lydia Wang9645c202009-10-10 19:08:27 +08001767 hda_nid_t nid, nid_vol, nid_vols[] = {0x17, 0x19, 0x1a, 0x1b};
Joseph Chanc577b8a2006-11-29 15:29:40 +01001768 int i, err;
1769
1770 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
1771 nid = cfg->line_out_pins[i];
1772
1773 if (!nid)
1774 continue;
1775
Lydia Wang9645c202009-10-10 19:08:27 +08001776 nid_vol = nid_vols[i];
Joseph Chanc577b8a2006-11-29 15:29:40 +01001777
1778 if (i == AUTO_SEQ_CENLFE) {
1779 /* Center/LFE */
1780 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001781 "Center Playback Volume",
1782 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1783 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001784 if (err < 0)
1785 return err;
1786 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1787 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001788 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1789 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001790 if (err < 0)
1791 return err;
1792 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1793 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001794 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
1795 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001796 if (err < 0)
1797 return err;
1798 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1799 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01001800 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
1801 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001802 if (err < 0)
1803 return err;
1804 } else if (i == AUTO_SEQ_FRONT){
1805 /* add control to mixer index 0 */
1806 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1807 "Master Front Playback Volume",
Lydia Wang9645c202009-10-10 19:08:27 +08001808 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001809 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001810 if (err < 0)
1811 return err;
1812 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1813 "Master Front Playback Switch",
Lydia Wang9645c202009-10-10 19:08:27 +08001814 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001815 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001816 if (err < 0)
1817 return err;
1818
1819 /* add control to PW3 */
1820 sprintf(name, "%s Playback Volume", chname[i]);
1821 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001822 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1823 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001824 if (err < 0)
1825 return err;
1826 sprintf(name, "%s Playback Switch", chname[i]);
1827 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001828 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
1829 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001830 if (err < 0)
1831 return err;
1832 } else {
1833 sprintf(name, "%s Playback Volume", chname[i]);
1834 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001835 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1836 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001837 if (err < 0)
1838 return err;
1839 sprintf(name, "%s Playback Switch", chname[i]);
1840 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01001841 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
1842 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01001843 if (err < 0)
1844 return err;
1845 }
1846 }
1847
1848 return 0;
1849}
1850
Harald Welte0aa62ae2008-09-09 15:58:27 +08001851static void create_hp_imux(struct via_spec *spec)
1852{
1853 int i;
1854 struct hda_input_mux *imux = &spec->private_imux[1];
1855 static const char *texts[] = { "OFF", "ON", NULL};
1856
1857 /* for hp mode select */
1858 i = 0;
1859 while (texts[i] != NULL) {
1860 imux->items[imux->num_items].label = texts[i];
1861 imux->items[imux->num_items].index = i;
1862 imux->num_items++;
1863 i++;
1864 }
1865
1866 spec->hp_mux = &spec->private_imux[1];
1867}
1868
Joseph Chanc577b8a2006-11-29 15:29:40 +01001869static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
1870{
1871 int err;
1872
1873 if (!pin)
1874 return 0;
1875
1876 spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
Lydia Wangcdc17842009-10-10 19:07:47 +08001877 spec->hp_independent_mode_index = 1;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001878
1879 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
1880 "Headphone Playback Volume",
1881 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1882 if (err < 0)
1883 return err;
1884 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
1885 "Headphone Playback Switch",
1886 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
1887 if (err < 0)
1888 return err;
1889
Harald Welte0aa62ae2008-09-09 15:58:27 +08001890 create_hp_imux(spec);
1891
Joseph Chanc577b8a2006-11-29 15:29:40 +01001892 return 0;
1893}
1894
1895/* create playback/capture controls for input pins */
1896static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
1897 const struct auto_pin_cfg *cfg)
1898{
1899 static char *labels[] = {
1900 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
1901 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08001902 struct hda_input_mux *imux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01001903 int i, err, idx = 0;
1904
1905 /* for internal loopback recording select */
1906 imux->items[imux->num_items].label = "Stereo Mixer";
1907 imux->items[imux->num_items].index = idx;
1908 imux->num_items++;
1909
1910 for (i = 0; i < AUTO_PIN_LAST; i++) {
1911 if (!cfg->input_pins[i])
1912 continue;
1913
1914 switch (cfg->input_pins[i]) {
1915 case 0x1d: /* Mic */
1916 idx = 2;
1917 break;
1918
1919 case 0x1e: /* Line In */
1920 idx = 3;
1921 break;
1922
1923 case 0x21: /* Front Mic */
1924 idx = 4;
1925 break;
1926
1927 case 0x24: /* CD */
1928 idx = 1;
1929 break;
1930 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08001931 err = via_new_analog_input(spec, labels[i], idx, 0x17);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001932 if (err < 0)
1933 return err;
1934 imux->items[imux->num_items].label = labels[i];
1935 imux->items[imux->num_items].index = idx;
1936 imux->num_items++;
1937 }
1938 return 0;
1939}
1940
Takashi Iwaicb53c622007-08-10 17:21:45 +02001941#ifdef CONFIG_SND_HDA_POWER_SAVE
1942static struct hda_amp_list vt1708_loopbacks[] = {
1943 { 0x17, HDA_INPUT, 1 },
1944 { 0x17, HDA_INPUT, 2 },
1945 { 0x17, HDA_INPUT, 3 },
1946 { 0x17, HDA_INPUT, 4 },
1947 { } /* end */
1948};
1949#endif
1950
Harald Welte76d9b0d2008-09-09 15:50:37 +08001951static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
1952{
1953 unsigned int def_conf;
1954 unsigned char seqassoc;
1955
Takashi Iwai2f334f92009-02-20 14:37:42 +01001956 def_conf = snd_hda_codec_get_pincfg(codec, nid);
Harald Welte76d9b0d2008-09-09 15:50:37 +08001957 seqassoc = (unsigned char) get_defcfg_association(def_conf);
1958 seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
Lydia Wang82ef9e42009-10-10 19:08:19 +08001959 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE
1960 && (seqassoc == 0xf0 || seqassoc == 0xff)) {
1961 def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
1962 snd_hda_codec_set_pincfg(codec, nid, def_conf);
Harald Welte76d9b0d2008-09-09 15:50:37 +08001963 }
1964
1965 return;
1966}
1967
Lydia Wang1f2e99f2009-10-10 19:08:17 +08001968static int vt1708_jack_detectect_get(struct snd_kcontrol *kcontrol,
1969 struct snd_ctl_elem_value *ucontrol)
1970{
1971 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1972 struct via_spec *spec = codec->spec;
1973
1974 if (spec->codec_type != VT1708)
1975 return 0;
1976 spec->vt1708_jack_detectect =
1977 !((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1);
1978 ucontrol->value.integer.value[0] = spec->vt1708_jack_detectect;
1979 return 0;
1980}
1981
1982static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol,
1983 struct snd_ctl_elem_value *ucontrol)
1984{
1985 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1986 struct via_spec *spec = codec->spec;
1987 int change;
1988
1989 if (spec->codec_type != VT1708)
1990 return 0;
1991 spec->vt1708_jack_detectect = ucontrol->value.integer.value[0];
1992 change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8))
1993 == !spec->vt1708_jack_detectect;
1994 if (spec->vt1708_jack_detectect) {
1995 mute_aa_path(codec, 1);
1996 notify_aa_path_ctls(codec);
1997 }
1998 return change;
1999}
2000
2001static struct snd_kcontrol_new vt1708_jack_detectect[] = {
2002 {
2003 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2004 .name = "Jack Detect",
2005 .count = 1,
2006 .info = snd_ctl_boolean_mono_info,
2007 .get = vt1708_jack_detectect_get,
2008 .put = vt1708_jack_detectect_put,
2009 },
2010 {} /* end */
2011};
2012
Joseph Chanc577b8a2006-11-29 15:29:40 +01002013static int vt1708_parse_auto_config(struct hda_codec *codec)
2014{
2015 struct via_spec *spec = codec->spec;
2016 int err;
2017
Harald Welte76d9b0d2008-09-09 15:50:37 +08002018 /* Add HP and CD pin config connect bit re-config action */
2019 vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
2020 vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
2021
Joseph Chanc577b8a2006-11-29 15:29:40 +01002022 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
2023 if (err < 0)
2024 return err;
2025 err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
2026 if (err < 0)
2027 return err;
2028 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2029 return 0; /* can't find valid BIOS pin config */
2030
2031 err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
2032 if (err < 0)
2033 return err;
2034 err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2035 if (err < 0)
2036 return err;
2037 err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
2038 if (err < 0)
2039 return err;
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002040 /* add jack detect on/off control */
2041 err = snd_hda_add_new_ctls(codec, vt1708_jack_detectect);
2042 if (err < 0)
2043 return err;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002044
2045 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2046
Takashi Iwai0852d7a2009-02-11 11:35:15 +01002047 if (spec->autocfg.dig_outs)
Joseph Chanc577b8a2006-11-29 15:29:40 +01002048 spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02002049 spec->dig_in_pin = VT1708_DIGIN_PIN;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002050 if (spec->autocfg.dig_in_pin)
2051 spec->dig_in_nid = VT1708_DIGIN_NID;
2052
Takashi Iwai603c4012008-07-30 15:01:44 +02002053 if (spec->kctls.list)
2054 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002055
Harald Welte69e52a82008-09-09 15:57:32 +08002056 spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002057
Harald Welte0aa62ae2008-09-09 15:58:27 +08002058 spec->input_mux = &spec->private_imux[0];
2059
Harald Weltef8fdd492008-09-15 22:41:31 +08002060 if (spec->hp_mux)
2061 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002062
Lydia Wang1564b282009-10-10 19:07:52 +08002063 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002064 return 1;
2065}
2066
2067/* init callback for auto-configuration model -- overriding the default init */
2068static int via_auto_init(struct hda_codec *codec)
2069{
2070 via_init(codec);
2071 via_auto_init_multi_out(codec);
2072 via_auto_init_hp_out(codec);
2073 via_auto_init_analog_input(codec);
2074 return 0;
2075}
2076
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002077static void vt1708_update_hp_jack_state(struct work_struct *work)
2078{
2079 struct via_spec *spec = container_of(work, struct via_spec,
2080 vt1708_hp_work.work);
2081 if (spec->codec_type != VT1708)
2082 return;
2083 /* if jack state toggled */
2084 if (spec->vt1708_hp_present
2085 != (snd_hda_codec_read(spec->codec, spec->autocfg.hp_pins[0], 0,
2086 AC_VERB_GET_PIN_SENSE, 0) >> 31)) {
2087 spec->vt1708_hp_present ^= 1;
2088 via_hp_automute(spec->codec);
2089 }
2090 vt1708_start_hp_work(spec);
2091}
2092
Takashi Iwai337b9d02009-07-07 18:18:59 +02002093static int get_mux_nids(struct hda_codec *codec)
2094{
2095 struct via_spec *spec = codec->spec;
2096 hda_nid_t nid, conn[8];
2097 unsigned int type;
2098 int i, n;
2099
2100 for (i = 0; i < spec->num_adc_nids; i++) {
2101 nid = spec->adc_nids[i];
2102 while (nid) {
Takashi Iwaia22d5432009-07-27 12:54:26 +02002103 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai1c55d522009-07-08 07:45:46 +02002104 if (type == AC_WID_PIN)
2105 break;
Takashi Iwai337b9d02009-07-07 18:18:59 +02002106 n = snd_hda_get_connections(codec, nid, conn,
2107 ARRAY_SIZE(conn));
2108 if (n <= 0)
2109 break;
2110 if (n > 1) {
2111 spec->mux_nids[i] = nid;
2112 break;
2113 }
2114 nid = conn[0];
2115 }
2116 }
Takashi Iwai1c55d522009-07-08 07:45:46 +02002117 return 0;
Takashi Iwai337b9d02009-07-07 18:18:59 +02002118}
2119
Joseph Chanc577b8a2006-11-29 15:29:40 +01002120static int patch_vt1708(struct hda_codec *codec)
2121{
2122 struct via_spec *spec;
2123 int err;
2124
2125 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08002126 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002127 if (spec == NULL)
2128 return -ENOMEM;
2129
2130 codec->spec = spec;
2131
2132 /* automatic parse from the BIOS config */
2133 err = vt1708_parse_auto_config(codec);
2134 if (err < 0) {
2135 via_free(codec);
2136 return err;
2137 } else if (!err) {
2138 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2139 "from BIOS. Using genenic mode...\n");
2140 }
2141
2142
2143 spec->stream_name_analog = "VT1708 Analog";
2144 spec->stream_analog_playback = &vt1708_pcm_analog_playback;
Takashi Iwaibc9b5622008-05-23 17:50:27 +02002145 /* disable 32bit format on VT1708 */
2146 if (codec->vendor_id == 0x11061708)
2147 spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002148 spec->stream_analog_capture = &vt1708_pcm_analog_capture;
2149
2150 spec->stream_name_digital = "VT1708 Digital";
2151 spec->stream_digital_playback = &vt1708_pcm_digital_playback;
2152 spec->stream_digital_capture = &vt1708_pcm_digital_capture;
2153
2154
2155 if (!spec->adc_nids && spec->input_mux) {
2156 spec->adc_nids = vt1708_adc_nids;
2157 spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
Takashi Iwai0f67a612009-08-31 08:12:29 +02002158 get_mux_nids(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002159 spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
2160 spec->num_mixers++;
2161 }
2162
2163 codec->patch_ops = via_patch_ops;
2164
2165 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02002166#ifdef CONFIG_SND_HDA_POWER_SAVE
2167 spec->loopback.amplist = vt1708_loopbacks;
2168#endif
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002169 spec->codec = codec;
2170 INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002171 return 0;
2172}
2173
2174/* capture mixer elements */
2175static struct snd_kcontrol_new vt1709_capture_mixer[] = {
2176 HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
2177 HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
2178 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
2179 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
2180 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
2181 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
2182 {
2183 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2184 /* The multiple "Capture Source" controls confuse alsamixer
2185 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +01002186 */
2187 /* .name = "Capture Source", */
2188 .name = "Input Source",
2189 .count = 1,
2190 .info = via_mux_enum_info,
2191 .get = via_mux_enum_get,
2192 .put = via_mux_enum_put,
2193 },
2194 { } /* end */
2195};
2196
Harald Welte69e52a82008-09-09 15:57:32 +08002197static struct hda_verb vt1709_uniwill_init_verbs[] = {
Lydia Wanga34df192009-10-10 19:08:01 +08002198 {0x20, AC_VERB_SET_UNSOLICITED_ENABLE,
2199 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
Harald Welte69e52a82008-09-09 15:57:32 +08002200 { }
2201};
2202
Joseph Chanc577b8a2006-11-29 15:29:40 +01002203/*
2204 * generic initialization of ADC, input mixers and output mixers
2205 */
2206static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
2207 /*
2208 * Unmute ADC0-2 and set the default input to mic-in
2209 */
2210 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2211 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2212 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2213
2214
Josepch Chanf7278fd2007-12-13 16:40:40 +01002215 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +01002216 * mixer widget
2217 */
2218 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +01002219 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2220 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2221 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2222 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2223 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +01002224
2225 /*
2226 * Set up output selector (0x1a, 0x1b, 0x29)
2227 */
2228 /* set vol=0 to output mixers */
2229 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2230 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2231 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2232
2233 /*
2234 * Unmute PW3 and PW4
2235 */
2236 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2237 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2238
2239 /* Set input of PW4 as AOW4 */
2240 {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
Joseph Chanc577b8a2006-11-29 15:29:40 +01002241 /* PW9 Output enable */
2242 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2243 { }
2244};
2245
2246static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
2247 .substreams = 1,
2248 .channels_min = 2,
2249 .channels_max = 10,
2250 .nid = 0x10, /* NID to query formats and rates */
2251 .ops = {
2252 .open = via_playback_pcm_open,
Lydia Wangc873cc22009-10-10 19:08:21 +08002253 .prepare = via_playback_multi_pcm_prepare,
2254 .cleanup = via_playback_multi_pcm_cleanup,
Joseph Chanc577b8a2006-11-29 15:29:40 +01002255 },
2256};
2257
2258static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
2259 .substreams = 1,
2260 .channels_min = 2,
2261 .channels_max = 6,
2262 .nid = 0x10, /* NID to query formats and rates */
2263 .ops = {
2264 .open = via_playback_pcm_open,
Lydia Wangc873cc22009-10-10 19:08:21 +08002265 .prepare = via_playback_multi_pcm_prepare,
2266 .cleanup = via_playback_multi_pcm_cleanup,
Joseph Chanc577b8a2006-11-29 15:29:40 +01002267 },
2268};
2269
2270static struct hda_pcm_stream vt1709_pcm_analog_capture = {
2271 .substreams = 2,
2272 .channels_min = 2,
2273 .channels_max = 2,
2274 .nid = 0x14, /* NID to query formats and rates */
2275 .ops = {
2276 .prepare = via_capture_pcm_prepare,
2277 .cleanup = via_capture_pcm_cleanup
2278 },
2279};
2280
2281static struct hda_pcm_stream vt1709_pcm_digital_playback = {
2282 .substreams = 1,
2283 .channels_min = 2,
2284 .channels_max = 2,
2285 /* NID is set in via_build_pcms */
2286 .ops = {
2287 .open = via_dig_playback_pcm_open,
2288 .close = via_dig_playback_pcm_close
2289 },
2290};
2291
2292static struct hda_pcm_stream vt1709_pcm_digital_capture = {
2293 .substreams = 1,
2294 .channels_min = 2,
2295 .channels_max = 2,
2296};
2297
2298static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
2299 const struct auto_pin_cfg *cfg)
2300{
2301 int i;
2302 hda_nid_t nid;
2303
2304 if (cfg->line_outs == 4) /* 10 channels */
2305 spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
2306 else if (cfg->line_outs == 3) /* 6 channels */
2307 spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
2308
2309 spec->multiout.dac_nids = spec->private_dac_nids;
2310
2311 if (cfg->line_outs == 4) { /* 10 channels */
2312 for (i = 0; i < cfg->line_outs; i++) {
2313 nid = cfg->line_out_pins[i];
2314 if (nid) {
2315 /* config dac list */
2316 switch (i) {
2317 case AUTO_SEQ_FRONT:
2318 /* AOW0 */
2319 spec->multiout.dac_nids[i] = 0x10;
2320 break;
2321 case AUTO_SEQ_CENLFE:
2322 /* AOW2 */
2323 spec->multiout.dac_nids[i] = 0x12;
2324 break;
2325 case AUTO_SEQ_SURROUND:
2326 /* AOW3 */
Harald Weltefb4cb772008-09-09 15:53:36 +08002327 spec->multiout.dac_nids[i] = 0x11;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002328 break;
2329 case AUTO_SEQ_SIDE:
2330 /* AOW1 */
Harald Weltefb4cb772008-09-09 15:53:36 +08002331 spec->multiout.dac_nids[i] = 0x27;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002332 break;
2333 default:
2334 break;
2335 }
2336 }
2337 }
2338 spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
2339
2340 } else if (cfg->line_outs == 3) { /* 6 channels */
2341 for(i = 0; i < cfg->line_outs; i++) {
2342 nid = cfg->line_out_pins[i];
2343 if (nid) {
2344 /* config dac list */
2345 switch(i) {
2346 case AUTO_SEQ_FRONT:
2347 /* AOW0 */
2348 spec->multiout.dac_nids[i] = 0x10;
2349 break;
2350 case AUTO_SEQ_CENLFE:
2351 /* AOW2 */
2352 spec->multiout.dac_nids[i] = 0x12;
2353 break;
2354 case AUTO_SEQ_SURROUND:
2355 /* AOW1 */
2356 spec->multiout.dac_nids[i] = 0x11;
2357 break;
2358 default:
2359 break;
2360 }
2361 }
2362 }
2363 }
2364
2365 return 0;
2366}
2367
2368/* add playback controls from the parsed DAC table */
2369static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
2370 const struct auto_pin_cfg *cfg)
2371{
2372 char name[32];
2373 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
Lydia Wang4483a2f2009-10-10 19:08:29 +08002374 hda_nid_t nid, nid_vol, nid_vols[] = {0x18, 0x1a, 0x1b, 0x29};
Joseph Chanc577b8a2006-11-29 15:29:40 +01002375 int i, err;
2376
2377 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2378 nid = cfg->line_out_pins[i];
2379
2380 if (!nid)
2381 continue;
2382
Lydia Wang4483a2f2009-10-10 19:08:29 +08002383 nid_vol = nid_vols[i];
2384
Joseph Chanc577b8a2006-11-29 15:29:40 +01002385 if (i == AUTO_SEQ_CENLFE) {
2386 /* Center/LFE */
2387 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2388 "Center Playback Volume",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002389 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002390 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002391 if (err < 0)
2392 return err;
2393 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2394 "LFE Playback Volume",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002395 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002396 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002397 if (err < 0)
2398 return err;
2399 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2400 "Center Playback Switch",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002401 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002402 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002403 if (err < 0)
2404 return err;
2405 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2406 "LFE Playback Switch",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002407 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002408 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002409 if (err < 0)
2410 return err;
2411 } else if (i == AUTO_SEQ_FRONT){
Lydia Wang4483a2f2009-10-10 19:08:29 +08002412 /* ADD control to mixer index 0 */
Joseph Chanc577b8a2006-11-29 15:29:40 +01002413 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2414 "Master Front Playback Volume",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002415 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002416 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002417 if (err < 0)
2418 return err;
2419 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2420 "Master Front Playback Switch",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002421 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002422 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002423 if (err < 0)
2424 return err;
2425
2426 /* add control to PW3 */
2427 sprintf(name, "%s Playback Volume", chname[i]);
2428 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002429 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2430 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002431 if (err < 0)
2432 return err;
2433 sprintf(name, "%s Playback Switch", chname[i]);
2434 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002435 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2436 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002437 if (err < 0)
2438 return err;
2439 } else if (i == AUTO_SEQ_SURROUND) {
2440 sprintf(name, "%s Playback Volume", chname[i]);
2441 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Lydia Wang4483a2f2009-10-10 19:08:29 +08002442 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002443 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002444 if (err < 0)
2445 return err;
2446 sprintf(name, "%s Playback Switch", chname[i]);
2447 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Lydia Wang4483a2f2009-10-10 19:08:29 +08002448 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002449 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002450 if (err < 0)
2451 return err;
2452 } else if (i == AUTO_SEQ_SIDE) {
2453 sprintf(name, "%s Playback Volume", chname[i]);
2454 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Lydia Wang4483a2f2009-10-10 19:08:29 +08002455 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002456 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002457 if (err < 0)
2458 return err;
2459 sprintf(name, "%s Playback Switch", chname[i]);
2460 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Lydia Wang4483a2f2009-10-10 19:08:29 +08002461 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002462 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002463 if (err < 0)
2464 return err;
2465 }
2466 }
2467
2468 return 0;
2469}
2470
2471static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2472{
2473 int err;
2474
2475 if (!pin)
2476 return 0;
2477
2478 if (spec->multiout.num_dacs == 5) /* 10 channels */
2479 spec->multiout.hp_nid = VT1709_HP_DAC_NID;
2480 else if (spec->multiout.num_dacs == 3) /* 6 channels */
2481 spec->multiout.hp_nid = 0;
Lydia Wangcdc17842009-10-10 19:07:47 +08002482 spec->hp_independent_mode_index = 1;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002483
2484 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2485 "Headphone Playback Volume",
2486 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2487 if (err < 0)
2488 return err;
2489 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2490 "Headphone Playback Switch",
2491 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2492 if (err < 0)
2493 return err;
2494
2495 return 0;
2496}
2497
2498/* create playback/capture controls for input pins */
2499static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
2500 const struct auto_pin_cfg *cfg)
2501{
2502 static char *labels[] = {
2503 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2504 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08002505 struct hda_input_mux *imux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01002506 int i, err, idx = 0;
2507
2508 /* for internal loopback recording select */
2509 imux->items[imux->num_items].label = "Stereo Mixer";
2510 imux->items[imux->num_items].index = idx;
2511 imux->num_items++;
2512
2513 for (i = 0; i < AUTO_PIN_LAST; i++) {
2514 if (!cfg->input_pins[i])
2515 continue;
2516
2517 switch (cfg->input_pins[i]) {
2518 case 0x1d: /* Mic */
2519 idx = 2;
2520 break;
2521
2522 case 0x1e: /* Line In */
2523 idx = 3;
2524 break;
2525
2526 case 0x21: /* Front Mic */
2527 idx = 4;
2528 break;
2529
2530 case 0x23: /* CD */
2531 idx = 1;
2532 break;
2533 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08002534 err = via_new_analog_input(spec, labels[i], idx, 0x18);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002535 if (err < 0)
2536 return err;
2537 imux->items[imux->num_items].label = labels[i];
2538 imux->items[imux->num_items].index = idx;
2539 imux->num_items++;
2540 }
2541 return 0;
2542}
2543
2544static int vt1709_parse_auto_config(struct hda_codec *codec)
2545{
2546 struct via_spec *spec = codec->spec;
2547 int err;
2548
2549 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
2550 if (err < 0)
2551 return err;
2552 err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
2553 if (err < 0)
2554 return err;
2555 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2556 return 0; /* can't find valid BIOS pin config */
2557
2558 err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
2559 if (err < 0)
2560 return err;
2561 err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2562 if (err < 0)
2563 return err;
2564 err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
2565 if (err < 0)
2566 return err;
2567
2568 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2569
Takashi Iwai0852d7a2009-02-11 11:35:15 +01002570 if (spec->autocfg.dig_outs)
Joseph Chanc577b8a2006-11-29 15:29:40 +01002571 spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02002572 spec->dig_in_pin = VT1709_DIGIN_PIN;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002573 if (spec->autocfg.dig_in_pin)
2574 spec->dig_in_nid = VT1709_DIGIN_NID;
2575
Takashi Iwai603c4012008-07-30 15:01:44 +02002576 if (spec->kctls.list)
2577 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002578
Harald Welte0aa62ae2008-09-09 15:58:27 +08002579 spec->input_mux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01002580
Harald Weltef8fdd492008-09-15 22:41:31 +08002581 if (spec->hp_mux)
2582 spec->mixers[spec->num_mixers++] = via_hp_mixer;
2583
Lydia Wang1564b282009-10-10 19:07:52 +08002584 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002585 return 1;
2586}
2587
Takashi Iwaicb53c622007-08-10 17:21:45 +02002588#ifdef CONFIG_SND_HDA_POWER_SAVE
2589static struct hda_amp_list vt1709_loopbacks[] = {
2590 { 0x18, HDA_INPUT, 1 },
2591 { 0x18, HDA_INPUT, 2 },
2592 { 0x18, HDA_INPUT, 3 },
2593 { 0x18, HDA_INPUT, 4 },
2594 { } /* end */
2595};
2596#endif
2597
Joseph Chanc577b8a2006-11-29 15:29:40 +01002598static int patch_vt1709_10ch(struct hda_codec *codec)
2599{
2600 struct via_spec *spec;
2601 int err;
2602
2603 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08002604 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002605 if (spec == NULL)
2606 return -ENOMEM;
2607
2608 codec->spec = spec;
2609
2610 err = vt1709_parse_auto_config(codec);
2611 if (err < 0) {
2612 via_free(codec);
2613 return err;
2614 } else if (!err) {
2615 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
2616 "Using genenic mode...\n");
2617 }
2618
Harald Welte69e52a82008-09-09 15:57:32 +08002619 spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs;
2620 spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002621
2622 spec->stream_name_analog = "VT1709 Analog";
2623 spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
2624 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
2625
2626 spec->stream_name_digital = "VT1709 Digital";
2627 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
2628 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
2629
2630
2631 if (!spec->adc_nids && spec->input_mux) {
2632 spec->adc_nids = vt1709_adc_nids;
2633 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02002634 get_mux_nids(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002635 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
2636 spec->num_mixers++;
2637 }
2638
2639 codec->patch_ops = via_patch_ops;
2640
2641 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08002642 codec->patch_ops.unsol_event = via_unsol_event;
Takashi Iwaicb53c622007-08-10 17:21:45 +02002643#ifdef CONFIG_SND_HDA_POWER_SAVE
2644 spec->loopback.amplist = vt1709_loopbacks;
2645#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01002646
2647 return 0;
2648}
2649/*
2650 * generic initialization of ADC, input mixers and output mixers
2651 */
2652static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
2653 /*
2654 * Unmute ADC0-2 and set the default input to mic-in
2655 */
2656 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2657 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2658 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2659
2660
2661 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2662 * mixer widget
2663 */
2664 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2665 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2666 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2667 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2668 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2669 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2670
2671 /*
2672 * Set up output selector (0x1a, 0x1b, 0x29)
2673 */
2674 /* set vol=0 to output mixers */
2675 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2676 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2677 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2678
2679 /*
2680 * Unmute PW3 and PW4
2681 */
2682 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2683 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2684
2685 /* Set input of PW4 as MW0 */
2686 {0x20, AC_VERB_SET_CONNECT_SEL, 0},
Joseph Chanc577b8a2006-11-29 15:29:40 +01002687 /* PW9 Output enable */
2688 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2689 { }
2690};
2691
2692static int patch_vt1709_6ch(struct hda_codec *codec)
2693{
2694 struct via_spec *spec;
2695 int err;
2696
2697 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08002698 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002699 if (spec == NULL)
2700 return -ENOMEM;
2701
2702 codec->spec = spec;
2703
2704 err = vt1709_parse_auto_config(codec);
2705 if (err < 0) {
2706 via_free(codec);
2707 return err;
2708 } else if (!err) {
2709 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
2710 "Using genenic mode...\n");
2711 }
2712
Harald Welte69e52a82008-09-09 15:57:32 +08002713 spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs;
2714 spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002715
2716 spec->stream_name_analog = "VT1709 Analog";
2717 spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
2718 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
2719
2720 spec->stream_name_digital = "VT1709 Digital";
2721 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
2722 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
2723
2724
2725 if (!spec->adc_nids && spec->input_mux) {
2726 spec->adc_nids = vt1709_adc_nids;
2727 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02002728 get_mux_nids(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002729 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
2730 spec->num_mixers++;
2731 }
2732
2733 codec->patch_ops = via_patch_ops;
2734
2735 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08002736 codec->patch_ops.unsol_event = via_unsol_event;
Takashi Iwaicb53c622007-08-10 17:21:45 +02002737#ifdef CONFIG_SND_HDA_POWER_SAVE
2738 spec->loopback.amplist = vt1709_loopbacks;
2739#endif
Josepch Chanf7278fd2007-12-13 16:40:40 +01002740 return 0;
2741}
2742
2743/* capture mixer elements */
2744static struct snd_kcontrol_new vt1708B_capture_mixer[] = {
2745 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
2746 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
2747 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
2748 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
2749 {
2750 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2751 /* The multiple "Capture Source" controls confuse alsamixer
2752 * So call somewhat different..
Josepch Chanf7278fd2007-12-13 16:40:40 +01002753 */
2754 /* .name = "Capture Source", */
2755 .name = "Input Source",
2756 .count = 1,
2757 .info = via_mux_enum_info,
2758 .get = via_mux_enum_get,
2759 .put = via_mux_enum_put,
2760 },
2761 { } /* end */
2762};
2763/*
2764 * generic initialization of ADC, input mixers and output mixers
2765 */
2766static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
2767 /*
2768 * Unmute ADC0-1 and set the default input to mic-in
2769 */
2770 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2771 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2772
2773
2774 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2775 * mixer widget
2776 */
2777 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2778 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2779 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2780 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2781 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2782 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2783
2784 /*
2785 * Set up output mixers
2786 */
2787 /* set vol=0 to output mixers */
2788 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2789 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2790 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2791
2792 /* Setup default input to PW4 */
2793 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1},
2794 /* PW9 Output enable */
2795 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2796 /* PW10 Input enable */
2797 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
2798 { }
2799};
2800
2801static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
2802 /*
2803 * Unmute ADC0-1 and set the default input to mic-in
2804 */
2805 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2806 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2807
2808
2809 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2810 * mixer widget
2811 */
2812 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2813 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2814 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2815 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2816 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2817 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2818
2819 /*
2820 * Set up output mixers
2821 */
2822 /* set vol=0 to output mixers */
2823 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2824 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2825 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2826
2827 /* Setup default input of PW4 to MW0 */
2828 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
2829 /* PW9 Output enable */
2830 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2831 /* PW10 Input enable */
2832 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
2833 { }
2834};
2835
Harald Welte69e52a82008-09-09 15:57:32 +08002836static struct hda_verb vt1708B_uniwill_init_verbs[] = {
Lydia Wanga34df192009-10-10 19:08:01 +08002837 {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
2838 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
2839 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
2840 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
2841 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
2842 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
2843 {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
2844 {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
2845 {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
Harald Welte69e52a82008-09-09 15:57:32 +08002846 { }
2847};
2848
Lydia Wang17314372009-10-10 19:07:37 +08002849static int via_pcm_open_close(struct hda_pcm_stream *hinfo,
2850 struct hda_codec *codec,
2851 struct snd_pcm_substream *substream)
2852{
2853 int idle = substream->pstr->substream_opened == 1
2854 && substream->ref_count == 0;
2855
2856 analog_low_current_mode(codec, idle);
2857 return 0;
2858}
2859
Josepch Chanf7278fd2007-12-13 16:40:40 +01002860static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08002861 .substreams = 2,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002862 .channels_min = 2,
2863 .channels_max = 8,
2864 .nid = 0x10, /* NID to query formats and rates */
2865 .ops = {
2866 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08002867 .prepare = via_playback_multi_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08002868 .cleanup = via_playback_multi_pcm_cleanup,
2869 .close = via_pcm_open_close
Josepch Chanf7278fd2007-12-13 16:40:40 +01002870 },
2871};
2872
2873static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08002874 .substreams = 2,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002875 .channels_min = 2,
2876 .channels_max = 4,
2877 .nid = 0x10, /* NID to query formats and rates */
2878 .ops = {
2879 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08002880 .prepare = via_playback_multi_pcm_prepare,
2881 .cleanup = via_playback_multi_pcm_cleanup
Josepch Chanf7278fd2007-12-13 16:40:40 +01002882 },
2883};
2884
2885static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
2886 .substreams = 2,
2887 .channels_min = 2,
2888 .channels_max = 2,
2889 .nid = 0x13, /* NID to query formats and rates */
2890 .ops = {
Lydia Wang17314372009-10-10 19:07:37 +08002891 .open = via_pcm_open_close,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002892 .prepare = via_capture_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08002893 .cleanup = via_capture_pcm_cleanup,
2894 .close = via_pcm_open_close
Josepch Chanf7278fd2007-12-13 16:40:40 +01002895 },
2896};
2897
2898static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
2899 .substreams = 1,
2900 .channels_min = 2,
2901 .channels_max = 2,
2902 /* NID is set in via_build_pcms */
2903 .ops = {
2904 .open = via_dig_playback_pcm_open,
2905 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02002906 .prepare = via_dig_playback_pcm_prepare,
2907 .cleanup = via_dig_playback_pcm_cleanup
Josepch Chanf7278fd2007-12-13 16:40:40 +01002908 },
2909};
2910
2911static struct hda_pcm_stream vt1708B_pcm_digital_capture = {
2912 .substreams = 1,
2913 .channels_min = 2,
2914 .channels_max = 2,
2915};
2916
2917/* fill in the dac_nids table from the parsed pin configuration */
2918static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
2919 const struct auto_pin_cfg *cfg)
2920{
2921 int i;
2922 hda_nid_t nid;
2923
2924 spec->multiout.num_dacs = cfg->line_outs;
2925
2926 spec->multiout.dac_nids = spec->private_dac_nids;
2927
2928 for (i = 0; i < 4; i++) {
2929 nid = cfg->line_out_pins[i];
2930 if (nid) {
2931 /* config dac list */
2932 switch (i) {
2933 case AUTO_SEQ_FRONT:
2934 spec->multiout.dac_nids[i] = 0x10;
2935 break;
2936 case AUTO_SEQ_CENLFE:
2937 spec->multiout.dac_nids[i] = 0x24;
2938 break;
2939 case AUTO_SEQ_SURROUND:
Harald Weltefb4cb772008-09-09 15:53:36 +08002940 spec->multiout.dac_nids[i] = 0x11;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002941 break;
2942 case AUTO_SEQ_SIDE:
Harald Weltefb4cb772008-09-09 15:53:36 +08002943 spec->multiout.dac_nids[i] = 0x25;
Josepch Chanf7278fd2007-12-13 16:40:40 +01002944 break;
2945 }
2946 }
2947 }
2948
2949 return 0;
2950}
2951
2952/* add playback controls from the parsed DAC table */
2953static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
2954 const struct auto_pin_cfg *cfg)
2955{
2956 char name[32];
2957 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
Harald Weltefb4cb772008-09-09 15:53:36 +08002958 hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27};
Josepch Chanf7278fd2007-12-13 16:40:40 +01002959 hda_nid_t nid, nid_vol = 0;
2960 int i, err;
2961
2962 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2963 nid = cfg->line_out_pins[i];
2964
2965 if (!nid)
2966 continue;
2967
2968 nid_vol = nid_vols[i];
2969
2970 if (i == AUTO_SEQ_CENLFE) {
2971 /* Center/LFE */
2972 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2973 "Center Playback Volume",
2974 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2975 HDA_OUTPUT));
2976 if (err < 0)
2977 return err;
2978 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2979 "LFE Playback Volume",
2980 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2981 HDA_OUTPUT));
2982 if (err < 0)
2983 return err;
2984 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2985 "Center Playback Switch",
2986 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2987 HDA_OUTPUT));
2988 if (err < 0)
2989 return err;
2990 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2991 "LFE Playback Switch",
2992 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2993 HDA_OUTPUT));
2994 if (err < 0)
2995 return err;
2996 } else if (i == AUTO_SEQ_FRONT) {
2997 /* add control to mixer index 0 */
2998 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2999 "Master Front Playback Volume",
3000 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3001 HDA_INPUT));
3002 if (err < 0)
3003 return err;
3004 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3005 "Master Front Playback Switch",
3006 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3007 HDA_INPUT));
3008 if (err < 0)
3009 return err;
3010
3011 /* add control to PW3 */
3012 sprintf(name, "%s Playback Volume", chname[i]);
3013 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3014 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3015 HDA_OUTPUT));
3016 if (err < 0)
3017 return err;
3018 sprintf(name, "%s Playback Switch", chname[i]);
3019 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3020 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3021 HDA_OUTPUT));
3022 if (err < 0)
3023 return err;
3024 } else {
3025 sprintf(name, "%s Playback Volume", chname[i]);
3026 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3027 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3028 HDA_OUTPUT));
3029 if (err < 0)
3030 return err;
3031 sprintf(name, "%s Playback Switch", chname[i]);
3032 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3033 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3034 HDA_OUTPUT));
3035 if (err < 0)
3036 return err;
3037 }
3038 }
3039
3040 return 0;
3041}
3042
3043static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
3044{
3045 int err;
3046
3047 if (!pin)
3048 return 0;
3049
3050 spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
Lydia Wangcdc17842009-10-10 19:07:47 +08003051 spec->hp_independent_mode_index = 1;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003052
3053 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3054 "Headphone Playback Volume",
3055 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3056 if (err < 0)
3057 return err;
3058 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3059 "Headphone Playback Switch",
3060 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3061 if (err < 0)
3062 return err;
3063
Harald Welte0aa62ae2008-09-09 15:58:27 +08003064 create_hp_imux(spec);
3065
Josepch Chanf7278fd2007-12-13 16:40:40 +01003066 return 0;
3067}
3068
3069/* create playback/capture controls for input pins */
3070static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
3071 const struct auto_pin_cfg *cfg)
3072{
3073 static char *labels[] = {
3074 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
3075 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08003076 struct hda_input_mux *imux = &spec->private_imux[0];
Josepch Chanf7278fd2007-12-13 16:40:40 +01003077 int i, err, idx = 0;
3078
3079 /* for internal loopback recording select */
3080 imux->items[imux->num_items].label = "Stereo Mixer";
3081 imux->items[imux->num_items].index = idx;
3082 imux->num_items++;
3083
3084 for (i = 0; i < AUTO_PIN_LAST; i++) {
3085 if (!cfg->input_pins[i])
3086 continue;
3087
3088 switch (cfg->input_pins[i]) {
3089 case 0x1a: /* Mic */
3090 idx = 2;
3091 break;
3092
3093 case 0x1b: /* Line In */
3094 idx = 3;
3095 break;
3096
3097 case 0x1e: /* Front Mic */
3098 idx = 4;
3099 break;
3100
3101 case 0x1f: /* CD */
3102 idx = 1;
3103 break;
3104 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08003105 err = via_new_analog_input(spec, labels[i], idx, 0x16);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003106 if (err < 0)
3107 return err;
3108 imux->items[imux->num_items].label = labels[i];
3109 imux->items[imux->num_items].index = idx;
3110 imux->num_items++;
3111 }
3112 return 0;
3113}
3114
3115static int vt1708B_parse_auto_config(struct hda_codec *codec)
3116{
3117 struct via_spec *spec = codec->spec;
3118 int err;
3119
3120 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
3121 if (err < 0)
3122 return err;
3123 err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg);
3124 if (err < 0)
3125 return err;
3126 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
3127 return 0; /* can't find valid BIOS pin config */
3128
3129 err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg);
3130 if (err < 0)
3131 return err;
3132 err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
3133 if (err < 0)
3134 return err;
3135 err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
3136 if (err < 0)
3137 return err;
3138
3139 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3140
Takashi Iwai0852d7a2009-02-11 11:35:15 +01003141 if (spec->autocfg.dig_outs)
Josepch Chanf7278fd2007-12-13 16:40:40 +01003142 spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02003143 spec->dig_in_pin = VT1708B_DIGIN_PIN;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003144 if (spec->autocfg.dig_in_pin)
3145 spec->dig_in_nid = VT1708B_DIGIN_NID;
3146
Takashi Iwai603c4012008-07-30 15:01:44 +02003147 if (spec->kctls.list)
3148 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003149
Harald Welte0aa62ae2008-09-09 15:58:27 +08003150 spec->input_mux = &spec->private_imux[0];
3151
Harald Weltef8fdd492008-09-15 22:41:31 +08003152 if (spec->hp_mux)
3153 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003154
Lydia Wang1564b282009-10-10 19:07:52 +08003155 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003156 return 1;
3157}
3158
3159#ifdef CONFIG_SND_HDA_POWER_SAVE
3160static struct hda_amp_list vt1708B_loopbacks[] = {
3161 { 0x16, HDA_INPUT, 1 },
3162 { 0x16, HDA_INPUT, 2 },
3163 { 0x16, HDA_INPUT, 3 },
3164 { 0x16, HDA_INPUT, 4 },
3165 { } /* end */
3166};
3167#endif
Lydia Wang518bf3b2009-10-10 19:07:29 +08003168static int patch_vt1708S(struct hda_codec *codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003169static int patch_vt1708B_8ch(struct hda_codec *codec)
3170{
3171 struct via_spec *spec;
3172 int err;
3173
Lydia Wang518bf3b2009-10-10 19:07:29 +08003174 if (get_codec_type(codec) == VT1708BCE)
3175 return patch_vt1708S(codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003176 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08003177 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003178 if (spec == NULL)
3179 return -ENOMEM;
3180
3181 codec->spec = spec;
3182
3183 /* automatic parse from the BIOS config */
3184 err = vt1708B_parse_auto_config(codec);
3185 if (err < 0) {
3186 via_free(codec);
3187 return err;
3188 } else if (!err) {
3189 printk(KERN_INFO "hda_codec: Cannot set up configuration "
3190 "from BIOS. Using genenic mode...\n");
3191 }
3192
Harald Welte69e52a82008-09-09 15:57:32 +08003193 spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs;
3194 spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003195
3196 spec->stream_name_analog = "VT1708B Analog";
3197 spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
3198 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
3199
3200 spec->stream_name_digital = "VT1708B Digital";
3201 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
3202 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
3203
3204 if (!spec->adc_nids && spec->input_mux) {
3205 spec->adc_nids = vt1708B_adc_nids;
3206 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02003207 get_mux_nids(codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003208 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
3209 spec->num_mixers++;
3210 }
3211
3212 codec->patch_ops = via_patch_ops;
3213
3214 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003215 codec->patch_ops.unsol_event = via_unsol_event;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003216#ifdef CONFIG_SND_HDA_POWER_SAVE
3217 spec->loopback.amplist = vt1708B_loopbacks;
3218#endif
3219
3220 return 0;
3221}
3222
3223static int patch_vt1708B_4ch(struct hda_codec *codec)
3224{
3225 struct via_spec *spec;
3226 int err;
3227
3228 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08003229 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003230 if (spec == NULL)
3231 return -ENOMEM;
3232
3233 codec->spec = spec;
3234
3235 /* automatic parse from the BIOS config */
3236 err = vt1708B_parse_auto_config(codec);
3237 if (err < 0) {
3238 via_free(codec);
3239 return err;
3240 } else if (!err) {
3241 printk(KERN_INFO "hda_codec: Cannot set up configuration "
3242 "from BIOS. Using genenic mode...\n");
3243 }
3244
Harald Welte69e52a82008-09-09 15:57:32 +08003245 spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs;
3246 spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003247
3248 spec->stream_name_analog = "VT1708B Analog";
3249 spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
3250 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
3251
3252 spec->stream_name_digital = "VT1708B Digital";
3253 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
3254 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
3255
3256 if (!spec->adc_nids && spec->input_mux) {
3257 spec->adc_nids = vt1708B_adc_nids;
3258 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02003259 get_mux_nids(codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003260 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
3261 spec->num_mixers++;
3262 }
3263
3264 codec->patch_ops = via_patch_ops;
3265
3266 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003267 codec->patch_ops.unsol_event = via_unsol_event;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003268#ifdef CONFIG_SND_HDA_POWER_SAVE
3269 spec->loopback.amplist = vt1708B_loopbacks;
3270#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01003271
3272 return 0;
3273}
3274
Harald Welted949cac2008-09-09 15:56:01 +08003275/* Patch for VT1708S */
3276
3277/* capture mixer elements */
3278static struct snd_kcontrol_new vt1708S_capture_mixer[] = {
3279 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
3280 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
3281 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
3282 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
Lydia Wang6369bcf2009-10-10 19:08:31 +08003283 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT),
3284 HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0,
3285 HDA_INPUT),
Harald Welted949cac2008-09-09 15:56:01 +08003286 {
3287 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3288 /* The multiple "Capture Source" controls confuse alsamixer
3289 * So call somewhat different..
3290 */
3291 /* .name = "Capture Source", */
3292 .name = "Input Source",
3293 .count = 1,
3294 .info = via_mux_enum_info,
3295 .get = via_mux_enum_get,
3296 .put = via_mux_enum_put,
3297 },
3298 { } /* end */
3299};
3300
3301static struct hda_verb vt1708S_volume_init_verbs[] = {
3302 /* Unmute ADC0-1 and set the default input to mic-in */
3303 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3304 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3305
3306 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the
3307 * analog-loopback mixer widget */
3308 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
3309 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3310 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3311 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3312 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3313 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
3314
3315 /* Setup default input of PW4 to MW0 */
3316 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
Harald Welte5691ec72008-09-15 22:42:26 +08003317 /* PW9, PW10 Output enable */
Harald Welted949cac2008-09-09 15:56:01 +08003318 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Harald Welte5691ec72008-09-15 22:42:26 +08003319 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Harald Welted7426322008-09-15 22:43:23 +08003320 /* Enable Mic Boost Volume backdoor */
3321 {0x1, 0xf98, 0x1},
Lydia Wangbc7e7e52009-10-10 19:08:32 +08003322 /* don't bybass mixer */
3323 {0x1, 0xf88, 0xc0},
Harald Welted949cac2008-09-09 15:56:01 +08003324 { }
3325};
3326
Harald Welte69e52a82008-09-09 15:57:32 +08003327static struct hda_verb vt1708S_uniwill_init_verbs[] = {
Lydia Wanga34df192009-10-10 19:08:01 +08003328 {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
3329 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
3330 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3331 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3332 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3333 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3334 {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3335 {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3336 {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
Harald Welte69e52a82008-09-09 15:57:32 +08003337 { }
3338};
3339
Harald Welted949cac2008-09-09 15:56:01 +08003340static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
3341 .substreams = 2,
3342 .channels_min = 2,
3343 .channels_max = 8,
3344 .nid = 0x10, /* NID to query formats and rates */
3345 .ops = {
3346 .open = via_playback_pcm_open,
Lydia Wangc873cc22009-10-10 19:08:21 +08003347 .prepare = via_playback_multi_pcm_prepare,
3348 .cleanup = via_playback_multi_pcm_cleanup,
Lydia Wang17314372009-10-10 19:07:37 +08003349 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08003350 },
3351};
3352
3353static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
3354 .substreams = 2,
3355 .channels_min = 2,
3356 .channels_max = 2,
3357 .nid = 0x13, /* NID to query formats and rates */
3358 .ops = {
Lydia Wang17314372009-10-10 19:07:37 +08003359 .open = via_pcm_open_close,
Harald Welted949cac2008-09-09 15:56:01 +08003360 .prepare = via_capture_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08003361 .cleanup = via_capture_pcm_cleanup,
3362 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08003363 },
3364};
3365
3366static struct hda_pcm_stream vt1708S_pcm_digital_playback = {
Takashi Iwai9da29272009-05-07 16:31:14 +02003367 .substreams = 1,
Harald Welted949cac2008-09-09 15:56:01 +08003368 .channels_min = 2,
3369 .channels_max = 2,
3370 /* NID is set in via_build_pcms */
3371 .ops = {
3372 .open = via_dig_playback_pcm_open,
3373 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02003374 .prepare = via_dig_playback_pcm_prepare,
3375 .cleanup = via_dig_playback_pcm_cleanup
Harald Welted949cac2008-09-09 15:56:01 +08003376 },
3377};
3378
3379/* fill in the dac_nids table from the parsed pin configuration */
3380static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
3381 const struct auto_pin_cfg *cfg)
3382{
3383 int i;
3384 hda_nid_t nid;
3385
3386 spec->multiout.num_dacs = cfg->line_outs;
3387
3388 spec->multiout.dac_nids = spec->private_dac_nids;
3389
3390 for (i = 0; i < 4; i++) {
3391 nid = cfg->line_out_pins[i];
3392 if (nid) {
3393 /* config dac list */
3394 switch (i) {
3395 case AUTO_SEQ_FRONT:
3396 spec->multiout.dac_nids[i] = 0x10;
3397 break;
3398 case AUTO_SEQ_CENLFE:
3399 spec->multiout.dac_nids[i] = 0x24;
3400 break;
3401 case AUTO_SEQ_SURROUND:
3402 spec->multiout.dac_nids[i] = 0x11;
3403 break;
3404 case AUTO_SEQ_SIDE:
3405 spec->multiout.dac_nids[i] = 0x25;
3406 break;
3407 }
3408 }
3409 }
3410
3411 return 0;
3412}
3413
3414/* add playback controls from the parsed DAC table */
3415static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
3416 const struct auto_pin_cfg *cfg)
3417{
3418 char name[32];
3419 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
3420 hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25};
3421 hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27};
3422 hda_nid_t nid, nid_vol, nid_mute;
3423 int i, err;
3424
3425 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
3426 nid = cfg->line_out_pins[i];
3427
3428 if (!nid)
3429 continue;
3430
3431 nid_vol = nid_vols[i];
3432 nid_mute = nid_mutes[i];
3433
3434 if (i == AUTO_SEQ_CENLFE) {
3435 /* Center/LFE */
3436 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3437 "Center Playback Volume",
3438 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
3439 HDA_OUTPUT));
3440 if (err < 0)
3441 return err;
3442 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3443 "LFE Playback Volume",
3444 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
3445 HDA_OUTPUT));
3446 if (err < 0)
3447 return err;
3448 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3449 "Center Playback Switch",
3450 HDA_COMPOSE_AMP_VAL(nid_mute,
3451 1, 0,
3452 HDA_OUTPUT));
3453 if (err < 0)
3454 return err;
3455 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3456 "LFE Playback Switch",
3457 HDA_COMPOSE_AMP_VAL(nid_mute,
3458 2, 0,
3459 HDA_OUTPUT));
3460 if (err < 0)
3461 return err;
3462 } else if (i == AUTO_SEQ_FRONT) {
3463 /* add control to mixer index 0 */
3464 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3465 "Master Front Playback Volume",
3466 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
3467 HDA_INPUT));
3468 if (err < 0)
3469 return err;
3470 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3471 "Master Front Playback Switch",
3472 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
3473 HDA_INPUT));
3474 if (err < 0)
3475 return err;
3476
3477 /* Front */
3478 sprintf(name, "%s Playback Volume", chname[i]);
3479 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3480 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3481 HDA_OUTPUT));
3482 if (err < 0)
3483 return err;
3484 sprintf(name, "%s Playback Switch", chname[i]);
3485 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3486 HDA_COMPOSE_AMP_VAL(nid_mute,
3487 3, 0,
3488 HDA_OUTPUT));
3489 if (err < 0)
3490 return err;
3491 } else {
3492 sprintf(name, "%s Playback Volume", chname[i]);
3493 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3494 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3495 HDA_OUTPUT));
3496 if (err < 0)
3497 return err;
3498 sprintf(name, "%s Playback Switch", chname[i]);
3499 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3500 HDA_COMPOSE_AMP_VAL(nid_mute,
3501 3, 0,
3502 HDA_OUTPUT));
3503 if (err < 0)
3504 return err;
3505 }
3506 }
3507
3508 return 0;
3509}
3510
3511static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
3512{
3513 int err;
3514
3515 if (!pin)
3516 return 0;
3517
3518 spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */
Lydia Wangcdc17842009-10-10 19:07:47 +08003519 spec->hp_independent_mode_index = 1;
Harald Welted949cac2008-09-09 15:56:01 +08003520
3521 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3522 "Headphone Playback Volume",
3523 HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
3524 if (err < 0)
3525 return err;
3526
3527 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3528 "Headphone Playback Switch",
3529 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3530 if (err < 0)
3531 return err;
3532
Harald Welte0aa62ae2008-09-09 15:58:27 +08003533 create_hp_imux(spec);
3534
Harald Welted949cac2008-09-09 15:56:01 +08003535 return 0;
3536}
3537
3538/* create playback/capture controls for input pins */
3539static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
3540 const struct auto_pin_cfg *cfg)
3541{
3542 static char *labels[] = {
3543 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
3544 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08003545 struct hda_input_mux *imux = &spec->private_imux[0];
Harald Welted949cac2008-09-09 15:56:01 +08003546 int i, err, idx = 0;
3547
3548 /* for internal loopback recording select */
3549 imux->items[imux->num_items].label = "Stereo Mixer";
3550 imux->items[imux->num_items].index = 5;
3551 imux->num_items++;
3552
3553 for (i = 0; i < AUTO_PIN_LAST; i++) {
3554 if (!cfg->input_pins[i])
3555 continue;
3556
3557 switch (cfg->input_pins[i]) {
3558 case 0x1a: /* Mic */
3559 idx = 2;
3560 break;
3561
3562 case 0x1b: /* Line In */
3563 idx = 3;
3564 break;
3565
3566 case 0x1e: /* Front Mic */
3567 idx = 4;
3568 break;
3569
3570 case 0x1f: /* CD */
3571 idx = 1;
3572 break;
3573 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08003574 err = via_new_analog_input(spec, labels[i], idx, 0x16);
Harald Welted949cac2008-09-09 15:56:01 +08003575 if (err < 0)
3576 return err;
3577 imux->items[imux->num_items].label = labels[i];
3578 imux->items[imux->num_items].index = idx-1;
3579 imux->num_items++;
3580 }
3581 return 0;
3582}
3583
Takashi Iwai9da29272009-05-07 16:31:14 +02003584/* fill out digital output widgets; one for master and one for slave outputs */
3585static void fill_dig_outs(struct hda_codec *codec)
3586{
3587 struct via_spec *spec = codec->spec;
3588 int i;
3589
3590 for (i = 0; i < spec->autocfg.dig_outs; i++) {
3591 hda_nid_t nid;
3592 int conn;
3593
3594 nid = spec->autocfg.dig_out_pins[i];
3595 if (!nid)
3596 continue;
3597 conn = snd_hda_get_connections(codec, nid, &nid, 1);
3598 if (conn < 1)
3599 continue;
3600 if (!spec->multiout.dig_out_nid)
3601 spec->multiout.dig_out_nid = nid;
3602 else {
3603 spec->slave_dig_outs[0] = nid;
3604 break; /* at most two dig outs */
3605 }
3606 }
3607}
3608
Harald Welted949cac2008-09-09 15:56:01 +08003609static int vt1708S_parse_auto_config(struct hda_codec *codec)
3610{
3611 struct via_spec *spec = codec->spec;
3612 int err;
Harald Welted949cac2008-09-09 15:56:01 +08003613
Takashi Iwai9da29272009-05-07 16:31:14 +02003614 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
Harald Welted949cac2008-09-09 15:56:01 +08003615 if (err < 0)
3616 return err;
3617 err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg);
3618 if (err < 0)
3619 return err;
3620 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
3621 return 0; /* can't find valid BIOS pin config */
3622
3623 err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg);
3624 if (err < 0)
3625 return err;
3626 err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
3627 if (err < 0)
3628 return err;
3629 err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
3630 if (err < 0)
3631 return err;
3632
3633 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3634
Takashi Iwai9da29272009-05-07 16:31:14 +02003635 fill_dig_outs(codec);
Harald Welte98aa34c2008-09-09 16:02:09 +08003636
Takashi Iwai603c4012008-07-30 15:01:44 +02003637 if (spec->kctls.list)
3638 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Harald Welted949cac2008-09-09 15:56:01 +08003639
Harald Welte0aa62ae2008-09-09 15:58:27 +08003640 spec->input_mux = &spec->private_imux[0];
3641
Harald Weltef8fdd492008-09-15 22:41:31 +08003642 if (spec->hp_mux)
3643 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08003644
Lydia Wang1564b282009-10-10 19:07:52 +08003645 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08003646 return 1;
3647}
3648
3649#ifdef CONFIG_SND_HDA_POWER_SAVE
3650static struct hda_amp_list vt1708S_loopbacks[] = {
3651 { 0x16, HDA_INPUT, 1 },
3652 { 0x16, HDA_INPUT, 2 },
3653 { 0x16, HDA_INPUT, 3 },
3654 { 0x16, HDA_INPUT, 4 },
3655 { } /* end */
3656};
3657#endif
3658
Lydia Wang6369bcf2009-10-10 19:08:31 +08003659static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin,
3660 int offset, int num_steps, int step_size)
3661{
3662 snd_hda_override_amp_caps(codec, pin, HDA_INPUT,
3663 (offset << AC_AMPCAP_OFFSET_SHIFT) |
3664 (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) |
3665 (step_size << AC_AMPCAP_STEP_SIZE_SHIFT) |
3666 (0 << AC_AMPCAP_MUTE_SHIFT));
3667}
3668
Harald Welted949cac2008-09-09 15:56:01 +08003669static int patch_vt1708S(struct hda_codec *codec)
3670{
3671 struct via_spec *spec;
3672 int err;
3673
3674 /* create a codec specific record */
3675 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3676 if (spec == NULL)
3677 return -ENOMEM;
3678
3679 codec->spec = spec;
3680
3681 /* automatic parse from the BIOS config */
3682 err = vt1708S_parse_auto_config(codec);
3683 if (err < 0) {
3684 via_free(codec);
3685 return err;
3686 } else if (!err) {
3687 printk(KERN_INFO "hda_codec: Cannot set up configuration "
3688 "from BIOS. Using genenic mode...\n");
3689 }
3690
Harald Welte69e52a82008-09-09 15:57:32 +08003691 spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
3692 spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs;
Harald Welted949cac2008-09-09 15:56:01 +08003693
3694 spec->stream_name_analog = "VT1708S Analog";
3695 spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
3696 spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
3697
3698 spec->stream_name_digital = "VT1708S Digital";
3699 spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
3700
3701 if (!spec->adc_nids && spec->input_mux) {
3702 spec->adc_nids = vt1708S_adc_nids;
3703 spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02003704 get_mux_nids(codec);
Lydia Wang6369bcf2009-10-10 19:08:31 +08003705 override_mic_boost(codec, 0x1a, 0, 3, 40);
3706 override_mic_boost(codec, 0x1e, 0, 3, 40);
Harald Welted949cac2008-09-09 15:56:01 +08003707 spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
3708 spec->num_mixers++;
3709 }
3710
3711 codec->patch_ops = via_patch_ops;
3712
3713 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003714 codec->patch_ops.unsol_event = via_unsol_event;
Harald Welted949cac2008-09-09 15:56:01 +08003715#ifdef CONFIG_SND_HDA_POWER_SAVE
3716 spec->loopback.amplist = vt1708S_loopbacks;
3717#endif
3718
Lydia Wang518bf3b2009-10-10 19:07:29 +08003719 /* correct names for VT1708BCE */
3720 if (get_codec_type(codec) == VT1708BCE) {
3721 kfree(codec->chip_name);
3722 codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
3723 snprintf(codec->bus->card->mixername,
3724 sizeof(codec->bus->card->mixername),
3725 "%s %s", codec->vendor_name, codec->chip_name);
3726 spec->stream_name_analog = "VT1708BCE Analog";
3727 spec->stream_name_digital = "VT1708BCE Digital";
3728 }
Harald Welted949cac2008-09-09 15:56:01 +08003729 return 0;
3730}
3731
3732/* Patch for VT1702 */
3733
3734/* capture mixer elements */
3735static struct snd_kcontrol_new vt1702_capture_mixer[] = {
3736 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
3737 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
3738 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
3739 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT),
3740 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT),
3741 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT),
3742 HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0,
3743 HDA_INPUT),
3744 {
3745 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3746 /* The multiple "Capture Source" controls confuse alsamixer
3747 * So call somewhat different..
3748 */
3749 /* .name = "Capture Source", */
3750 .name = "Input Source",
3751 .count = 1,
3752 .info = via_mux_enum_info,
3753 .get = via_mux_enum_get,
3754 .put = via_mux_enum_put,
3755 },
3756 { } /* end */
3757};
3758
3759static struct hda_verb vt1702_volume_init_verbs[] = {
3760 /*
3761 * Unmute ADC0-1 and set the default input to mic-in
3762 */
3763 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3764 {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3765 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3766
3767
3768 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3769 * mixer widget
3770 */
3771 /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */
3772 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3773 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3774 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3775 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3776 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3777
3778 /* Setup default input of PW4 to MW0 */
3779 {0x17, AC_VERB_SET_CONNECT_SEL, 0x1},
3780 /* PW6 PW7 Output enable */
3781 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
3782 {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Lydia Wangbc7e7e52009-10-10 19:08:32 +08003783 /* mixer enable */
3784 {0x1, 0xF88, 0x3},
3785 /* GPIO 0~2 */
3786 {0x1, 0xF82, 0x3F},
Harald Welted949cac2008-09-09 15:56:01 +08003787 { }
3788};
3789
Harald Welte69e52a82008-09-09 15:57:32 +08003790static struct hda_verb vt1702_uniwill_init_verbs[] = {
Lydia Wanga34df192009-10-10 19:08:01 +08003791 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE,
3792 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
3793 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3794 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3795 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3796 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
Harald Welte69e52a82008-09-09 15:57:32 +08003797 { }
3798};
3799
Harald Welted949cac2008-09-09 15:56:01 +08003800static struct hda_pcm_stream vt1702_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08003801 .substreams = 2,
Harald Welted949cac2008-09-09 15:56:01 +08003802 .channels_min = 2,
3803 .channels_max = 2,
3804 .nid = 0x10, /* NID to query formats and rates */
3805 .ops = {
3806 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08003807 .prepare = via_playback_multi_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08003808 .cleanup = via_playback_multi_pcm_cleanup,
3809 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08003810 },
3811};
3812
3813static struct hda_pcm_stream vt1702_pcm_analog_capture = {
3814 .substreams = 3,
3815 .channels_min = 2,
3816 .channels_max = 2,
3817 .nid = 0x12, /* NID to query formats and rates */
3818 .ops = {
Lydia Wang17314372009-10-10 19:07:37 +08003819 .open = via_pcm_open_close,
Harald Welted949cac2008-09-09 15:56:01 +08003820 .prepare = via_capture_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08003821 .cleanup = via_capture_pcm_cleanup,
3822 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08003823 },
3824};
3825
3826static struct hda_pcm_stream vt1702_pcm_digital_playback = {
Harald Welte5691ec72008-09-15 22:42:26 +08003827 .substreams = 2,
Harald Welted949cac2008-09-09 15:56:01 +08003828 .channels_min = 2,
3829 .channels_max = 2,
3830 /* NID is set in via_build_pcms */
3831 .ops = {
3832 .open = via_dig_playback_pcm_open,
3833 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02003834 .prepare = via_dig_playback_pcm_prepare,
3835 .cleanup = via_dig_playback_pcm_cleanup
Harald Welted949cac2008-09-09 15:56:01 +08003836 },
3837};
3838
3839/* fill in the dac_nids table from the parsed pin configuration */
3840static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
3841 const struct auto_pin_cfg *cfg)
3842{
3843 spec->multiout.num_dacs = 1;
3844 spec->multiout.dac_nids = spec->private_dac_nids;
3845
3846 if (cfg->line_out_pins[0]) {
3847 /* config dac list */
3848 spec->multiout.dac_nids[0] = 0x10;
3849 }
3850
3851 return 0;
3852}
3853
3854/* add playback controls from the parsed DAC table */
3855static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
3856 const struct auto_pin_cfg *cfg)
3857{
3858 int err;
3859
3860 if (!cfg->line_out_pins[0])
3861 return -1;
3862
3863 /* add control to mixer index 0 */
3864 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3865 "Master Front Playback Volume",
3866 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
3867 if (err < 0)
3868 return err;
3869 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3870 "Master Front Playback Switch",
3871 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
3872 if (err < 0)
3873 return err;
3874
3875 /* Front */
3876 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3877 "Front Playback Volume",
3878 HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT));
3879 if (err < 0)
3880 return err;
3881 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3882 "Front Playback Switch",
3883 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT));
3884 if (err < 0)
3885 return err;
3886
3887 return 0;
3888}
3889
3890static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
3891{
Lydia Wang0713efe2009-10-10 19:07:43 +08003892 int err, i;
3893 struct hda_input_mux *imux;
3894 static const char *texts[] = { "ON", "OFF", NULL};
Harald Welted949cac2008-09-09 15:56:01 +08003895 if (!pin)
3896 return 0;
Harald Welted949cac2008-09-09 15:56:01 +08003897 spec->multiout.hp_nid = 0x1D;
Lydia Wangcdc17842009-10-10 19:07:47 +08003898 spec->hp_independent_mode_index = 0;
Harald Welted949cac2008-09-09 15:56:01 +08003899
3900 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3901 "Headphone Playback Volume",
3902 HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT));
3903 if (err < 0)
3904 return err;
3905
3906 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3907 "Headphone Playback Switch",
3908 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3909 if (err < 0)
3910 return err;
3911
Lydia Wang0713efe2009-10-10 19:07:43 +08003912 imux = &spec->private_imux[1];
Harald Welte0aa62ae2008-09-09 15:58:27 +08003913
Lydia Wang0713efe2009-10-10 19:07:43 +08003914 /* for hp mode select */
3915 i = 0;
3916 while (texts[i] != NULL) {
3917 imux->items[imux->num_items].label = texts[i];
3918 imux->items[imux->num_items].index = i;
3919 imux->num_items++;
3920 i++;
3921 }
3922
3923 spec->hp_mux = &spec->private_imux[1];
Harald Welted949cac2008-09-09 15:56:01 +08003924 return 0;
3925}
3926
3927/* create playback/capture controls for input pins */
3928static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
3929 const struct auto_pin_cfg *cfg)
3930{
3931 static char *labels[] = {
3932 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
3933 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08003934 struct hda_input_mux *imux = &spec->private_imux[0];
Harald Welted949cac2008-09-09 15:56:01 +08003935 int i, err, idx = 0;
3936
3937 /* for internal loopback recording select */
3938 imux->items[imux->num_items].label = "Stereo Mixer";
3939 imux->items[imux->num_items].index = 3;
3940 imux->num_items++;
3941
3942 for (i = 0; i < AUTO_PIN_LAST; i++) {
3943 if (!cfg->input_pins[i])
3944 continue;
3945
3946 switch (cfg->input_pins[i]) {
3947 case 0x14: /* Mic */
3948 idx = 1;
3949 break;
3950
3951 case 0x15: /* Line In */
3952 idx = 2;
3953 break;
3954
3955 case 0x18: /* Front Mic */
3956 idx = 3;
3957 break;
3958 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08003959 err = via_new_analog_input(spec, labels[i], idx, 0x1A);
Harald Welted949cac2008-09-09 15:56:01 +08003960 if (err < 0)
3961 return err;
3962 imux->items[imux->num_items].label = labels[i];
3963 imux->items[imux->num_items].index = idx-1;
3964 imux->num_items++;
3965 }
3966 return 0;
3967}
3968
3969static int vt1702_parse_auto_config(struct hda_codec *codec)
3970{
3971 struct via_spec *spec = codec->spec;
3972 int err;
Harald Welted949cac2008-09-09 15:56:01 +08003973
Takashi Iwai9da29272009-05-07 16:31:14 +02003974 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
Harald Welted949cac2008-09-09 15:56:01 +08003975 if (err < 0)
3976 return err;
3977 err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg);
3978 if (err < 0)
3979 return err;
3980 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
3981 return 0; /* can't find valid BIOS pin config */
3982
3983 err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg);
3984 if (err < 0)
3985 return err;
3986 err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
3987 if (err < 0)
3988 return err;
Lydia Wangc2c02ea2009-10-10 19:07:32 +08003989 /* limit AA path volume to 0 dB */
3990 snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT,
3991 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
3992 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3993 (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3994 (1 << AC_AMPCAP_MUTE_SHIFT));
Harald Welted949cac2008-09-09 15:56:01 +08003995 err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
3996 if (err < 0)
3997 return err;
3998
3999 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4000
Takashi Iwai9da29272009-05-07 16:31:14 +02004001 fill_dig_outs(codec);
Harald Welte98aa34c2008-09-09 16:02:09 +08004002
Takashi Iwai603c4012008-07-30 15:01:44 +02004003 if (spec->kctls.list)
4004 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Harald Welted949cac2008-09-09 15:56:01 +08004005
Harald Welte0aa62ae2008-09-09 15:58:27 +08004006 spec->input_mux = &spec->private_imux[0];
4007
Harald Weltef8fdd492008-09-15 22:41:31 +08004008 if (spec->hp_mux)
4009 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08004010
4011 return 1;
4012}
4013
4014#ifdef CONFIG_SND_HDA_POWER_SAVE
4015static struct hda_amp_list vt1702_loopbacks[] = {
4016 { 0x1A, HDA_INPUT, 1 },
4017 { 0x1A, HDA_INPUT, 2 },
4018 { 0x1A, HDA_INPUT, 3 },
4019 { 0x1A, HDA_INPUT, 4 },
4020 { } /* end */
4021};
4022#endif
4023
4024static int patch_vt1702(struct hda_codec *codec)
4025{
4026 struct via_spec *spec;
4027 int err;
Harald Welted949cac2008-09-09 15:56:01 +08004028
4029 /* create a codec specific record */
4030 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4031 if (spec == NULL)
4032 return -ENOMEM;
4033
4034 codec->spec = spec;
4035
4036 /* automatic parse from the BIOS config */
4037 err = vt1702_parse_auto_config(codec);
4038 if (err < 0) {
4039 via_free(codec);
4040 return err;
4041 } else if (!err) {
4042 printk(KERN_INFO "hda_codec: Cannot set up configuration "
4043 "from BIOS. Using genenic mode...\n");
4044 }
4045
Harald Welte69e52a82008-09-09 15:57:32 +08004046 spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs;
4047 spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs;
Harald Welted949cac2008-09-09 15:56:01 +08004048
4049 spec->stream_name_analog = "VT1702 Analog";
4050 spec->stream_analog_playback = &vt1702_pcm_analog_playback;
4051 spec->stream_analog_capture = &vt1702_pcm_analog_capture;
4052
4053 spec->stream_name_digital = "VT1702 Digital";
4054 spec->stream_digital_playback = &vt1702_pcm_digital_playback;
4055
4056 if (!spec->adc_nids && spec->input_mux) {
4057 spec->adc_nids = vt1702_adc_nids;
4058 spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02004059 get_mux_nids(codec);
Harald Welted949cac2008-09-09 15:56:01 +08004060 spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
4061 spec->num_mixers++;
4062 }
4063
4064 codec->patch_ops = via_patch_ops;
4065
4066 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08004067 codec->patch_ops.unsol_event = via_unsol_event;
Harald Welted949cac2008-09-09 15:56:01 +08004068#ifdef CONFIG_SND_HDA_POWER_SAVE
4069 spec->loopback.amplist = vt1702_loopbacks;
4070#endif
4071
Harald Welted949cac2008-09-09 15:56:01 +08004072 return 0;
4073}
4074
Lydia Wangeb7188c2009-10-10 19:08:34 +08004075/* Patch for VT1718S */
4076
4077/* capture mixer elements */
4078static struct snd_kcontrol_new vt1718S_capture_mixer[] = {
4079 HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
4080 HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
4081 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
4082 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
4083 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
4084 HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0,
4085 HDA_INPUT),
4086 {
4087 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4088 /* The multiple "Capture Source" controls confuse alsamixer
4089 * So call somewhat different..
4090 */
4091 .name = "Input Source",
4092 .count = 2,
4093 .info = via_mux_enum_info,
4094 .get = via_mux_enum_get,
4095 .put = via_mux_enum_put,
4096 },
4097 { } /* end */
4098};
4099
4100static struct hda_verb vt1718S_volume_init_verbs[] = {
4101 /*
4102 * Unmute ADC0-1 and set the default input to mic-in
4103 */
4104 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4105 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4106
4107
4108 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4109 * mixer widget
4110 */
4111 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
4112 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4113 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4114 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4115 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4116 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4117
4118 /* Setup default input of Front HP to MW9 */
4119 {0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
4120 /* PW9 PW10 Output enable */
4121 {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
4122 {0x2e, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
4123 /* PW11 Input enable */
4124 {0x2f, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_IN_EN},
4125 /* Enable Boost Volume backdoor */
4126 {0x1, 0xf88, 0x8},
4127 /* MW0/1/2/3/4: un-mute index 0 (AOWx), mute index 1 (MW9) */
4128 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4129 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4130 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4131 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4132 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4133 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4134 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4135 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4136 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4137 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4138 /* set MUX1 = 2 (AOW4), MUX2 = 1 (AOW3) */
4139 {0x34, AC_VERB_SET_CONNECT_SEL, 0x2},
4140 {0x35, AC_VERB_SET_CONNECT_SEL, 0x1},
4141 /* Unmute MW4's index 0 */
4142 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4143 { }
4144};
4145
4146
4147static struct hda_verb vt1718S_uniwill_init_verbs[] = {
4148 {0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
4149 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
4150 {0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4151 {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4152 {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4153 {0x27, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4154 {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4155 {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4156 {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4157 { }
4158};
4159
4160static struct hda_pcm_stream vt1718S_pcm_analog_playback = {
4161 .substreams = 2,
4162 .channels_min = 2,
4163 .channels_max = 10,
4164 .nid = 0x8, /* NID to query formats and rates */
4165 .ops = {
4166 .open = via_playback_pcm_open,
4167 .prepare = via_playback_multi_pcm_prepare,
4168 .cleanup = via_playback_multi_pcm_cleanup,
4169 .close = via_pcm_open_close,
4170 },
4171};
4172
4173static struct hda_pcm_stream vt1718S_pcm_analog_capture = {
4174 .substreams = 2,
4175 .channels_min = 2,
4176 .channels_max = 2,
4177 .nid = 0x10, /* NID to query formats and rates */
4178 .ops = {
4179 .open = via_pcm_open_close,
4180 .prepare = via_capture_pcm_prepare,
4181 .cleanup = via_capture_pcm_cleanup,
4182 .close = via_pcm_open_close,
4183 },
4184};
4185
4186static struct hda_pcm_stream vt1718S_pcm_digital_playback = {
4187 .substreams = 2,
4188 .channels_min = 2,
4189 .channels_max = 2,
4190 .rates = SNDRV_PCM_RATE_48000,
4191 /* NID is set in via_build_pcms */
4192 .ops = {
4193 .open = via_dig_playback_pcm_open,
4194 .close = via_dig_playback_pcm_close,
4195 .prepare = via_dig_playback_pcm_prepare,
4196 .cleanup = via_dig_playback_pcm_cleanup
4197 },
4198};
4199
4200static struct hda_pcm_stream vt1718S_pcm_digital_capture = {
4201 .substreams = 1,
4202 .channels_min = 2,
4203 .channels_max = 2,
4204};
4205
4206/* fill in the dac_nids table from the parsed pin configuration */
4207static int vt1718S_auto_fill_dac_nids(struct via_spec *spec,
4208 const struct auto_pin_cfg *cfg)
4209{
4210 int i;
4211 hda_nid_t nid;
4212
4213 spec->multiout.num_dacs = cfg->line_outs;
4214
4215 spec->multiout.dac_nids = spec->private_dac_nids;
4216
4217 for (i = 0; i < 4; i++) {
4218 nid = cfg->line_out_pins[i];
4219 if (nid) {
4220 /* config dac list */
4221 switch (i) {
4222 case AUTO_SEQ_FRONT:
4223 spec->multiout.dac_nids[i] = 0x8;
4224 break;
4225 case AUTO_SEQ_CENLFE:
4226 spec->multiout.dac_nids[i] = 0xa;
4227 break;
4228 case AUTO_SEQ_SURROUND:
4229 spec->multiout.dac_nids[i] = 0x9;
4230 break;
4231 case AUTO_SEQ_SIDE:
4232 spec->multiout.dac_nids[i] = 0xb;
4233 break;
4234 }
4235 }
4236 }
4237
4238 return 0;
4239}
4240
4241/* add playback controls from the parsed DAC table */
4242static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec,
4243 const struct auto_pin_cfg *cfg)
4244{
4245 char name[32];
4246 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
4247 hda_nid_t nid_vols[] = {0x8, 0x9, 0xa, 0xb};
4248 hda_nid_t nid_mutes[] = {0x24, 0x25, 0x26, 0x27};
4249 hda_nid_t nid, nid_vol, nid_mute = 0;
4250 int i, err;
4251
4252 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
4253 nid = cfg->line_out_pins[i];
4254
4255 if (!nid)
4256 continue;
4257 nid_vol = nid_vols[i];
4258 nid_mute = nid_mutes[i];
4259
4260 if (i == AUTO_SEQ_CENLFE) {
4261 /* Center/LFE */
4262 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4263 "Center Playback Volume",
4264 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
4265 HDA_OUTPUT));
4266 if (err < 0)
4267 return err;
4268 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4269 "LFE Playback Volume",
4270 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
4271 HDA_OUTPUT));
4272 if (err < 0)
4273 return err;
4274 err = via_add_control(
4275 spec, VIA_CTL_WIDGET_MUTE,
4276 "Center Playback Switch",
4277 HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0,
4278 HDA_OUTPUT));
4279 if (err < 0)
4280 return err;
4281 err = via_add_control(
4282 spec, VIA_CTL_WIDGET_MUTE,
4283 "LFE Playback Switch",
4284 HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0,
4285 HDA_OUTPUT));
4286 if (err < 0)
4287 return err;
4288 } else if (i == AUTO_SEQ_FRONT) {
4289 /* Front */
4290 sprintf(name, "%s Playback Volume", chname[i]);
4291 err = via_add_control(
4292 spec, VIA_CTL_WIDGET_VOL, name,
4293 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
4294 if (err < 0)
4295 return err;
4296 sprintf(name, "%s Playback Switch", chname[i]);
4297 err = via_add_control(
4298 spec, VIA_CTL_WIDGET_MUTE, name,
4299 HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
4300 HDA_OUTPUT));
4301 if (err < 0)
4302 return err;
4303 } else {
4304 sprintf(name, "%s Playback Volume", chname[i]);
4305 err = via_add_control(
4306 spec, VIA_CTL_WIDGET_VOL, name,
4307 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
4308 if (err < 0)
4309 return err;
4310 sprintf(name, "%s Playback Switch", chname[i]);
4311 err = via_add_control(
4312 spec, VIA_CTL_WIDGET_MUTE, name,
4313 HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
4314 HDA_OUTPUT));
4315 if (err < 0)
4316 return err;
4317 }
4318 }
4319 return 0;
4320}
4321
4322static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
4323{
4324 int err;
4325
4326 if (!pin)
4327 return 0;
4328
4329 spec->multiout.hp_nid = 0xc; /* AOW4 */
4330 spec->hp_independent_mode_index = 1;
4331
4332 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4333 "Headphone Playback Volume",
4334 HDA_COMPOSE_AMP_VAL(0xc, 3, 0, HDA_OUTPUT));
4335 if (err < 0)
4336 return err;
4337
4338 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
4339 "Headphone Playback Switch",
4340 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4341 if (err < 0)
4342 return err;
4343
4344 create_hp_imux(spec);
4345 return 0;
4346}
4347
4348/* create playback/capture controls for input pins */
4349static int vt1718S_auto_create_analog_input_ctls(struct via_spec *spec,
4350 const struct auto_pin_cfg *cfg)
4351{
4352 static char *labels[] = {
4353 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
4354 };
4355 struct hda_input_mux *imux = &spec->private_imux[0];
4356 int i, err, idx = 0;
4357
4358 /* for internal loopback recording select */
4359 imux->items[imux->num_items].label = "Stereo Mixer";
4360 imux->items[imux->num_items].index = 5;
4361 imux->num_items++;
4362
4363 for (i = 0; i < AUTO_PIN_LAST; i++) {
4364 if (!cfg->input_pins[i])
4365 continue;
4366
4367 switch (cfg->input_pins[i]) {
4368 case 0x2b: /* Mic */
4369 idx = 1;
4370 break;
4371
4372 case 0x2a: /* Line In */
4373 idx = 2;
4374 break;
4375
4376 case 0x29: /* Front Mic */
4377 idx = 3;
4378 break;
4379
4380 case 0x2c: /* CD */
4381 idx = 0;
4382 break;
4383 }
4384 err = via_new_analog_input(spec, labels[i], idx, 0x21);
4385 if (err < 0)
4386 return err;
4387 imux->items[imux->num_items].label = labels[i];
4388 imux->items[imux->num_items].index = idx;
4389 imux->num_items++;
4390 }
4391 return 0;
4392}
4393
4394static int vt1718S_parse_auto_config(struct hda_codec *codec)
4395{
4396 struct via_spec *spec = codec->spec;
4397 int err;
4398
4399 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
4400
4401 if (err < 0)
4402 return err;
4403 err = vt1718S_auto_fill_dac_nids(spec, &spec->autocfg);
4404 if (err < 0)
4405 return err;
4406 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
4407 return 0; /* can't find valid BIOS pin config */
4408
4409 err = vt1718S_auto_create_multi_out_ctls(spec, &spec->autocfg);
4410 if (err < 0)
4411 return err;
4412 err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
4413 if (err < 0)
4414 return err;
4415 err = vt1718S_auto_create_analog_input_ctls(spec, &spec->autocfg);
4416 if (err < 0)
4417 return err;
4418
4419 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4420
4421 fill_dig_outs(codec);
4422
4423 if (spec->autocfg.dig_in_pin && codec->vendor_id == 0x11060428)
4424 spec->dig_in_nid = 0x13;
4425
4426 if (spec->kctls.list)
4427 spec->mixers[spec->num_mixers++] = spec->kctls.list;
4428
4429 spec->input_mux = &spec->private_imux[0];
4430
4431 if (spec->hp_mux)
4432 spec->mixers[spec->num_mixers++] = via_hp_mixer;
4433
4434 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
4435
4436 return 1;
4437}
4438
4439#ifdef CONFIG_SND_HDA_POWER_SAVE
4440static struct hda_amp_list vt1718S_loopbacks[] = {
4441 { 0x21, HDA_INPUT, 1 },
4442 { 0x21, HDA_INPUT, 2 },
4443 { 0x21, HDA_INPUT, 3 },
4444 { 0x21, HDA_INPUT, 4 },
4445 { } /* end */
4446};
4447#endif
4448
4449static int patch_vt1718S(struct hda_codec *codec)
4450{
4451 struct via_spec *spec;
4452 int err;
4453
4454 /* create a codec specific record */
4455 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4456 if (spec == NULL)
4457 return -ENOMEM;
4458
4459 codec->spec = spec;
4460
4461 /* automatic parse from the BIOS config */
4462 err = vt1718S_parse_auto_config(codec);
4463 if (err < 0) {
4464 via_free(codec);
4465 return err;
4466 } else if (!err) {
4467 printk(KERN_INFO "hda_codec: Cannot set up configuration "
4468 "from BIOS. Using genenic mode...\n");
4469 }
4470
4471 spec->init_verbs[spec->num_iverbs++] = vt1718S_volume_init_verbs;
4472 spec->init_verbs[spec->num_iverbs++] = vt1718S_uniwill_init_verbs;
4473
Lydia Wangbb3c6bf2009-10-10 19:08:39 +08004474 if (codec->vendor_id == 0x11060441)
4475 spec->stream_name_analog = "VT2020 Analog";
4476 else if (codec->vendor_id == 0x11064441)
4477 spec->stream_name_analog = "VT1828S Analog";
4478 else
4479 spec->stream_name_analog = "VT1718S Analog";
Lydia Wangeb7188c2009-10-10 19:08:34 +08004480 spec->stream_analog_playback = &vt1718S_pcm_analog_playback;
4481 spec->stream_analog_capture = &vt1718S_pcm_analog_capture;
4482
Lydia Wangbb3c6bf2009-10-10 19:08:39 +08004483 if (codec->vendor_id == 0x11060441)
4484 spec->stream_name_digital = "VT2020 Digital";
4485 else if (codec->vendor_id == 0x11064441)
4486 spec->stream_name_digital = "VT1828S Digital";
4487 else
4488 spec->stream_name_digital = "VT1718S Digital";
Lydia Wangeb7188c2009-10-10 19:08:34 +08004489 spec->stream_digital_playback = &vt1718S_pcm_digital_playback;
Lydia Wangbb3c6bf2009-10-10 19:08:39 +08004490 if (codec->vendor_id == 0x11060428 || codec->vendor_id == 0x11060441)
Lydia Wangeb7188c2009-10-10 19:08:34 +08004491 spec->stream_digital_capture = &vt1718S_pcm_digital_capture;
4492
4493 if (!spec->adc_nids && spec->input_mux) {
4494 spec->adc_nids = vt1718S_adc_nids;
4495 spec->num_adc_nids = ARRAY_SIZE(vt1718S_adc_nids);
4496 get_mux_nids(codec);
Lydia Wangbb3c6bf2009-10-10 19:08:39 +08004497 override_mic_boost(codec, 0x2b, 0, 3, 40);
4498 override_mic_boost(codec, 0x29, 0, 3, 40);
Lydia Wangeb7188c2009-10-10 19:08:34 +08004499 spec->mixers[spec->num_mixers] = vt1718S_capture_mixer;
4500 spec->num_mixers++;
4501 }
4502
4503 codec->patch_ops = via_patch_ops;
4504
4505 codec->patch_ops.init = via_auto_init;
4506 codec->patch_ops.unsol_event = via_unsol_event,
4507
4508#ifdef CONFIG_SND_HDA_POWER_SAVE
4509 spec->loopback.amplist = vt1718S_loopbacks;
4510#endif
4511
4512 return 0;
4513}
Lydia Wangf3db4232009-10-10 19:08:41 +08004514
4515/* Patch for VT1716S */
4516
4517static int vt1716s_dmic_info(struct snd_kcontrol *kcontrol,
4518 struct snd_ctl_elem_info *uinfo)
4519{
4520 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
4521 uinfo->count = 1;
4522 uinfo->value.integer.min = 0;
4523 uinfo->value.integer.max = 1;
4524 return 0;
4525}
4526
4527static int vt1716s_dmic_get(struct snd_kcontrol *kcontrol,
4528 struct snd_ctl_elem_value *ucontrol)
4529{
4530 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4531 int index = 0;
4532
4533 index = snd_hda_codec_read(codec, 0x26, 0,
4534 AC_VERB_GET_CONNECT_SEL, 0);
4535 if (index != -1)
4536 *ucontrol->value.integer.value = index;
4537
4538 return 0;
4539}
4540
4541static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,
4542 struct snd_ctl_elem_value *ucontrol)
4543{
4544 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4545 struct via_spec *spec = codec->spec;
4546 int index = *ucontrol->value.integer.value;
4547
4548 snd_hda_codec_write(codec, 0x26, 0,
4549 AC_VERB_SET_CONNECT_SEL, index);
4550 spec->dmic_enabled = index;
4551 set_jack_power_state(codec);
4552
4553 return 1;
4554}
4555
4556/* capture mixer elements */
4557static struct snd_kcontrol_new vt1716S_capture_mixer[] = {
4558 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
4559 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
4560 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
4561 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
4562 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT),
4563 HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0,
4564 HDA_INPUT),
4565 {
4566 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4567 .name = "Input Source",
4568 .count = 1,
4569 .info = via_mux_enum_info,
4570 .get = via_mux_enum_get,
4571 .put = via_mux_enum_put,
4572 },
4573 { } /* end */
4574};
4575
4576static struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
4577 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT),
4578 {
4579 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4580 .name = "Digital Mic Capture Switch",
4581 .count = 1,
4582 .info = vt1716s_dmic_info,
4583 .get = vt1716s_dmic_get,
4584 .put = vt1716s_dmic_put,
4585 },
4586 {} /* end */
4587};
4588
4589
4590/* mono-out mixer elements */
4591static struct snd_kcontrol_new vt1716S_mono_out_mixer[] = {
4592 HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT),
4593 { } /* end */
4594};
4595
4596static struct hda_verb vt1716S_volume_init_verbs[] = {
4597 /*
4598 * Unmute ADC0-1 and set the default input to mic-in
4599 */
4600 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4601 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4602
4603
4604 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4605 * mixer widget
4606 */
4607 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
4608 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4609 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4610 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4611 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4612 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4613
4614 /* MUX Indices: Stereo Mixer = 5 */
4615 {0x17, AC_VERB_SET_CONNECT_SEL, 0x5},
4616
4617 /* Setup default input of PW4 to MW0 */
4618 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
4619
4620 /* Setup default input of SW1 as MW0 */
4621 {0x18, AC_VERB_SET_CONNECT_SEL, 0x1},
4622
4623 /* Setup default input of SW4 as AOW0 */
4624 {0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
4625
4626 /* PW9 PW10 Output enable */
4627 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4628 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4629
4630 /* Unmute SW1, PW12 */
4631 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4632 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4633 /* PW12 Output enable */
4634 {0x2a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4635 /* Enable Boost Volume backdoor */
4636 {0x1, 0xf8a, 0x80},
4637 /* don't bybass mixer */
4638 {0x1, 0xf88, 0xc0},
4639 /* Enable mono output */
4640 {0x1, 0xf90, 0x08},
4641 { }
4642};
4643
4644
4645static struct hda_verb vt1716S_uniwill_init_verbs[] = {
4646 {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
4647 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
4648 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4649 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4650 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4651 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE,
4652 AC_USRSP_EN | VIA_MONO_EVENT | VIA_JACK_EVENT},
4653 {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4654 {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4655 { }
4656};
4657
4658static struct hda_pcm_stream vt1716S_pcm_analog_playback = {
4659 .substreams = 2,
4660 .channels_min = 2,
4661 .channels_max = 6,
4662 .nid = 0x10, /* NID to query formats and rates */
4663 .ops = {
4664 .open = via_playback_pcm_open,
4665 .prepare = via_playback_multi_pcm_prepare,
4666 .cleanup = via_playback_multi_pcm_cleanup,
4667 .close = via_pcm_open_close,
4668 },
4669};
4670
4671static struct hda_pcm_stream vt1716S_pcm_analog_capture = {
4672 .substreams = 2,
4673 .channels_min = 2,
4674 .channels_max = 2,
4675 .nid = 0x13, /* NID to query formats and rates */
4676 .ops = {
4677 .open = via_pcm_open_close,
4678 .prepare = via_capture_pcm_prepare,
4679 .cleanup = via_capture_pcm_cleanup,
4680 .close = via_pcm_open_close,
4681 },
4682};
4683
4684static struct hda_pcm_stream vt1716S_pcm_digital_playback = {
4685 .substreams = 2,
4686 .channels_min = 2,
4687 .channels_max = 2,
4688 .rates = SNDRV_PCM_RATE_48000,
4689 /* NID is set in via_build_pcms */
4690 .ops = {
4691 .open = via_dig_playback_pcm_open,
4692 .close = via_dig_playback_pcm_close,
4693 .prepare = via_dig_playback_pcm_prepare,
4694 .cleanup = via_dig_playback_pcm_cleanup
4695 },
4696};
4697
4698/* fill in the dac_nids table from the parsed pin configuration */
4699static int vt1716S_auto_fill_dac_nids(struct via_spec *spec,
4700 const struct auto_pin_cfg *cfg)
4701{ int i;
4702 hda_nid_t nid;
4703
4704 spec->multiout.num_dacs = cfg->line_outs;
4705
4706 spec->multiout.dac_nids = spec->private_dac_nids;
4707
4708 for (i = 0; i < 3; i++) {
4709 nid = cfg->line_out_pins[i];
4710 if (nid) {
4711 /* config dac list */
4712 switch (i) {
4713 case AUTO_SEQ_FRONT:
4714 spec->multiout.dac_nids[i] = 0x10;
4715 break;
4716 case AUTO_SEQ_CENLFE:
4717 spec->multiout.dac_nids[i] = 0x25;
4718 break;
4719 case AUTO_SEQ_SURROUND:
4720 spec->multiout.dac_nids[i] = 0x11;
4721 break;
4722 }
4723 }
4724 }
4725
4726 return 0;
4727}
4728
4729/* add playback controls from the parsed DAC table */
4730static int vt1716S_auto_create_multi_out_ctls(struct via_spec *spec,
4731 const struct auto_pin_cfg *cfg)
4732{
4733 char name[32];
4734 static const char *chname[3] = { "Front", "Surround", "C/LFE" };
4735 hda_nid_t nid_vols[] = {0x10, 0x11, 0x25};
4736 hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x27};
4737 hda_nid_t nid, nid_vol, nid_mute;
4738 int i, err;
4739
4740 for (i = 0; i <= AUTO_SEQ_CENLFE; i++) {
4741 nid = cfg->line_out_pins[i];
4742
4743 if (!nid)
4744 continue;
4745
4746 nid_vol = nid_vols[i];
4747 nid_mute = nid_mutes[i];
4748
4749 if (i == AUTO_SEQ_CENLFE) {
4750 err = via_add_control(
4751 spec, VIA_CTL_WIDGET_VOL,
4752 "Center Playback Volume",
4753 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
4754 if (err < 0)
4755 return err;
4756 err = via_add_control(
4757 spec, VIA_CTL_WIDGET_VOL,
4758 "LFE Playback Volume",
4759 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
4760 if (err < 0)
4761 return err;
4762 err = via_add_control(
4763 spec, VIA_CTL_WIDGET_MUTE,
4764 "Center Playback Switch",
4765 HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0,
4766 HDA_OUTPUT));
4767 if (err < 0)
4768 return err;
4769 err = via_add_control(
4770 spec, VIA_CTL_WIDGET_MUTE,
4771 "LFE Playback Switch",
4772 HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0,
4773 HDA_OUTPUT));
4774 if (err < 0)
4775 return err;
4776 } else if (i == AUTO_SEQ_FRONT) {
4777
4778 err = via_add_control(
4779 spec, VIA_CTL_WIDGET_VOL,
4780 "Master Front Playback Volume",
4781 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT));
4782 if (err < 0)
4783 return err;
4784 err = via_add_control(
4785 spec, VIA_CTL_WIDGET_MUTE,
4786 "Master Front Playback Switch",
4787 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT));
4788 if (err < 0)
4789 return err;
4790
4791 sprintf(name, "%s Playback Volume", chname[i]);
4792 err = via_add_control(
4793 spec, VIA_CTL_WIDGET_VOL, name,
4794 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
4795 if (err < 0)
4796 return err;
4797 sprintf(name, "%s Playback Switch", chname[i]);
4798 err = via_add_control(
4799 spec, VIA_CTL_WIDGET_MUTE, name,
4800 HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
4801 HDA_OUTPUT));
4802 if (err < 0)
4803 return err;
4804 } else {
4805 sprintf(name, "%s Playback Volume", chname[i]);
4806 err = via_add_control(
4807 spec, VIA_CTL_WIDGET_VOL, name,
4808 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
4809 if (err < 0)
4810 return err;
4811 sprintf(name, "%s Playback Switch", chname[i]);
4812 err = via_add_control(
4813 spec, VIA_CTL_WIDGET_MUTE, name,
4814 HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
4815 HDA_OUTPUT));
4816 if (err < 0)
4817 return err;
4818 }
4819 }
4820 return 0;
4821}
4822
4823static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
4824{
4825 int err;
4826
4827 if (!pin)
4828 return 0;
4829
4830 spec->multiout.hp_nid = 0x25; /* AOW3 */
4831 spec->hp_independent_mode_index = 1;
4832
4833 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4834 "Headphone Playback Volume",
4835 HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
4836 if (err < 0)
4837 return err;
4838
4839 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
4840 "Headphone Playback Switch",
4841 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4842 if (err < 0)
4843 return err;
4844
4845 create_hp_imux(spec);
4846 return 0;
4847}
4848
4849/* create playback/capture controls for input pins */
4850static int vt1716S_auto_create_analog_input_ctls(struct via_spec *spec,
4851 const struct auto_pin_cfg *cfg)
4852{
4853 static char *labels[] = {
4854 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
4855 };
4856 struct hda_input_mux *imux = &spec->private_imux[0];
4857 int i, err, idx = 0;
4858
4859 /* for internal loopback recording select */
4860 imux->items[imux->num_items].label = "Stereo Mixer";
4861 imux->items[imux->num_items].index = 5;
4862 imux->num_items++;
4863
4864 for (i = 0; i < AUTO_PIN_LAST; i++) {
4865 if (!cfg->input_pins[i])
4866 continue;
4867
4868 switch (cfg->input_pins[i]) {
4869 case 0x1a: /* Mic */
4870 idx = 2;
4871 break;
4872
4873 case 0x1b: /* Line In */
4874 idx = 3;
4875 break;
4876
4877 case 0x1e: /* Front Mic */
4878 idx = 4;
4879 break;
4880
4881 case 0x1f: /* CD */
4882 idx = 1;
4883 break;
4884 }
4885 err = via_new_analog_input(spec, labels[i], idx, 0x16);
4886 if (err < 0)
4887 return err;
4888 imux->items[imux->num_items].label = labels[i];
4889 imux->items[imux->num_items].index = idx-1;
4890 imux->num_items++;
4891 }
4892 return 0;
4893}
4894
4895static int vt1716S_parse_auto_config(struct hda_codec *codec)
4896{
4897 struct via_spec *spec = codec->spec;
4898 int err;
4899
4900 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
4901 if (err < 0)
4902 return err;
4903 err = vt1716S_auto_fill_dac_nids(spec, &spec->autocfg);
4904 if (err < 0)
4905 return err;
4906 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
4907 return 0; /* can't find valid BIOS pin config */
4908
4909 err = vt1716S_auto_create_multi_out_ctls(spec, &spec->autocfg);
4910 if (err < 0)
4911 return err;
4912 err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
4913 if (err < 0)
4914 return err;
4915 err = vt1716S_auto_create_analog_input_ctls(spec, &spec->autocfg);
4916 if (err < 0)
4917 return err;
4918
4919 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4920
4921 fill_dig_outs(codec);
4922
4923 if (spec->kctls.list)
4924 spec->mixers[spec->num_mixers++] = spec->kctls.list;
4925
4926 spec->input_mux = &spec->private_imux[0];
4927
4928 if (spec->hp_mux)
4929 spec->mixers[spec->num_mixers++] = via_hp_mixer;
4930
4931 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
4932
4933 return 1;
4934}
4935
4936#ifdef CONFIG_SND_HDA_POWER_SAVE
4937static struct hda_amp_list vt1716S_loopbacks[] = {
4938 { 0x16, HDA_INPUT, 1 },
4939 { 0x16, HDA_INPUT, 2 },
4940 { 0x16, HDA_INPUT, 3 },
4941 { 0x16, HDA_INPUT, 4 },
4942 { } /* end */
4943};
4944#endif
4945
4946static int patch_vt1716S(struct hda_codec *codec)
4947{
4948 struct via_spec *spec;
4949 int err;
4950
4951 /* create a codec specific record */
4952 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4953 if (spec == NULL)
4954 return -ENOMEM;
4955
4956 codec->spec = spec;
4957
4958 /* automatic parse from the BIOS config */
4959 err = vt1716S_parse_auto_config(codec);
4960 if (err < 0) {
4961 via_free(codec);
4962 return err;
4963 } else if (!err) {
4964 printk(KERN_INFO "hda_codec: Cannot set up configuration "
4965 "from BIOS. Using genenic mode...\n");
4966 }
4967
4968 spec->init_verbs[spec->num_iverbs++] = vt1716S_volume_init_verbs;
4969 spec->init_verbs[spec->num_iverbs++] = vt1716S_uniwill_init_verbs;
4970
4971 spec->stream_name_analog = "VT1716S Analog";
4972 spec->stream_analog_playback = &vt1716S_pcm_analog_playback;
4973 spec->stream_analog_capture = &vt1716S_pcm_analog_capture;
4974
4975 spec->stream_name_digital = "VT1716S Digital";
4976 spec->stream_digital_playback = &vt1716S_pcm_digital_playback;
4977
4978 if (!spec->adc_nids && spec->input_mux) {
4979 spec->adc_nids = vt1716S_adc_nids;
4980 spec->num_adc_nids = ARRAY_SIZE(vt1716S_adc_nids);
4981 get_mux_nids(codec);
4982 override_mic_boost(codec, 0x1a, 0, 3, 40);
4983 override_mic_boost(codec, 0x1e, 0, 3, 40);
4984 spec->mixers[spec->num_mixers] = vt1716S_capture_mixer;
4985 spec->num_mixers++;
4986 }
4987
4988 spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer;
4989 spec->num_mixers++;
4990
4991 spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer;
4992
4993 codec->patch_ops = via_patch_ops;
4994
4995 codec->patch_ops.init = via_auto_init;
4996 codec->patch_ops.unsol_event = via_unsol_event,
4997
4998#ifdef CONFIG_SND_HDA_POWER_SAVE
4999 spec->loopback.amplist = vt1716S_loopbacks;
5000#endif
5001
5002 return 0;
5003}
Joseph Chanc577b8a2006-11-29 15:29:40 +01005004/*
5005 * patch entries
5006 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +01005007static struct hda_codec_preset snd_hda_preset_via[] = {
Takashi Iwai3218c172008-12-18 09:17:56 +01005008 { .id = 0x11061708, .name = "VT1708", .patch = patch_vt1708},
5009 { .id = 0x11061709, .name = "VT1708", .patch = patch_vt1708},
5010 { .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708},
5011 { .id = 0x1106170b, .name = "VT1708", .patch = patch_vt1708},
5012 { .id = 0x1106e710, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005013 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005014 { .id = 0x1106e711, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005015 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005016 { .id = 0x1106e712, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005017 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005018 { .id = 0x1106e713, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005019 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005020 { .id = 0x1106e714, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005021 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005022 { .id = 0x1106e715, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005023 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005024 { .id = 0x1106e716, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005025 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005026 { .id = 0x1106e717, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005027 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005028 { .id = 0x1106e720, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005029 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005030 { .id = 0x1106e721, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005031 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005032 { .id = 0x1106e722, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005033 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005034 { .id = 0x1106e723, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005035 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005036 { .id = 0x1106e724, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005037 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005038 { .id = 0x1106e725, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005039 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005040 { .id = 0x1106e726, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005041 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005042 { .id = 0x1106e727, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01005043 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01005044 { .id = 0x11060397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08005045 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01005046 { .id = 0x11061397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08005047 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01005048 { .id = 0x11062397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08005049 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01005050 { .id = 0x11063397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08005051 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01005052 { .id = 0x11064397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08005053 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01005054 { .id = 0x11065397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08005055 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01005056 { .id = 0x11066397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08005057 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01005058 { .id = 0x11067397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08005059 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01005060 { .id = 0x11060398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08005061 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01005062 { .id = 0x11061398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08005063 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01005064 { .id = 0x11062398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08005065 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01005066 { .id = 0x11063398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08005067 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01005068 { .id = 0x11064398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08005069 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01005070 { .id = 0x11065398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08005071 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01005072 { .id = 0x11066398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08005073 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01005074 { .id = 0x11067398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08005075 .patch = patch_vt1702},
Lydia Wangeb7188c2009-10-10 19:08:34 +08005076 { .id = 0x11060428, .name = "VT1718S",
5077 .patch = patch_vt1718S},
5078 { .id = 0x11064428, .name = "VT1718S",
5079 .patch = patch_vt1718S},
Lydia Wangbb3c6bf2009-10-10 19:08:39 +08005080 { .id = 0x11060441, .name = "VT2020",
5081 .patch = patch_vt1718S},
5082 { .id = 0x11064441, .name = "VT1828S",
5083 .patch = patch_vt1718S},
Lydia Wangf3db4232009-10-10 19:08:41 +08005084 { .id = 0x11060433, .name = "VT1716S",
5085 .patch = patch_vt1716S},
5086 { .id = 0x1106a721, .name = "VT1716S",
5087 .patch = patch_vt1716S},
Joseph Chanc577b8a2006-11-29 15:29:40 +01005088 {} /* terminator */
5089};
Takashi Iwai1289e9e2008-11-27 15:47:11 +01005090
5091MODULE_ALIAS("snd-hda-codec-id:1106*");
5092
5093static struct hda_codec_preset_list via_list = {
5094 .preset = snd_hda_preset_via,
5095 .owner = THIS_MODULE,
5096};
5097
5098MODULE_LICENSE("GPL");
5099MODULE_DESCRIPTION("VIA HD-audio codec");
5100
5101static int __init patch_via_init(void)
5102{
5103 return snd_hda_add_codec_preset(&via_list);
5104}
5105
5106static void __exit patch_via_exit(void)
5107{
5108 snd_hda_delete_codec_preset(&via_list);
5109}
5110
5111module_init(patch_via_init)
5112module_exit(patch_via_exit)