blob: 5a856009c916b8f466931d5029456ece0ed82f41 [file] [log] [blame]
Joseph Chanc577b8a2006-11-29 15:29:40 +01001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
Lydia Wang8e865972009-10-10 19:08:52 +08004 * HD audio interface patch for VIA VT17xx/VT18xx/VT20xx codec
Joseph Chanc577b8a2006-11-29 15:29:40 +01005 *
Lydia Wang8e865972009-10-10 19:08:52 +08006 * (C) 2006-2009 VIA Technology, Inc.
7 * (C) 2006-2008 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 * * * * * * * * * * * * * * * * */
Lydia Wang377ff312009-10-10 19:08:55 +080025/* */
Joseph Chanc577b8a2006-11-29 15:29:40 +010026/* 2006-03-03 Lydia Wang Create the basic patch to support VT1708 codec */
Lydia Wang377ff312009-10-10 19:08:55 +080027/* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */
28/* 2006-08-02 Lydia Wang Add support to VT1709 codec */
Joseph Chanc577b8a2006-11-29 15:29:40 +010029/* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */
Lydia Wang377ff312009-10-10 19:08:55 +080030/* 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 */
Lydia Wang377ff312009-10-10 19:08:55 +080034/* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */
35/* 2008-04-09 Lydia Wang Add mute front speaker when HP plugin */
36/* 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 */
Lydia Wang377ff312009-10-10 19:08:55 +080038/* 2008-09-15 Logan Li Add VT1708S Mic Boost workaround/backdoor */
Lydia Wang8e865972009-10-10 19:08:52 +080039/* 2009-02-16 Logan Li Add support for VT1718S */
40/* 2009-03-13 Logan Li Add support for VT1716S */
41/* 2009-04-14 Lydai Wang Add support for VT1828S and VT2020 */
42/* 2009-07-08 Lydia Wang Add support for VT2002P */
43/* 2009-07-21 Lydia Wang Add support for VT1812 */
Lydia Wang36dd5c42009-10-20 13:18:04 +080044/* 2009-09-19 Lydia Wang Add support for VT1818S */
Lydia Wang377ff312009-10-10 19:08:55 +080045/* */
Joseph Chanc577b8a2006-11-29 15:29:40 +010046/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
47
48
Joseph Chanc577b8a2006-11-29 15:29:40 +010049#include <linux/init.h>
50#include <linux/delay.h>
51#include <linux/slab.h>
Joseph Chanc577b8a2006-11-29 15:29:40 +010052#include <sound/core.h>
Harald Welte0aa62ae2008-09-09 15:58:27 +080053#include <sound/asoundef.h>
Joseph Chanc577b8a2006-11-29 15:29:40 +010054#include "hda_codec.h"
55#include "hda_local.h"
Joseph Chanc577b8a2006-11-29 15:29:40 +010056
57/* amp values */
58#define AMP_VAL_IDX_SHIFT 19
59#define AMP_VAL_IDX_MASK (0x0f<<19)
60
Joseph Chanc577b8a2006-11-29 15:29:40 +010061/* Pin Widget NID */
62#define VT1708_HP_NID 0x13
63#define VT1708_DIGOUT_NID 0x14
64#define VT1708_DIGIN_NID 0x16
Josepch Chanf7278fd2007-12-13 16:40:40 +010065#define VT1708_DIGIN_PIN 0x26
Harald Welted949cac2008-09-09 15:56:01 +080066#define VT1708_HP_PIN_NID 0x20
67#define VT1708_CD_PIN_NID 0x24
Joseph Chanc577b8a2006-11-29 15:29:40 +010068
69#define VT1709_HP_DAC_NID 0x28
70#define VT1709_DIGOUT_NID 0x13
71#define VT1709_DIGIN_NID 0x17
Josepch Chanf7278fd2007-12-13 16:40:40 +010072#define VT1709_DIGIN_PIN 0x25
73
74#define VT1708B_HP_NID 0x25
75#define VT1708B_DIGOUT_NID 0x12
76#define VT1708B_DIGIN_NID 0x15
77#define VT1708B_DIGIN_PIN 0x21
Joseph Chanc577b8a2006-11-29 15:29:40 +010078
Harald Welted949cac2008-09-09 15:56:01 +080079#define VT1708S_HP_NID 0x25
80#define VT1708S_DIGOUT_NID 0x12
81
82#define VT1702_HP_NID 0x17
83#define VT1702_DIGOUT_NID 0x11
84
Harald Welted7426322008-09-15 22:43:23 +080085enum VIA_HDA_CODEC {
86 UNKNOWN = -1,
87 VT1708,
88 VT1709_10CH,
89 VT1709_6CH,
90 VT1708B_8CH,
91 VT1708B_4CH,
92 VT1708S,
Lydia Wang518bf3b2009-10-10 19:07:29 +080093 VT1708BCE,
Harald Welted7426322008-09-15 22:43:23 +080094 VT1702,
Lydia Wangeb7188c2009-10-10 19:08:34 +080095 VT1718S,
Lydia Wangf3db4232009-10-10 19:08:41 +080096 VT1716S,
Lydia Wang25eaba22009-10-10 19:08:43 +080097 VT2002P,
Lydia Wangab6734e2009-10-10 19:08:46 +080098 VT1812,
Harald Welted7426322008-09-15 22:43:23 +080099 CODEC_TYPES,
100};
101
Lydia Wang1f2e99f2009-10-10 19:08:17 +0800102struct via_spec {
103 /* codec parameterization */
Lydia Wangf3db4232009-10-10 19:08:41 +0800104 struct snd_kcontrol_new *mixers[6];
Lydia Wang1f2e99f2009-10-10 19:08:17 +0800105 unsigned int num_mixers;
106
107 struct hda_verb *init_verbs[5];
108 unsigned int num_iverbs;
109
110 char *stream_name_analog;
111 struct hda_pcm_stream *stream_analog_playback;
112 struct hda_pcm_stream *stream_analog_capture;
113
114 char *stream_name_digital;
115 struct hda_pcm_stream *stream_digital_playback;
116 struct hda_pcm_stream *stream_digital_capture;
117
118 /* playback */
119 struct hda_multi_out multiout;
120 hda_nid_t slave_dig_outs[2];
121
122 /* capture */
123 unsigned int num_adc_nids;
124 hda_nid_t *adc_nids;
125 hda_nid_t mux_nids[3];
126 hda_nid_t dig_in_nid;
127 hda_nid_t dig_in_pin;
128
129 /* capture source */
130 const struct hda_input_mux *input_mux;
131 unsigned int cur_mux[3];
132
133 /* PCM information */
134 struct hda_pcm pcm_rec[3];
135
136 /* dynamic controls, init_verbs and input_mux */
137 struct auto_pin_cfg autocfg;
138 struct snd_array kctls;
139 struct hda_input_mux private_imux[2];
140 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
141
142 /* HP mode source */
143 const struct hda_input_mux *hp_mux;
144 unsigned int hp_independent_mode;
145 unsigned int hp_independent_mode_index;
146 unsigned int smart51_enabled;
Lydia Wangf3db4232009-10-10 19:08:41 +0800147 unsigned int dmic_enabled;
Lydia Wang1f2e99f2009-10-10 19:08:17 +0800148 enum VIA_HDA_CODEC codec_type;
149
150 /* work to check hp jack state */
151 struct hda_codec *codec;
152 struct delayed_work vt1708_hp_work;
153 int vt1708_jack_detectect;
154 int vt1708_hp_present;
155#ifdef CONFIG_SND_HDA_POWER_SAVE
156 struct hda_loopback_check loopback;
157#endif
158};
159
Lydia Wang744ff5f2009-10-10 19:07:26 +0800160static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
Harald Welted7426322008-09-15 22:43:23 +0800161{
Lydia Wang744ff5f2009-10-10 19:07:26 +0800162 u32 vendor_id = codec->vendor_id;
Harald Welted7426322008-09-15 22:43:23 +0800163 u16 ven_id = vendor_id >> 16;
164 u16 dev_id = vendor_id & 0xffff;
165 enum VIA_HDA_CODEC codec_type;
166
167 /* get codec type */
168 if (ven_id != 0x1106)
169 codec_type = UNKNOWN;
170 else if (dev_id >= 0x1708 && dev_id <= 0x170b)
171 codec_type = VT1708;
172 else if (dev_id >= 0xe710 && dev_id <= 0xe713)
173 codec_type = VT1709_10CH;
174 else if (dev_id >= 0xe714 && dev_id <= 0xe717)
175 codec_type = VT1709_6CH;
Lydia Wang518bf3b2009-10-10 19:07:29 +0800176 else if (dev_id >= 0xe720 && dev_id <= 0xe723) {
Harald Welted7426322008-09-15 22:43:23 +0800177 codec_type = VT1708B_8CH;
Lydia Wang518bf3b2009-10-10 19:07:29 +0800178 if (snd_hda_param_read(codec, 0x16, AC_PAR_CONNLIST_LEN) == 0x7)
179 codec_type = VT1708BCE;
180 } else if (dev_id >= 0xe724 && dev_id <= 0xe727)
Harald Welted7426322008-09-15 22:43:23 +0800181 codec_type = VT1708B_4CH;
182 else if ((dev_id & 0xfff) == 0x397
183 && (dev_id >> 12) < 8)
184 codec_type = VT1708S;
185 else if ((dev_id & 0xfff) == 0x398
186 && (dev_id >> 12) < 8)
187 codec_type = VT1702;
Lydia Wangeb7188c2009-10-10 19:08:34 +0800188 else if ((dev_id & 0xfff) == 0x428
189 && (dev_id >> 12) < 8)
190 codec_type = VT1718S;
Lydia Wangf3db4232009-10-10 19:08:41 +0800191 else if (dev_id == 0x0433 || dev_id == 0xa721)
192 codec_type = VT1716S;
Lydia Wangbb3c6bfc2009-10-10 19:08:39 +0800193 else if (dev_id == 0x0441 || dev_id == 0x4441)
194 codec_type = VT1718S;
Lydia Wang25eaba22009-10-10 19:08:43 +0800195 else if (dev_id == 0x0438 || dev_id == 0x4438)
196 codec_type = VT2002P;
Lydia Wangab6734e2009-10-10 19:08:46 +0800197 else if (dev_id == 0x0448)
198 codec_type = VT1812;
Lydia Wang36dd5c42009-10-20 13:18:04 +0800199 else if (dev_id == 0x0440)
200 codec_type = VT1708S;
Harald Welted7426322008-09-15 22:43:23 +0800201 else
202 codec_type = UNKNOWN;
203 return codec_type;
204};
205
Harald Welte69e52a82008-09-09 15:57:32 +0800206#define VIA_HP_EVENT 0x01
207#define VIA_GPIO_EVENT 0x02
Lydia Wanga34df192009-10-10 19:08:01 +0800208#define VIA_JACK_EVENT 0x04
Lydia Wangf3db4232009-10-10 19:08:41 +0800209#define VIA_MONO_EVENT 0x08
Lydia Wang25eaba22009-10-10 19:08:43 +0800210#define VIA_SPEAKER_EVENT 0x10
211#define VIA_BIND_HP_EVENT 0x20
Harald Welte69e52a82008-09-09 15:57:32 +0800212
Joseph Chanc577b8a2006-11-29 15:29:40 +0100213enum {
214 VIA_CTL_WIDGET_VOL,
215 VIA_CTL_WIDGET_MUTE,
Lydia Wangf5271102009-10-10 19:07:35 +0800216 VIA_CTL_WIDGET_ANALOG_MUTE,
Lydia Wang25eaba22009-10-10 19:08:43 +0800217 VIA_CTL_WIDGET_BIND_PIN_MUTE,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100218};
219
220enum {
Harald Welteeb14a462008-09-09 15:40:38 +0800221 AUTO_SEQ_FRONT = 0,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100222 AUTO_SEQ_SURROUND,
223 AUTO_SEQ_CENLFE,
224 AUTO_SEQ_SIDE
225};
226
Lydia Wangf5271102009-10-10 19:07:35 +0800227static void analog_low_current_mode(struct hda_codec *codec, int stream_idle);
228static void set_jack_power_state(struct hda_codec *codec);
Lydia Wang1f2e99f2009-10-10 19:08:17 +0800229static int is_aa_path_mute(struct hda_codec *codec);
230
231static void vt1708_start_hp_work(struct via_spec *spec)
232{
233 if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
234 return;
235 snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
236 !spec->vt1708_jack_detectect);
237 if (!delayed_work_pending(&spec->vt1708_hp_work))
238 schedule_delayed_work(&spec->vt1708_hp_work,
239 msecs_to_jiffies(100));
240}
241
242static void vt1708_stop_hp_work(struct via_spec *spec)
243{
244 if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
245 return;
246 if (snd_hda_get_bool_hint(spec->codec, "analog_loopback_hp_detect") == 1
247 && !is_aa_path_mute(spec->codec))
248 return;
249 snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
250 !spec->vt1708_jack_detectect);
251 cancel_delayed_work(&spec->vt1708_hp_work);
252 flush_scheduled_work();
253}
Lydia Wangf5271102009-10-10 19:07:35 +0800254
Lydia Wang25eaba22009-10-10 19:08:43 +0800255
Lydia Wangf5271102009-10-10 19:07:35 +0800256static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
257 struct snd_ctl_elem_value *ucontrol)
258{
259 int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
260 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
261
262 set_jack_power_state(codec);
263 analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1);
Lydia Wang1f2e99f2009-10-10 19:08:17 +0800264 if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) {
265 if (is_aa_path_mute(codec))
266 vt1708_start_hp_work(codec->spec);
267 else
268 vt1708_stop_hp_work(codec->spec);
269 }
Lydia Wangf5271102009-10-10 19:07:35 +0800270 return change;
271}
272
273/* modify .put = snd_hda_mixer_amp_switch_put */
274#define ANALOG_INPUT_MUTE \
275 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
276 .name = NULL, \
277 .index = 0, \
278 .info = snd_hda_mixer_amp_switch_info, \
279 .get = snd_hda_mixer_amp_switch_get, \
280 .put = analog_input_switch_put, \
281 .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
282
Lydia Wang25eaba22009-10-10 19:08:43 +0800283static void via_hp_bind_automute(struct hda_codec *codec);
284
285static int bind_pin_switch_put(struct snd_kcontrol *kcontrol,
286 struct snd_ctl_elem_value *ucontrol)
287{
288 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
289 struct via_spec *spec = codec->spec;
290 int i;
291 int change = 0;
292
293 long *valp = ucontrol->value.integer.value;
294 int lmute, rmute;
295 if (strstr(kcontrol->id.name, "Switch") == NULL) {
296 snd_printd("Invalid control!\n");
297 return change;
298 }
299 change = snd_hda_mixer_amp_switch_put(kcontrol,
300 ucontrol);
301 /* Get mute value */
302 lmute = *valp ? 0 : HDA_AMP_MUTE;
303 valp++;
304 rmute = *valp ? 0 : HDA_AMP_MUTE;
305
306 /* Set hp pins */
307 if (!spec->hp_independent_mode) {
308 for (i = 0; i < spec->autocfg.hp_outs; i++) {
309 snd_hda_codec_amp_update(
310 codec, spec->autocfg.hp_pins[i],
311 0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
312 lmute);
313 snd_hda_codec_amp_update(
314 codec, spec->autocfg.hp_pins[i],
315 1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
316 rmute);
317 }
318 }
319
320 if (!lmute && !rmute) {
321 /* Line Outs */
322 for (i = 0; i < spec->autocfg.line_outs; i++)
323 snd_hda_codec_amp_stereo(
324 codec, spec->autocfg.line_out_pins[i],
325 HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
326 /* Speakers */
327 for (i = 0; i < spec->autocfg.speaker_outs; i++)
328 snd_hda_codec_amp_stereo(
329 codec, spec->autocfg.speaker_pins[i],
330 HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
331 /* unmute */
332 via_hp_bind_automute(codec);
333
334 } else {
335 if (lmute) {
336 /* Mute all left channels */
337 for (i = 1; i < spec->autocfg.line_outs; i++)
338 snd_hda_codec_amp_update(
339 codec,
340 spec->autocfg.line_out_pins[i],
341 0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
342 lmute);
343 for (i = 0; i < spec->autocfg.speaker_outs; i++)
344 snd_hda_codec_amp_update(
345 codec,
346 spec->autocfg.speaker_pins[i],
347 0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
348 lmute);
349 }
350 if (rmute) {
351 /* mute all right channels */
352 for (i = 1; i < spec->autocfg.line_outs; i++)
353 snd_hda_codec_amp_update(
354 codec,
355 spec->autocfg.line_out_pins[i],
356 1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
357 rmute);
358 for (i = 0; i < spec->autocfg.speaker_outs; i++)
359 snd_hda_codec_amp_update(
360 codec,
361 spec->autocfg.speaker_pins[i],
362 1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
363 rmute);
364 }
365 }
366 return change;
367}
368
369#define BIND_PIN_MUTE \
370 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
371 .name = NULL, \
372 .index = 0, \
373 .info = snd_hda_mixer_amp_switch_info, \
374 .get = snd_hda_mixer_amp_switch_get, \
375 .put = bind_pin_switch_put, \
376 .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
377
Lydia Wang71eb7dc2009-10-10 19:08:49 +0800378static struct snd_kcontrol_new via_control_templates[] = {
Joseph Chanc577b8a2006-11-29 15:29:40 +0100379 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
380 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Lydia Wangf5271102009-10-10 19:07:35 +0800381 ANALOG_INPUT_MUTE,
Lydia Wang25eaba22009-10-10 19:08:43 +0800382 BIND_PIN_MUTE,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100383};
384
Joseph Chanc577b8a2006-11-29 15:29:40 +0100385static hda_nid_t vt1708_adc_nids[2] = {
386 /* ADC1-2 */
387 0x15, 0x27
388};
389
390static hda_nid_t vt1709_adc_nids[3] = {
391 /* ADC1-2 */
392 0x14, 0x15, 0x16
393};
394
Josepch Chanf7278fd2007-12-13 16:40:40 +0100395static hda_nid_t vt1708B_adc_nids[2] = {
396 /* ADC1-2 */
397 0x13, 0x14
398};
399
Harald Welted949cac2008-09-09 15:56:01 +0800400static hda_nid_t vt1708S_adc_nids[2] = {
401 /* ADC1-2 */
402 0x13, 0x14
403};
404
405static hda_nid_t vt1702_adc_nids[3] = {
406 /* ADC1-2 */
407 0x12, 0x20, 0x1F
408};
409
Lydia Wangeb7188c2009-10-10 19:08:34 +0800410static hda_nid_t vt1718S_adc_nids[2] = {
411 /* ADC1-2 */
412 0x10, 0x11
413};
414
Lydia Wangf3db4232009-10-10 19:08:41 +0800415static hda_nid_t vt1716S_adc_nids[2] = {
416 /* ADC1-2 */
417 0x13, 0x14
418};
419
Lydia Wang25eaba22009-10-10 19:08:43 +0800420static hda_nid_t vt2002P_adc_nids[2] = {
421 /* ADC1-2 */
422 0x10, 0x11
423};
424
Lydia Wangab6734e2009-10-10 19:08:46 +0800425static hda_nid_t vt1812_adc_nids[2] = {
426 /* ADC1-2 */
427 0x10, 0x11
428};
429
430
Joseph Chanc577b8a2006-11-29 15:29:40 +0100431/* add dynamic controls */
432static int via_add_control(struct via_spec *spec, int type, const char *name,
433 unsigned long val)
434{
435 struct snd_kcontrol_new *knew;
436
Takashi Iwai603c4012008-07-30 15:01:44 +0200437 snd_array_init(&spec->kctls, sizeof(*knew), 32);
438 knew = snd_array_new(&spec->kctls);
439 if (!knew)
440 return -ENOMEM;
Lydia Wang71eb7dc2009-10-10 19:08:49 +0800441 *knew = via_control_templates[type];
Joseph Chanc577b8a2006-11-29 15:29:40 +0100442 knew->name = kstrdup(name, GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100443 if (!knew->name)
444 return -ENOMEM;
445 knew->private_value = val;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100446 return 0;
447}
448
Takashi Iwai603c4012008-07-30 15:01:44 +0200449static void via_free_kctls(struct hda_codec *codec)
450{
451 struct via_spec *spec = codec->spec;
452
453 if (spec->kctls.list) {
454 struct snd_kcontrol_new *kctl = spec->kctls.list;
455 int i;
456 for (i = 0; i < spec->kctls.used; i++)
457 kfree(kctl[i].name);
458 }
459 snd_array_free(&spec->kctls);
460}
461
Joseph Chanc577b8a2006-11-29 15:29:40 +0100462/* create input playback/capture controls for the given pin */
Lydia Wang9510e8d2009-10-10 19:07:39 +0800463static int via_new_analog_input(struct via_spec *spec, const char *ctlname,
464 int idx, int mix_nid)
Joseph Chanc577b8a2006-11-29 15:29:40 +0100465{
466 char name[32];
467 int err;
468
469 sprintf(name, "%s Playback Volume", ctlname);
470 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
471 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
472 if (err < 0)
473 return err;
474 sprintf(name, "%s Playback Switch", ctlname);
Lydia Wangf5271102009-10-10 19:07:35 +0800475 err = via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name,
Joseph Chanc577b8a2006-11-29 15:29:40 +0100476 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
477 if (err < 0)
478 return err;
479 return 0;
480}
481
482static void via_auto_set_output_and_unmute(struct hda_codec *codec,
483 hda_nid_t nid, int pin_type,
484 int dac_idx)
485{
486 /* set as output */
487 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
488 pin_type);
489 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
490 AMP_OUT_UNMUTE);
Takashi Iwaid3a11e62009-07-07 13:43:35 +0200491 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
Lydia Wang377ff312009-10-10 19:08:55 +0800492 snd_hda_codec_write(codec, nid, 0,
Takashi Iwaid3a11e62009-07-07 13:43:35 +0200493 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
Joseph Chanc577b8a2006-11-29 15:29:40 +0100494}
495
496
497static void via_auto_init_multi_out(struct hda_codec *codec)
498{
499 struct via_spec *spec = codec->spec;
500 int i;
501
502 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
503 hda_nid_t nid = spec->autocfg.line_out_pins[i];
504 if (nid)
505 via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
506 }
507}
508
509static void via_auto_init_hp_out(struct hda_codec *codec)
510{
511 struct via_spec *spec = codec->spec;
512 hda_nid_t pin;
Lydia Wang25eaba22009-10-10 19:08:43 +0800513 int i;
Joseph Chanc577b8a2006-11-29 15:29:40 +0100514
Lydia Wang25eaba22009-10-10 19:08:43 +0800515 for (i = 0; i < spec->autocfg.hp_outs; i++) {
516 pin = spec->autocfg.hp_pins[i];
517 if (pin) /* connect to front */
518 via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
519 }
Joseph Chanc577b8a2006-11-29 15:29:40 +0100520}
521
522static void via_auto_init_analog_input(struct hda_codec *codec)
523{
524 struct via_spec *spec = codec->spec;
525 int i;
526
527 for (i = 0; i < AUTO_PIN_LAST; i++) {
528 hda_nid_t nid = spec->autocfg.input_pins[i];
529
530 snd_hda_codec_write(codec, nid, 0,
531 AC_VERB_SET_PIN_WIDGET_CONTROL,
532 (i <= AUTO_PIN_FRONT_MIC ?
533 PIN_VREF50 : PIN_IN));
534
535 }
536}
Lydia Wangf5271102009-10-10 19:07:35 +0800537
Lydia Wang1564b282009-10-10 19:07:52 +0800538static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
539
Lydia Wangf5271102009-10-10 19:07:35 +0800540static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
541 unsigned int *affected_parm)
542{
543 unsigned parm;
544 unsigned def_conf = snd_hda_codec_get_pincfg(codec, nid);
545 unsigned no_presence = (def_conf & AC_DEFCFG_MISC)
546 >> AC_DEFCFG_MISC_SHIFT
547 & AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */
548 unsigned present = snd_hda_codec_read(codec, nid, 0,
549 AC_VERB_GET_PIN_SENSE, 0) >> 31;
Lydia Wang1564b282009-10-10 19:07:52 +0800550 struct via_spec *spec = codec->spec;
551 if ((spec->smart51_enabled && is_smart51_pins(spec, nid))
552 || ((no_presence || present)
553 && get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) {
Lydia Wangf5271102009-10-10 19:07:35 +0800554 *affected_parm = AC_PWRST_D0; /* if it's connected */
555 parm = AC_PWRST_D0;
556 } else
557 parm = AC_PWRST_D3;
558
559 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
560}
561
562static void set_jack_power_state(struct hda_codec *codec)
563{
564 struct via_spec *spec = codec->spec;
565 int imux_is_smixer;
566 unsigned int parm;
567
568 if (spec->codec_type == VT1702) {
569 imux_is_smixer = snd_hda_codec_read(
570 codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
571 /* inputs */
572 /* PW 1/2/5 (14h/15h/18h) */
573 parm = AC_PWRST_D3;
574 set_pin_power_state(codec, 0x14, &parm);
575 set_pin_power_state(codec, 0x15, &parm);
576 set_pin_power_state(codec, 0x18, &parm);
577 if (imux_is_smixer)
578 parm = AC_PWRST_D0; /* SW0 = stereo mixer (idx 3) */
579 /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
580 snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
581 parm);
582 snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE,
583 parm);
584 snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
585 parm);
586 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE,
587 parm);
588
589 /* outputs */
590 /* PW 3/4 (16h/17h) */
591 parm = AC_PWRST_D3;
592 set_pin_power_state(codec, 0x16, &parm);
593 set_pin_power_state(codec, 0x17, &parm);
594 /* MW0 (1ah), AOW 0/1 (10h/1dh) */
595 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
596 imux_is_smixer ? AC_PWRST_D0 : parm);
597 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
598 parm);
599 snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE,
600 parm);
601 } else if (spec->codec_type == VT1708B_8CH
602 || spec->codec_type == VT1708B_4CH
603 || spec->codec_type == VT1708S) {
604 /* SW0 (17h) = stereo mixer */
605 int is_8ch = spec->codec_type != VT1708B_4CH;
606 imux_is_smixer = snd_hda_codec_read(
607 codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
608 == ((spec->codec_type == VT1708S) ? 5 : 0);
609 /* inputs */
610 /* PW 1/2/5 (1ah/1bh/1eh) */
611 parm = AC_PWRST_D3;
612 set_pin_power_state(codec, 0x1a, &parm);
613 set_pin_power_state(codec, 0x1b, &parm);
614 set_pin_power_state(codec, 0x1e, &parm);
615 if (imux_is_smixer)
616 parm = AC_PWRST_D0;
617 /* SW0 (17h), AIW 0/1 (13h/14h) */
618 snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
619 parm);
620 snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
621 parm);
622 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
623 parm);
624
625 /* outputs */
626 /* PW0 (19h), SW1 (18h), AOW1 (11h) */
627 parm = AC_PWRST_D3;
628 set_pin_power_state(codec, 0x19, &parm);
629 snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
630 parm);
631 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
632 parm);
633
634 /* PW6 (22h), SW2 (26h), AOW2 (24h) */
635 if (is_8ch) {
636 parm = AC_PWRST_D3;
637 set_pin_power_state(codec, 0x22, &parm);
638 snd_hda_codec_write(codec, 0x26, 0,
639 AC_VERB_SET_POWER_STATE, parm);
640 snd_hda_codec_write(codec, 0x24, 0,
641 AC_VERB_SET_POWER_STATE, parm);
642 }
643
644 /* PW 3/4/7 (1ch/1dh/23h) */
645 parm = AC_PWRST_D3;
646 /* force to D0 for internal Speaker */
647 set_pin_power_state(codec, 0x1c, &parm);
648 set_pin_power_state(codec, 0x1d, &parm);
649 if (is_8ch)
650 set_pin_power_state(codec, 0x23, &parm);
651 /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
652 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
653 imux_is_smixer ? AC_PWRST_D0 : parm);
654 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
655 parm);
656 if (is_8ch) {
657 snd_hda_codec_write(codec, 0x25, 0,
658 AC_VERB_SET_POWER_STATE, parm);
659 snd_hda_codec_write(codec, 0x27, 0,
660 AC_VERB_SET_POWER_STATE, parm);
661 }
Lydia Wangeb7188c2009-10-10 19:08:34 +0800662 } else if (spec->codec_type == VT1718S) {
663 /* MUX6 (1eh) = stereo mixer */
664 imux_is_smixer = snd_hda_codec_read(
665 codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
666 /* inputs */
667 /* PW 5/6/7 (29h/2ah/2bh) */
668 parm = AC_PWRST_D3;
669 set_pin_power_state(codec, 0x29, &parm);
670 set_pin_power_state(codec, 0x2a, &parm);
671 set_pin_power_state(codec, 0x2b, &parm);
672 if (imux_is_smixer)
673 parm = AC_PWRST_D0;
674 /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */
675 snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE,
676 parm);
677 snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
678 parm);
679 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
680 parm);
681 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
682 parm);
683
684 /* outputs */
685 /* PW3 (27h), MW2 (1ah), AOW3 (bh) */
686 parm = AC_PWRST_D3;
687 set_pin_power_state(codec, 0x27, &parm);
688 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
689 parm);
690 snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE,
691 parm);
692
693 /* PW2 (26h), AOW2 (ah) */
694 parm = AC_PWRST_D3;
695 set_pin_power_state(codec, 0x26, &parm);
696 snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE,
697 parm);
698
699 /* PW0/1 (24h/25h) */
700 parm = AC_PWRST_D3;
701 set_pin_power_state(codec, 0x24, &parm);
702 set_pin_power_state(codec, 0x25, &parm);
703 if (!spec->hp_independent_mode) /* check for redirected HP */
704 set_pin_power_state(codec, 0x28, &parm);
705 snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE,
706 parm);
707 snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE,
708 parm);
709 /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
710 snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE,
711 imux_is_smixer ? AC_PWRST_D0 : parm);
712 if (spec->hp_independent_mode) {
713 /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */
714 parm = AC_PWRST_D3;
715 set_pin_power_state(codec, 0x28, &parm);
716 snd_hda_codec_write(codec, 0x1b, 0,
717 AC_VERB_SET_POWER_STATE, parm);
718 snd_hda_codec_write(codec, 0x34, 0,
719 AC_VERB_SET_POWER_STATE, parm);
720 snd_hda_codec_write(codec, 0xc, 0,
721 AC_VERB_SET_POWER_STATE, parm);
722 }
Lydia Wangf3db4232009-10-10 19:08:41 +0800723 } else if (spec->codec_type == VT1716S) {
724 unsigned int mono_out, present;
725 /* SW0 (17h) = stereo mixer */
726 imux_is_smixer = snd_hda_codec_read(
727 codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
728 /* inputs */
729 /* PW 1/2/5 (1ah/1bh/1eh) */
730 parm = AC_PWRST_D3;
731 set_pin_power_state(codec, 0x1a, &parm);
732 set_pin_power_state(codec, 0x1b, &parm);
733 set_pin_power_state(codec, 0x1e, &parm);
734 if (imux_is_smixer)
735 parm = AC_PWRST_D0;
736 /* SW0 (17h), AIW0(13h) */
737 snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
738 parm);
739 snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
740 parm);
741
742 parm = AC_PWRST_D3;
743 set_pin_power_state(codec, 0x1e, &parm);
744 /* PW11 (22h) */
745 if (spec->dmic_enabled)
746 set_pin_power_state(codec, 0x22, &parm);
747 else
748 snd_hda_codec_write(
749 codec, 0x22, 0,
750 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
751
752 /* SW2(26h), AIW1(14h) */
753 snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE,
754 parm);
755 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
756 parm);
757
758 /* outputs */
759 /* PW0 (19h), SW1 (18h), AOW1 (11h) */
760 parm = AC_PWRST_D3;
761 set_pin_power_state(codec, 0x19, &parm);
762 /* Smart 5.1 PW2(1bh) */
763 if (spec->smart51_enabled)
764 set_pin_power_state(codec, 0x1b, &parm);
765 snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
766 parm);
767 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
768 parm);
769
770 /* PW7 (23h), SW3 (27h), AOW3 (25h) */
771 parm = AC_PWRST_D3;
772 set_pin_power_state(codec, 0x23, &parm);
773 /* Smart 5.1 PW1(1ah) */
774 if (spec->smart51_enabled)
775 set_pin_power_state(codec, 0x1a, &parm);
776 snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE,
777 parm);
778
779 /* Smart 5.1 PW5(1eh) */
780 if (spec->smart51_enabled)
781 set_pin_power_state(codec, 0x1e, &parm);
782 snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE,
783 parm);
784
785 /* Mono out */
786 /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/
787 present = snd_hda_codec_read(
788 codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
789 if (present)
790 mono_out = 0;
791 else {
792 present = snd_hda_codec_read(
793 codec, 0x1d, 0, AC_VERB_GET_PIN_SENSE, 0)
794 & 0x80000000;
795 if (!spec->hp_independent_mode && present)
796 mono_out = 0;
797 else
798 mono_out = 1;
799 }
800 parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3;
801 snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE,
802 parm);
803 snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE,
804 parm);
805 snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE,
806 parm);
807
808 /* PW 3/4 (1ch/1dh) */
809 parm = AC_PWRST_D3;
810 set_pin_power_state(codec, 0x1c, &parm);
811 set_pin_power_state(codec, 0x1d, &parm);
812 /* HP Independent Mode, power on AOW3 */
813 if (spec->hp_independent_mode)
814 snd_hda_codec_write(codec, 0x25, 0,
815 AC_VERB_SET_POWER_STATE, parm);
816
817 /* force to D0 for internal Speaker */
818 /* MW0 (16h), AOW0 (10h) */
819 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
820 imux_is_smixer ? AC_PWRST_D0 : parm);
821 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
822 mono_out ? AC_PWRST_D0 : parm);
Lydia Wang25eaba22009-10-10 19:08:43 +0800823 } else if (spec->codec_type == VT2002P) {
824 unsigned int present;
825 /* MUX9 (1eh) = stereo mixer */
826 imux_is_smixer = snd_hda_codec_read(
827 codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
828 /* inputs */
829 /* PW 5/6/7 (29h/2ah/2bh) */
830 parm = AC_PWRST_D3;
831 set_pin_power_state(codec, 0x29, &parm);
832 set_pin_power_state(codec, 0x2a, &parm);
833 set_pin_power_state(codec, 0x2b, &parm);
834 if (imux_is_smixer)
835 parm = AC_PWRST_D0;
836 /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */
837 snd_hda_codec_write(codec, 0x1e, 0,
838 AC_VERB_SET_POWER_STATE, parm);
839 snd_hda_codec_write(codec, 0x1f, 0,
840 AC_VERB_SET_POWER_STATE, parm);
841 snd_hda_codec_write(codec, 0x10, 0,
842 AC_VERB_SET_POWER_STATE, parm);
843 snd_hda_codec_write(codec, 0x11, 0,
844 AC_VERB_SET_POWER_STATE, parm);
845
846 /* outputs */
847 /* AOW0 (8h)*/
848 snd_hda_codec_write(codec, 0x8, 0,
849 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
850
851 /* PW4 (26h), MW4 (1ch), MUX4(37h) */
852 parm = AC_PWRST_D3;
853 set_pin_power_state(codec, 0x26, &parm);
854 snd_hda_codec_write(codec, 0x1c, 0,
855 AC_VERB_SET_POWER_STATE, parm);
856 snd_hda_codec_write(codec, 0x37,
857 0, AC_VERB_SET_POWER_STATE, parm);
858
859 /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */
860 parm = AC_PWRST_D3;
861 set_pin_power_state(codec, 0x25, &parm);
862 snd_hda_codec_write(codec, 0x19, 0,
863 AC_VERB_SET_POWER_STATE, parm);
864 snd_hda_codec_write(codec, 0x35, 0,
865 AC_VERB_SET_POWER_STATE, parm);
866 if (spec->hp_independent_mode) {
867 snd_hda_codec_write(codec, 0x9, 0,
868 AC_VERB_SET_POWER_STATE, parm);
869 }
870
871 /* Class-D */
872 /* PW0 (24h), MW0(18h), MUX0(34h) */
873 present = snd_hda_codec_read(
874 codec, 0x25, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
875 parm = AC_PWRST_D3;
876 set_pin_power_state(codec, 0x24, &parm);
877 if (present) {
878 snd_hda_codec_write(
879 codec, 0x18, 0,
880 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
881 snd_hda_codec_write(
882 codec, 0x34, 0,
883 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
884 } else {
885 snd_hda_codec_write(
886 codec, 0x18, 0,
887 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
888 snd_hda_codec_write(
889 codec, 0x34, 0,
890 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
891 }
892
893 /* Mono Out */
894 /* PW15 (31h), MW8(17h), MUX8(3bh) */
895 present = snd_hda_codec_read(
896 codec, 0x26, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
897 parm = AC_PWRST_D3;
898 set_pin_power_state(codec, 0x31, &parm);
899 if (present) {
900 snd_hda_codec_write(
901 codec, 0x17, 0,
902 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
903 snd_hda_codec_write(
904 codec, 0x3b, 0,
905 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
906 } else {
907 snd_hda_codec_write(
908 codec, 0x17, 0,
909 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
910 snd_hda_codec_write(
911 codec, 0x3b, 0,
912 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
913 }
914
915 /* MW9 (21h) */
916 if (imux_is_smixer || !is_aa_path_mute(codec))
917 snd_hda_codec_write(
918 codec, 0x21, 0,
919 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
920 else
921 snd_hda_codec_write(
922 codec, 0x21, 0,
923 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Lydia Wangab6734e2009-10-10 19:08:46 +0800924 } else if (spec->codec_type == VT1812) {
925 unsigned int present;
926 /* MUX10 (1eh) = stereo mixer */
927 imux_is_smixer = snd_hda_codec_read(
928 codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
929 /* inputs */
930 /* PW 5/6/7 (29h/2ah/2bh) */
931 parm = AC_PWRST_D3;
932 set_pin_power_state(codec, 0x29, &parm);
933 set_pin_power_state(codec, 0x2a, &parm);
934 set_pin_power_state(codec, 0x2b, &parm);
935 if (imux_is_smixer)
936 parm = AC_PWRST_D0;
937 /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */
938 snd_hda_codec_write(codec, 0x1e, 0,
939 AC_VERB_SET_POWER_STATE, parm);
940 snd_hda_codec_write(codec, 0x1f, 0,
941 AC_VERB_SET_POWER_STATE, parm);
942 snd_hda_codec_write(codec, 0x10, 0,
943 AC_VERB_SET_POWER_STATE, parm);
944 snd_hda_codec_write(codec, 0x11, 0,
945 AC_VERB_SET_POWER_STATE, parm);
946
947 /* outputs */
948 /* AOW0 (8h)*/
949 snd_hda_codec_write(codec, 0x8, 0,
950 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
951
952 /* PW4 (28h), MW4 (18h), MUX4(38h) */
953 parm = AC_PWRST_D3;
954 set_pin_power_state(codec, 0x28, &parm);
955 snd_hda_codec_write(codec, 0x18, 0,
956 AC_VERB_SET_POWER_STATE, parm);
957 snd_hda_codec_write(codec, 0x38, 0,
958 AC_VERB_SET_POWER_STATE, parm);
959
960 /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
961 parm = AC_PWRST_D3;
962 set_pin_power_state(codec, 0x25, &parm);
963 snd_hda_codec_write(codec, 0x15, 0,
964 AC_VERB_SET_POWER_STATE, parm);
965 snd_hda_codec_write(codec, 0x35, 0,
966 AC_VERB_SET_POWER_STATE, parm);
967 if (spec->hp_independent_mode) {
968 snd_hda_codec_write(codec, 0x9, 0,
969 AC_VERB_SET_POWER_STATE, parm);
970 }
971
972 /* Internal Speaker */
973 /* PW0 (24h), MW0(14h), MUX0(34h) */
974 present = snd_hda_codec_read(
975 codec, 0x25, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
976 parm = AC_PWRST_D3;
977 set_pin_power_state(codec, 0x24, &parm);
978 if (present) {
979 snd_hda_codec_write(codec, 0x14, 0,
980 AC_VERB_SET_POWER_STATE,
981 AC_PWRST_D3);
982 snd_hda_codec_write(codec, 0x34, 0,
983 AC_VERB_SET_POWER_STATE,
984 AC_PWRST_D3);
985 } else {
986 snd_hda_codec_write(codec, 0x14, 0,
987 AC_VERB_SET_POWER_STATE,
988 AC_PWRST_D0);
989 snd_hda_codec_write(codec, 0x34, 0,
990 AC_VERB_SET_POWER_STATE,
991 AC_PWRST_D0);
992 }
993 /* Mono Out */
994 /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */
995 present = snd_hda_codec_read(
996 codec, 0x28, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
997 parm = AC_PWRST_D3;
998 set_pin_power_state(codec, 0x31, &parm);
999 if (present) {
1000 snd_hda_codec_write(codec, 0x1c, 0,
1001 AC_VERB_SET_POWER_STATE,
1002 AC_PWRST_D3);
1003 snd_hda_codec_write(codec, 0x3c, 0,
1004 AC_VERB_SET_POWER_STATE,
1005 AC_PWRST_D3);
1006 snd_hda_codec_write(codec, 0x3e, 0,
1007 AC_VERB_SET_POWER_STATE,
1008 AC_PWRST_D3);
1009 } else {
1010 snd_hda_codec_write(codec, 0x1c, 0,
1011 AC_VERB_SET_POWER_STATE,
1012 AC_PWRST_D0);
1013 snd_hda_codec_write(codec, 0x3c, 0,
1014 AC_VERB_SET_POWER_STATE,
1015 AC_PWRST_D0);
1016 snd_hda_codec_write(codec, 0x3e, 0,
1017 AC_VERB_SET_POWER_STATE,
1018 AC_PWRST_D0);
1019 }
1020
1021 /* PW15 (33h), MW15 (1dh), MUX15(3dh) */
1022 parm = AC_PWRST_D3;
1023 set_pin_power_state(codec, 0x33, &parm);
1024 snd_hda_codec_write(codec, 0x1d, 0,
1025 AC_VERB_SET_POWER_STATE, parm);
1026 snd_hda_codec_write(codec, 0x3d, 0,
1027 AC_VERB_SET_POWER_STATE, parm);
1028
1029 /* MW9 (21h) */
1030 if (imux_is_smixer || !is_aa_path_mute(codec))
1031 snd_hda_codec_write(
1032 codec, 0x21, 0,
1033 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
1034 else
1035 snd_hda_codec_write(
1036 codec, 0x21, 0,
1037 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Lydia Wangf5271102009-10-10 19:07:35 +08001038 }
1039}
1040
Joseph Chanc577b8a2006-11-29 15:29:40 +01001041/*
1042 * input MUX handling
1043 */
1044static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
1045 struct snd_ctl_elem_info *uinfo)
1046{
1047 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1048 struct via_spec *spec = codec->spec;
1049 return snd_hda_input_mux_info(spec->input_mux, uinfo);
1050}
1051
1052static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
1053 struct snd_ctl_elem_value *ucontrol)
1054{
1055 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1056 struct via_spec *spec = codec->spec;
1057 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1058
1059 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
1060 return 0;
1061}
1062
1063static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
1064 struct snd_ctl_elem_value *ucontrol)
1065{
1066 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1067 struct via_spec *spec = codec->spec;
1068 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001069
Takashi Iwai337b9d02009-07-07 18:18:59 +02001070 if (!spec->mux_nids[adc_idx])
1071 return -EINVAL;
Lydia Wanga80e6e32009-10-10 19:07:55 +08001072 /* switch to D0 beofre change index */
1073 if (snd_hda_codec_read(codec, spec->mux_nids[adc_idx], 0,
1074 AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0)
1075 snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0,
1076 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
1077 /* update jack power state */
1078 set_jack_power_state(codec);
1079
Takashi Iwai337b9d02009-07-07 18:18:59 +02001080 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
1081 spec->mux_nids[adc_idx],
1082 &spec->cur_mux[adc_idx]);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001083}
1084
Harald Welte0aa62ae2008-09-09 15:58:27 +08001085static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
1086 struct snd_ctl_elem_info *uinfo)
1087{
1088 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1089 struct via_spec *spec = codec->spec;
1090 return snd_hda_input_mux_info(spec->hp_mux, uinfo);
1091}
1092
1093static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
1094 struct snd_ctl_elem_value *ucontrol)
1095{
1096 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1097 struct via_spec *spec = codec->spec;
Lydia Wangeb7188c2009-10-10 19:08:34 +08001098 hda_nid_t nid;
1099 unsigned int pinsel;
Harald Welte0aa62ae2008-09-09 15:58:27 +08001100
Lydia Wangeb7188c2009-10-10 19:08:34 +08001101 switch (spec->codec_type) {
1102 case VT1718S:
1103 nid = 0x34;
1104 break;
Lydia Wang25eaba22009-10-10 19:08:43 +08001105 case VT2002P:
1106 nid = 0x35;
1107 break;
Lydia Wangab6734e2009-10-10 19:08:46 +08001108 case VT1812:
1109 nid = 0x3d;
1110 break;
Lydia Wangeb7188c2009-10-10 19:08:34 +08001111 default:
1112 nid = spec->autocfg.hp_pins[0];
1113 break;
1114 }
1115 /* use !! to translate conn sel 2 for VT1718S */
1116 pinsel = !!snd_hda_codec_read(codec, nid, 0,
1117 AC_VERB_GET_CONNECT_SEL,
1118 0x00);
Harald Welte0aa62ae2008-09-09 15:58:27 +08001119 ucontrol->value.enumerated.item[0] = pinsel;
1120
1121 return 0;
1122}
1123
Lydia Wang0713efe2009-10-10 19:07:43 +08001124static void activate_ctl(struct hda_codec *codec, const char *name, int active)
1125{
1126 struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name);
1127 if (ctl) {
1128 ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
1129 ctl->vd[0].access |= active
1130 ? 0 : SNDRV_CTL_ELEM_ACCESS_INACTIVE;
1131 snd_ctl_notify(codec->bus->card,
1132 SNDRV_CTL_EVENT_MASK_VALUE, &ctl->id);
1133 }
1134}
1135
Lydia Wangcdc17842009-10-10 19:07:47 +08001136static int update_side_mute_status(struct hda_codec *codec)
1137{
1138 /* mute side channel */
1139 struct via_spec *spec = codec->spec;
1140 unsigned int parm = spec->hp_independent_mode
1141 ? AMP_OUT_MUTE : AMP_OUT_UNMUTE;
1142 hda_nid_t sw3;
1143
1144 switch (spec->codec_type) {
1145 case VT1708:
1146 sw3 = 0x1b;
1147 break;
1148 case VT1709_10CH:
1149 sw3 = 0x29;
1150 break;
1151 case VT1708B_8CH:
1152 case VT1708S:
1153 sw3 = 0x27;
1154 break;
1155 default:
1156 sw3 = 0;
1157 break;
1158 }
1159
1160 if (sw3)
1161 snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE,
1162 parm);
1163 return 0;
1164}
1165
Harald Welte0aa62ae2008-09-09 15:58:27 +08001166static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
1167 struct snd_ctl_elem_value *ucontrol)
1168{
1169 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1170 struct via_spec *spec = codec->spec;
1171 hda_nid_t nid = spec->autocfg.hp_pins[0];
1172 unsigned int pinsel = ucontrol->value.enumerated.item[0];
Lydia Wangcdc17842009-10-10 19:07:47 +08001173 /* Get Independent Mode index of headphone pin widget */
1174 spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel
1175 ? 1 : 0;
Harald Welte0aa62ae2008-09-09 15:58:27 +08001176
Lydia Wangeb7188c2009-10-10 19:08:34 +08001177 switch (spec->codec_type) {
1178 case VT1718S:
1179 nid = 0x34;
1180 pinsel = pinsel ? 2 : 0; /* indep HP use AOW4 (index 2) */
1181 spec->multiout.num_dacs = 4;
1182 break;
Lydia Wang25eaba22009-10-10 19:08:43 +08001183 case VT2002P:
1184 nid = 0x35;
1185 break;
Lydia Wangab6734e2009-10-10 19:08:46 +08001186 case VT1812:
1187 nid = 0x3d;
1188 break;
Lydia Wangeb7188c2009-10-10 19:08:34 +08001189 default:
1190 nid = spec->autocfg.hp_pins[0];
1191 break;
1192 }
Lydia Wangcdc17842009-10-10 19:07:47 +08001193 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel);
Harald Welte0aa62ae2008-09-09 15:58:27 +08001194
Lydia Wangcdc17842009-10-10 19:07:47 +08001195 if (spec->multiout.hp_nid && spec->multiout.hp_nid
1196 != spec->multiout.dac_nids[HDA_FRONT])
1197 snd_hda_codec_setup_stream(codec, spec->multiout.hp_nid,
1198 0, 0, 0);
Harald Welte0aa62ae2008-09-09 15:58:27 +08001199
Lydia Wangcdc17842009-10-10 19:07:47 +08001200 update_side_mute_status(codec);
Lydia Wang0713efe2009-10-10 19:07:43 +08001201 /* update HP volume/swtich active state */
1202 if (spec->codec_type == VT1708S
Lydia Wangeb7188c2009-10-10 19:08:34 +08001203 || spec->codec_type == VT1702
Lydia Wangf3db4232009-10-10 19:08:41 +08001204 || spec->codec_type == VT1718S
Lydia Wang25eaba22009-10-10 19:08:43 +08001205 || spec->codec_type == VT1716S
Lydia Wangab6734e2009-10-10 19:08:46 +08001206 || spec->codec_type == VT2002P
1207 || spec->codec_type == VT1812) {
Lydia Wang0713efe2009-10-10 19:07:43 +08001208 activate_ctl(codec, "Headphone Playback Volume",
1209 spec->hp_independent_mode);
1210 activate_ctl(codec, "Headphone Playback Switch",
1211 spec->hp_independent_mode);
1212 }
Harald Welte0aa62ae2008-09-09 15:58:27 +08001213 return 0;
1214}
1215
1216static struct snd_kcontrol_new via_hp_mixer[] = {
1217 {
1218 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1219 .name = "Independent HP",
1220 .count = 1,
1221 .info = via_independent_hp_info,
1222 .get = via_independent_hp_get,
1223 .put = via_independent_hp_put,
1224 },
1225 { } /* end */
1226};
1227
Lydia Wang1564b282009-10-10 19:07:52 +08001228static void notify_aa_path_ctls(struct hda_codec *codec)
1229{
1230 int i;
1231 struct snd_ctl_elem_id id;
1232 const char *labels[] = {"Mic", "Front Mic", "Line"};
1233
1234 memset(&id, 0, sizeof(id));
1235 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1236 for (i = 0; i < ARRAY_SIZE(labels); i++) {
1237 sprintf(id.name, "%s Playback Volume", labels[i]);
1238 snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
1239 &id);
1240 }
1241}
1242
1243static void mute_aa_path(struct hda_codec *codec, int mute)
1244{
1245 struct via_spec *spec = codec->spec;
1246 hda_nid_t nid_mixer;
1247 int start_idx;
1248 int end_idx;
1249 int i;
1250 /* get nid of MW0 and start & end index */
1251 switch (spec->codec_type) {
1252 case VT1708:
1253 nid_mixer = 0x17;
1254 start_idx = 2;
1255 end_idx = 4;
1256 break;
1257 case VT1709_10CH:
1258 case VT1709_6CH:
1259 nid_mixer = 0x18;
1260 start_idx = 2;
1261 end_idx = 4;
1262 break;
1263 case VT1708B_8CH:
1264 case VT1708B_4CH:
1265 case VT1708S:
Lydia Wangf3db4232009-10-10 19:08:41 +08001266 case VT1716S:
Lydia Wang1564b282009-10-10 19:07:52 +08001267 nid_mixer = 0x16;
1268 start_idx = 2;
1269 end_idx = 4;
1270 break;
1271 default:
1272 return;
1273 }
1274 /* check AA path's mute status */
1275 for (i = start_idx; i <= end_idx; i++) {
1276 int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE;
1277 snd_hda_codec_amp_stereo(codec, nid_mixer, HDA_INPUT, i,
1278 HDA_AMP_MUTE, val);
1279 }
1280}
1281static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin)
1282{
1283 int res = 0;
1284 int index;
1285 for (index = AUTO_PIN_MIC; index < AUTO_PIN_FRONT_LINE; index++) {
1286 if (pin == spec->autocfg.input_pins[index]) {
1287 res = 1;
1288 break;
1289 }
1290 }
1291 return res;
1292}
1293
1294static int via_smart51_info(struct snd_kcontrol *kcontrol,
1295 struct snd_ctl_elem_info *uinfo)
1296{
1297 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1298 uinfo->count = 1;
1299 uinfo->value.integer.min = 0;
1300 uinfo->value.integer.max = 1;
1301 return 0;
1302}
1303
1304static int via_smart51_get(struct snd_kcontrol *kcontrol,
1305 struct snd_ctl_elem_value *ucontrol)
1306{
1307 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1308 struct via_spec *spec = codec->spec;
1309 int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
1310 int on = 1;
1311 int i;
1312
1313 for (i = 0; i < ARRAY_SIZE(index); i++) {
1314 hda_nid_t nid = spec->autocfg.input_pins[index[i]];
1315 if (nid) {
1316 int ctl =
1317 snd_hda_codec_read(codec, nid, 0,
1318 AC_VERB_GET_PIN_WIDGET_CONTROL,
1319 0);
1320 if (i == AUTO_PIN_FRONT_MIC
Lydia Wangeb7188c2009-10-10 19:08:34 +08001321 && spec->hp_independent_mode
1322 && spec->codec_type != VT1718S)
Lydia Wang1564b282009-10-10 19:07:52 +08001323 continue; /* ignore FMic for independent HP */
1324 if (ctl & AC_PINCTL_IN_EN
1325 && !(ctl & AC_PINCTL_OUT_EN))
1326 on = 0;
1327 }
1328 }
1329 *ucontrol->value.integer.value = on;
1330 return 0;
1331}
1332
1333static int via_smart51_put(struct snd_kcontrol *kcontrol,
1334 struct snd_ctl_elem_value *ucontrol)
1335{
1336 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1337 struct via_spec *spec = codec->spec;
1338 int out_in = *ucontrol->value.integer.value
1339 ? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN;
1340 int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
1341 int i;
1342
1343 for (i = 0; i < ARRAY_SIZE(index); i++) {
1344 hda_nid_t nid = spec->autocfg.input_pins[index[i]];
1345 if (i == AUTO_PIN_FRONT_MIC
Lydia Wangeb7188c2009-10-10 19:08:34 +08001346 && spec->hp_independent_mode
1347 && spec->codec_type != VT1718S)
Lydia Wang1564b282009-10-10 19:07:52 +08001348 continue; /* don't retask FMic for independent HP */
1349 if (nid) {
1350 unsigned int parm = snd_hda_codec_read(
1351 codec, nid, 0,
1352 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
1353 parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
1354 parm |= out_in;
1355 snd_hda_codec_write(codec, nid, 0,
1356 AC_VERB_SET_PIN_WIDGET_CONTROL,
1357 parm);
1358 if (out_in == AC_PINCTL_OUT_EN) {
1359 mute_aa_path(codec, 1);
1360 notify_aa_path_ctls(codec);
1361 }
Lydia Wangeb7188c2009-10-10 19:08:34 +08001362 if (spec->codec_type == VT1718S)
1363 snd_hda_codec_amp_stereo(
1364 codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE,
1365 HDA_AMP_UNMUTE);
Lydia Wang1564b282009-10-10 19:07:52 +08001366 }
1367 if (i == AUTO_PIN_FRONT_MIC) {
Lydia Wangf3db4232009-10-10 19:08:41 +08001368 if (spec->codec_type == VT1708S
1369 || spec->codec_type == VT1716S) {
Lydia Wang1564b282009-10-10 19:07:52 +08001370 /* input = index 1 (AOW3) */
1371 snd_hda_codec_write(
1372 codec, nid, 0,
1373 AC_VERB_SET_CONNECT_SEL, 1);
1374 snd_hda_codec_amp_stereo(
1375 codec, nid, HDA_OUTPUT,
1376 0, HDA_AMP_MUTE, HDA_AMP_UNMUTE);
1377 }
1378 }
1379 }
1380 spec->smart51_enabled = *ucontrol->value.integer.value;
1381 set_jack_power_state(codec);
1382 return 1;
1383}
1384
1385static struct snd_kcontrol_new via_smart51_mixer[] = {
1386 {
1387 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1388 .name = "Smart 5.1",
1389 .count = 1,
1390 .info = via_smart51_info,
1391 .get = via_smart51_get,
1392 .put = via_smart51_put,
1393 },
1394 {} /* end */
1395};
1396
Joseph Chanc577b8a2006-11-29 15:29:40 +01001397/* capture mixer elements */
1398static struct snd_kcontrol_new vt1708_capture_mixer[] = {
1399 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
1400 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
1401 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
1402 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
1403 {
1404 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1405 /* The multiple "Capture Source" controls confuse alsamixer
1406 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +01001407 */
1408 /* .name = "Capture Source", */
1409 .name = "Input Source",
1410 .count = 1,
1411 .info = via_mux_enum_info,
1412 .get = via_mux_enum_get,
1413 .put = via_mux_enum_put,
1414 },
1415 { } /* end */
1416};
Lydia Wangf5271102009-10-10 19:07:35 +08001417
1418/* check AA path's mute statue */
1419static int is_aa_path_mute(struct hda_codec *codec)
1420{
1421 int mute = 1;
1422 hda_nid_t nid_mixer;
1423 int start_idx;
1424 int end_idx;
1425 int i;
1426 struct via_spec *spec = codec->spec;
1427 /* get nid of MW0 and start & end index */
1428 switch (spec->codec_type) {
1429 case VT1708B_8CH:
1430 case VT1708B_4CH:
1431 case VT1708S:
Lydia Wangf3db4232009-10-10 19:08:41 +08001432 case VT1716S:
Lydia Wangf5271102009-10-10 19:07:35 +08001433 nid_mixer = 0x16;
1434 start_idx = 2;
1435 end_idx = 4;
1436 break;
1437 case VT1702:
1438 nid_mixer = 0x1a;
1439 start_idx = 1;
1440 end_idx = 3;
1441 break;
Lydia Wangeb7188c2009-10-10 19:08:34 +08001442 case VT1718S:
1443 nid_mixer = 0x21;
1444 start_idx = 1;
1445 end_idx = 3;
1446 break;
Lydia Wang25eaba22009-10-10 19:08:43 +08001447 case VT2002P:
Lydia Wangab6734e2009-10-10 19:08:46 +08001448 case VT1812:
Lydia Wang25eaba22009-10-10 19:08:43 +08001449 nid_mixer = 0x21;
1450 start_idx = 0;
1451 end_idx = 2;
1452 break;
Lydia Wangf5271102009-10-10 19:07:35 +08001453 default:
1454 return 0;
1455 }
1456 /* check AA path's mute status */
1457 for (i = start_idx; i <= end_idx; i++) {
1458 unsigned int con_list = snd_hda_codec_read(
1459 codec, nid_mixer, 0, AC_VERB_GET_CONNECT_LIST, i/4*4);
1460 int shift = 8 * (i % 4);
1461 hda_nid_t nid_pin = (con_list & (0xff << shift)) >> shift;
1462 unsigned int defconf = snd_hda_codec_get_pincfg(codec, nid_pin);
1463 if (get_defcfg_connect(defconf) == AC_JACK_PORT_COMPLEX) {
1464 /* check mute status while the pin is connected */
1465 int mute_l = snd_hda_codec_amp_read(codec, nid_mixer, 0,
1466 HDA_INPUT, i) >> 7;
1467 int mute_r = snd_hda_codec_amp_read(codec, nid_mixer, 1,
1468 HDA_INPUT, i) >> 7;
1469 if (!mute_l || !mute_r) {
1470 mute = 0;
1471 break;
1472 }
1473 }
1474 }
1475 return mute;
1476}
1477
1478/* enter/exit analog low-current mode */
1479static void analog_low_current_mode(struct hda_codec *codec, int stream_idle)
1480{
1481 struct via_spec *spec = codec->spec;
1482 static int saved_stream_idle = 1; /* saved stream idle status */
1483 int enable = is_aa_path_mute(codec);
1484 unsigned int verb = 0;
1485 unsigned int parm = 0;
1486
1487 if (stream_idle == -1) /* stream status did not change */
1488 enable = enable && saved_stream_idle;
1489 else {
1490 enable = enable && stream_idle;
1491 saved_stream_idle = stream_idle;
1492 }
1493
1494 /* decide low current mode's verb & parameter */
1495 switch (spec->codec_type) {
1496 case VT1708B_8CH:
1497 case VT1708B_4CH:
1498 verb = 0xf70;
1499 parm = enable ? 0x02 : 0x00; /* 0x02: 2/3x, 0x00: 1x */
1500 break;
1501 case VT1708S:
Lydia Wangeb7188c2009-10-10 19:08:34 +08001502 case VT1718S:
Lydia Wangf3db4232009-10-10 19:08:41 +08001503 case VT1716S:
Lydia Wangf5271102009-10-10 19:07:35 +08001504 verb = 0xf73;
1505 parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */
1506 break;
1507 case VT1702:
1508 verb = 0xf73;
1509 parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */
1510 break;
Lydia Wang25eaba22009-10-10 19:08:43 +08001511 case VT2002P:
Lydia Wangab6734e2009-10-10 19:08:46 +08001512 case VT1812:
Lydia Wang25eaba22009-10-10 19:08:43 +08001513 verb = 0xf93;
1514 parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */
1515 break;
Lydia Wangf5271102009-10-10 19:07:35 +08001516 default:
1517 return; /* other codecs are not supported */
1518 }
1519 /* send verb */
1520 snd_hda_codec_write(codec, codec->afg, 0, verb, parm);
1521}
1522
Joseph Chanc577b8a2006-11-29 15:29:40 +01001523/*
1524 * generic initialization of ADC, input mixers and output mixers
1525 */
1526static struct hda_verb vt1708_volume_init_verbs[] = {
1527 /*
1528 * Unmute ADC0-1 and set the default input to mic-in
1529 */
1530 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1531 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1532
1533
Josepch Chanf7278fd2007-12-13 16:40:40 +01001534 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +01001535 * mixer widget
1536 */
1537 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +01001538 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1539 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1540 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
1541 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
1542 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001543
1544 /*
1545 * Set up output mixers (0x19 - 0x1b)
1546 */
1547 /* set vol=0 to output mixers */
1548 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1549 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1550 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Lydia Wang377ff312009-10-10 19:08:55 +08001551
Lydia Wangbfdc6752009-10-10 19:08:50 +08001552 /* Setup default input MW0 to PW4 */
1553 {0x20, AC_VERB_SET_CONNECT_SEL, 0},
Joseph Chanc577b8a2006-11-29 15:29:40 +01001554 /* PW9 Output enable */
1555 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Josepch Chanf7278fd2007-12-13 16:40:40 +01001556 { }
Joseph Chanc577b8a2006-11-29 15:29:40 +01001557};
1558
1559static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
1560 struct hda_codec *codec,
1561 struct snd_pcm_substream *substream)
1562{
1563 struct via_spec *spec = codec->spec;
Lydia Wang17314372009-10-10 19:07:37 +08001564 int idle = substream->pstr->substream_opened == 1
1565 && substream->ref_count == 0;
Lydia Wang17314372009-10-10 19:07:37 +08001566 analog_low_current_mode(codec, idle);
Takashi Iwai9a081602008-02-12 18:37:26 +01001567 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
1568 hinfo);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001569}
1570
Harald Welte0aa62ae2008-09-09 15:58:27 +08001571static void playback_multi_pcm_prep_0(struct hda_codec *codec,
1572 unsigned int stream_tag,
1573 unsigned int format,
1574 struct snd_pcm_substream *substream)
1575{
1576 struct via_spec *spec = codec->spec;
1577 struct hda_multi_out *mout = &spec->multiout;
1578 hda_nid_t *nids = mout->dac_nids;
1579 int chs = substream->runtime->channels;
1580 int i;
1581
1582 mutex_lock(&codec->spdif_mutex);
1583 if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
1584 if (chs == 2 &&
1585 snd_hda_is_supported_format(codec, mout->dig_out_nid,
1586 format) &&
1587 !(codec->spdif_status & IEC958_AES0_NONAUDIO)) {
1588 mout->dig_out_used = HDA_DIG_ANALOG_DUP;
1589 /* turn off SPDIF once; otherwise the IEC958 bits won't
1590 * be updated */
1591 if (codec->spdif_ctls & AC_DIG1_ENABLE)
1592 snd_hda_codec_write(codec, mout->dig_out_nid, 0,
1593 AC_VERB_SET_DIGI_CONVERT_1,
1594 codec->spdif_ctls &
1595 ~AC_DIG1_ENABLE & 0xff);
1596 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
1597 stream_tag, 0, format);
1598 /* turn on again (if needed) */
1599 if (codec->spdif_ctls & AC_DIG1_ENABLE)
1600 snd_hda_codec_write(codec, mout->dig_out_nid, 0,
1601 AC_VERB_SET_DIGI_CONVERT_1,
1602 codec->spdif_ctls & 0xff);
1603 } else {
1604 mout->dig_out_used = 0;
1605 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
1606 0, 0, 0);
1607 }
1608 }
1609 mutex_unlock(&codec->spdif_mutex);
1610
1611 /* front */
1612 snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag,
1613 0, format);
1614
Lydia Wangeb7188c2009-10-10 19:08:34 +08001615 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT]
1616 && !spec->hp_independent_mode)
Harald Welte0aa62ae2008-09-09 15:58:27 +08001617 /* headphone out will just decode front left/right (stereo) */
1618 snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag,
1619 0, format);
1620
1621 /* extra outputs copied from front */
1622 for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
1623 if (mout->extra_out_nid[i])
1624 snd_hda_codec_setup_stream(codec,
1625 mout->extra_out_nid[i],
1626 stream_tag, 0, format);
1627
1628 /* surrounds */
1629 for (i = 1; i < mout->num_dacs; i++) {
1630 if (chs >= (i + 1) * 2) /* independent out */
1631 snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
1632 i * 2, format);
1633 else /* copy front */
1634 snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
1635 0, format);
1636 }
1637}
1638
1639static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
1640 struct hda_codec *codec,
1641 unsigned int stream_tag,
1642 unsigned int format,
1643 struct snd_pcm_substream *substream)
1644{
1645 struct via_spec *spec = codec->spec;
1646 struct hda_multi_out *mout = &spec->multiout;
1647 hda_nid_t *nids = mout->dac_nids;
1648
1649 if (substream->number == 0)
1650 playback_multi_pcm_prep_0(codec, stream_tag, format,
1651 substream);
1652 else {
1653 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
1654 spec->hp_independent_mode)
1655 snd_hda_codec_setup_stream(codec, mout->hp_nid,
1656 stream_tag, 0, format);
1657 }
Lydia Wang1f2e99f2009-10-10 19:08:17 +08001658 vt1708_start_hp_work(spec);
Harald Welte0aa62ae2008-09-09 15:58:27 +08001659 return 0;
1660}
1661
1662static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
1663 struct hda_codec *codec,
1664 struct snd_pcm_substream *substream)
1665{
1666 struct via_spec *spec = codec->spec;
1667 struct hda_multi_out *mout = &spec->multiout;
1668 hda_nid_t *nids = mout->dac_nids;
1669 int i;
1670
1671 if (substream->number == 0) {
1672 for (i = 0; i < mout->num_dacs; i++)
1673 snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
1674
1675 if (mout->hp_nid && !spec->hp_independent_mode)
1676 snd_hda_codec_setup_stream(codec, mout->hp_nid,
1677 0, 0, 0);
1678
1679 for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
1680 if (mout->extra_out_nid[i])
1681 snd_hda_codec_setup_stream(codec,
1682 mout->extra_out_nid[i],
1683 0, 0, 0);
1684 mutex_lock(&codec->spdif_mutex);
1685 if (mout->dig_out_nid &&
1686 mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
1687 snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
1688 0, 0, 0);
1689 mout->dig_out_used = 0;
1690 }
1691 mutex_unlock(&codec->spdif_mutex);
1692 } else {
1693 if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
1694 spec->hp_independent_mode)
1695 snd_hda_codec_setup_stream(codec, mout->hp_nid,
1696 0, 0, 0);
1697 }
Lydia Wang1f2e99f2009-10-10 19:08:17 +08001698 vt1708_stop_hp_work(spec);
Harald Welte0aa62ae2008-09-09 15:58:27 +08001699 return 0;
1700}
1701
Joseph Chanc577b8a2006-11-29 15:29:40 +01001702/*
1703 * Digital out
1704 */
1705static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1706 struct hda_codec *codec,
1707 struct snd_pcm_substream *substream)
1708{
1709 struct via_spec *spec = codec->spec;
1710 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1711}
1712
1713static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1714 struct hda_codec *codec,
1715 struct snd_pcm_substream *substream)
1716{
1717 struct via_spec *spec = codec->spec;
1718 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1719}
1720
Harald Welte5691ec72008-09-15 22:42:26 +08001721static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
Harald Welte98aa34c2008-09-09 16:02:09 +08001722 struct hda_codec *codec,
1723 unsigned int stream_tag,
1724 unsigned int format,
1725 struct snd_pcm_substream *substream)
1726{
1727 struct via_spec *spec = codec->spec;
Takashi Iwai9da29272009-05-07 16:31:14 +02001728 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1729 stream_tag, format, substream);
1730}
Harald Welte5691ec72008-09-15 22:42:26 +08001731
Takashi Iwai9da29272009-05-07 16:31:14 +02001732static int via_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1733 struct hda_codec *codec,
1734 struct snd_pcm_substream *substream)
1735{
1736 struct via_spec *spec = codec->spec;
1737 snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
Harald Welte98aa34c2008-09-09 16:02:09 +08001738 return 0;
1739}
1740
Joseph Chanc577b8a2006-11-29 15:29:40 +01001741/*
1742 * Analog capture
1743 */
1744static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1745 struct hda_codec *codec,
1746 unsigned int stream_tag,
1747 unsigned int format,
1748 struct snd_pcm_substream *substream)
1749{
1750 struct via_spec *spec = codec->spec;
1751
1752 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1753 stream_tag, 0, format);
1754 return 0;
1755}
1756
1757static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1758 struct hda_codec *codec,
1759 struct snd_pcm_substream *substream)
1760{
1761 struct via_spec *spec = codec->spec;
Takashi Iwai888afa12008-03-18 09:57:50 +01001762 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001763 return 0;
1764}
1765
1766static struct hda_pcm_stream vt1708_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08001767 .substreams = 2,
Joseph Chanc577b8a2006-11-29 15:29:40 +01001768 .channels_min = 2,
1769 .channels_max = 8,
1770 .nid = 0x10, /* NID to query formats and rates */
1771 .ops = {
1772 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08001773 .prepare = via_playback_multi_pcm_prepare,
1774 .cleanup = via_playback_multi_pcm_cleanup
Joseph Chanc577b8a2006-11-29 15:29:40 +01001775 },
1776};
1777
Takashi Iwaibc9b562382008-05-23 17:50:27 +02001778static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
Lydia Wangc873cc22009-10-10 19:08:21 +08001779 .substreams = 2,
Takashi Iwaibc9b562382008-05-23 17:50:27 +02001780 .channels_min = 2,
1781 .channels_max = 8,
1782 .nid = 0x10, /* NID to query formats and rates */
1783 /* We got noisy outputs on the right channel on VT1708 when
1784 * 24bit samples are used. Until any workaround is found,
1785 * disable the 24bit format, so far.
1786 */
1787 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1788 .ops = {
1789 .open = via_playback_pcm_open,
Lydia Wangc873cc22009-10-10 19:08:21 +08001790 .prepare = via_playback_multi_pcm_prepare,
1791 .cleanup = via_playback_multi_pcm_cleanup
Takashi Iwaibc9b562382008-05-23 17:50:27 +02001792 },
1793};
1794
Joseph Chanc577b8a2006-11-29 15:29:40 +01001795static struct hda_pcm_stream vt1708_pcm_analog_capture = {
1796 .substreams = 2,
1797 .channels_min = 2,
1798 .channels_max = 2,
1799 .nid = 0x15, /* NID to query formats and rates */
1800 .ops = {
1801 .prepare = via_capture_pcm_prepare,
1802 .cleanup = via_capture_pcm_cleanup
1803 },
1804};
1805
1806static struct hda_pcm_stream vt1708_pcm_digital_playback = {
1807 .substreams = 1,
1808 .channels_min = 2,
1809 .channels_max = 2,
1810 /* NID is set in via_build_pcms */
1811 .ops = {
1812 .open = via_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001813 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02001814 .prepare = via_dig_playback_pcm_prepare,
1815 .cleanup = via_dig_playback_pcm_cleanup
Joseph Chanc577b8a2006-11-29 15:29:40 +01001816 },
1817};
1818
1819static struct hda_pcm_stream vt1708_pcm_digital_capture = {
1820 .substreams = 1,
1821 .channels_min = 2,
1822 .channels_max = 2,
1823};
1824
1825static int via_build_controls(struct hda_codec *codec)
1826{
1827 struct via_spec *spec = codec->spec;
1828 int err;
1829 int i;
1830
1831 for (i = 0; i < spec->num_mixers; i++) {
1832 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1833 if (err < 0)
1834 return err;
1835 }
1836
1837 if (spec->multiout.dig_out_nid) {
1838 err = snd_hda_create_spdif_out_ctls(codec,
1839 spec->multiout.dig_out_nid);
1840 if (err < 0)
1841 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001842 err = snd_hda_create_spdif_share_sw(codec,
1843 &spec->multiout);
1844 if (err < 0)
1845 return err;
1846 spec->multiout.share_spdif = 1;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001847 }
1848 if (spec->dig_in_nid) {
1849 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1850 if (err < 0)
1851 return err;
1852 }
Lydia Wang17314372009-10-10 19:07:37 +08001853
1854 /* init power states */
1855 set_jack_power_state(codec);
1856 analog_low_current_mode(codec, 1);
1857
Takashi Iwai603c4012008-07-30 15:01:44 +02001858 via_free_kctls(codec); /* no longer needed */
Joseph Chanc577b8a2006-11-29 15:29:40 +01001859 return 0;
1860}
1861
1862static int via_build_pcms(struct hda_codec *codec)
1863{
1864 struct via_spec *spec = codec->spec;
1865 struct hda_pcm *info = spec->pcm_rec;
1866
1867 codec->num_pcms = 1;
1868 codec->pcm_info = info;
1869
1870 info->name = spec->stream_name_analog;
Lydia Wang377ff312009-10-10 19:08:55 +08001871 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
1872 *(spec->stream_analog_playback);
1873 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
1874 spec->multiout.dac_nids[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01001875 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
1876 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
1877
1878 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
1879 spec->multiout.max_channels;
1880
1881 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1882 codec->num_pcms++;
1883 info++;
1884 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01001885 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001886 if (spec->multiout.dig_out_nid) {
1887 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
1888 *(spec->stream_digital_playback);
1889 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
1890 spec->multiout.dig_out_nid;
1891 }
1892 if (spec->dig_in_nid) {
1893 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
1894 *(spec->stream_digital_capture);
1895 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
1896 spec->dig_in_nid;
1897 }
1898 }
1899
1900 return 0;
1901}
1902
1903static void via_free(struct hda_codec *codec)
1904{
1905 struct via_spec *spec = codec->spec;
Joseph Chanc577b8a2006-11-29 15:29:40 +01001906
1907 if (!spec)
1908 return;
1909
Takashi Iwai603c4012008-07-30 15:01:44 +02001910 via_free_kctls(codec);
Lydia Wang1f2e99f2009-10-10 19:08:17 +08001911 vt1708_stop_hp_work(spec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01001912 kfree(codec->spec);
1913}
1914
Harald Welte69e52a82008-09-09 15:57:32 +08001915/* mute internal speaker if HP is plugged */
1916static void via_hp_automute(struct hda_codec *codec)
1917{
Lydia Wangdcf34c82009-10-10 19:08:15 +08001918 unsigned int present = 0;
Harald Welte69e52a82008-09-09 15:57:32 +08001919 struct via_spec *spec = codec->spec;
1920
1921 present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
1922 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Lydia Wangdcf34c82009-10-10 19:08:15 +08001923
1924 if (!spec->hp_independent_mode) {
1925 struct snd_ctl_elem_id id;
1926 /* auto mute */
1927 snd_hda_codec_amp_stereo(
1928 codec, spec->autocfg.line_out_pins[0], HDA_OUTPUT, 0,
1929 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
1930 /* notify change */
1931 memset(&id, 0, sizeof(id));
1932 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1933 strcpy(id.name, "Front Playback Switch");
1934 snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
1935 &id);
1936 }
Harald Welte69e52a82008-09-09 15:57:32 +08001937}
1938
Lydia Wangf3db4232009-10-10 19:08:41 +08001939/* mute mono out if HP or Line out is plugged */
1940static void via_mono_automute(struct hda_codec *codec)
1941{
1942 unsigned int hp_present, lineout_present;
1943 struct via_spec *spec = codec->spec;
1944
1945 if (spec->codec_type != VT1716S)
1946 return;
1947
1948 lineout_present = snd_hda_codec_read(
1949 codec, spec->autocfg.line_out_pins[0], 0,
1950 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1951
1952 /* Mute Mono Out if Line Out is plugged */
1953 if (lineout_present) {
1954 snd_hda_codec_amp_stereo(
1955 codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE, HDA_AMP_MUTE);
1956 return;
1957 }
1958
1959 hp_present = snd_hda_codec_read(
1960 codec, spec->autocfg.hp_pins[0], 0,
1961 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1962
1963 if (!spec->hp_independent_mode)
1964 snd_hda_codec_amp_stereo(
1965 codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE,
1966 hp_present ? HDA_AMP_MUTE : 0);
1967}
1968
Harald Welte69e52a82008-09-09 15:57:32 +08001969static void via_gpio_control(struct hda_codec *codec)
1970{
1971 unsigned int gpio_data;
1972 unsigned int vol_counter;
1973 unsigned int vol;
1974 unsigned int master_vol;
1975
1976 struct via_spec *spec = codec->spec;
1977
1978 gpio_data = snd_hda_codec_read(codec, codec->afg, 0,
1979 AC_VERB_GET_GPIO_DATA, 0) & 0x03;
1980
1981 vol_counter = (snd_hda_codec_read(codec, codec->afg, 0,
1982 0xF84, 0) & 0x3F0000) >> 16;
1983
1984 vol = vol_counter & 0x1F;
1985 master_vol = snd_hda_codec_read(codec, 0x1A, 0,
1986 AC_VERB_GET_AMP_GAIN_MUTE,
1987 AC_AMP_GET_INPUT);
1988
1989 if (gpio_data == 0x02) {
1990 /* unmute line out */
1991 snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
1992 HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
1993
1994 if (vol_counter & 0x20) {
1995 /* decrease volume */
1996 if (vol > master_vol)
1997 vol = master_vol;
1998 snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT,
1999 0, HDA_AMP_VOLMASK,
2000 master_vol-vol);
2001 } else {
2002 /* increase volume */
2003 snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, 0,
2004 HDA_AMP_VOLMASK,
2005 ((master_vol+vol) > 0x2A) ? 0x2A :
2006 (master_vol+vol));
2007 }
2008 } else if (!(gpio_data & 0x02)) {
2009 /* mute line out */
2010 snd_hda_codec_amp_stereo(codec,
2011 spec->autocfg.line_out_pins[0],
2012 HDA_OUTPUT, 0, HDA_AMP_MUTE,
2013 HDA_AMP_MUTE);
2014 }
2015}
2016
Lydia Wang25eaba22009-10-10 19:08:43 +08002017/* mute Internal-Speaker if HP is plugged */
2018static void via_speaker_automute(struct hda_codec *codec)
2019{
2020 unsigned int hp_present;
2021 struct via_spec *spec = codec->spec;
2022
Lydia Wangab6734e2009-10-10 19:08:46 +08002023 if (spec->codec_type != VT2002P && spec->codec_type != VT1812)
Lydia Wang25eaba22009-10-10 19:08:43 +08002024 return;
2025
2026 hp_present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
2027 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
2028
2029 if (!spec->hp_independent_mode) {
2030 struct snd_ctl_elem_id id;
2031 snd_hda_codec_amp_stereo(
2032 codec, spec->autocfg.speaker_pins[0], HDA_OUTPUT, 0,
2033 HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0);
2034 /* notify change */
2035 memset(&id, 0, sizeof(id));
2036 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
2037 strcpy(id.name, "Speaker Playback Switch");
2038 snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
2039 &id);
2040 }
2041}
2042
2043/* mute line-out and internal speaker if HP is plugged */
2044static void via_hp_bind_automute(struct hda_codec *codec)
2045{
akpm@linux-foundation.org01a17962009-11-13 16:47:10 -08002046 /* use long instead of int below just to avoid an internal compiler
2047 * error with gcc 4.0.x
2048 */
2049 unsigned long hp_present, present = 0;
Lydia Wang25eaba22009-10-10 19:08:43 +08002050 struct via_spec *spec = codec->spec;
2051 int i;
2052
2053 if (!spec->autocfg.hp_pins[0] || !spec->autocfg.line_out_pins[0])
2054 return;
2055
2056 hp_present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
2057 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
2058
2059 present = snd_hda_codec_read(codec, spec->autocfg.line_out_pins[0], 0,
2060 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
2061
2062 if (!spec->hp_independent_mode) {
2063 /* Mute Line-Outs */
2064 for (i = 0; i < spec->autocfg.line_outs; i++)
2065 snd_hda_codec_amp_stereo(
2066 codec, spec->autocfg.line_out_pins[i],
2067 HDA_OUTPUT, 0,
2068 HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0);
2069 if (hp_present)
2070 present = hp_present;
2071 }
2072 /* Speakers */
2073 for (i = 0; i < spec->autocfg.speaker_outs; i++)
2074 snd_hda_codec_amp_stereo(
2075 codec, spec->autocfg.speaker_pins[i], HDA_OUTPUT, 0,
2076 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
2077}
2078
2079
Harald Welte69e52a82008-09-09 15:57:32 +08002080/* unsolicited event for jack sensing */
2081static void via_unsol_event(struct hda_codec *codec,
2082 unsigned int res)
2083{
2084 res >>= 26;
Lydia Wanga34df192009-10-10 19:08:01 +08002085 if (res & VIA_HP_EVENT)
Harald Welte69e52a82008-09-09 15:57:32 +08002086 via_hp_automute(codec);
Lydia Wanga34df192009-10-10 19:08:01 +08002087 if (res & VIA_GPIO_EVENT)
Harald Welte69e52a82008-09-09 15:57:32 +08002088 via_gpio_control(codec);
Lydia Wanga34df192009-10-10 19:08:01 +08002089 if (res & VIA_JACK_EVENT)
2090 set_jack_power_state(codec);
Lydia Wangf3db4232009-10-10 19:08:41 +08002091 if (res & VIA_MONO_EVENT)
2092 via_mono_automute(codec);
Lydia Wang25eaba22009-10-10 19:08:43 +08002093 if (res & VIA_SPEAKER_EVENT)
2094 via_speaker_automute(codec);
2095 if (res & VIA_BIND_HP_EVENT)
2096 via_hp_bind_automute(codec);
Harald Welte69e52a82008-09-09 15:57:32 +08002097}
2098
Joseph Chanc577b8a2006-11-29 15:29:40 +01002099static int via_init(struct hda_codec *codec)
2100{
2101 struct via_spec *spec = codec->spec;
Harald Welte69e52a82008-09-09 15:57:32 +08002102 int i;
2103 for (i = 0; i < spec->num_iverbs; i++)
2104 snd_hda_sequence_write(codec, spec->init_verbs[i]);
2105
Lydia Wang518bf3b2009-10-10 19:07:29 +08002106 spec->codec_type = get_codec_type(codec);
2107 if (spec->codec_type == VT1708BCE)
2108 spec->codec_type = VT1708S; /* VT1708BCE & VT1708S are almost
2109 same */
Josepch Chanf7278fd2007-12-13 16:40:40 +01002110 /* Lydia Add for EAPD enable */
2111 if (!spec->dig_in_nid) { /* No Digital In connection */
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02002112 if (spec->dig_in_pin) {
2113 snd_hda_codec_write(codec, spec->dig_in_pin, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002114 AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwai12b74c82008-01-15 12:39:38 +01002115 PIN_OUT);
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02002116 snd_hda_codec_write(codec, spec->dig_in_pin, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002117 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
2118 }
Takashi Iwai12b74c82008-01-15 12:39:38 +01002119 } else /* enable SPDIF-input pin */
2120 snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
2121 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
Josepch Chanf7278fd2007-12-13 16:40:40 +01002122
Takashi Iwai9da29272009-05-07 16:31:14 +02002123 /* assign slave outs */
2124 if (spec->slave_dig_outs[0])
2125 codec->slave_dig_outs = spec->slave_dig_outs;
Harald Welte5691ec72008-09-15 22:42:26 +08002126
Lydia Wang377ff312009-10-10 19:08:55 +08002127 return 0;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002128}
2129
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002130#ifdef SND_HDA_NEEDS_RESUME
2131static int via_suspend(struct hda_codec *codec, pm_message_t state)
2132{
2133 struct via_spec *spec = codec->spec;
2134 vt1708_stop_hp_work(spec);
2135 return 0;
2136}
2137#endif
2138
Takashi Iwaicb53c622007-08-10 17:21:45 +02002139#ifdef CONFIG_SND_HDA_POWER_SAVE
2140static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2141{
2142 struct via_spec *spec = codec->spec;
2143 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2144}
2145#endif
2146
Joseph Chanc577b8a2006-11-29 15:29:40 +01002147/*
2148 */
2149static struct hda_codec_ops via_patch_ops = {
2150 .build_controls = via_build_controls,
2151 .build_pcms = via_build_pcms,
2152 .init = via_init,
2153 .free = via_free,
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002154#ifdef SND_HDA_NEEDS_RESUME
2155 .suspend = via_suspend,
2156#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02002157#ifdef CONFIG_SND_HDA_POWER_SAVE
2158 .check_power_status = via_check_power_status,
2159#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01002160};
2161
2162/* fill in the dac_nids table from the parsed pin configuration */
2163static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
2164 const struct auto_pin_cfg *cfg)
2165{
2166 int i;
2167 hda_nid_t nid;
2168
2169 spec->multiout.num_dacs = cfg->line_outs;
2170
2171 spec->multiout.dac_nids = spec->private_dac_nids;
Lydia Wang377ff312009-10-10 19:08:55 +08002172
2173 for (i = 0; i < 4; i++) {
Joseph Chanc577b8a2006-11-29 15:29:40 +01002174 nid = cfg->line_out_pins[i];
2175 if (nid) {
2176 /* config dac list */
2177 switch (i) {
2178 case AUTO_SEQ_FRONT:
2179 spec->multiout.dac_nids[i] = 0x10;
2180 break;
2181 case AUTO_SEQ_CENLFE:
2182 spec->multiout.dac_nids[i] = 0x12;
2183 break;
2184 case AUTO_SEQ_SURROUND:
Harald Weltefb4cb772008-09-09 15:53:36 +08002185 spec->multiout.dac_nids[i] = 0x11;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002186 break;
2187 case AUTO_SEQ_SIDE:
Harald Weltefb4cb772008-09-09 15:53:36 +08002188 spec->multiout.dac_nids[i] = 0x13;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002189 break;
2190 }
2191 }
2192 }
2193
2194 return 0;
2195}
2196
2197/* add playback controls from the parsed DAC table */
2198static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
2199 const struct auto_pin_cfg *cfg)
2200{
2201 char name[32];
2202 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
Lydia Wang9645c202009-10-10 19:08:27 +08002203 hda_nid_t nid, nid_vol, nid_vols[] = {0x17, 0x19, 0x1a, 0x1b};
Joseph Chanc577b8a2006-11-29 15:29:40 +01002204 int i, err;
2205
2206 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2207 nid = cfg->line_out_pins[i];
2208
2209 if (!nid)
2210 continue;
Lydia Wang377ff312009-10-10 19:08:55 +08002211
Lydia Wang9645c202009-10-10 19:08:27 +08002212 nid_vol = nid_vols[i];
Joseph Chanc577b8a2006-11-29 15:29:40 +01002213
2214 if (i == AUTO_SEQ_CENLFE) {
2215 /* Center/LFE */
2216 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002217 "Center Playback Volume",
2218 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2219 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002220 if (err < 0)
2221 return err;
2222 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2223 "LFE Playback Volume",
Josepch Chanf7278fd2007-12-13 16:40:40 +01002224 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2225 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002226 if (err < 0)
2227 return err;
2228 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2229 "Center Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01002230 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2231 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002232 if (err < 0)
2233 return err;
2234 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2235 "LFE Playback Switch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01002236 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2237 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002238 if (err < 0)
2239 return err;
Lydia Wang377ff312009-10-10 19:08:55 +08002240 } else if (i == AUTO_SEQ_FRONT) {
Joseph Chanc577b8a2006-11-29 15:29:40 +01002241 /* add control to mixer index 0 */
2242 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2243 "Master Front Playback Volume",
Lydia Wang9645c202009-10-10 19:08:27 +08002244 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002245 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002246 if (err < 0)
2247 return err;
2248 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2249 "Master Front Playback Switch",
Lydia Wang9645c202009-10-10 19:08:27 +08002250 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002251 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002252 if (err < 0)
2253 return err;
Lydia Wang377ff312009-10-10 19:08:55 +08002254
Joseph Chanc577b8a2006-11-29 15:29:40 +01002255 /* add control to PW3 */
2256 sprintf(name, "%s Playback Volume", chname[i]);
2257 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002258 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2259 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002260 if (err < 0)
2261 return err;
2262 sprintf(name, "%s Playback Switch", chname[i]);
2263 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002264 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2265 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002266 if (err < 0)
2267 return err;
2268 } else {
2269 sprintf(name, "%s Playback Volume", chname[i]);
2270 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002271 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2272 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002273 if (err < 0)
2274 return err;
2275 sprintf(name, "%s Playback Switch", chname[i]);
2276 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002277 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2278 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002279 if (err < 0)
2280 return err;
2281 }
2282 }
2283
2284 return 0;
2285}
2286
Harald Welte0aa62ae2008-09-09 15:58:27 +08002287static void create_hp_imux(struct via_spec *spec)
2288{
2289 int i;
2290 struct hda_input_mux *imux = &spec->private_imux[1];
2291 static const char *texts[] = { "OFF", "ON", NULL};
2292
2293 /* for hp mode select */
2294 i = 0;
2295 while (texts[i] != NULL) {
2296 imux->items[imux->num_items].label = texts[i];
2297 imux->items[imux->num_items].index = i;
2298 imux->num_items++;
2299 i++;
2300 }
2301
2302 spec->hp_mux = &spec->private_imux[1];
2303}
2304
Joseph Chanc577b8a2006-11-29 15:29:40 +01002305static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2306{
2307 int err;
2308
2309 if (!pin)
2310 return 0;
2311
2312 spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
Lydia Wangcdc17842009-10-10 19:07:47 +08002313 spec->hp_independent_mode_index = 1;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002314
2315 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2316 "Headphone Playback Volume",
2317 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2318 if (err < 0)
2319 return err;
2320 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2321 "Headphone Playback Switch",
2322 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2323 if (err < 0)
2324 return err;
2325
Harald Welte0aa62ae2008-09-09 15:58:27 +08002326 create_hp_imux(spec);
2327
Joseph Chanc577b8a2006-11-29 15:29:40 +01002328 return 0;
2329}
2330
2331/* create playback/capture controls for input pins */
2332static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
2333 const struct auto_pin_cfg *cfg)
2334{
2335 static char *labels[] = {
2336 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2337 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08002338 struct hda_input_mux *imux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01002339 int i, err, idx = 0;
2340
2341 /* for internal loopback recording select */
2342 imux->items[imux->num_items].label = "Stereo Mixer";
2343 imux->items[imux->num_items].index = idx;
2344 imux->num_items++;
2345
2346 for (i = 0; i < AUTO_PIN_LAST; i++) {
2347 if (!cfg->input_pins[i])
2348 continue;
2349
2350 switch (cfg->input_pins[i]) {
2351 case 0x1d: /* Mic */
2352 idx = 2;
2353 break;
Lydia Wang377ff312009-10-10 19:08:55 +08002354
Joseph Chanc577b8a2006-11-29 15:29:40 +01002355 case 0x1e: /* Line In */
2356 idx = 3;
2357 break;
2358
2359 case 0x21: /* Front Mic */
2360 idx = 4;
2361 break;
2362
2363 case 0x24: /* CD */
2364 idx = 1;
2365 break;
2366 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08002367 err = via_new_analog_input(spec, labels[i], idx, 0x17);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002368 if (err < 0)
2369 return err;
2370 imux->items[imux->num_items].label = labels[i];
2371 imux->items[imux->num_items].index = idx;
2372 imux->num_items++;
2373 }
2374 return 0;
2375}
2376
Takashi Iwaicb53c622007-08-10 17:21:45 +02002377#ifdef CONFIG_SND_HDA_POWER_SAVE
2378static struct hda_amp_list vt1708_loopbacks[] = {
2379 { 0x17, HDA_INPUT, 1 },
2380 { 0x17, HDA_INPUT, 2 },
2381 { 0x17, HDA_INPUT, 3 },
2382 { 0x17, HDA_INPUT, 4 },
2383 { } /* end */
2384};
2385#endif
2386
Harald Welte76d9b0d2008-09-09 15:50:37 +08002387static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
2388{
2389 unsigned int def_conf;
2390 unsigned char seqassoc;
2391
Takashi Iwai2f334f92009-02-20 14:37:42 +01002392 def_conf = snd_hda_codec_get_pincfg(codec, nid);
Harald Welte76d9b0d2008-09-09 15:50:37 +08002393 seqassoc = (unsigned char) get_defcfg_association(def_conf);
2394 seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
Lydia Wang82ef9e42009-10-10 19:08:19 +08002395 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE
2396 && (seqassoc == 0xf0 || seqassoc == 0xff)) {
2397 def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
2398 snd_hda_codec_set_pincfg(codec, nid, def_conf);
Harald Welte76d9b0d2008-09-09 15:50:37 +08002399 }
2400
2401 return;
2402}
2403
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002404static int vt1708_jack_detectect_get(struct snd_kcontrol *kcontrol,
2405 struct snd_ctl_elem_value *ucontrol)
2406{
2407 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2408 struct via_spec *spec = codec->spec;
2409
2410 if (spec->codec_type != VT1708)
2411 return 0;
2412 spec->vt1708_jack_detectect =
2413 !((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1);
2414 ucontrol->value.integer.value[0] = spec->vt1708_jack_detectect;
2415 return 0;
2416}
2417
2418static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol,
2419 struct snd_ctl_elem_value *ucontrol)
2420{
2421 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2422 struct via_spec *spec = codec->spec;
2423 int change;
2424
2425 if (spec->codec_type != VT1708)
2426 return 0;
2427 spec->vt1708_jack_detectect = ucontrol->value.integer.value[0];
2428 change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8))
2429 == !spec->vt1708_jack_detectect;
2430 if (spec->vt1708_jack_detectect) {
2431 mute_aa_path(codec, 1);
2432 notify_aa_path_ctls(codec);
2433 }
2434 return change;
2435}
2436
2437static struct snd_kcontrol_new vt1708_jack_detectect[] = {
2438 {
2439 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2440 .name = "Jack Detect",
2441 .count = 1,
2442 .info = snd_ctl_boolean_mono_info,
2443 .get = vt1708_jack_detectect_get,
2444 .put = vt1708_jack_detectect_put,
2445 },
2446 {} /* end */
2447};
2448
Joseph Chanc577b8a2006-11-29 15:29:40 +01002449static int vt1708_parse_auto_config(struct hda_codec *codec)
2450{
2451 struct via_spec *spec = codec->spec;
2452 int err;
2453
Harald Welte76d9b0d2008-09-09 15:50:37 +08002454 /* Add HP and CD pin config connect bit re-config action */
2455 vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
2456 vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
2457
Joseph Chanc577b8a2006-11-29 15:29:40 +01002458 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
2459 if (err < 0)
2460 return err;
2461 err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
2462 if (err < 0)
2463 return err;
2464 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2465 return 0; /* can't find valid BIOS pin config */
2466
2467 err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
2468 if (err < 0)
2469 return err;
2470 err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2471 if (err < 0)
2472 return err;
2473 err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
2474 if (err < 0)
2475 return err;
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002476 /* add jack detect on/off control */
2477 err = snd_hda_add_new_ctls(codec, vt1708_jack_detectect);
2478 if (err < 0)
2479 return err;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002480
2481 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2482
Takashi Iwai0852d7a2009-02-11 11:35:15 +01002483 if (spec->autocfg.dig_outs)
Joseph Chanc577b8a2006-11-29 15:29:40 +01002484 spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02002485 spec->dig_in_pin = VT1708_DIGIN_PIN;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002486 if (spec->autocfg.dig_in_pin)
2487 spec->dig_in_nid = VT1708_DIGIN_NID;
2488
Takashi Iwai603c4012008-07-30 15:01:44 +02002489 if (spec->kctls.list)
2490 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002491
Harald Welte69e52a82008-09-09 15:57:32 +08002492 spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002493
Harald Welte0aa62ae2008-09-09 15:58:27 +08002494 spec->input_mux = &spec->private_imux[0];
2495
Harald Weltef8fdd492008-09-15 22:41:31 +08002496 if (spec->hp_mux)
2497 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002498
Lydia Wang1564b282009-10-10 19:07:52 +08002499 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002500 return 1;
2501}
2502
2503/* init callback for auto-configuration model -- overriding the default init */
2504static int via_auto_init(struct hda_codec *codec)
2505{
Lydia Wang25eaba22009-10-10 19:08:43 +08002506 struct via_spec *spec = codec->spec;
2507
Joseph Chanc577b8a2006-11-29 15:29:40 +01002508 via_init(codec);
2509 via_auto_init_multi_out(codec);
2510 via_auto_init_hp_out(codec);
2511 via_auto_init_analog_input(codec);
Lydia Wangab6734e2009-10-10 19:08:46 +08002512 if (spec->codec_type == VT2002P || spec->codec_type == VT1812) {
Lydia Wang25eaba22009-10-10 19:08:43 +08002513 via_hp_bind_automute(codec);
2514 } else {
2515 via_hp_automute(codec);
2516 via_speaker_automute(codec);
2517 }
2518
Joseph Chanc577b8a2006-11-29 15:29:40 +01002519 return 0;
2520}
2521
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002522static void vt1708_update_hp_jack_state(struct work_struct *work)
2523{
2524 struct via_spec *spec = container_of(work, struct via_spec,
2525 vt1708_hp_work.work);
2526 if (spec->codec_type != VT1708)
2527 return;
2528 /* if jack state toggled */
2529 if (spec->vt1708_hp_present
2530 != (snd_hda_codec_read(spec->codec, spec->autocfg.hp_pins[0], 0,
2531 AC_VERB_GET_PIN_SENSE, 0) >> 31)) {
2532 spec->vt1708_hp_present ^= 1;
2533 via_hp_automute(spec->codec);
2534 }
2535 vt1708_start_hp_work(spec);
2536}
2537
Takashi Iwai337b9d02009-07-07 18:18:59 +02002538static int get_mux_nids(struct hda_codec *codec)
2539{
2540 struct via_spec *spec = codec->spec;
2541 hda_nid_t nid, conn[8];
2542 unsigned int type;
2543 int i, n;
2544
2545 for (i = 0; i < spec->num_adc_nids; i++) {
2546 nid = spec->adc_nids[i];
2547 while (nid) {
Takashi Iwaia22d5432009-07-27 12:54:26 +02002548 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai1c55d522009-07-08 07:45:46 +02002549 if (type == AC_WID_PIN)
2550 break;
Takashi Iwai337b9d02009-07-07 18:18:59 +02002551 n = snd_hda_get_connections(codec, nid, conn,
2552 ARRAY_SIZE(conn));
2553 if (n <= 0)
2554 break;
2555 if (n > 1) {
2556 spec->mux_nids[i] = nid;
2557 break;
2558 }
2559 nid = conn[0];
2560 }
2561 }
Takashi Iwai1c55d522009-07-08 07:45:46 +02002562 return 0;
Takashi Iwai337b9d02009-07-07 18:18:59 +02002563}
2564
Joseph Chanc577b8a2006-11-29 15:29:40 +01002565static int patch_vt1708(struct hda_codec *codec)
2566{
2567 struct via_spec *spec;
2568 int err;
2569
2570 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08002571 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002572 if (spec == NULL)
2573 return -ENOMEM;
2574
2575 codec->spec = spec;
2576
2577 /* automatic parse from the BIOS config */
2578 err = vt1708_parse_auto_config(codec);
2579 if (err < 0) {
2580 via_free(codec);
2581 return err;
2582 } else if (!err) {
2583 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2584 "from BIOS. Using genenic mode...\n");
2585 }
2586
Lydia Wang377ff312009-10-10 19:08:55 +08002587
Joseph Chanc577b8a2006-11-29 15:29:40 +01002588 spec->stream_name_analog = "VT1708 Analog";
2589 spec->stream_analog_playback = &vt1708_pcm_analog_playback;
Takashi Iwaibc9b562382008-05-23 17:50:27 +02002590 /* disable 32bit format on VT1708 */
2591 if (codec->vendor_id == 0x11061708)
2592 spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002593 spec->stream_analog_capture = &vt1708_pcm_analog_capture;
2594
2595 spec->stream_name_digital = "VT1708 Digital";
2596 spec->stream_digital_playback = &vt1708_pcm_digital_playback;
2597 spec->stream_digital_capture = &vt1708_pcm_digital_capture;
2598
Lydia Wang377ff312009-10-10 19:08:55 +08002599
Joseph Chanc577b8a2006-11-29 15:29:40 +01002600 if (!spec->adc_nids && spec->input_mux) {
2601 spec->adc_nids = vt1708_adc_nids;
2602 spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
Takashi Iwai0f67a612009-08-31 08:12:29 +02002603 get_mux_nids(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002604 spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
2605 spec->num_mixers++;
2606 }
2607
2608 codec->patch_ops = via_patch_ops;
2609
2610 codec->patch_ops.init = via_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02002611#ifdef CONFIG_SND_HDA_POWER_SAVE
2612 spec->loopback.amplist = vt1708_loopbacks;
2613#endif
Lydia Wang1f2e99f2009-10-10 19:08:17 +08002614 spec->codec = codec;
2615 INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002616 return 0;
2617}
2618
2619/* capture mixer elements */
2620static struct snd_kcontrol_new vt1709_capture_mixer[] = {
2621 HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
2622 HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
2623 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
2624 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
2625 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
2626 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
2627 {
2628 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2629 /* The multiple "Capture Source" controls confuse alsamixer
2630 * So call somewhat different..
Joseph Chanc577b8a2006-11-29 15:29:40 +01002631 */
2632 /* .name = "Capture Source", */
2633 .name = "Input Source",
2634 .count = 1,
2635 .info = via_mux_enum_info,
2636 .get = via_mux_enum_get,
2637 .put = via_mux_enum_put,
2638 },
2639 { } /* end */
2640};
2641
Harald Welte69e52a82008-09-09 15:57:32 +08002642static struct hda_verb vt1709_uniwill_init_verbs[] = {
Lydia Wanga34df192009-10-10 19:08:01 +08002643 {0x20, AC_VERB_SET_UNSOLICITED_ENABLE,
2644 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
Harald Welte69e52a82008-09-09 15:57:32 +08002645 { }
2646};
2647
Joseph Chanc577b8a2006-11-29 15:29:40 +01002648/*
2649 * generic initialization of ADC, input mixers and output mixers
2650 */
2651static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
2652 /*
2653 * Unmute ADC0-2 and set the default input to mic-in
2654 */
2655 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2656 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2657 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2658
2659
Josepch Chanf7278fd2007-12-13 16:40:40 +01002660 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Joseph Chanc577b8a2006-11-29 15:29:40 +01002661 * mixer widget
2662 */
2663 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
Josepch Chanf7278fd2007-12-13 16:40:40 +01002664 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2665 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2666 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2667 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2668 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Joseph Chanc577b8a2006-11-29 15:29:40 +01002669
2670 /*
2671 * Set up output selector (0x1a, 0x1b, 0x29)
2672 */
2673 /* set vol=0 to output mixers */
2674 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2675 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2676 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2677
2678 /*
2679 * Unmute PW3 and PW4
2680 */
2681 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2682 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2683
Lydia Wangbfdc6752009-10-10 19:08:50 +08002684 /* Set input of PW4 as MW0 */
2685 {0x20, AC_VERB_SET_CONNECT_SEL, 0},
Joseph Chanc577b8a2006-11-29 15:29:40 +01002686 /* PW9 Output enable */
2687 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2688 { }
2689};
2690
2691static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
2692 .substreams = 1,
2693 .channels_min = 2,
2694 .channels_max = 10,
2695 .nid = 0x10, /* NID to query formats and rates */
2696 .ops = {
2697 .open = via_playback_pcm_open,
Lydia Wangc873cc22009-10-10 19:08:21 +08002698 .prepare = via_playback_multi_pcm_prepare,
2699 .cleanup = via_playback_multi_pcm_cleanup,
Joseph Chanc577b8a2006-11-29 15:29:40 +01002700 },
2701};
2702
2703static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
2704 .substreams = 1,
2705 .channels_min = 2,
2706 .channels_max = 6,
2707 .nid = 0x10, /* NID to query formats and rates */
2708 .ops = {
2709 .open = via_playback_pcm_open,
Lydia Wangc873cc22009-10-10 19:08:21 +08002710 .prepare = via_playback_multi_pcm_prepare,
2711 .cleanup = via_playback_multi_pcm_cleanup,
Joseph Chanc577b8a2006-11-29 15:29:40 +01002712 },
2713};
2714
2715static struct hda_pcm_stream vt1709_pcm_analog_capture = {
2716 .substreams = 2,
2717 .channels_min = 2,
2718 .channels_max = 2,
2719 .nid = 0x14, /* NID to query formats and rates */
2720 .ops = {
2721 .prepare = via_capture_pcm_prepare,
2722 .cleanup = via_capture_pcm_cleanup
2723 },
2724};
2725
2726static struct hda_pcm_stream vt1709_pcm_digital_playback = {
2727 .substreams = 1,
2728 .channels_min = 2,
2729 .channels_max = 2,
2730 /* NID is set in via_build_pcms */
2731 .ops = {
2732 .open = via_dig_playback_pcm_open,
2733 .close = via_dig_playback_pcm_close
2734 },
2735};
2736
2737static struct hda_pcm_stream vt1709_pcm_digital_capture = {
2738 .substreams = 1,
2739 .channels_min = 2,
2740 .channels_max = 2,
2741};
2742
2743static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
2744 const struct auto_pin_cfg *cfg)
2745{
2746 int i;
2747 hda_nid_t nid;
2748
2749 if (cfg->line_outs == 4) /* 10 channels */
2750 spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
2751 else if (cfg->line_outs == 3) /* 6 channels */
2752 spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
2753
2754 spec->multiout.dac_nids = spec->private_dac_nids;
2755
2756 if (cfg->line_outs == 4) { /* 10 channels */
2757 for (i = 0; i < cfg->line_outs; i++) {
2758 nid = cfg->line_out_pins[i];
2759 if (nid) {
2760 /* config dac list */
2761 switch (i) {
2762 case AUTO_SEQ_FRONT:
2763 /* AOW0 */
2764 spec->multiout.dac_nids[i] = 0x10;
2765 break;
2766 case AUTO_SEQ_CENLFE:
2767 /* AOW2 */
2768 spec->multiout.dac_nids[i] = 0x12;
2769 break;
2770 case AUTO_SEQ_SURROUND:
2771 /* AOW3 */
Harald Weltefb4cb772008-09-09 15:53:36 +08002772 spec->multiout.dac_nids[i] = 0x11;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002773 break;
2774 case AUTO_SEQ_SIDE:
2775 /* AOW1 */
Harald Weltefb4cb772008-09-09 15:53:36 +08002776 spec->multiout.dac_nids[i] = 0x27;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002777 break;
2778 default:
2779 break;
2780 }
2781 }
2782 }
2783 spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
2784
2785 } else if (cfg->line_outs == 3) { /* 6 channels */
Lydia Wang377ff312009-10-10 19:08:55 +08002786 for (i = 0; i < cfg->line_outs; i++) {
Joseph Chanc577b8a2006-11-29 15:29:40 +01002787 nid = cfg->line_out_pins[i];
2788 if (nid) {
2789 /* config dac list */
Lydia Wang377ff312009-10-10 19:08:55 +08002790 switch (i) {
Joseph Chanc577b8a2006-11-29 15:29:40 +01002791 case AUTO_SEQ_FRONT:
2792 /* AOW0 */
2793 spec->multiout.dac_nids[i] = 0x10;
2794 break;
2795 case AUTO_SEQ_CENLFE:
2796 /* AOW2 */
2797 spec->multiout.dac_nids[i] = 0x12;
2798 break;
2799 case AUTO_SEQ_SURROUND:
2800 /* AOW1 */
2801 spec->multiout.dac_nids[i] = 0x11;
2802 break;
2803 default:
2804 break;
2805 }
2806 }
2807 }
2808 }
2809
2810 return 0;
2811}
2812
2813/* add playback controls from the parsed DAC table */
2814static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
2815 const struct auto_pin_cfg *cfg)
2816{
2817 char name[32];
2818 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
Lydia Wang4483a2f2009-10-10 19:08:29 +08002819 hda_nid_t nid, nid_vol, nid_vols[] = {0x18, 0x1a, 0x1b, 0x29};
Joseph Chanc577b8a2006-11-29 15:29:40 +01002820 int i, err;
2821
2822 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2823 nid = cfg->line_out_pins[i];
2824
Lydia Wang377ff312009-10-10 19:08:55 +08002825 if (!nid)
Joseph Chanc577b8a2006-11-29 15:29:40 +01002826 continue;
2827
Lydia Wang4483a2f2009-10-10 19:08:29 +08002828 nid_vol = nid_vols[i];
2829
Joseph Chanc577b8a2006-11-29 15:29:40 +01002830 if (i == AUTO_SEQ_CENLFE) {
2831 /* Center/LFE */
2832 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2833 "Center Playback Volume",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002834 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002835 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002836 if (err < 0)
2837 return err;
2838 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2839 "LFE Playback Volume",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002840 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002841 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002842 if (err < 0)
2843 return err;
2844 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2845 "Center Playback Switch",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002846 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002847 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002848 if (err < 0)
2849 return err;
2850 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2851 "LFE Playback Switch",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002852 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002853 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002854 if (err < 0)
2855 return err;
Lydia Wang377ff312009-10-10 19:08:55 +08002856 } else if (i == AUTO_SEQ_FRONT) {
Lydia Wang4483a2f2009-10-10 19:08:29 +08002857 /* ADD control to mixer index 0 */
Joseph Chanc577b8a2006-11-29 15:29:40 +01002858 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2859 "Master Front Playback Volume",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002860 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002861 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002862 if (err < 0)
2863 return err;
2864 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2865 "Master Front Playback Switch",
Lydia Wang4483a2f2009-10-10 19:08:29 +08002866 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002867 HDA_INPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002868 if (err < 0)
2869 return err;
Lydia Wang377ff312009-10-10 19:08:55 +08002870
Joseph Chanc577b8a2006-11-29 15:29:40 +01002871 /* add control to PW3 */
2872 sprintf(name, "%s Playback Volume", chname[i]);
2873 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002874 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2875 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002876 if (err < 0)
2877 return err;
2878 sprintf(name, "%s Playback Switch", chname[i]);
2879 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002880 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2881 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002882 if (err < 0)
2883 return err;
2884 } else if (i == AUTO_SEQ_SURROUND) {
2885 sprintf(name, "%s Playback Volume", chname[i]);
2886 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Lydia Wang4483a2f2009-10-10 19:08:29 +08002887 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002888 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002889 if (err < 0)
2890 return err;
2891 sprintf(name, "%s Playback Switch", chname[i]);
2892 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Lydia Wang4483a2f2009-10-10 19:08:29 +08002893 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002894 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002895 if (err < 0)
2896 return err;
2897 } else if (i == AUTO_SEQ_SIDE) {
2898 sprintf(name, "%s Playback Volume", chname[i]);
2899 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
Lydia Wang4483a2f2009-10-10 19:08:29 +08002900 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002901 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002902 if (err < 0)
2903 return err;
2904 sprintf(name, "%s Playback Switch", chname[i]);
2905 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
Lydia Wang4483a2f2009-10-10 19:08:29 +08002906 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
Josepch Chanf7278fd2007-12-13 16:40:40 +01002907 HDA_OUTPUT));
Joseph Chanc577b8a2006-11-29 15:29:40 +01002908 if (err < 0)
2909 return err;
2910 }
2911 }
2912
2913 return 0;
2914}
2915
2916static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2917{
2918 int err;
2919
2920 if (!pin)
2921 return 0;
2922
2923 if (spec->multiout.num_dacs == 5) /* 10 channels */
2924 spec->multiout.hp_nid = VT1709_HP_DAC_NID;
2925 else if (spec->multiout.num_dacs == 3) /* 6 channels */
2926 spec->multiout.hp_nid = 0;
Lydia Wangcdc17842009-10-10 19:07:47 +08002927 spec->hp_independent_mode_index = 1;
Joseph Chanc577b8a2006-11-29 15:29:40 +01002928
2929 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2930 "Headphone Playback Volume",
2931 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2932 if (err < 0)
2933 return err;
2934 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2935 "Headphone Playback Switch",
2936 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2937 if (err < 0)
2938 return err;
2939
2940 return 0;
2941}
2942
2943/* create playback/capture controls for input pins */
2944static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
2945 const struct auto_pin_cfg *cfg)
2946{
2947 static char *labels[] = {
2948 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2949 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08002950 struct hda_input_mux *imux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01002951 int i, err, idx = 0;
2952
2953 /* for internal loopback recording select */
2954 imux->items[imux->num_items].label = "Stereo Mixer";
2955 imux->items[imux->num_items].index = idx;
2956 imux->num_items++;
2957
2958 for (i = 0; i < AUTO_PIN_LAST; i++) {
2959 if (!cfg->input_pins[i])
2960 continue;
2961
2962 switch (cfg->input_pins[i]) {
2963 case 0x1d: /* Mic */
2964 idx = 2;
2965 break;
Lydia Wang377ff312009-10-10 19:08:55 +08002966
Joseph Chanc577b8a2006-11-29 15:29:40 +01002967 case 0x1e: /* Line In */
2968 idx = 3;
2969 break;
2970
2971 case 0x21: /* Front Mic */
2972 idx = 4;
2973 break;
2974
2975 case 0x23: /* CD */
2976 idx = 1;
2977 break;
2978 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08002979 err = via_new_analog_input(spec, labels[i], idx, 0x18);
Joseph Chanc577b8a2006-11-29 15:29:40 +01002980 if (err < 0)
2981 return err;
2982 imux->items[imux->num_items].label = labels[i];
2983 imux->items[imux->num_items].index = idx;
2984 imux->num_items++;
2985 }
2986 return 0;
2987}
2988
2989static int vt1709_parse_auto_config(struct hda_codec *codec)
2990{
2991 struct via_spec *spec = codec->spec;
2992 int err;
2993
2994 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
2995 if (err < 0)
2996 return err;
2997 err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
2998 if (err < 0)
2999 return err;
3000 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
3001 return 0; /* can't find valid BIOS pin config */
3002
3003 err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
3004 if (err < 0)
3005 return err;
3006 err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
3007 if (err < 0)
3008 return err;
3009 err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
3010 if (err < 0)
3011 return err;
3012
3013 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3014
Takashi Iwai0852d7a2009-02-11 11:35:15 +01003015 if (spec->autocfg.dig_outs)
Joseph Chanc577b8a2006-11-29 15:29:40 +01003016 spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02003017 spec->dig_in_pin = VT1709_DIGIN_PIN;
Joseph Chanc577b8a2006-11-29 15:29:40 +01003018 if (spec->autocfg.dig_in_pin)
3019 spec->dig_in_nid = VT1709_DIGIN_NID;
3020
Takashi Iwai603c4012008-07-30 15:01:44 +02003021 if (spec->kctls.list)
3022 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Joseph Chanc577b8a2006-11-29 15:29:40 +01003023
Harald Welte0aa62ae2008-09-09 15:58:27 +08003024 spec->input_mux = &spec->private_imux[0];
Joseph Chanc577b8a2006-11-29 15:29:40 +01003025
Harald Weltef8fdd492008-09-15 22:41:31 +08003026 if (spec->hp_mux)
3027 spec->mixers[spec->num_mixers++] = via_hp_mixer;
3028
Lydia Wang1564b282009-10-10 19:07:52 +08003029 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
Joseph Chanc577b8a2006-11-29 15:29:40 +01003030 return 1;
3031}
3032
Takashi Iwaicb53c622007-08-10 17:21:45 +02003033#ifdef CONFIG_SND_HDA_POWER_SAVE
3034static struct hda_amp_list vt1709_loopbacks[] = {
3035 { 0x18, HDA_INPUT, 1 },
3036 { 0x18, HDA_INPUT, 2 },
3037 { 0x18, HDA_INPUT, 3 },
3038 { 0x18, HDA_INPUT, 4 },
3039 { } /* end */
3040};
3041#endif
3042
Joseph Chanc577b8a2006-11-29 15:29:40 +01003043static int patch_vt1709_10ch(struct hda_codec *codec)
3044{
3045 struct via_spec *spec;
3046 int err;
3047
3048 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08003049 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01003050 if (spec == NULL)
3051 return -ENOMEM;
3052
3053 codec->spec = spec;
3054
3055 err = vt1709_parse_auto_config(codec);
3056 if (err < 0) {
3057 via_free(codec);
3058 return err;
3059 } else if (!err) {
3060 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
3061 "Using genenic mode...\n");
3062 }
3063
Harald Welte69e52a82008-09-09 15:57:32 +08003064 spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs;
3065 spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01003066
3067 spec->stream_name_analog = "VT1709 Analog";
3068 spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
3069 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
3070
3071 spec->stream_name_digital = "VT1709 Digital";
3072 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
3073 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
3074
Lydia Wang377ff312009-10-10 19:08:55 +08003075
Joseph Chanc577b8a2006-11-29 15:29:40 +01003076 if (!spec->adc_nids && spec->input_mux) {
3077 spec->adc_nids = vt1709_adc_nids;
3078 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02003079 get_mux_nids(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01003080 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
3081 spec->num_mixers++;
3082 }
3083
3084 codec->patch_ops = via_patch_ops;
3085
3086 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003087 codec->patch_ops.unsol_event = via_unsol_event;
Takashi Iwaicb53c622007-08-10 17:21:45 +02003088#ifdef CONFIG_SND_HDA_POWER_SAVE
3089 spec->loopback.amplist = vt1709_loopbacks;
3090#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01003091
3092 return 0;
3093}
3094/*
3095 * generic initialization of ADC, input mixers and output mixers
3096 */
3097static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
3098 /*
3099 * Unmute ADC0-2 and set the default input to mic-in
3100 */
3101 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3102 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3103 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3104
3105
3106 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3107 * mixer widget
3108 */
3109 /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
3110 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3111 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3112 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3113 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3114 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
3115
3116 /*
3117 * Set up output selector (0x1a, 0x1b, 0x29)
3118 */
3119 /* set vol=0 to output mixers */
3120 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3121 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3122 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3123
3124 /*
3125 * Unmute PW3 and PW4
3126 */
3127 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3128 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3129
3130 /* Set input of PW4 as MW0 */
3131 {0x20, AC_VERB_SET_CONNECT_SEL, 0},
Joseph Chanc577b8a2006-11-29 15:29:40 +01003132 /* PW9 Output enable */
3133 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
3134 { }
3135};
3136
3137static int patch_vt1709_6ch(struct hda_codec *codec)
3138{
3139 struct via_spec *spec;
3140 int err;
3141
3142 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08003143 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Joseph Chanc577b8a2006-11-29 15:29:40 +01003144 if (spec == NULL)
3145 return -ENOMEM;
3146
3147 codec->spec = spec;
3148
3149 err = vt1709_parse_auto_config(codec);
3150 if (err < 0) {
3151 via_free(codec);
3152 return err;
3153 } else if (!err) {
3154 printk(KERN_INFO "hda_codec: Cannot set up configuration. "
3155 "Using genenic mode...\n");
3156 }
3157
Harald Welte69e52a82008-09-09 15:57:32 +08003158 spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs;
3159 spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
Joseph Chanc577b8a2006-11-29 15:29:40 +01003160
3161 spec->stream_name_analog = "VT1709 Analog";
3162 spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
3163 spec->stream_analog_capture = &vt1709_pcm_analog_capture;
3164
3165 spec->stream_name_digital = "VT1709 Digital";
3166 spec->stream_digital_playback = &vt1709_pcm_digital_playback;
3167 spec->stream_digital_capture = &vt1709_pcm_digital_capture;
3168
Lydia Wang377ff312009-10-10 19:08:55 +08003169
Joseph Chanc577b8a2006-11-29 15:29:40 +01003170 if (!spec->adc_nids && spec->input_mux) {
3171 spec->adc_nids = vt1709_adc_nids;
3172 spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02003173 get_mux_nids(codec);
Joseph Chanc577b8a2006-11-29 15:29:40 +01003174 spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
3175 spec->num_mixers++;
3176 }
3177
3178 codec->patch_ops = via_patch_ops;
3179
3180 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003181 codec->patch_ops.unsol_event = via_unsol_event;
Takashi Iwaicb53c622007-08-10 17:21:45 +02003182#ifdef CONFIG_SND_HDA_POWER_SAVE
3183 spec->loopback.amplist = vt1709_loopbacks;
3184#endif
Josepch Chanf7278fd2007-12-13 16:40:40 +01003185 return 0;
3186}
3187
3188/* capture mixer elements */
3189static struct snd_kcontrol_new vt1708B_capture_mixer[] = {
3190 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
3191 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
3192 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
3193 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
3194 {
3195 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3196 /* The multiple "Capture Source" controls confuse alsamixer
3197 * So call somewhat different..
Josepch Chanf7278fd2007-12-13 16:40:40 +01003198 */
3199 /* .name = "Capture Source", */
3200 .name = "Input Source",
3201 .count = 1,
3202 .info = via_mux_enum_info,
3203 .get = via_mux_enum_get,
3204 .put = via_mux_enum_put,
3205 },
3206 { } /* end */
3207};
3208/*
3209 * generic initialization of ADC, input mixers and output mixers
3210 */
3211static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
3212 /*
3213 * Unmute ADC0-1 and set the default input to mic-in
3214 */
3215 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3216 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3217
3218
3219 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3220 * mixer widget
3221 */
3222 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
3223 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3224 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3225 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3226 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3227 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
3228
3229 /*
3230 * Set up output mixers
3231 */
3232 /* set vol=0 to output mixers */
3233 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3234 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3235 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3236
3237 /* Setup default input to PW4 */
Lydia Wangbfdc6752009-10-10 19:08:50 +08003238 {0x1d, AC_VERB_SET_CONNECT_SEL, 0},
Josepch Chanf7278fd2007-12-13 16:40:40 +01003239 /* PW9 Output enable */
3240 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
3241 /* PW10 Input enable */
3242 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
3243 { }
3244};
3245
3246static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
3247 /*
3248 * Unmute ADC0-1 and set the default input to mic-in
3249 */
3250 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3251 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3252
3253
3254 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3255 * mixer widget
3256 */
3257 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
3258 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3259 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3260 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3261 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3262 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
3263
3264 /*
3265 * Set up output mixers
3266 */
3267 /* set vol=0 to output mixers */
3268 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3269 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3270 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3271
3272 /* Setup default input of PW4 to MW0 */
3273 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
3274 /* PW9 Output enable */
3275 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
3276 /* PW10 Input enable */
3277 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
3278 { }
3279};
3280
Harald Welte69e52a82008-09-09 15:57:32 +08003281static struct hda_verb vt1708B_uniwill_init_verbs[] = {
Lydia Wanga34df192009-10-10 19:08:01 +08003282 {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
3283 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
3284 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3285 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3286 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3287 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3288 {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3289 {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3290 {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
Harald Welte69e52a82008-09-09 15:57:32 +08003291 { }
3292};
3293
Lydia Wang17314372009-10-10 19:07:37 +08003294static int via_pcm_open_close(struct hda_pcm_stream *hinfo,
3295 struct hda_codec *codec,
3296 struct snd_pcm_substream *substream)
3297{
3298 int idle = substream->pstr->substream_opened == 1
3299 && substream->ref_count == 0;
3300
3301 analog_low_current_mode(codec, idle);
3302 return 0;
3303}
3304
Josepch Chanf7278fd2007-12-13 16:40:40 +01003305static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08003306 .substreams = 2,
Josepch Chanf7278fd2007-12-13 16:40:40 +01003307 .channels_min = 2,
3308 .channels_max = 8,
3309 .nid = 0x10, /* NID to query formats and rates */
3310 .ops = {
3311 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08003312 .prepare = via_playback_multi_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08003313 .cleanup = via_playback_multi_pcm_cleanup,
3314 .close = via_pcm_open_close
Josepch Chanf7278fd2007-12-13 16:40:40 +01003315 },
3316};
3317
3318static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08003319 .substreams = 2,
Josepch Chanf7278fd2007-12-13 16:40:40 +01003320 .channels_min = 2,
3321 .channels_max = 4,
3322 .nid = 0x10, /* NID to query formats and rates */
3323 .ops = {
3324 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08003325 .prepare = via_playback_multi_pcm_prepare,
3326 .cleanup = via_playback_multi_pcm_cleanup
Josepch Chanf7278fd2007-12-13 16:40:40 +01003327 },
3328};
3329
3330static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
3331 .substreams = 2,
3332 .channels_min = 2,
3333 .channels_max = 2,
3334 .nid = 0x13, /* NID to query formats and rates */
3335 .ops = {
Lydia Wang17314372009-10-10 19:07:37 +08003336 .open = via_pcm_open_close,
Josepch Chanf7278fd2007-12-13 16:40:40 +01003337 .prepare = via_capture_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08003338 .cleanup = via_capture_pcm_cleanup,
3339 .close = via_pcm_open_close
Josepch Chanf7278fd2007-12-13 16:40:40 +01003340 },
3341};
3342
3343static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
3344 .substreams = 1,
3345 .channels_min = 2,
3346 .channels_max = 2,
3347 /* NID is set in via_build_pcms */
3348 .ops = {
3349 .open = via_dig_playback_pcm_open,
3350 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02003351 .prepare = via_dig_playback_pcm_prepare,
3352 .cleanup = via_dig_playback_pcm_cleanup
Josepch Chanf7278fd2007-12-13 16:40:40 +01003353 },
3354};
3355
3356static struct hda_pcm_stream vt1708B_pcm_digital_capture = {
3357 .substreams = 1,
3358 .channels_min = 2,
3359 .channels_max = 2,
3360};
3361
3362/* fill in the dac_nids table from the parsed pin configuration */
3363static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
3364 const struct auto_pin_cfg *cfg)
3365{
3366 int i;
3367 hda_nid_t nid;
3368
3369 spec->multiout.num_dacs = cfg->line_outs;
3370
3371 spec->multiout.dac_nids = spec->private_dac_nids;
3372
3373 for (i = 0; i < 4; i++) {
3374 nid = cfg->line_out_pins[i];
3375 if (nid) {
3376 /* config dac list */
3377 switch (i) {
3378 case AUTO_SEQ_FRONT:
3379 spec->multiout.dac_nids[i] = 0x10;
3380 break;
3381 case AUTO_SEQ_CENLFE:
3382 spec->multiout.dac_nids[i] = 0x24;
3383 break;
3384 case AUTO_SEQ_SURROUND:
Harald Weltefb4cb772008-09-09 15:53:36 +08003385 spec->multiout.dac_nids[i] = 0x11;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003386 break;
3387 case AUTO_SEQ_SIDE:
Harald Weltefb4cb772008-09-09 15:53:36 +08003388 spec->multiout.dac_nids[i] = 0x25;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003389 break;
3390 }
3391 }
3392 }
3393
3394 return 0;
3395}
3396
3397/* add playback controls from the parsed DAC table */
3398static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
3399 const struct auto_pin_cfg *cfg)
3400{
3401 char name[32];
3402 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
Harald Weltefb4cb772008-09-09 15:53:36 +08003403 hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27};
Josepch Chanf7278fd2007-12-13 16:40:40 +01003404 hda_nid_t nid, nid_vol = 0;
3405 int i, err;
3406
3407 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
3408 nid = cfg->line_out_pins[i];
3409
3410 if (!nid)
3411 continue;
3412
3413 nid_vol = nid_vols[i];
3414
3415 if (i == AUTO_SEQ_CENLFE) {
3416 /* Center/LFE */
3417 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3418 "Center Playback Volume",
3419 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
3420 HDA_OUTPUT));
3421 if (err < 0)
3422 return err;
3423 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3424 "LFE Playback Volume",
3425 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
3426 HDA_OUTPUT));
3427 if (err < 0)
3428 return err;
3429 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3430 "Center Playback Switch",
3431 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
3432 HDA_OUTPUT));
3433 if (err < 0)
3434 return err;
3435 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3436 "LFE Playback Switch",
3437 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
3438 HDA_OUTPUT));
3439 if (err < 0)
3440 return err;
3441 } else if (i == AUTO_SEQ_FRONT) {
3442 /* add control to mixer index 0 */
3443 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3444 "Master Front Playback Volume",
3445 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3446 HDA_INPUT));
3447 if (err < 0)
3448 return err;
3449 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3450 "Master Front Playback Switch",
3451 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3452 HDA_INPUT));
3453 if (err < 0)
3454 return err;
3455
3456 /* add control to PW3 */
3457 sprintf(name, "%s Playback Volume", chname[i]);
3458 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3459 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3460 HDA_OUTPUT));
3461 if (err < 0)
3462 return err;
3463 sprintf(name, "%s Playback Switch", chname[i]);
3464 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3465 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3466 HDA_OUTPUT));
3467 if (err < 0)
3468 return err;
3469 } else {
3470 sprintf(name, "%s Playback Volume", chname[i]);
3471 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3472 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3473 HDA_OUTPUT));
3474 if (err < 0)
3475 return err;
3476 sprintf(name, "%s Playback Switch", chname[i]);
3477 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3478 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3479 HDA_OUTPUT));
3480 if (err < 0)
3481 return err;
3482 }
3483 }
3484
3485 return 0;
3486}
3487
3488static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
3489{
3490 int err;
3491
3492 if (!pin)
3493 return 0;
3494
3495 spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
Lydia Wangcdc17842009-10-10 19:07:47 +08003496 spec->hp_independent_mode_index = 1;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003497
3498 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3499 "Headphone Playback Volume",
3500 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3501 if (err < 0)
3502 return err;
3503 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3504 "Headphone Playback Switch",
3505 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3506 if (err < 0)
3507 return err;
3508
Harald Welte0aa62ae2008-09-09 15:58:27 +08003509 create_hp_imux(spec);
3510
Josepch Chanf7278fd2007-12-13 16:40:40 +01003511 return 0;
3512}
3513
3514/* create playback/capture controls for input pins */
3515static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
3516 const struct auto_pin_cfg *cfg)
3517{
3518 static char *labels[] = {
3519 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
3520 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08003521 struct hda_input_mux *imux = &spec->private_imux[0];
Josepch Chanf7278fd2007-12-13 16:40:40 +01003522 int i, err, idx = 0;
3523
3524 /* for internal loopback recording select */
3525 imux->items[imux->num_items].label = "Stereo Mixer";
3526 imux->items[imux->num_items].index = idx;
3527 imux->num_items++;
3528
3529 for (i = 0; i < AUTO_PIN_LAST; i++) {
3530 if (!cfg->input_pins[i])
3531 continue;
3532
3533 switch (cfg->input_pins[i]) {
3534 case 0x1a: /* Mic */
3535 idx = 2;
3536 break;
3537
3538 case 0x1b: /* Line In */
3539 idx = 3;
3540 break;
3541
3542 case 0x1e: /* Front Mic */
3543 idx = 4;
3544 break;
3545
3546 case 0x1f: /* CD */
3547 idx = 1;
3548 break;
3549 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08003550 err = via_new_analog_input(spec, labels[i], idx, 0x16);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003551 if (err < 0)
3552 return err;
3553 imux->items[imux->num_items].label = labels[i];
3554 imux->items[imux->num_items].index = idx;
3555 imux->num_items++;
3556 }
3557 return 0;
3558}
3559
3560static int vt1708B_parse_auto_config(struct hda_codec *codec)
3561{
3562 struct via_spec *spec = codec->spec;
3563 int err;
3564
3565 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
3566 if (err < 0)
3567 return err;
3568 err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg);
3569 if (err < 0)
3570 return err;
3571 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
3572 return 0; /* can't find valid BIOS pin config */
3573
3574 err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg);
3575 if (err < 0)
3576 return err;
3577 err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
3578 if (err < 0)
3579 return err;
3580 err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
3581 if (err < 0)
3582 return err;
3583
3584 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3585
Takashi Iwai0852d7a2009-02-11 11:35:15 +01003586 if (spec->autocfg.dig_outs)
Josepch Chanf7278fd2007-12-13 16:40:40 +01003587 spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
Takashi Iwai55d1d6c2009-07-07 13:39:03 +02003588 spec->dig_in_pin = VT1708B_DIGIN_PIN;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003589 if (spec->autocfg.dig_in_pin)
3590 spec->dig_in_nid = VT1708B_DIGIN_NID;
3591
Takashi Iwai603c4012008-07-30 15:01:44 +02003592 if (spec->kctls.list)
3593 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003594
Harald Welte0aa62ae2008-09-09 15:58:27 +08003595 spec->input_mux = &spec->private_imux[0];
3596
Harald Weltef8fdd492008-09-15 22:41:31 +08003597 if (spec->hp_mux)
3598 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003599
Lydia Wang1564b282009-10-10 19:07:52 +08003600 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003601 return 1;
3602}
3603
3604#ifdef CONFIG_SND_HDA_POWER_SAVE
3605static struct hda_amp_list vt1708B_loopbacks[] = {
3606 { 0x16, HDA_INPUT, 1 },
3607 { 0x16, HDA_INPUT, 2 },
3608 { 0x16, HDA_INPUT, 3 },
3609 { 0x16, HDA_INPUT, 4 },
3610 { } /* end */
3611};
3612#endif
Lydia Wang518bf3b2009-10-10 19:07:29 +08003613static int patch_vt1708S(struct hda_codec *codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003614static int patch_vt1708B_8ch(struct hda_codec *codec)
3615{
3616 struct via_spec *spec;
3617 int err;
3618
Lydia Wang518bf3b2009-10-10 19:07:29 +08003619 if (get_codec_type(codec) == VT1708BCE)
3620 return patch_vt1708S(codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003621 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08003622 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003623 if (spec == NULL)
3624 return -ENOMEM;
3625
3626 codec->spec = spec;
3627
3628 /* automatic parse from the BIOS config */
3629 err = vt1708B_parse_auto_config(codec);
3630 if (err < 0) {
3631 via_free(codec);
3632 return err;
3633 } else if (!err) {
3634 printk(KERN_INFO "hda_codec: Cannot set up configuration "
3635 "from BIOS. Using genenic mode...\n");
3636 }
3637
Harald Welte69e52a82008-09-09 15:57:32 +08003638 spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs;
3639 spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003640
3641 spec->stream_name_analog = "VT1708B Analog";
3642 spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
3643 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
3644
3645 spec->stream_name_digital = "VT1708B Digital";
3646 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
3647 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
3648
3649 if (!spec->adc_nids && spec->input_mux) {
3650 spec->adc_nids = vt1708B_adc_nids;
3651 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02003652 get_mux_nids(codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003653 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
3654 spec->num_mixers++;
3655 }
3656
3657 codec->patch_ops = via_patch_ops;
3658
3659 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003660 codec->patch_ops.unsol_event = via_unsol_event;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003661#ifdef CONFIG_SND_HDA_POWER_SAVE
3662 spec->loopback.amplist = vt1708B_loopbacks;
3663#endif
3664
3665 return 0;
3666}
3667
3668static int patch_vt1708B_4ch(struct hda_codec *codec)
3669{
3670 struct via_spec *spec;
3671 int err;
3672
3673 /* create a codec specific record */
Harald Welteeb14a462008-09-09 15:40:38 +08003674 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003675 if (spec == NULL)
3676 return -ENOMEM;
3677
3678 codec->spec = spec;
3679
3680 /* automatic parse from the BIOS config */
3681 err = vt1708B_parse_auto_config(codec);
3682 if (err < 0) {
3683 via_free(codec);
3684 return err;
3685 } else if (!err) {
3686 printk(KERN_INFO "hda_codec: Cannot set up configuration "
3687 "from BIOS. Using genenic mode...\n");
3688 }
3689
Harald Welte69e52a82008-09-09 15:57:32 +08003690 spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs;
3691 spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003692
3693 spec->stream_name_analog = "VT1708B Analog";
3694 spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
3695 spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
3696
3697 spec->stream_name_digital = "VT1708B Digital";
3698 spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
3699 spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
3700
3701 if (!spec->adc_nids && spec->input_mux) {
3702 spec->adc_nids = vt1708B_adc_nids;
3703 spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02003704 get_mux_nids(codec);
Josepch Chanf7278fd2007-12-13 16:40:40 +01003705 spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
3706 spec->num_mixers++;
3707 }
3708
3709 codec->patch_ops = via_patch_ops;
3710
3711 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08003712 codec->patch_ops.unsol_event = via_unsol_event;
Josepch Chanf7278fd2007-12-13 16:40:40 +01003713#ifdef CONFIG_SND_HDA_POWER_SAVE
3714 spec->loopback.amplist = vt1708B_loopbacks;
3715#endif
Joseph Chanc577b8a2006-11-29 15:29:40 +01003716
3717 return 0;
3718}
3719
Harald Welted949cac2008-09-09 15:56:01 +08003720/* Patch for VT1708S */
3721
3722/* capture mixer elements */
3723static struct snd_kcontrol_new vt1708S_capture_mixer[] = {
3724 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
3725 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
3726 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
3727 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
Lydia Wang6369bcf2009-10-10 19:08:31 +08003728 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT),
3729 HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0,
3730 HDA_INPUT),
Harald Welted949cac2008-09-09 15:56:01 +08003731 {
3732 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3733 /* The multiple "Capture Source" controls confuse alsamixer
3734 * So call somewhat different..
3735 */
3736 /* .name = "Capture Source", */
3737 .name = "Input Source",
3738 .count = 1,
3739 .info = via_mux_enum_info,
3740 .get = via_mux_enum_get,
3741 .put = via_mux_enum_put,
3742 },
3743 { } /* end */
3744};
3745
3746static struct hda_verb vt1708S_volume_init_verbs[] = {
3747 /* Unmute ADC0-1 and set the default input to mic-in */
3748 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3749 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3750
3751 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the
3752 * analog-loopback mixer widget */
3753 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
3754 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3755 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3756 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3757 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3758 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
3759
3760 /* Setup default input of PW4 to MW0 */
3761 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
Harald Welte5691ec72008-09-15 22:42:26 +08003762 /* PW9, PW10 Output enable */
Harald Welted949cac2008-09-09 15:56:01 +08003763 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Harald Welte5691ec72008-09-15 22:42:26 +08003764 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Harald Welted7426322008-09-15 22:43:23 +08003765 /* Enable Mic Boost Volume backdoor */
3766 {0x1, 0xf98, 0x1},
Lydia Wangbc7e7e52009-10-10 19:08:32 +08003767 /* don't bybass mixer */
3768 {0x1, 0xf88, 0xc0},
Harald Welted949cac2008-09-09 15:56:01 +08003769 { }
3770};
3771
Harald Welte69e52a82008-09-09 15:57:32 +08003772static struct hda_verb vt1708S_uniwill_init_verbs[] = {
Lydia Wanga34df192009-10-10 19:08:01 +08003773 {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
3774 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
3775 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3776 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3777 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3778 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3779 {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3780 {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
3781 {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
Harald Welte69e52a82008-09-09 15:57:32 +08003782 { }
3783};
3784
Harald Welted949cac2008-09-09 15:56:01 +08003785static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
3786 .substreams = 2,
3787 .channels_min = 2,
3788 .channels_max = 8,
3789 .nid = 0x10, /* NID to query formats and rates */
3790 .ops = {
3791 .open = via_playback_pcm_open,
Lydia Wangc873cc22009-10-10 19:08:21 +08003792 .prepare = via_playback_multi_pcm_prepare,
3793 .cleanup = via_playback_multi_pcm_cleanup,
Lydia Wang17314372009-10-10 19:07:37 +08003794 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08003795 },
3796};
3797
3798static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
3799 .substreams = 2,
3800 .channels_min = 2,
3801 .channels_max = 2,
3802 .nid = 0x13, /* NID to query formats and rates */
3803 .ops = {
Lydia Wang17314372009-10-10 19:07:37 +08003804 .open = via_pcm_open_close,
Harald Welted949cac2008-09-09 15:56:01 +08003805 .prepare = via_capture_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08003806 .cleanup = via_capture_pcm_cleanup,
3807 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08003808 },
3809};
3810
3811static struct hda_pcm_stream vt1708S_pcm_digital_playback = {
Takashi Iwai9da29272009-05-07 16:31:14 +02003812 .substreams = 1,
Harald Welted949cac2008-09-09 15:56:01 +08003813 .channels_min = 2,
3814 .channels_max = 2,
3815 /* NID is set in via_build_pcms */
3816 .ops = {
3817 .open = via_dig_playback_pcm_open,
3818 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02003819 .prepare = via_dig_playback_pcm_prepare,
3820 .cleanup = via_dig_playback_pcm_cleanup
Harald Welted949cac2008-09-09 15:56:01 +08003821 },
3822};
3823
3824/* fill in the dac_nids table from the parsed pin configuration */
3825static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
3826 const struct auto_pin_cfg *cfg)
3827{
3828 int i;
3829 hda_nid_t nid;
3830
3831 spec->multiout.num_dacs = cfg->line_outs;
3832
3833 spec->multiout.dac_nids = spec->private_dac_nids;
3834
3835 for (i = 0; i < 4; i++) {
3836 nid = cfg->line_out_pins[i];
3837 if (nid) {
3838 /* config dac list */
3839 switch (i) {
3840 case AUTO_SEQ_FRONT:
3841 spec->multiout.dac_nids[i] = 0x10;
3842 break;
3843 case AUTO_SEQ_CENLFE:
3844 spec->multiout.dac_nids[i] = 0x24;
3845 break;
3846 case AUTO_SEQ_SURROUND:
3847 spec->multiout.dac_nids[i] = 0x11;
3848 break;
3849 case AUTO_SEQ_SIDE:
3850 spec->multiout.dac_nids[i] = 0x25;
3851 break;
3852 }
3853 }
3854 }
3855
3856 return 0;
3857}
3858
3859/* add playback controls from the parsed DAC table */
3860static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
3861 const struct auto_pin_cfg *cfg)
3862{
3863 char name[32];
3864 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
3865 hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25};
3866 hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27};
3867 hda_nid_t nid, nid_vol, nid_mute;
3868 int i, err;
3869
3870 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
3871 nid = cfg->line_out_pins[i];
3872
3873 if (!nid)
3874 continue;
3875
3876 nid_vol = nid_vols[i];
3877 nid_mute = nid_mutes[i];
3878
3879 if (i == AUTO_SEQ_CENLFE) {
3880 /* Center/LFE */
3881 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3882 "Center Playback Volume",
3883 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
3884 HDA_OUTPUT));
3885 if (err < 0)
3886 return err;
3887 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3888 "LFE Playback Volume",
3889 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
3890 HDA_OUTPUT));
3891 if (err < 0)
3892 return err;
3893 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3894 "Center Playback Switch",
3895 HDA_COMPOSE_AMP_VAL(nid_mute,
3896 1, 0,
3897 HDA_OUTPUT));
3898 if (err < 0)
3899 return err;
3900 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3901 "LFE Playback Switch",
3902 HDA_COMPOSE_AMP_VAL(nid_mute,
3903 2, 0,
3904 HDA_OUTPUT));
3905 if (err < 0)
3906 return err;
3907 } else if (i == AUTO_SEQ_FRONT) {
3908 /* add control to mixer index 0 */
3909 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3910 "Master Front Playback Volume",
3911 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
3912 HDA_INPUT));
3913 if (err < 0)
3914 return err;
3915 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3916 "Master Front Playback Switch",
3917 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
3918 HDA_INPUT));
3919 if (err < 0)
3920 return err;
3921
3922 /* Front */
3923 sprintf(name, "%s Playback Volume", chname[i]);
3924 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3925 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3926 HDA_OUTPUT));
3927 if (err < 0)
3928 return err;
3929 sprintf(name, "%s Playback Switch", chname[i]);
3930 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3931 HDA_COMPOSE_AMP_VAL(nid_mute,
3932 3, 0,
3933 HDA_OUTPUT));
3934 if (err < 0)
3935 return err;
3936 } else {
3937 sprintf(name, "%s Playback Volume", chname[i]);
3938 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
3939 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
3940 HDA_OUTPUT));
3941 if (err < 0)
3942 return err;
3943 sprintf(name, "%s Playback Switch", chname[i]);
3944 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
3945 HDA_COMPOSE_AMP_VAL(nid_mute,
3946 3, 0,
3947 HDA_OUTPUT));
3948 if (err < 0)
3949 return err;
3950 }
3951 }
3952
3953 return 0;
3954}
3955
3956static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
3957{
3958 int err;
3959
3960 if (!pin)
3961 return 0;
3962
3963 spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */
Lydia Wangcdc17842009-10-10 19:07:47 +08003964 spec->hp_independent_mode_index = 1;
Harald Welted949cac2008-09-09 15:56:01 +08003965
3966 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
3967 "Headphone Playback Volume",
3968 HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
3969 if (err < 0)
3970 return err;
3971
3972 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
3973 "Headphone Playback Switch",
3974 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3975 if (err < 0)
3976 return err;
3977
Harald Welte0aa62ae2008-09-09 15:58:27 +08003978 create_hp_imux(spec);
3979
Harald Welted949cac2008-09-09 15:56:01 +08003980 return 0;
3981}
3982
3983/* create playback/capture controls for input pins */
3984static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
3985 const struct auto_pin_cfg *cfg)
3986{
3987 static char *labels[] = {
3988 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
3989 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08003990 struct hda_input_mux *imux = &spec->private_imux[0];
Harald Welted949cac2008-09-09 15:56:01 +08003991 int i, err, idx = 0;
3992
3993 /* for internal loopback recording select */
3994 imux->items[imux->num_items].label = "Stereo Mixer";
3995 imux->items[imux->num_items].index = 5;
3996 imux->num_items++;
3997
3998 for (i = 0; i < AUTO_PIN_LAST; i++) {
3999 if (!cfg->input_pins[i])
4000 continue;
4001
4002 switch (cfg->input_pins[i]) {
4003 case 0x1a: /* Mic */
4004 idx = 2;
4005 break;
4006
4007 case 0x1b: /* Line In */
4008 idx = 3;
4009 break;
4010
4011 case 0x1e: /* Front Mic */
4012 idx = 4;
4013 break;
4014
4015 case 0x1f: /* CD */
4016 idx = 1;
4017 break;
4018 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08004019 err = via_new_analog_input(spec, labels[i], idx, 0x16);
Harald Welted949cac2008-09-09 15:56:01 +08004020 if (err < 0)
4021 return err;
4022 imux->items[imux->num_items].label = labels[i];
4023 imux->items[imux->num_items].index = idx-1;
4024 imux->num_items++;
4025 }
4026 return 0;
4027}
4028
Takashi Iwai9da29272009-05-07 16:31:14 +02004029/* fill out digital output widgets; one for master and one for slave outputs */
4030static void fill_dig_outs(struct hda_codec *codec)
4031{
4032 struct via_spec *spec = codec->spec;
4033 int i;
4034
4035 for (i = 0; i < spec->autocfg.dig_outs; i++) {
4036 hda_nid_t nid;
4037 int conn;
4038
4039 nid = spec->autocfg.dig_out_pins[i];
4040 if (!nid)
4041 continue;
4042 conn = snd_hda_get_connections(codec, nid, &nid, 1);
4043 if (conn < 1)
4044 continue;
4045 if (!spec->multiout.dig_out_nid)
4046 spec->multiout.dig_out_nid = nid;
4047 else {
4048 spec->slave_dig_outs[0] = nid;
4049 break; /* at most two dig outs */
4050 }
4051 }
4052}
4053
Harald Welted949cac2008-09-09 15:56:01 +08004054static int vt1708S_parse_auto_config(struct hda_codec *codec)
4055{
4056 struct via_spec *spec = codec->spec;
4057 int err;
Harald Welted949cac2008-09-09 15:56:01 +08004058
Takashi Iwai9da29272009-05-07 16:31:14 +02004059 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
Harald Welted949cac2008-09-09 15:56:01 +08004060 if (err < 0)
4061 return err;
4062 err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg);
4063 if (err < 0)
4064 return err;
4065 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
4066 return 0; /* can't find valid BIOS pin config */
4067
4068 err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg);
4069 if (err < 0)
4070 return err;
4071 err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
4072 if (err < 0)
4073 return err;
4074 err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
4075 if (err < 0)
4076 return err;
4077
4078 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4079
Takashi Iwai9da29272009-05-07 16:31:14 +02004080 fill_dig_outs(codec);
Harald Welte98aa34c2008-09-09 16:02:09 +08004081
Takashi Iwai603c4012008-07-30 15:01:44 +02004082 if (spec->kctls.list)
4083 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Harald Welted949cac2008-09-09 15:56:01 +08004084
Harald Welte0aa62ae2008-09-09 15:58:27 +08004085 spec->input_mux = &spec->private_imux[0];
4086
Harald Weltef8fdd492008-09-15 22:41:31 +08004087 if (spec->hp_mux)
4088 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08004089
Lydia Wang1564b282009-10-10 19:07:52 +08004090 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08004091 return 1;
4092}
4093
4094#ifdef CONFIG_SND_HDA_POWER_SAVE
4095static struct hda_amp_list vt1708S_loopbacks[] = {
4096 { 0x16, HDA_INPUT, 1 },
4097 { 0x16, HDA_INPUT, 2 },
4098 { 0x16, HDA_INPUT, 3 },
4099 { 0x16, HDA_INPUT, 4 },
4100 { } /* end */
4101};
4102#endif
4103
Lydia Wang6369bcf2009-10-10 19:08:31 +08004104static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin,
4105 int offset, int num_steps, int step_size)
4106{
4107 snd_hda_override_amp_caps(codec, pin, HDA_INPUT,
4108 (offset << AC_AMPCAP_OFFSET_SHIFT) |
4109 (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) |
4110 (step_size << AC_AMPCAP_STEP_SIZE_SHIFT) |
4111 (0 << AC_AMPCAP_MUTE_SHIFT));
4112}
4113
Harald Welted949cac2008-09-09 15:56:01 +08004114static int patch_vt1708S(struct hda_codec *codec)
4115{
4116 struct via_spec *spec;
4117 int err;
4118
4119 /* create a codec specific record */
4120 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4121 if (spec == NULL)
4122 return -ENOMEM;
4123
4124 codec->spec = spec;
4125
4126 /* automatic parse from the BIOS config */
4127 err = vt1708S_parse_auto_config(codec);
4128 if (err < 0) {
4129 via_free(codec);
4130 return err;
4131 } else if (!err) {
4132 printk(KERN_INFO "hda_codec: Cannot set up configuration "
4133 "from BIOS. Using genenic mode...\n");
4134 }
4135
Harald Welte69e52a82008-09-09 15:57:32 +08004136 spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
4137 spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs;
Harald Welted949cac2008-09-09 15:56:01 +08004138
Lydia Wang36dd5c42009-10-20 13:18:04 +08004139 if (codec->vendor_id == 0x11060440)
4140 spec->stream_name_analog = "VT1818S Analog";
4141 else
4142 spec->stream_name_analog = "VT1708S Analog";
Harald Welted949cac2008-09-09 15:56:01 +08004143 spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
4144 spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
4145
Lydia Wang36dd5c42009-10-20 13:18:04 +08004146 if (codec->vendor_id == 0x11060440)
4147 spec->stream_name_digital = "VT1818S Digital";
4148 else
4149 spec->stream_name_digital = "VT1708S Digital";
Harald Welted949cac2008-09-09 15:56:01 +08004150 spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
4151
4152 if (!spec->adc_nids && spec->input_mux) {
4153 spec->adc_nids = vt1708S_adc_nids;
4154 spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02004155 get_mux_nids(codec);
Lydia Wang6369bcf2009-10-10 19:08:31 +08004156 override_mic_boost(codec, 0x1a, 0, 3, 40);
4157 override_mic_boost(codec, 0x1e, 0, 3, 40);
Harald Welted949cac2008-09-09 15:56:01 +08004158 spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
4159 spec->num_mixers++;
4160 }
4161
4162 codec->patch_ops = via_patch_ops;
4163
4164 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08004165 codec->patch_ops.unsol_event = via_unsol_event;
Harald Welted949cac2008-09-09 15:56:01 +08004166#ifdef CONFIG_SND_HDA_POWER_SAVE
4167 spec->loopback.amplist = vt1708S_loopbacks;
4168#endif
4169
Lydia Wang518bf3b2009-10-10 19:07:29 +08004170 /* correct names for VT1708BCE */
4171 if (get_codec_type(codec) == VT1708BCE) {
4172 kfree(codec->chip_name);
4173 codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
4174 snprintf(codec->bus->card->mixername,
4175 sizeof(codec->bus->card->mixername),
4176 "%s %s", codec->vendor_name, codec->chip_name);
4177 spec->stream_name_analog = "VT1708BCE Analog";
4178 spec->stream_name_digital = "VT1708BCE Digital";
4179 }
Harald Welted949cac2008-09-09 15:56:01 +08004180 return 0;
4181}
4182
4183/* Patch for VT1702 */
4184
4185/* capture mixer elements */
4186static struct snd_kcontrol_new vt1702_capture_mixer[] = {
4187 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
4188 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
4189 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
4190 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT),
4191 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT),
4192 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT),
4193 HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0,
4194 HDA_INPUT),
4195 {
4196 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4197 /* The multiple "Capture Source" controls confuse alsamixer
4198 * So call somewhat different..
4199 */
4200 /* .name = "Capture Source", */
4201 .name = "Input Source",
4202 .count = 1,
4203 .info = via_mux_enum_info,
4204 .get = via_mux_enum_get,
4205 .put = via_mux_enum_put,
4206 },
4207 { } /* end */
4208};
4209
4210static struct hda_verb vt1702_volume_init_verbs[] = {
4211 /*
4212 * Unmute ADC0-1 and set the default input to mic-in
4213 */
4214 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4215 {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4216 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4217
4218
4219 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4220 * mixer widget
4221 */
4222 /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */
4223 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4224 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4225 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4226 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
4227 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4228
4229 /* Setup default input of PW4 to MW0 */
4230 {0x17, AC_VERB_SET_CONNECT_SEL, 0x1},
4231 /* PW6 PW7 Output enable */
4232 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4233 {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
Lydia Wangbc7e7e52009-10-10 19:08:32 +08004234 /* mixer enable */
4235 {0x1, 0xF88, 0x3},
4236 /* GPIO 0~2 */
4237 {0x1, 0xF82, 0x3F},
Harald Welted949cac2008-09-09 15:56:01 +08004238 { }
4239};
4240
Harald Welte69e52a82008-09-09 15:57:32 +08004241static struct hda_verb vt1702_uniwill_init_verbs[] = {
Lydia Wanga34df192009-10-10 19:08:01 +08004242 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE,
4243 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
4244 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4245 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4246 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4247 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
Harald Welte69e52a82008-09-09 15:57:32 +08004248 { }
4249};
4250
Harald Welted949cac2008-09-09 15:56:01 +08004251static struct hda_pcm_stream vt1702_pcm_analog_playback = {
Harald Welte0aa62ae2008-09-09 15:58:27 +08004252 .substreams = 2,
Harald Welted949cac2008-09-09 15:56:01 +08004253 .channels_min = 2,
4254 .channels_max = 2,
4255 .nid = 0x10, /* NID to query formats and rates */
4256 .ops = {
4257 .open = via_playback_pcm_open,
Harald Welte0aa62ae2008-09-09 15:58:27 +08004258 .prepare = via_playback_multi_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08004259 .cleanup = via_playback_multi_pcm_cleanup,
4260 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08004261 },
4262};
4263
4264static struct hda_pcm_stream vt1702_pcm_analog_capture = {
4265 .substreams = 3,
4266 .channels_min = 2,
4267 .channels_max = 2,
4268 .nid = 0x12, /* NID to query formats and rates */
4269 .ops = {
Lydia Wang17314372009-10-10 19:07:37 +08004270 .open = via_pcm_open_close,
Harald Welted949cac2008-09-09 15:56:01 +08004271 .prepare = via_capture_pcm_prepare,
Lydia Wang17314372009-10-10 19:07:37 +08004272 .cleanup = via_capture_pcm_cleanup,
4273 .close = via_pcm_open_close
Harald Welted949cac2008-09-09 15:56:01 +08004274 },
4275};
4276
4277static struct hda_pcm_stream vt1702_pcm_digital_playback = {
Harald Welte5691ec72008-09-15 22:42:26 +08004278 .substreams = 2,
Harald Welted949cac2008-09-09 15:56:01 +08004279 .channels_min = 2,
4280 .channels_max = 2,
4281 /* NID is set in via_build_pcms */
4282 .ops = {
4283 .open = via_dig_playback_pcm_open,
4284 .close = via_dig_playback_pcm_close,
Takashi Iwai9da29272009-05-07 16:31:14 +02004285 .prepare = via_dig_playback_pcm_prepare,
4286 .cleanup = via_dig_playback_pcm_cleanup
Harald Welted949cac2008-09-09 15:56:01 +08004287 },
4288};
4289
4290/* fill in the dac_nids table from the parsed pin configuration */
4291static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
4292 const struct auto_pin_cfg *cfg)
4293{
4294 spec->multiout.num_dacs = 1;
4295 spec->multiout.dac_nids = spec->private_dac_nids;
4296
4297 if (cfg->line_out_pins[0]) {
4298 /* config dac list */
4299 spec->multiout.dac_nids[0] = 0x10;
4300 }
4301
4302 return 0;
4303}
4304
4305/* add playback controls from the parsed DAC table */
4306static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
4307 const struct auto_pin_cfg *cfg)
4308{
4309 int err;
4310
4311 if (!cfg->line_out_pins[0])
4312 return -1;
4313
4314 /* add control to mixer index 0 */
4315 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4316 "Master Front Playback Volume",
4317 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
4318 if (err < 0)
4319 return err;
4320 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
4321 "Master Front Playback Switch",
4322 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
4323 if (err < 0)
4324 return err;
4325
4326 /* Front */
4327 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4328 "Front Playback Volume",
4329 HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT));
4330 if (err < 0)
4331 return err;
4332 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
4333 "Front Playback Switch",
4334 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT));
4335 if (err < 0)
4336 return err;
4337
4338 return 0;
4339}
4340
4341static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
4342{
Lydia Wang0713efe2009-10-10 19:07:43 +08004343 int err, i;
4344 struct hda_input_mux *imux;
4345 static const char *texts[] = { "ON", "OFF", NULL};
Harald Welted949cac2008-09-09 15:56:01 +08004346 if (!pin)
4347 return 0;
Harald Welted949cac2008-09-09 15:56:01 +08004348 spec->multiout.hp_nid = 0x1D;
Lydia Wangcdc17842009-10-10 19:07:47 +08004349 spec->hp_independent_mode_index = 0;
Harald Welted949cac2008-09-09 15:56:01 +08004350
4351 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4352 "Headphone Playback Volume",
4353 HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT));
4354 if (err < 0)
4355 return err;
4356
4357 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
4358 "Headphone Playback Switch",
4359 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4360 if (err < 0)
4361 return err;
4362
Lydia Wang0713efe2009-10-10 19:07:43 +08004363 imux = &spec->private_imux[1];
Harald Welte0aa62ae2008-09-09 15:58:27 +08004364
Lydia Wang0713efe2009-10-10 19:07:43 +08004365 /* for hp mode select */
4366 i = 0;
4367 while (texts[i] != NULL) {
4368 imux->items[imux->num_items].label = texts[i];
4369 imux->items[imux->num_items].index = i;
4370 imux->num_items++;
4371 i++;
4372 }
4373
4374 spec->hp_mux = &spec->private_imux[1];
Harald Welted949cac2008-09-09 15:56:01 +08004375 return 0;
4376}
4377
4378/* create playback/capture controls for input pins */
4379static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
4380 const struct auto_pin_cfg *cfg)
4381{
4382 static char *labels[] = {
4383 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
4384 };
Harald Welte0aa62ae2008-09-09 15:58:27 +08004385 struct hda_input_mux *imux = &spec->private_imux[0];
Harald Welted949cac2008-09-09 15:56:01 +08004386 int i, err, idx = 0;
4387
4388 /* for internal loopback recording select */
4389 imux->items[imux->num_items].label = "Stereo Mixer";
4390 imux->items[imux->num_items].index = 3;
4391 imux->num_items++;
4392
4393 for (i = 0; i < AUTO_PIN_LAST; i++) {
4394 if (!cfg->input_pins[i])
4395 continue;
4396
4397 switch (cfg->input_pins[i]) {
4398 case 0x14: /* Mic */
4399 idx = 1;
4400 break;
4401
4402 case 0x15: /* Line In */
4403 idx = 2;
4404 break;
4405
4406 case 0x18: /* Front Mic */
4407 idx = 3;
4408 break;
4409 }
Lydia Wang9510e8d2009-10-10 19:07:39 +08004410 err = via_new_analog_input(spec, labels[i], idx, 0x1A);
Harald Welted949cac2008-09-09 15:56:01 +08004411 if (err < 0)
4412 return err;
4413 imux->items[imux->num_items].label = labels[i];
4414 imux->items[imux->num_items].index = idx-1;
4415 imux->num_items++;
4416 }
4417 return 0;
4418}
4419
4420static int vt1702_parse_auto_config(struct hda_codec *codec)
4421{
4422 struct via_spec *spec = codec->spec;
4423 int err;
Harald Welted949cac2008-09-09 15:56:01 +08004424
Takashi Iwai9da29272009-05-07 16:31:14 +02004425 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
Harald Welted949cac2008-09-09 15:56:01 +08004426 if (err < 0)
4427 return err;
4428 err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg);
4429 if (err < 0)
4430 return err;
4431 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
4432 return 0; /* can't find valid BIOS pin config */
4433
4434 err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg);
4435 if (err < 0)
4436 return err;
4437 err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
4438 if (err < 0)
4439 return err;
Lydia Wangc2c02ea2009-10-10 19:07:32 +08004440 /* limit AA path volume to 0 dB */
4441 snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT,
4442 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4443 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4444 (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4445 (1 << AC_AMPCAP_MUTE_SHIFT));
Harald Welted949cac2008-09-09 15:56:01 +08004446 err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
4447 if (err < 0)
4448 return err;
4449
4450 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4451
Takashi Iwai9da29272009-05-07 16:31:14 +02004452 fill_dig_outs(codec);
Harald Welte98aa34c2008-09-09 16:02:09 +08004453
Takashi Iwai603c4012008-07-30 15:01:44 +02004454 if (spec->kctls.list)
4455 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Harald Welted949cac2008-09-09 15:56:01 +08004456
Harald Welte0aa62ae2008-09-09 15:58:27 +08004457 spec->input_mux = &spec->private_imux[0];
4458
Harald Weltef8fdd492008-09-15 22:41:31 +08004459 if (spec->hp_mux)
4460 spec->mixers[spec->num_mixers++] = via_hp_mixer;
Harald Welted949cac2008-09-09 15:56:01 +08004461
4462 return 1;
4463}
4464
4465#ifdef CONFIG_SND_HDA_POWER_SAVE
4466static struct hda_amp_list vt1702_loopbacks[] = {
4467 { 0x1A, HDA_INPUT, 1 },
4468 { 0x1A, HDA_INPUT, 2 },
4469 { 0x1A, HDA_INPUT, 3 },
4470 { 0x1A, HDA_INPUT, 4 },
4471 { } /* end */
4472};
4473#endif
4474
4475static int patch_vt1702(struct hda_codec *codec)
4476{
4477 struct via_spec *spec;
4478 int err;
Harald Welted949cac2008-09-09 15:56:01 +08004479
4480 /* create a codec specific record */
4481 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4482 if (spec == NULL)
4483 return -ENOMEM;
4484
4485 codec->spec = spec;
4486
4487 /* automatic parse from the BIOS config */
4488 err = vt1702_parse_auto_config(codec);
4489 if (err < 0) {
4490 via_free(codec);
4491 return err;
4492 } else if (!err) {
4493 printk(KERN_INFO "hda_codec: Cannot set up configuration "
4494 "from BIOS. Using genenic mode...\n");
4495 }
4496
Harald Welte69e52a82008-09-09 15:57:32 +08004497 spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs;
4498 spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs;
Harald Welted949cac2008-09-09 15:56:01 +08004499
4500 spec->stream_name_analog = "VT1702 Analog";
4501 spec->stream_analog_playback = &vt1702_pcm_analog_playback;
4502 spec->stream_analog_capture = &vt1702_pcm_analog_capture;
4503
4504 spec->stream_name_digital = "VT1702 Digital";
4505 spec->stream_digital_playback = &vt1702_pcm_digital_playback;
4506
4507 if (!spec->adc_nids && spec->input_mux) {
4508 spec->adc_nids = vt1702_adc_nids;
4509 spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
Takashi Iwai337b9d02009-07-07 18:18:59 +02004510 get_mux_nids(codec);
Harald Welted949cac2008-09-09 15:56:01 +08004511 spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
4512 spec->num_mixers++;
4513 }
4514
4515 codec->patch_ops = via_patch_ops;
4516
4517 codec->patch_ops.init = via_auto_init;
Harald Welte69e52a82008-09-09 15:57:32 +08004518 codec->patch_ops.unsol_event = via_unsol_event;
Harald Welted949cac2008-09-09 15:56:01 +08004519#ifdef CONFIG_SND_HDA_POWER_SAVE
4520 spec->loopback.amplist = vt1702_loopbacks;
4521#endif
4522
Harald Welted949cac2008-09-09 15:56:01 +08004523 return 0;
4524}
4525
Lydia Wangeb7188c2009-10-10 19:08:34 +08004526/* Patch for VT1718S */
4527
4528/* capture mixer elements */
4529static struct snd_kcontrol_new vt1718S_capture_mixer[] = {
4530 HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
4531 HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
4532 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
4533 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
4534 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
4535 HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0,
4536 HDA_INPUT),
4537 {
4538 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4539 /* The multiple "Capture Source" controls confuse alsamixer
4540 * So call somewhat different..
4541 */
4542 .name = "Input Source",
4543 .count = 2,
4544 .info = via_mux_enum_info,
4545 .get = via_mux_enum_get,
4546 .put = via_mux_enum_put,
4547 },
4548 { } /* end */
4549};
4550
4551static struct hda_verb vt1718S_volume_init_verbs[] = {
4552 /*
4553 * Unmute ADC0-1 and set the default input to mic-in
4554 */
4555 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4556 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4557
4558
4559 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4560 * mixer widget
4561 */
4562 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
4563 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4564 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4565 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4566 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4567 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4568
4569 /* Setup default input of Front HP to MW9 */
4570 {0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
4571 /* PW9 PW10 Output enable */
4572 {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
4573 {0x2e, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
4574 /* PW11 Input enable */
4575 {0x2f, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_IN_EN},
4576 /* Enable Boost Volume backdoor */
4577 {0x1, 0xf88, 0x8},
4578 /* MW0/1/2/3/4: un-mute index 0 (AOWx), mute index 1 (MW9) */
4579 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4580 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4581 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4582 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4583 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4584 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4585 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4586 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4587 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4588 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4589 /* set MUX1 = 2 (AOW4), MUX2 = 1 (AOW3) */
4590 {0x34, AC_VERB_SET_CONNECT_SEL, 0x2},
4591 {0x35, AC_VERB_SET_CONNECT_SEL, 0x1},
4592 /* Unmute MW4's index 0 */
4593 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4594 { }
4595};
4596
4597
4598static struct hda_verb vt1718S_uniwill_init_verbs[] = {
4599 {0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
4600 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
4601 {0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4602 {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4603 {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4604 {0x27, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4605 {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4606 {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4607 {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
4608 { }
4609};
4610
4611static struct hda_pcm_stream vt1718S_pcm_analog_playback = {
4612 .substreams = 2,
4613 .channels_min = 2,
4614 .channels_max = 10,
4615 .nid = 0x8, /* NID to query formats and rates */
4616 .ops = {
4617 .open = via_playback_pcm_open,
4618 .prepare = via_playback_multi_pcm_prepare,
4619 .cleanup = via_playback_multi_pcm_cleanup,
4620 .close = via_pcm_open_close,
4621 },
4622};
4623
4624static struct hda_pcm_stream vt1718S_pcm_analog_capture = {
4625 .substreams = 2,
4626 .channels_min = 2,
4627 .channels_max = 2,
4628 .nid = 0x10, /* NID to query formats and rates */
4629 .ops = {
4630 .open = via_pcm_open_close,
4631 .prepare = via_capture_pcm_prepare,
4632 .cleanup = via_capture_pcm_cleanup,
4633 .close = via_pcm_open_close,
4634 },
4635};
4636
4637static struct hda_pcm_stream vt1718S_pcm_digital_playback = {
4638 .substreams = 2,
4639 .channels_min = 2,
4640 .channels_max = 2,
Lydia Wangeb7188c2009-10-10 19:08:34 +08004641 /* NID is set in via_build_pcms */
4642 .ops = {
4643 .open = via_dig_playback_pcm_open,
4644 .close = via_dig_playback_pcm_close,
4645 .prepare = via_dig_playback_pcm_prepare,
4646 .cleanup = via_dig_playback_pcm_cleanup
4647 },
4648};
4649
4650static struct hda_pcm_stream vt1718S_pcm_digital_capture = {
4651 .substreams = 1,
4652 .channels_min = 2,
4653 .channels_max = 2,
4654};
4655
4656/* fill in the dac_nids table from the parsed pin configuration */
4657static int vt1718S_auto_fill_dac_nids(struct via_spec *spec,
4658 const struct auto_pin_cfg *cfg)
4659{
4660 int i;
4661 hda_nid_t nid;
4662
4663 spec->multiout.num_dacs = cfg->line_outs;
4664
4665 spec->multiout.dac_nids = spec->private_dac_nids;
4666
4667 for (i = 0; i < 4; i++) {
4668 nid = cfg->line_out_pins[i];
4669 if (nid) {
4670 /* config dac list */
4671 switch (i) {
4672 case AUTO_SEQ_FRONT:
4673 spec->multiout.dac_nids[i] = 0x8;
4674 break;
4675 case AUTO_SEQ_CENLFE:
4676 spec->multiout.dac_nids[i] = 0xa;
4677 break;
4678 case AUTO_SEQ_SURROUND:
4679 spec->multiout.dac_nids[i] = 0x9;
4680 break;
4681 case AUTO_SEQ_SIDE:
4682 spec->multiout.dac_nids[i] = 0xb;
4683 break;
4684 }
4685 }
4686 }
4687
4688 return 0;
4689}
4690
4691/* add playback controls from the parsed DAC table */
4692static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec,
4693 const struct auto_pin_cfg *cfg)
4694{
4695 char name[32];
4696 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
4697 hda_nid_t nid_vols[] = {0x8, 0x9, 0xa, 0xb};
4698 hda_nid_t nid_mutes[] = {0x24, 0x25, 0x26, 0x27};
4699 hda_nid_t nid, nid_vol, nid_mute = 0;
4700 int i, err;
4701
4702 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
4703 nid = cfg->line_out_pins[i];
4704
4705 if (!nid)
4706 continue;
4707 nid_vol = nid_vols[i];
4708 nid_mute = nid_mutes[i];
4709
4710 if (i == AUTO_SEQ_CENLFE) {
4711 /* Center/LFE */
4712 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4713 "Center Playback Volume",
4714 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
4715 HDA_OUTPUT));
4716 if (err < 0)
4717 return err;
4718 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4719 "LFE Playback Volume",
4720 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
4721 HDA_OUTPUT));
4722 if (err < 0)
4723 return err;
4724 err = via_add_control(
4725 spec, VIA_CTL_WIDGET_MUTE,
4726 "Center Playback Switch",
4727 HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0,
4728 HDA_OUTPUT));
4729 if (err < 0)
4730 return err;
4731 err = via_add_control(
4732 spec, VIA_CTL_WIDGET_MUTE,
4733 "LFE Playback Switch",
4734 HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0,
4735 HDA_OUTPUT));
4736 if (err < 0)
4737 return err;
4738 } else if (i == AUTO_SEQ_FRONT) {
4739 /* Front */
4740 sprintf(name, "%s Playback Volume", chname[i]);
4741 err = via_add_control(
4742 spec, VIA_CTL_WIDGET_VOL, name,
4743 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
4744 if (err < 0)
4745 return err;
4746 sprintf(name, "%s Playback Switch", chname[i]);
4747 err = via_add_control(
4748 spec, VIA_CTL_WIDGET_MUTE, name,
4749 HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
4750 HDA_OUTPUT));
4751 if (err < 0)
4752 return err;
4753 } else {
4754 sprintf(name, "%s Playback Volume", chname[i]);
4755 err = via_add_control(
4756 spec, VIA_CTL_WIDGET_VOL, name,
4757 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
4758 if (err < 0)
4759 return err;
4760 sprintf(name, "%s Playback Switch", chname[i]);
4761 err = via_add_control(
4762 spec, VIA_CTL_WIDGET_MUTE, name,
4763 HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
4764 HDA_OUTPUT));
4765 if (err < 0)
4766 return err;
4767 }
4768 }
4769 return 0;
4770}
4771
4772static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
4773{
4774 int err;
4775
4776 if (!pin)
4777 return 0;
4778
4779 spec->multiout.hp_nid = 0xc; /* AOW4 */
4780 spec->hp_independent_mode_index = 1;
4781
4782 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
4783 "Headphone Playback Volume",
4784 HDA_COMPOSE_AMP_VAL(0xc, 3, 0, HDA_OUTPUT));
4785 if (err < 0)
4786 return err;
4787
4788 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
4789 "Headphone Playback Switch",
4790 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4791 if (err < 0)
4792 return err;
4793
4794 create_hp_imux(spec);
4795 return 0;
4796}
4797
4798/* create playback/capture controls for input pins */
4799static int vt1718S_auto_create_analog_input_ctls(struct via_spec *spec,
4800 const struct auto_pin_cfg *cfg)
4801{
4802 static char *labels[] = {
4803 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
4804 };
4805 struct hda_input_mux *imux = &spec->private_imux[0];
4806 int i, err, idx = 0;
4807
4808 /* for internal loopback recording select */
4809 imux->items[imux->num_items].label = "Stereo Mixer";
4810 imux->items[imux->num_items].index = 5;
4811 imux->num_items++;
4812
4813 for (i = 0; i < AUTO_PIN_LAST; i++) {
4814 if (!cfg->input_pins[i])
4815 continue;
4816
4817 switch (cfg->input_pins[i]) {
4818 case 0x2b: /* Mic */
4819 idx = 1;
4820 break;
4821
4822 case 0x2a: /* Line In */
4823 idx = 2;
4824 break;
4825
4826 case 0x29: /* Front Mic */
4827 idx = 3;
4828 break;
4829
4830 case 0x2c: /* CD */
4831 idx = 0;
4832 break;
4833 }
4834 err = via_new_analog_input(spec, labels[i], idx, 0x21);
4835 if (err < 0)
4836 return err;
4837 imux->items[imux->num_items].label = labels[i];
4838 imux->items[imux->num_items].index = idx;
4839 imux->num_items++;
4840 }
4841 return 0;
4842}
4843
4844static int vt1718S_parse_auto_config(struct hda_codec *codec)
4845{
4846 struct via_spec *spec = codec->spec;
4847 int err;
4848
4849 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
4850
4851 if (err < 0)
4852 return err;
4853 err = vt1718S_auto_fill_dac_nids(spec, &spec->autocfg);
4854 if (err < 0)
4855 return err;
4856 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
4857 return 0; /* can't find valid BIOS pin config */
4858
4859 err = vt1718S_auto_create_multi_out_ctls(spec, &spec->autocfg);
4860 if (err < 0)
4861 return err;
4862 err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
4863 if (err < 0)
4864 return err;
4865 err = vt1718S_auto_create_analog_input_ctls(spec, &spec->autocfg);
4866 if (err < 0)
4867 return err;
4868
4869 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4870
4871 fill_dig_outs(codec);
4872
4873 if (spec->autocfg.dig_in_pin && codec->vendor_id == 0x11060428)
4874 spec->dig_in_nid = 0x13;
4875
4876 if (spec->kctls.list)
4877 spec->mixers[spec->num_mixers++] = spec->kctls.list;
4878
4879 spec->input_mux = &spec->private_imux[0];
4880
4881 if (spec->hp_mux)
4882 spec->mixers[spec->num_mixers++] = via_hp_mixer;
4883
4884 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
4885
4886 return 1;
4887}
4888
4889#ifdef CONFIG_SND_HDA_POWER_SAVE
4890static struct hda_amp_list vt1718S_loopbacks[] = {
4891 { 0x21, HDA_INPUT, 1 },
4892 { 0x21, HDA_INPUT, 2 },
4893 { 0x21, HDA_INPUT, 3 },
4894 { 0x21, HDA_INPUT, 4 },
4895 { } /* end */
4896};
4897#endif
4898
4899static int patch_vt1718S(struct hda_codec *codec)
4900{
4901 struct via_spec *spec;
4902 int err;
4903
4904 /* create a codec specific record */
4905 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4906 if (spec == NULL)
4907 return -ENOMEM;
4908
4909 codec->spec = spec;
4910
4911 /* automatic parse from the BIOS config */
4912 err = vt1718S_parse_auto_config(codec);
4913 if (err < 0) {
4914 via_free(codec);
4915 return err;
4916 } else if (!err) {
4917 printk(KERN_INFO "hda_codec: Cannot set up configuration "
4918 "from BIOS. Using genenic mode...\n");
4919 }
4920
4921 spec->init_verbs[spec->num_iverbs++] = vt1718S_volume_init_verbs;
4922 spec->init_verbs[spec->num_iverbs++] = vt1718S_uniwill_init_verbs;
4923
Lydia Wangbb3c6bfc2009-10-10 19:08:39 +08004924 if (codec->vendor_id == 0x11060441)
4925 spec->stream_name_analog = "VT2020 Analog";
4926 else if (codec->vendor_id == 0x11064441)
4927 spec->stream_name_analog = "VT1828S Analog";
4928 else
4929 spec->stream_name_analog = "VT1718S Analog";
Lydia Wangeb7188c2009-10-10 19:08:34 +08004930 spec->stream_analog_playback = &vt1718S_pcm_analog_playback;
4931 spec->stream_analog_capture = &vt1718S_pcm_analog_capture;
4932
Lydia Wangbb3c6bfc2009-10-10 19:08:39 +08004933 if (codec->vendor_id == 0x11060441)
4934 spec->stream_name_digital = "VT2020 Digital";
4935 else if (codec->vendor_id == 0x11064441)
4936 spec->stream_name_digital = "VT1828S Digital";
4937 else
4938 spec->stream_name_digital = "VT1718S Digital";
Lydia Wangeb7188c2009-10-10 19:08:34 +08004939 spec->stream_digital_playback = &vt1718S_pcm_digital_playback;
Lydia Wangbb3c6bfc2009-10-10 19:08:39 +08004940 if (codec->vendor_id == 0x11060428 || codec->vendor_id == 0x11060441)
Lydia Wangeb7188c2009-10-10 19:08:34 +08004941 spec->stream_digital_capture = &vt1718S_pcm_digital_capture;
4942
4943 if (!spec->adc_nids && spec->input_mux) {
4944 spec->adc_nids = vt1718S_adc_nids;
4945 spec->num_adc_nids = ARRAY_SIZE(vt1718S_adc_nids);
4946 get_mux_nids(codec);
Lydia Wangbb3c6bfc2009-10-10 19:08:39 +08004947 override_mic_boost(codec, 0x2b, 0, 3, 40);
4948 override_mic_boost(codec, 0x29, 0, 3, 40);
Lydia Wangeb7188c2009-10-10 19:08:34 +08004949 spec->mixers[spec->num_mixers] = vt1718S_capture_mixer;
4950 spec->num_mixers++;
4951 }
4952
4953 codec->patch_ops = via_patch_ops;
4954
4955 codec->patch_ops.init = via_auto_init;
Stephen Rothwell0f483272009-10-12 15:56:17 +11004956 codec->patch_ops.unsol_event = via_unsol_event;
Lydia Wangeb7188c2009-10-10 19:08:34 +08004957
4958#ifdef CONFIG_SND_HDA_POWER_SAVE
4959 spec->loopback.amplist = vt1718S_loopbacks;
4960#endif
4961
4962 return 0;
4963}
Lydia Wangf3db4232009-10-10 19:08:41 +08004964
4965/* Patch for VT1716S */
4966
4967static int vt1716s_dmic_info(struct snd_kcontrol *kcontrol,
4968 struct snd_ctl_elem_info *uinfo)
4969{
4970 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
4971 uinfo->count = 1;
4972 uinfo->value.integer.min = 0;
4973 uinfo->value.integer.max = 1;
4974 return 0;
4975}
4976
4977static int vt1716s_dmic_get(struct snd_kcontrol *kcontrol,
4978 struct snd_ctl_elem_value *ucontrol)
4979{
4980 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4981 int index = 0;
4982
4983 index = snd_hda_codec_read(codec, 0x26, 0,
4984 AC_VERB_GET_CONNECT_SEL, 0);
4985 if (index != -1)
4986 *ucontrol->value.integer.value = index;
4987
4988 return 0;
4989}
4990
4991static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,
4992 struct snd_ctl_elem_value *ucontrol)
4993{
4994 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4995 struct via_spec *spec = codec->spec;
4996 int index = *ucontrol->value.integer.value;
4997
4998 snd_hda_codec_write(codec, 0x26, 0,
4999 AC_VERB_SET_CONNECT_SEL, index);
5000 spec->dmic_enabled = index;
5001 set_jack_power_state(codec);
5002
5003 return 1;
5004}
5005
5006/* capture mixer elements */
5007static struct snd_kcontrol_new vt1716S_capture_mixer[] = {
5008 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
5009 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
5010 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
5011 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
5012 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT),
5013 HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0,
5014 HDA_INPUT),
5015 {
5016 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5017 .name = "Input Source",
5018 .count = 1,
5019 .info = via_mux_enum_info,
5020 .get = via_mux_enum_get,
5021 .put = via_mux_enum_put,
5022 },
5023 { } /* end */
5024};
5025
5026static struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
5027 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT),
5028 {
5029 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5030 .name = "Digital Mic Capture Switch",
5031 .count = 1,
5032 .info = vt1716s_dmic_info,
5033 .get = vt1716s_dmic_get,
5034 .put = vt1716s_dmic_put,
5035 },
5036 {} /* end */
5037};
5038
5039
5040/* mono-out mixer elements */
5041static struct snd_kcontrol_new vt1716S_mono_out_mixer[] = {
5042 HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT),
5043 { } /* end */
5044};
5045
5046static struct hda_verb vt1716S_volume_init_verbs[] = {
5047 /*
5048 * Unmute ADC0-1 and set the default input to mic-in
5049 */
5050 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5051 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5052
5053
5054 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5055 * mixer widget
5056 */
5057 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
5058 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5059 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5060 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5061 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5062 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5063
5064 /* MUX Indices: Stereo Mixer = 5 */
5065 {0x17, AC_VERB_SET_CONNECT_SEL, 0x5},
5066
5067 /* Setup default input of PW4 to MW0 */
5068 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
5069
5070 /* Setup default input of SW1 as MW0 */
5071 {0x18, AC_VERB_SET_CONNECT_SEL, 0x1},
5072
5073 /* Setup default input of SW4 as AOW0 */
5074 {0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
5075
5076 /* PW9 PW10 Output enable */
5077 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5078 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5079
5080 /* Unmute SW1, PW12 */
5081 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5082 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5083 /* PW12 Output enable */
5084 {0x2a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5085 /* Enable Boost Volume backdoor */
5086 {0x1, 0xf8a, 0x80},
5087 /* don't bybass mixer */
5088 {0x1, 0xf88, 0xc0},
5089 /* Enable mono output */
5090 {0x1, 0xf90, 0x08},
5091 { }
5092};
5093
5094
5095static struct hda_verb vt1716S_uniwill_init_verbs[] = {
5096 {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
5097 AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
5098 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5099 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5100 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5101 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE,
5102 AC_USRSP_EN | VIA_MONO_EVENT | VIA_JACK_EVENT},
5103 {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5104 {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5105 { }
5106};
5107
5108static struct hda_pcm_stream vt1716S_pcm_analog_playback = {
5109 .substreams = 2,
5110 .channels_min = 2,
5111 .channels_max = 6,
5112 .nid = 0x10, /* NID to query formats and rates */
5113 .ops = {
5114 .open = via_playback_pcm_open,
5115 .prepare = via_playback_multi_pcm_prepare,
5116 .cleanup = via_playback_multi_pcm_cleanup,
5117 .close = via_pcm_open_close,
5118 },
5119};
5120
5121static struct hda_pcm_stream vt1716S_pcm_analog_capture = {
5122 .substreams = 2,
5123 .channels_min = 2,
5124 .channels_max = 2,
5125 .nid = 0x13, /* NID to query formats and rates */
5126 .ops = {
5127 .open = via_pcm_open_close,
5128 .prepare = via_capture_pcm_prepare,
5129 .cleanup = via_capture_pcm_cleanup,
5130 .close = via_pcm_open_close,
5131 },
5132};
5133
5134static struct hda_pcm_stream vt1716S_pcm_digital_playback = {
5135 .substreams = 2,
5136 .channels_min = 2,
5137 .channels_max = 2,
Lydia Wangf3db4232009-10-10 19:08:41 +08005138 /* NID is set in via_build_pcms */
5139 .ops = {
5140 .open = via_dig_playback_pcm_open,
5141 .close = via_dig_playback_pcm_close,
5142 .prepare = via_dig_playback_pcm_prepare,
5143 .cleanup = via_dig_playback_pcm_cleanup
5144 },
5145};
5146
5147/* fill in the dac_nids table from the parsed pin configuration */
5148static int vt1716S_auto_fill_dac_nids(struct via_spec *spec,
5149 const struct auto_pin_cfg *cfg)
5150{ int i;
5151 hda_nid_t nid;
5152
5153 spec->multiout.num_dacs = cfg->line_outs;
5154
5155 spec->multiout.dac_nids = spec->private_dac_nids;
5156
5157 for (i = 0; i < 3; i++) {
5158 nid = cfg->line_out_pins[i];
5159 if (nid) {
5160 /* config dac list */
5161 switch (i) {
5162 case AUTO_SEQ_FRONT:
5163 spec->multiout.dac_nids[i] = 0x10;
5164 break;
5165 case AUTO_SEQ_CENLFE:
5166 spec->multiout.dac_nids[i] = 0x25;
5167 break;
5168 case AUTO_SEQ_SURROUND:
5169 spec->multiout.dac_nids[i] = 0x11;
5170 break;
5171 }
5172 }
5173 }
5174
5175 return 0;
5176}
5177
5178/* add playback controls from the parsed DAC table */
5179static int vt1716S_auto_create_multi_out_ctls(struct via_spec *spec,
5180 const struct auto_pin_cfg *cfg)
5181{
5182 char name[32];
5183 static const char *chname[3] = { "Front", "Surround", "C/LFE" };
5184 hda_nid_t nid_vols[] = {0x10, 0x11, 0x25};
5185 hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x27};
5186 hda_nid_t nid, nid_vol, nid_mute;
5187 int i, err;
5188
5189 for (i = 0; i <= AUTO_SEQ_CENLFE; i++) {
5190 nid = cfg->line_out_pins[i];
5191
5192 if (!nid)
5193 continue;
5194
5195 nid_vol = nid_vols[i];
5196 nid_mute = nid_mutes[i];
5197
5198 if (i == AUTO_SEQ_CENLFE) {
5199 err = via_add_control(
5200 spec, VIA_CTL_WIDGET_VOL,
5201 "Center Playback Volume",
5202 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
5203 if (err < 0)
5204 return err;
5205 err = via_add_control(
5206 spec, VIA_CTL_WIDGET_VOL,
5207 "LFE Playback Volume",
5208 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
5209 if (err < 0)
5210 return err;
5211 err = via_add_control(
5212 spec, VIA_CTL_WIDGET_MUTE,
5213 "Center Playback Switch",
5214 HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0,
5215 HDA_OUTPUT));
5216 if (err < 0)
5217 return err;
5218 err = via_add_control(
5219 spec, VIA_CTL_WIDGET_MUTE,
5220 "LFE Playback Switch",
5221 HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0,
5222 HDA_OUTPUT));
5223 if (err < 0)
5224 return err;
5225 } else if (i == AUTO_SEQ_FRONT) {
5226
5227 err = via_add_control(
5228 spec, VIA_CTL_WIDGET_VOL,
5229 "Master Front Playback Volume",
5230 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT));
5231 if (err < 0)
5232 return err;
5233 err = via_add_control(
5234 spec, VIA_CTL_WIDGET_MUTE,
5235 "Master Front Playback Switch",
5236 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT));
5237 if (err < 0)
5238 return err;
5239
5240 sprintf(name, "%s Playback Volume", chname[i]);
5241 err = via_add_control(
5242 spec, VIA_CTL_WIDGET_VOL, name,
5243 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
5244 if (err < 0)
5245 return err;
5246 sprintf(name, "%s Playback Switch", chname[i]);
5247 err = via_add_control(
5248 spec, VIA_CTL_WIDGET_MUTE, name,
5249 HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
5250 HDA_OUTPUT));
5251 if (err < 0)
5252 return err;
5253 } else {
5254 sprintf(name, "%s Playback Volume", chname[i]);
5255 err = via_add_control(
5256 spec, VIA_CTL_WIDGET_VOL, name,
5257 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
5258 if (err < 0)
5259 return err;
5260 sprintf(name, "%s Playback Switch", chname[i]);
5261 err = via_add_control(
5262 spec, VIA_CTL_WIDGET_MUTE, name,
5263 HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
5264 HDA_OUTPUT));
5265 if (err < 0)
5266 return err;
5267 }
5268 }
5269 return 0;
5270}
5271
5272static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
5273{
5274 int err;
5275
5276 if (!pin)
5277 return 0;
5278
5279 spec->multiout.hp_nid = 0x25; /* AOW3 */
5280 spec->hp_independent_mode_index = 1;
5281
5282 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
5283 "Headphone Playback Volume",
5284 HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
5285 if (err < 0)
5286 return err;
5287
5288 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
5289 "Headphone Playback Switch",
5290 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
5291 if (err < 0)
5292 return err;
5293
5294 create_hp_imux(spec);
5295 return 0;
5296}
5297
5298/* create playback/capture controls for input pins */
5299static int vt1716S_auto_create_analog_input_ctls(struct via_spec *spec,
5300 const struct auto_pin_cfg *cfg)
5301{
5302 static char *labels[] = {
5303 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
5304 };
5305 struct hda_input_mux *imux = &spec->private_imux[0];
5306 int i, err, idx = 0;
5307
5308 /* for internal loopback recording select */
5309 imux->items[imux->num_items].label = "Stereo Mixer";
5310 imux->items[imux->num_items].index = 5;
5311 imux->num_items++;
5312
5313 for (i = 0; i < AUTO_PIN_LAST; i++) {
5314 if (!cfg->input_pins[i])
5315 continue;
5316
5317 switch (cfg->input_pins[i]) {
5318 case 0x1a: /* Mic */
5319 idx = 2;
5320 break;
5321
5322 case 0x1b: /* Line In */
5323 idx = 3;
5324 break;
5325
5326 case 0x1e: /* Front Mic */
5327 idx = 4;
5328 break;
5329
5330 case 0x1f: /* CD */
5331 idx = 1;
5332 break;
5333 }
5334 err = via_new_analog_input(spec, labels[i], idx, 0x16);
5335 if (err < 0)
5336 return err;
5337 imux->items[imux->num_items].label = labels[i];
5338 imux->items[imux->num_items].index = idx-1;
5339 imux->num_items++;
5340 }
5341 return 0;
5342}
5343
5344static int vt1716S_parse_auto_config(struct hda_codec *codec)
5345{
5346 struct via_spec *spec = codec->spec;
5347 int err;
5348
5349 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
5350 if (err < 0)
5351 return err;
5352 err = vt1716S_auto_fill_dac_nids(spec, &spec->autocfg);
5353 if (err < 0)
5354 return err;
5355 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
5356 return 0; /* can't find valid BIOS pin config */
5357
5358 err = vt1716S_auto_create_multi_out_ctls(spec, &spec->autocfg);
5359 if (err < 0)
5360 return err;
5361 err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
5362 if (err < 0)
5363 return err;
5364 err = vt1716S_auto_create_analog_input_ctls(spec, &spec->autocfg);
5365 if (err < 0)
5366 return err;
5367
5368 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5369
5370 fill_dig_outs(codec);
5371
5372 if (spec->kctls.list)
5373 spec->mixers[spec->num_mixers++] = spec->kctls.list;
5374
5375 spec->input_mux = &spec->private_imux[0];
5376
5377 if (spec->hp_mux)
5378 spec->mixers[spec->num_mixers++] = via_hp_mixer;
5379
5380 spec->mixers[spec->num_mixers++] = via_smart51_mixer;
5381
5382 return 1;
5383}
5384
5385#ifdef CONFIG_SND_HDA_POWER_SAVE
5386static struct hda_amp_list vt1716S_loopbacks[] = {
5387 { 0x16, HDA_INPUT, 1 },
5388 { 0x16, HDA_INPUT, 2 },
5389 { 0x16, HDA_INPUT, 3 },
5390 { 0x16, HDA_INPUT, 4 },
5391 { } /* end */
5392};
5393#endif
5394
5395static int patch_vt1716S(struct hda_codec *codec)
5396{
5397 struct via_spec *spec;
5398 int err;
5399
5400 /* create a codec specific record */
5401 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5402 if (spec == NULL)
5403 return -ENOMEM;
5404
5405 codec->spec = spec;
5406
5407 /* automatic parse from the BIOS config */
5408 err = vt1716S_parse_auto_config(codec);
5409 if (err < 0) {
5410 via_free(codec);
5411 return err;
5412 } else if (!err) {
5413 printk(KERN_INFO "hda_codec: Cannot set up configuration "
5414 "from BIOS. Using genenic mode...\n");
5415 }
5416
5417 spec->init_verbs[spec->num_iverbs++] = vt1716S_volume_init_verbs;
5418 spec->init_verbs[spec->num_iverbs++] = vt1716S_uniwill_init_verbs;
5419
5420 spec->stream_name_analog = "VT1716S Analog";
5421 spec->stream_analog_playback = &vt1716S_pcm_analog_playback;
5422 spec->stream_analog_capture = &vt1716S_pcm_analog_capture;
5423
5424 spec->stream_name_digital = "VT1716S Digital";
5425 spec->stream_digital_playback = &vt1716S_pcm_digital_playback;
5426
5427 if (!spec->adc_nids && spec->input_mux) {
5428 spec->adc_nids = vt1716S_adc_nids;
5429 spec->num_adc_nids = ARRAY_SIZE(vt1716S_adc_nids);
5430 get_mux_nids(codec);
5431 override_mic_boost(codec, 0x1a, 0, 3, 40);
5432 override_mic_boost(codec, 0x1e, 0, 3, 40);
5433 spec->mixers[spec->num_mixers] = vt1716S_capture_mixer;
5434 spec->num_mixers++;
5435 }
5436
5437 spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer;
5438 spec->num_mixers++;
5439
5440 spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer;
5441
5442 codec->patch_ops = via_patch_ops;
5443
5444 codec->patch_ops.init = via_auto_init;
Stephen Rothwell0f483272009-10-12 15:56:17 +11005445 codec->patch_ops.unsol_event = via_unsol_event;
Lydia Wangf3db4232009-10-10 19:08:41 +08005446
5447#ifdef CONFIG_SND_HDA_POWER_SAVE
5448 spec->loopback.amplist = vt1716S_loopbacks;
5449#endif
5450
5451 return 0;
5452}
Lydia Wang25eaba22009-10-10 19:08:43 +08005453
5454/* for vt2002P */
5455
5456/* capture mixer elements */
5457static struct snd_kcontrol_new vt2002P_capture_mixer[] = {
5458 HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
5459 HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
5460 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
5461 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
5462 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
5463 HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0,
5464 HDA_INPUT),
5465 {
5466 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5467 /* The multiple "Capture Source" controls confuse alsamixer
5468 * So call somewhat different..
5469 */
5470 /* .name = "Capture Source", */
5471 .name = "Input Source",
5472 .count = 2,
5473 .info = via_mux_enum_info,
5474 .get = via_mux_enum_get,
5475 .put = via_mux_enum_put,
5476 },
5477 { } /* end */
5478};
5479
5480static struct hda_verb vt2002P_volume_init_verbs[] = {
5481 /*
5482 * Unmute ADC0-1 and set the default input to mic-in
5483 */
5484 {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5485 {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5486
5487
5488 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5489 * mixer widget
5490 */
5491 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
5492 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5493 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5494 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5495 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5496 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5497
5498 /* MUX Indices: Mic = 0 */
5499 {0x1e, AC_VERB_SET_CONNECT_SEL, 0},
5500 {0x1f, AC_VERB_SET_CONNECT_SEL, 0},
5501
5502 /* PW9 Output enable */
5503 {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
5504
5505 /* Enable Boost Volume backdoor */
5506 {0x1, 0xfb9, 0x24},
5507
5508 /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
5509 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5510 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5511 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5512 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5513 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5514 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5515 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5516 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5517
5518 /* set MUX0/1/4/8 = 0 (AOW0) */
5519 {0x34, AC_VERB_SET_CONNECT_SEL, 0},
5520 {0x35, AC_VERB_SET_CONNECT_SEL, 0},
5521 {0x37, AC_VERB_SET_CONNECT_SEL, 0},
5522 {0x3b, AC_VERB_SET_CONNECT_SEL, 0},
5523
5524 /* set PW0 index=0 (MW0) */
5525 {0x24, AC_VERB_SET_CONNECT_SEL, 0},
5526
5527 /* Enable AOW0 to MW9 */
5528 {0x1, 0xfb8, 0x88},
5529 { }
5530};
5531
5532
5533static struct hda_verb vt2002P_uniwill_init_verbs[] = {
5534 {0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
5535 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
5536 {0x26, AC_VERB_SET_UNSOLICITED_ENABLE,
5537 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
5538 {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5539 {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5540 {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5541 { }
5542};
5543
5544static struct hda_pcm_stream vt2002P_pcm_analog_playback = {
5545 .substreams = 2,
5546 .channels_min = 2,
5547 .channels_max = 2,
5548 .nid = 0x8, /* NID to query formats and rates */
5549 .ops = {
5550 .open = via_playback_pcm_open,
5551 .prepare = via_playback_multi_pcm_prepare,
5552 .cleanup = via_playback_multi_pcm_cleanup,
5553 .close = via_pcm_open_close,
5554 },
5555};
5556
5557static struct hda_pcm_stream vt2002P_pcm_analog_capture = {
5558 .substreams = 2,
5559 .channels_min = 2,
5560 .channels_max = 2,
5561 .nid = 0x10, /* NID to query formats and rates */
5562 .ops = {
5563 .open = via_pcm_open_close,
5564 .prepare = via_capture_pcm_prepare,
5565 .cleanup = via_capture_pcm_cleanup,
5566 .close = via_pcm_open_close,
5567 },
5568};
5569
5570static struct hda_pcm_stream vt2002P_pcm_digital_playback = {
5571 .substreams = 1,
5572 .channels_min = 2,
5573 .channels_max = 2,
Lydia Wang25eaba22009-10-10 19:08:43 +08005574 /* NID is set in via_build_pcms */
5575 .ops = {
5576 .open = via_dig_playback_pcm_open,
5577 .close = via_dig_playback_pcm_close,
5578 .prepare = via_dig_playback_pcm_prepare,
5579 .cleanup = via_dig_playback_pcm_cleanup
5580 },
5581};
5582
5583/* fill in the dac_nids table from the parsed pin configuration */
5584static int vt2002P_auto_fill_dac_nids(struct via_spec *spec,
5585 const struct auto_pin_cfg *cfg)
5586{
5587 spec->multiout.num_dacs = 1;
5588 spec->multiout.dac_nids = spec->private_dac_nids;
5589 if (cfg->line_out_pins[0])
5590 spec->multiout.dac_nids[0] = 0x8;
5591 return 0;
5592}
5593
5594/* add playback controls from the parsed DAC table */
5595static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec,
5596 const struct auto_pin_cfg *cfg)
5597{
5598 int err;
5599
5600 if (!cfg->line_out_pins[0])
5601 return -1;
5602
5603
5604 /* Line-Out: PortE */
5605 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
5606 "Master Front Playback Volume",
5607 HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT));
5608 if (err < 0)
5609 return err;
5610 err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
5611 "Master Front Playback Switch",
5612 HDA_COMPOSE_AMP_VAL(0x26, 3, 0, HDA_OUTPUT));
5613 if (err < 0)
5614 return err;
5615
5616 return 0;
5617}
5618
5619static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
5620{
5621 int err;
5622
5623 if (!pin)
5624 return 0;
5625
5626 spec->multiout.hp_nid = 0x9;
5627 spec->hp_independent_mode_index = 1;
5628
5629 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
5630 "Headphone Playback Volume",
5631 HDA_COMPOSE_AMP_VAL(
5632 spec->multiout.hp_nid, 3, 0, HDA_OUTPUT));
5633 if (err < 0)
5634 return err;
5635
5636 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
5637 "Headphone Playback Switch",
5638 HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
5639 if (err < 0)
5640 return err;
5641
5642 create_hp_imux(spec);
5643 return 0;
5644}
5645
5646/* create playback/capture controls for input pins */
5647static int vt2002P_auto_create_analog_input_ctls(struct via_spec *spec,
5648 const struct auto_pin_cfg *cfg)
5649{
5650 static char *labels[] = {
5651 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
5652 };
5653 struct hda_input_mux *imux = &spec->private_imux[0];
5654 int i, err, idx = 0;
5655
5656 for (i = 0; i < AUTO_PIN_LAST; i++) {
5657 if (!cfg->input_pins[i])
5658 continue;
5659
5660 switch (cfg->input_pins[i]) {
5661 case 0x2b: /* Mic */
5662 idx = 0;
5663 break;
5664
5665 case 0x2a: /* Line In */
5666 idx = 1;
5667 break;
5668
5669 case 0x29: /* Front Mic */
5670 idx = 2;
5671 break;
5672 }
5673 err = via_new_analog_input(spec, labels[i], idx, 0x21);
5674 if (err < 0)
5675 return err;
5676 imux->items[imux->num_items].label = labels[i];
5677 imux->items[imux->num_items].index = idx;
5678 imux->num_items++;
5679 }
5680
5681 /* build volume/mute control of loopback */
5682 err = via_new_analog_input(spec, "Stereo Mixer", 3, 0x21);
5683 if (err < 0)
5684 return err;
5685
5686 /* for internal loopback recording select */
5687 imux->items[imux->num_items].label = "Stereo Mixer";
5688 imux->items[imux->num_items].index = 3;
5689 imux->num_items++;
5690
5691 /* for digital mic select */
5692 imux->items[imux->num_items].label = "Digital Mic";
5693 imux->items[imux->num_items].index = 4;
5694 imux->num_items++;
5695
5696 return 0;
5697}
5698
5699static int vt2002P_parse_auto_config(struct hda_codec *codec)
5700{
5701 struct via_spec *spec = codec->spec;
5702 int err;
5703
5704
5705 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
5706 if (err < 0)
5707 return err;
5708
5709 err = vt2002P_auto_fill_dac_nids(spec, &spec->autocfg);
5710 if (err < 0)
5711 return err;
5712
5713 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
5714 return 0; /* can't find valid BIOS pin config */
5715
5716 err = vt2002P_auto_create_multi_out_ctls(spec, &spec->autocfg);
5717 if (err < 0)
5718 return err;
5719 err = vt2002P_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
5720 if (err < 0)
5721 return err;
5722 err = vt2002P_auto_create_analog_input_ctls(spec, &spec->autocfg);
5723 if (err < 0)
5724 return err;
5725
5726 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5727
5728 fill_dig_outs(codec);
5729
5730 if (spec->kctls.list)
5731 spec->mixers[spec->num_mixers++] = spec->kctls.list;
5732
5733 spec->input_mux = &spec->private_imux[0];
5734
5735 if (spec->hp_mux)
5736 spec->mixers[spec->num_mixers++] = via_hp_mixer;
5737
5738 return 1;
5739}
5740
5741#ifdef CONFIG_SND_HDA_POWER_SAVE
5742static struct hda_amp_list vt2002P_loopbacks[] = {
5743 { 0x21, HDA_INPUT, 0 },
5744 { 0x21, HDA_INPUT, 1 },
5745 { 0x21, HDA_INPUT, 2 },
5746 { } /* end */
5747};
5748#endif
5749
5750
5751/* patch for vt2002P */
5752static int patch_vt2002P(struct hda_codec *codec)
5753{
5754 struct via_spec *spec;
5755 int err;
5756
5757 /* create a codec specific record */
5758 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5759 if (spec == NULL)
5760 return -ENOMEM;
5761
5762 codec->spec = spec;
5763
5764 /* automatic parse from the BIOS config */
5765 err = vt2002P_parse_auto_config(codec);
5766 if (err < 0) {
5767 via_free(codec);
5768 return err;
5769 } else if (!err) {
5770 printk(KERN_INFO "hda_codec: Cannot set up configuration "
5771 "from BIOS. Using genenic mode...\n");
5772 }
5773
5774 spec->init_verbs[spec->num_iverbs++] = vt2002P_volume_init_verbs;
5775 spec->init_verbs[spec->num_iverbs++] = vt2002P_uniwill_init_verbs;
5776
5777 spec->stream_name_analog = "VT2002P Analog";
5778 spec->stream_analog_playback = &vt2002P_pcm_analog_playback;
5779 spec->stream_analog_capture = &vt2002P_pcm_analog_capture;
5780
5781 spec->stream_name_digital = "VT2002P Digital";
5782 spec->stream_digital_playback = &vt2002P_pcm_digital_playback;
5783
5784 if (!spec->adc_nids && spec->input_mux) {
5785 spec->adc_nids = vt2002P_adc_nids;
5786 spec->num_adc_nids = ARRAY_SIZE(vt2002P_adc_nids);
5787 get_mux_nids(codec);
5788 override_mic_boost(codec, 0x2b, 0, 3, 40);
5789 override_mic_boost(codec, 0x29, 0, 3, 40);
5790 spec->mixers[spec->num_mixers] = vt2002P_capture_mixer;
5791 spec->num_mixers++;
5792 }
5793
5794 codec->patch_ops = via_patch_ops;
5795
5796 codec->patch_ops.init = via_auto_init;
Stephen Rothwell0f483272009-10-12 15:56:17 +11005797 codec->patch_ops.unsol_event = via_unsol_event;
Lydia Wang25eaba22009-10-10 19:08:43 +08005798
5799#ifdef CONFIG_SND_HDA_POWER_SAVE
5800 spec->loopback.amplist = vt2002P_loopbacks;
5801#endif
5802
5803 return 0;
5804}
Lydia Wangab6734e2009-10-10 19:08:46 +08005805
5806/* for vt1812 */
5807
5808/* capture mixer elements */
5809static struct snd_kcontrol_new vt1812_capture_mixer[] = {
5810 HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
5811 HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
5812 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
5813 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
5814 HDA_CODEC_MUTE("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
5815 HDA_CODEC_MUTE("Front Mic Boost Capture Volume", 0x29, 0x0,
5816 HDA_INPUT),
5817 {
5818 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5819 /* The multiple "Capture Source" controls confuse alsamixer
5820 * So call somewhat different..
5821 */
5822 .name = "Input Source",
5823 .count = 2,
5824 .info = via_mux_enum_info,
5825 .get = via_mux_enum_get,
5826 .put = via_mux_enum_put,
5827 },
5828 { } /* end */
5829};
5830
5831static struct hda_verb vt1812_volume_init_verbs[] = {
5832 /*
5833 * Unmute ADC0-1 and set the default input to mic-in
5834 */
5835 {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5836 {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5837
5838
5839 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5840 * mixer widget
5841 */
5842 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
5843 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5844 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5845 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5846 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5847 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5848
5849 /* MUX Indices: Mic = 0 */
5850 {0x1e, AC_VERB_SET_CONNECT_SEL, 0},
5851 {0x1f, AC_VERB_SET_CONNECT_SEL, 0},
5852
5853 /* PW9 Output enable */
5854 {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
5855
5856 /* Enable Boost Volume backdoor */
5857 {0x1, 0xfb9, 0x24},
5858
5859 /* MW0/1/4/13/15: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
5860 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5861 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5862 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5863 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5864 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5865 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5866 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5867 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5868 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5869 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5870
5871 /* set MUX0/1/4/13/15 = 0 (AOW0) */
5872 {0x34, AC_VERB_SET_CONNECT_SEL, 0},
5873 {0x35, AC_VERB_SET_CONNECT_SEL, 0},
5874 {0x38, AC_VERB_SET_CONNECT_SEL, 0},
5875 {0x3c, AC_VERB_SET_CONNECT_SEL, 0},
5876 {0x3d, AC_VERB_SET_CONNECT_SEL, 0},
5877
5878 /* Enable AOW0 to MW9 */
5879 {0x1, 0xfb8, 0xa8},
5880 { }
5881};
5882
5883
5884static struct hda_verb vt1812_uniwill_init_verbs[] = {
5885 {0x33, AC_VERB_SET_UNSOLICITED_ENABLE,
5886 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
5887 {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT },
5888 {0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
5889 AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
5890 {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5891 {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5892 {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
5893 { }
5894};
5895
5896static struct hda_pcm_stream vt1812_pcm_analog_playback = {
5897 .substreams = 2,
5898 .channels_min = 2,
5899 .channels_max = 2,
5900 .nid = 0x8, /* NID to query formats and rates */
5901 .ops = {
5902 .open = via_playback_pcm_open,
5903 .prepare = via_playback_multi_pcm_prepare,
5904 .cleanup = via_playback_multi_pcm_cleanup,
5905 .close = via_pcm_open_close,
5906 },
5907};
5908
5909static struct hda_pcm_stream vt1812_pcm_analog_capture = {
5910 .substreams = 2,
5911 .channels_min = 2,
5912 .channels_max = 2,
5913 .nid = 0x10, /* NID to query formats and rates */
5914 .ops = {
5915 .open = via_pcm_open_close,
5916 .prepare = via_capture_pcm_prepare,
5917 .cleanup = via_capture_pcm_cleanup,
5918 .close = via_pcm_open_close,
5919 },
5920};
5921
5922static struct hda_pcm_stream vt1812_pcm_digital_playback = {
5923 .substreams = 1,
5924 .channels_min = 2,
5925 .channels_max = 2,
Lydia Wangab6734e2009-10-10 19:08:46 +08005926 /* NID is set in via_build_pcms */
5927 .ops = {
5928 .open = via_dig_playback_pcm_open,
5929 .close = via_dig_playback_pcm_close,
5930 .prepare = via_dig_playback_pcm_prepare,
5931 .cleanup = via_dig_playback_pcm_cleanup
5932 },
5933};
5934/* fill in the dac_nids table from the parsed pin configuration */
5935static int vt1812_auto_fill_dac_nids(struct via_spec *spec,
5936 const struct auto_pin_cfg *cfg)
5937{
5938 spec->multiout.num_dacs = 1;
5939 spec->multiout.dac_nids = spec->private_dac_nids;
5940 if (cfg->line_out_pins[0])
5941 spec->multiout.dac_nids[0] = 0x8;
5942 return 0;
5943}
5944
5945
5946/* add playback controls from the parsed DAC table */
5947static int vt1812_auto_create_multi_out_ctls(struct via_spec *spec,
5948 const struct auto_pin_cfg *cfg)
5949{
5950 int err;
5951
5952 if (!cfg->line_out_pins[0])
5953 return -1;
5954
5955 /* Line-Out: PortE */
5956 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
5957 "Master Front Playback Volume",
5958 HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT));
5959 if (err < 0)
5960 return err;
5961 err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
5962 "Master Front Playback Switch",
5963 HDA_COMPOSE_AMP_VAL(0x28, 3, 0, HDA_OUTPUT));
5964 if (err < 0)
5965 return err;
5966
5967 return 0;
5968}
5969
5970static int vt1812_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
5971{
5972 int err;
5973
5974 if (!pin)
5975 return 0;
5976
5977 spec->multiout.hp_nid = 0x9;
5978 spec->hp_independent_mode_index = 1;
5979
5980
5981 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
5982 "Headphone Playback Volume",
5983 HDA_COMPOSE_AMP_VAL(
5984 spec->multiout.hp_nid, 3, 0, HDA_OUTPUT));
5985 if (err < 0)
5986 return err;
5987
5988 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
5989 "Headphone Playback Switch",
5990 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
5991 if (err < 0)
5992 return err;
5993
5994 create_hp_imux(spec);
5995 return 0;
5996}
5997
5998/* create playback/capture controls for input pins */
5999static int vt1812_auto_create_analog_input_ctls(struct via_spec *spec,
6000 const struct auto_pin_cfg *cfg)
6001{
6002 static char *labels[] = {
6003 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
6004 };
6005 struct hda_input_mux *imux = &spec->private_imux[0];
6006 int i, err, idx = 0;
6007
6008 for (i = 0; i < AUTO_PIN_LAST; i++) {
6009 if (!cfg->input_pins[i])
6010 continue;
6011
6012 switch (cfg->input_pins[i]) {
6013 case 0x2b: /* Mic */
6014 idx = 0;
6015 break;
6016
6017 case 0x2a: /* Line In */
6018 idx = 1;
6019 break;
6020
6021 case 0x29: /* Front Mic */
6022 idx = 2;
6023 break;
6024 }
6025 err = via_new_analog_input(spec, labels[i], idx, 0x21);
6026 if (err < 0)
6027 return err;
6028 imux->items[imux->num_items].label = labels[i];
6029 imux->items[imux->num_items].index = idx;
6030 imux->num_items++;
6031 }
6032 /* build volume/mute control of loopback */
6033 err = via_new_analog_input(spec, "Stereo Mixer", 5, 0x21);
6034 if (err < 0)
6035 return err;
6036
6037 /* for internal loopback recording select */
6038 imux->items[imux->num_items].label = "Stereo Mixer";
6039 imux->items[imux->num_items].index = 5;
6040 imux->num_items++;
6041
6042 /* for digital mic select */
6043 imux->items[imux->num_items].label = "Digital Mic";
6044 imux->items[imux->num_items].index = 6;
6045 imux->num_items++;
6046
6047 return 0;
6048}
6049
6050static int vt1812_parse_auto_config(struct hda_codec *codec)
6051{
6052 struct via_spec *spec = codec->spec;
6053 int err;
6054
6055
6056 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
6057 if (err < 0)
6058 return err;
6059 fill_dig_outs(codec);
6060 err = vt1812_auto_fill_dac_nids(spec, &spec->autocfg);
6061 if (err < 0)
6062 return err;
6063
6064 if (!spec->autocfg.line_outs && !spec->autocfg.hp_outs)
6065 return 0; /* can't find valid BIOS pin config */
6066
6067 err = vt1812_auto_create_multi_out_ctls(spec, &spec->autocfg);
6068 if (err < 0)
6069 return err;
6070 err = vt1812_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
6071 if (err < 0)
6072 return err;
6073 err = vt1812_auto_create_analog_input_ctls(spec, &spec->autocfg);
6074 if (err < 0)
6075 return err;
6076
6077 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
6078
6079 fill_dig_outs(codec);
6080
6081 if (spec->kctls.list)
6082 spec->mixers[spec->num_mixers++] = spec->kctls.list;
6083
6084 spec->input_mux = &spec->private_imux[0];
6085
6086 if (spec->hp_mux)
6087 spec->mixers[spec->num_mixers++] = via_hp_mixer;
6088
6089 return 1;
6090}
6091
6092#ifdef CONFIG_SND_HDA_POWER_SAVE
6093static struct hda_amp_list vt1812_loopbacks[] = {
6094 { 0x21, HDA_INPUT, 0 },
6095 { 0x21, HDA_INPUT, 1 },
6096 { 0x21, HDA_INPUT, 2 },
6097 { } /* end */
6098};
6099#endif
6100
6101
6102/* patch for vt1812 */
6103static int patch_vt1812(struct hda_codec *codec)
6104{
6105 struct via_spec *spec;
6106 int err;
6107
6108 /* create a codec specific record */
6109 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
6110 if (spec == NULL)
6111 return -ENOMEM;
6112
6113 codec->spec = spec;
6114
6115 /* automatic parse from the BIOS config */
6116 err = vt1812_parse_auto_config(codec);
6117 if (err < 0) {
6118 via_free(codec);
6119 return err;
6120 } else if (!err) {
6121 printk(KERN_INFO "hda_codec: Cannot set up configuration "
6122 "from BIOS. Using genenic mode...\n");
6123 }
6124
6125
6126 spec->init_verbs[spec->num_iverbs++] = vt1812_volume_init_verbs;
6127 spec->init_verbs[spec->num_iverbs++] = vt1812_uniwill_init_verbs;
6128
6129 spec->stream_name_analog = "VT1812 Analog";
6130 spec->stream_analog_playback = &vt1812_pcm_analog_playback;
6131 spec->stream_analog_capture = &vt1812_pcm_analog_capture;
6132
6133 spec->stream_name_digital = "VT1812 Digital";
6134 spec->stream_digital_playback = &vt1812_pcm_digital_playback;
6135
6136
6137 if (!spec->adc_nids && spec->input_mux) {
6138 spec->adc_nids = vt1812_adc_nids;
6139 spec->num_adc_nids = ARRAY_SIZE(vt1812_adc_nids);
6140 get_mux_nids(codec);
6141 override_mic_boost(codec, 0x2b, 0, 3, 40);
6142 override_mic_boost(codec, 0x29, 0, 3, 40);
6143 spec->mixers[spec->num_mixers] = vt1812_capture_mixer;
6144 spec->num_mixers++;
6145 }
6146
6147 codec->patch_ops = via_patch_ops;
6148
6149 codec->patch_ops.init = via_auto_init;
Stephen Rothwell0f483272009-10-12 15:56:17 +11006150 codec->patch_ops.unsol_event = via_unsol_event;
Lydia Wangab6734e2009-10-10 19:08:46 +08006151
6152#ifdef CONFIG_SND_HDA_POWER_SAVE
6153 spec->loopback.amplist = vt1812_loopbacks;
6154#endif
6155
6156 return 0;
6157}
6158
Joseph Chanc577b8a2006-11-29 15:29:40 +01006159/*
6160 * patch entries
6161 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +01006162static struct hda_codec_preset snd_hda_preset_via[] = {
Takashi Iwai3218c172008-12-18 09:17:56 +01006163 { .id = 0x11061708, .name = "VT1708", .patch = patch_vt1708},
6164 { .id = 0x11061709, .name = "VT1708", .patch = patch_vt1708},
6165 { .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708},
6166 { .id = 0x1106170b, .name = "VT1708", .patch = patch_vt1708},
6167 { .id = 0x1106e710, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006168 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006169 { .id = 0x1106e711, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006170 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006171 { .id = 0x1106e712, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006172 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006173 { .id = 0x1106e713, .name = "VT1709 10-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006174 .patch = patch_vt1709_10ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006175 { .id = 0x1106e714, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006176 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006177 { .id = 0x1106e715, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006178 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006179 { .id = 0x1106e716, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006180 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006181 { .id = 0x1106e717, .name = "VT1709 6-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006182 .patch = patch_vt1709_6ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006183 { .id = 0x1106e720, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006184 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006185 { .id = 0x1106e721, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006186 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006187 { .id = 0x1106e722, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006188 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006189 { .id = 0x1106e723, .name = "VT1708B 8-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006190 .patch = patch_vt1708B_8ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006191 { .id = 0x1106e724, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006192 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006193 { .id = 0x1106e725, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006194 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006195 { .id = 0x1106e726, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006196 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006197 { .id = 0x1106e727, .name = "VT1708B 4-Ch",
Josepch Chanf7278fd2007-12-13 16:40:40 +01006198 .patch = patch_vt1708B_4ch},
Takashi Iwai3218c172008-12-18 09:17:56 +01006199 { .id = 0x11060397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08006200 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01006201 { .id = 0x11061397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08006202 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01006203 { .id = 0x11062397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08006204 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01006205 { .id = 0x11063397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08006206 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01006207 { .id = 0x11064397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08006208 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01006209 { .id = 0x11065397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08006210 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01006211 { .id = 0x11066397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08006212 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01006213 { .id = 0x11067397, .name = "VT1708S",
Harald Welted949cac2008-09-09 15:56:01 +08006214 .patch = patch_vt1708S},
Takashi Iwai3218c172008-12-18 09:17:56 +01006215 { .id = 0x11060398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08006216 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01006217 { .id = 0x11061398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08006218 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01006219 { .id = 0x11062398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08006220 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01006221 { .id = 0x11063398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08006222 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01006223 { .id = 0x11064398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08006224 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01006225 { .id = 0x11065398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08006226 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01006227 { .id = 0x11066398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08006228 .patch = patch_vt1702},
Takashi Iwai3218c172008-12-18 09:17:56 +01006229 { .id = 0x11067398, .name = "VT1702",
Harald Welted949cac2008-09-09 15:56:01 +08006230 .patch = patch_vt1702},
Lydia Wangeb7188c2009-10-10 19:08:34 +08006231 { .id = 0x11060428, .name = "VT1718S",
6232 .patch = patch_vt1718S},
6233 { .id = 0x11064428, .name = "VT1718S",
6234 .patch = patch_vt1718S},
Lydia Wangbb3c6bfc2009-10-10 19:08:39 +08006235 { .id = 0x11060441, .name = "VT2020",
6236 .patch = patch_vt1718S},
6237 { .id = 0x11064441, .name = "VT1828S",
6238 .patch = patch_vt1718S},
Lydia Wangf3db4232009-10-10 19:08:41 +08006239 { .id = 0x11060433, .name = "VT1716S",
6240 .patch = patch_vt1716S},
6241 { .id = 0x1106a721, .name = "VT1716S",
6242 .patch = patch_vt1716S},
Lydia Wang25eaba22009-10-10 19:08:43 +08006243 { .id = 0x11060438, .name = "VT2002P", .patch = patch_vt2002P},
6244 { .id = 0x11064438, .name = "VT2002P", .patch = patch_vt2002P},
Lydia Wangab6734e2009-10-10 19:08:46 +08006245 { .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812},
Lydia Wang36dd5c42009-10-20 13:18:04 +08006246 { .id = 0x11060440, .name = "VT1818S",
6247 .patch = patch_vt1708S},
Joseph Chanc577b8a2006-11-29 15:29:40 +01006248 {} /* terminator */
6249};
Takashi Iwai1289e9e2008-11-27 15:47:11 +01006250
6251MODULE_ALIAS("snd-hda-codec-id:1106*");
6252
6253static struct hda_codec_preset_list via_list = {
6254 .preset = snd_hda_preset_via,
6255 .owner = THIS_MODULE,
6256};
6257
6258MODULE_LICENSE("GPL");
6259MODULE_DESCRIPTION("VIA HD-audio codec");
6260
6261static int __init patch_via_init(void)
6262{
6263 return snd_hda_add_codec_preset(&via_list);
6264}
6265
6266static void __exit patch_via_exit(void)
6267{
6268 snd_hda_delete_codec_preset(&via_list);
6269}
6270
6271module_init(patch_via_init)
6272module_exit(patch_via_exit)